Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal/devconfig: add PackageSpec for parsing package strings #1878

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

gcurtis
Copy link
Collaborator

@gcurtis gcurtis commented Mar 6, 2024

Attempt to formalize raw Devbox package strings (hereby called package specs) by introducing a new PackageSpec type.

This commit just adds the new parsing logic, it doesn't integrate it with any other code yet. The PackageSpec type is the result of parsing a raw string with ParsePackageSpec:

type PackageSpec struct {
	Name, Version       string
	Installable         flake.Installable
	AttrPathInstallable flake.Installable
	RunX                types.PkgRef
}

func ParsePackageSpec(raw, nixpkgsCommit string) PackageSpec

When a package spec is ambiguous, ParsePackageSpec will populate the PackageSpec fields with all possible interpretations. For example, the spec go could be go@latest, a flake named go, or the attribute path nixpkgs#go. It's up to a resolver to try them in some priority order and pick one.

Attempt to formalize raw Devbox package strings (hereby called package
specs) by introducing a new `PackageSpec` type.

This commit just adds the new parsing logic, it doesn't integrate it
with any other code yet. The `PackageSpec` type is the result of parsing
a raw string with `ParsePackageSpec`:

	type PackageSpec struct {
		Name, Version       string
		Installable         flake.Installable
		AttrPathInstallable flake.Installable
		RunX                types.PkgRef
	}

	func ParsePackageSpec(raw, nixpkgsCommit string) PackageSpec

When a package spec is ambiguous, `ParsePackageSpec` will populate the
`PackageSpec` fields with all possible interpretations. For example, the
spec `go` could be `go@latest`, a flake named `go`, or the attribute
path `nixpkgs#go`. It's up to a resolver to try them in some priority
order and pick one.
@gcurtis gcurtis requested review from savil and mikeland73 March 6, 2024 23:13
Copy link
Contributor

@mikeland73 mikeland73 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be really nice to have. Take a look at comments before we settle on parsing implementation.

Comment on lines +375 to +386
// | Syntax | Example | Description |
// | ---------------- | --------------------------- | ------------------------------------ |
// | name@version | [email protected] | Resolved w/ search service |
// | name | go | Same as above; implies @latest |
// | flake | github:/nixos/nixpkgs#go | Matches Nix installable syntax |
// | attr path | go | Equivalent to flake:nixpkgs#go |
// | legacy attr path | go | Uses deprecated nixpkgs.commit field |
// | runx | runx:golangci/golangci-lint | Experimental |
//
// Most package specs are ambiguous, making it impossible to tell which exact
// syntax the user intended. PackageSpec parses as many as it can and leaves it
// up to the caller to prioritize and resolve them.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should understand a string that has no version and is not a flake/runx to always mean attribute path. Thoughts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tricky part is that almost any string is a valid flake reference due to indirect flakes. Still, I’d be onboard with saying we just don’t support scheme-less indirect flakes. So whereas Nix does:

foo → flake:foo
flake:foo → flake:foo

Devbox would do:

foo → flake:nixpkgs#foo
flake:foo → flake:foo

That still leaves ambiguity between Devbox packages and attribute paths though. We can't tell if nodePackages.@angular/cli is named nodePackages.@angular/cli or named nodePackages. with version angular/cli without querying the search service.

// | Syntax | Example | Description |
// | ---------------- | --------------------------- | ------------------------------------ |
// | name@version | [email protected] | Resolved w/ search service |
// | name | go | Same as above; implies @latest |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not really valid. (or should not be). I was under impression that anything without a version is understood to mean:

nixpkgs/<hash>#attr

When someone goes devbox add go it adds go@latest to devbox.json.

If someone does devbox add stdenv.cc.cc.lib which is not in the index, then it should add stdenv.cc.cc.lib which represents nixpkgs/<hash>#stdenv.cc.cc.lib

If someone manually edits the devbox.json to add attribute paths without @version flag they get nixpkgs/<hash>#attr

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also support nixpkgs attribute path via nixpkgs#hello

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, I didn't realize that devbox add go and manually adding go to devbox.json did different things. I never would've guessed that {"packages": ["go"]} gives me an old version of Go, especially because there's no nixpkgs.commit field.

Could we align the CLI and config to both follow the CLI's behavior of checking for an @latest version? Having the same package string mean different things depending on if it's given on the command line vs. a config is pretty confusing IMO.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder how often that @latest user is accidentally mentioned on GitHub.

// | name | go | Same as above; implies @latest |
// | flake | github:/nixos/nixpkgs#go | Matches Nix installable syntax |
// | attr path | go | Equivalent to flake:nixpkgs#go |
// | legacy attr path | go | Uses deprecated nixpkgs.commit field |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it deprecated? We removed it because we don't really want anyone to use it. I guess our preference would be for folks to use the hash in the package they want?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, our docs say it's deprecated and will eventually be removed. I think pinning using a revision in a flake reference is clearer.

// For example, the package spec "cachix" is a Devbox package (implied @latest),
// a flake ref (cachix), and an attribute path (nixpkgs#cachix). When resolving
// the package, Devbox must pick one (most likely cachix@latest).
type PackageSpec struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit should this go in own file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants