-
Notifications
You must be signed in to change notification settings - Fork 265
[nix profile list] parse using --json in new nix version #1308
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
Conversation
Current dependencies on/for this PR:
This comment was auto-generated by Graphite. |
4189b2a
to
e90ae04
Compare
e90ae04
to
2fd0217
Compare
2fd0217
to
cf23256
Compare
internal/nix/nix.go
Outdated
|
||
// versionRegex parses the output of `nix --version` to capture the semver version string | ||
// example output: nix (Nix) 2.13.3 | ||
var versionRegex = regexp.MustCompile(`nix\s\(Nix\)\s([0-9]+.[0-9]+.[0-9]+)`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, you can use
instead of \s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should make this more forgiving. the second term should be (.*)
with trimmed space?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And then you can use strings.TrimPrefix("nix (Nix)")
to make this code simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I'll switch to TrimPrefix
internal/nix/nixprofile/profile.go
Outdated
) (map[string]*NixProfileListItem, error) { | ||
|
||
lines, err := nix.ProfileList(writer, profileDir) | ||
version, err := nix.Version() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't return error here. That puts us at a risk of failing even when we would do correct thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(e.g. what if in some past version nix --version
returned something weird, we're better off just trying with useJSON = false
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure I follow. What do you mean "failing even when we do correct thing?"
In general, I'd prefer erroring here if we fail to get the nix version properly. Otherwise, we'll error below with a more obscure error...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we fail to read the version and ignore the error, we can continue doing what we were doing before. Otherwise we'll have introduced a new error and potentially break old nix installations that were already working.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just try running nix profile list --json
and if it fails try nix profile list
(without the flag). Then you don't need to do the version comparison stuff. Example with old Nix:
$ nix profile list --json
error: unrecognised flag '--json'
Try 'nix --help' for more information.
$ nix profile list
0 flake:nixpkgs#legacyPackages.aarch64-darwin.fuse github:NixOS/nixpkgs/d0f2758381caca8b4fb4a6cac61721cc9de06bd9#legacyPackages.aarch64-darwin.fuse /nix/store/8pqmbsp8zkq8656k5yaravbaxixaaa3c-macfuse-stubs-4.4.1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a concrete example:
Imagine that in nix v2.1.0 running nix --version
returns 2.1.0
without the nix (Nix)
prefix. Then this function would return an error and we would stop execution. But in this case, version
would be ""
which would currently set useJSON
to false. So it's a case where ignoring the error would cause correct execution but returning an error would cause execution to break.
We don't want to break any old versions of nix, so I think just assuming useJSON is false if we can't parse the version is the correct way to go.
internal/nix/nixprofile/profile.go
Outdated
// if version is >= 2.17, we can use the json output | ||
useJSON := vercheck.SemverCompare(version, "2.17") >= 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use 2.17.0
(2.17 is technically not valid semver)
This defaults to false if version is not semver. Is that OK? (I think probably yes)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ugh... good point
let me check the behavior of this vercheck.SemverCompare
for 2.17
like output.
btw, do we know if nix --version
prints 2.17
or 2.17.0
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internal/nix/nixprofile/profile.go
Outdated
unlockedReference: element.OriginalURL, | ||
lockedReference: element.URL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mikeland73 do we think I got this mapping right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's not 1 to 1 on either locked or unlocked. I'm taking a look
internal/nix/nixprofile/profile.go
Outdated
} | ||
|
||
// if version is >= 2.17.0, we can use the json output | ||
useJSON := vercheck.SemverCompare(version, "2.17.0") >= 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am somewhat concerned about this failing in an unexpected way. The underlying function call will return:
// An invalid semantic version string is considered less than a valid one.
// All invalid semantic version strings compare equal to each other.
According to https://lazamar.co.uk/nix-versions/?channel=nixpkgs-unstable&package=nix, there may be some prerelease versions of nix that have non-standard semver versions.
However, these prerelease versions also appear to be rather old, and not present in newer releases of nix. So, maybe this is okay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is OK. non semver versions will be considered older which defaults to the non --json.
I think as a follow up after this PR we could:
(only use the --json
flag if we're sure version is higher (e.g. both are semver)) and then try to parse things both ways (try one and if it fails try the other)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. If we can get away with not needing to parse the version, then that would be nice.
internal/nix/nixprofile/profile.go
Outdated
) (map[string]*NixProfileListItem, error) { | ||
|
||
lines, err := nix.ProfileList(writer, profileDir) | ||
version, err := nix.Version() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just try running nix profile list --json
and if it fails try nix profile list
(without the flag). Then you don't need to do the version comparison stuff. Example with old Nix:
$ nix profile list --json
error: unrecognised flag '--json'
Try 'nix --help' for more information.
$ nix profile list
0 flake:nixpkgs#legacyPackages.aarch64-darwin.fuse github:NixOS/nixpkgs/d0f2758381caca8b4fb4a6cac61721cc9de06bd9#legacyPackages.aarch64-darwin.fuse /nix/store/8pqmbsp8zkq8656k5yaravbaxixaaa3c-macfuse-stubs-4.4.1
@gcurtis @mikeland73 PTAL: simplified to "try with --json" and "fallback to non-json way upon any error" |
internal/nix/nixprofile/profile.go
Outdated
} | ||
|
||
output, err = nix.ProfileList(writer, profileDir, false /*useJSON*/) | ||
if err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ugh, this should be err != nil
…ckedReference with json output
## Summary Since we saw CLI format change (See #1308) we should test against many nix versions. Possible followup: In `main` should we run all nix versions? ## How was it tested? CICD
Suspect IssuesThis pull request has been deployed and Sentry has observed the following issues:
Did you find this useful? React with a 👍 or 👎 |
Summary
Problem:
Latest nix version of 2.17 changes the output format of
nix profile list
to be:Previously, the "keys" didn't exist in the output. This broke how we were parsing the output.
Fix in pseudo code:
the older nix versions don't support --json
How was it tested?
in some devbox projects: