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

flake: fix lib.trivial.version when used from a flake #257100

Merged
merged 6 commits into from
Dec 11, 2023

Conversation

Ma27
Copy link
Member

@Ma27 Ma27 commented Sep 24, 2023

Description of changes

A lot of fetchers from Nix's own libfetchers also provide the information that lib.trivial aims to expose with version/versionSuffix/revision. In fact you don't even need a nixpkgs channel to get a proper version suffix because of that!

Unfortunately this isn't used currently. When using the nixpkgs flake, but not nixpkgs.lib.nixosSystem to build a NixOS configuration, the version will always be YY.MMpre-git. One example is e.g. colmena which evaluates configurations via
import (npkgs.path + "/nixos/lib/eval-config.nix").

This patch ensures that the version suffix (i.e. the normalized last modified date + git revision) is correctly exposed in lib.trivial. Additionally, the change is injected into the following locations:

  • lib: with that, something like

    $ nix eval nixpkgs#lib.trivial.version
    23.05.20230921.cf8bf79
    

    is working fine (i.e. rather than 23.05pre-git).

  • legacyPackages to make sure that e.g. legacyPackages.<system>.nixos has correct version info. This also applies to everything else using pkgs.lib.trivial for that purpose.

  • overlays.default which can be applied to a nixpkgs and changes the previous pkgs.lib from said nixpkgs to also contain the correct version/revision/etc..

    This is useful for people using nixpkgs as flake input, but importing it manually with

    import inputs.nixpkgs { }
    

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandbox = true set in nix.conf? (See Nix manual)
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 23.11 Release Notes (or backporting 23.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

@Ma27 Ma27 requested review from lheckemann and roberth September 24, 2023 15:15
@ofborg ofborg bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 0 This PR does not cause any packages to rebuild on Linux labels Sep 24, 2023
@Ma27 Ma27 force-pushed the version-info-lib branch from 7c515b3 to 9209b2e Compare October 9, 2023 15:52
Copy link
Member

@roberth roberth left a comment

Choose a reason for hiding this comment

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

Generally good idea, but not quite complete.

flake.nix Outdated
Comment on lines 26 to 20
overlays.default = final: prev: {
lib = prev.lib.extend libVersionInfoOverlay;
};
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if this should be exposed, and if so, I don't know about default - maybe setLibVersion? Shouldn't this always be pre-applied? Users shouldn't have to care about this.
I guess import nixpkgsFlake { } will not work like that, so we should provide an alternative, such as nixpkgsFlake.pkgs { }.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't know about default - maybe setLibVersion?

Yeah, that's a bad name, yours seems better.

Shouldn't this always be pre-applied? Users shouldn't have to care about this.

It is pre-applied when using inputs.nixpkgs.legacyPackages.

If you use import inputs.nixpkgs I'd expect that default.nix is evaluated in pure mode for me, i.e. no additional flake involvement.

so we should provide an alternative, such as nixpkgsFlake.pkgs { }.

I'm not sure I follow here, what exactly do you mean?

Given the expectation I described above, I think it's OK though to not apply overlays magically here. And isn't it under discussion whether import inputs.foo (i.e. as a path) should be deprecated anyways?

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed the naming of the overlay.

Won't resolve though until we're aligned on how to deal with import inputs.nixpkgs.

Copy link
Member Author

Choose a reason for hiding this comment

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

Is the naming OK and the fact that you'd have to apply this manually when doing import inputs.nixpkgs @roberth? Also, anything else to discuss / fix? :)

Copy link
Member

Choose a reason for hiding this comment

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

I think we should discourage import inputs.nixpkgs, because it just can't work well. It's just not something that can ever work as well as the actual flake outputs, unless flakes allows outPath to be a __functor function. I really don't know what to think of that... It should probably be an explicit feature of flakes and not something that allows arbitrary stuff to be put in outPath. And even then it's kind of bad because of import "${inputs.nixpkgs}".

Ignoring all that ugliness for now, I think the nixpkgs should provide a proper lib-based entrypoint into Nixpkgs, just like we have lib.nixosSystem. That way it can actually work well, and not be a strange experience. (import a flake, really?)

Some possible names

  • lib.nixpkgs: not a fan because Nixpkgs should be more than just the function that returns "pkgs"
  • lib.callNixpkgs: arbitrary enough that we don't paint ourselves into a corner just yet

We should probably get the arguments right this time, along the lines of
{ hostPlatform, buildPlatform ? hostPlatform, config , overlays }: instead of the unholy mess that we have in default.nix. Maybe default.nix should stay bad, as a motivator for people to use the better entrypoint?

(As mentioned in the review, I think we should solve all these problems in a new PR after merging this one, and not have overlays in the outputs for this)

flake.nix Outdated Show resolved Hide resolved
@Ma27 Ma27 force-pushed the version-info-lib branch from 9209b2e to 11b4242 Compare October 10, 2023 12:19
@Ma27
Copy link
Member Author

Ma27 commented Oct 18, 2023

gentle ping @roberth

@Ma27 Ma27 requested a review from roberth October 20, 2023 10:16
@github-actions github-actions bot added the 6.topic: lib The Nixpkgs function library label Oct 20, 2023
@ofborg ofborg bot added 10.rebuild-linux: 1-10 and removed 10.rebuild-linux: 0 This PR does not cause any packages to rebuild on Linux labels Oct 20, 2023
Copy link
Member

@roberth roberth left a comment

Choose a reason for hiding this comment

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

Only nit picks. Would like another reviewer to have a look.
Maybe @infinisil or @lheckemann have opinions?

lib/flake.nix Outdated Show resolved Hide resolved
lib/__flake-version-info.nix Outdated Show resolved Hide resolved
lib/__flake-version-info.nix Outdated Show resolved Hide resolved
@infinisil
Copy link
Member

I'll take a look later today 👍

Copy link
Member

@infinisil infinisil left a comment

Choose a reason for hiding this comment

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

The idea is okay, but I think it should be implemented differently.

lib/__flake-version-info.nix Outdated Show resolved Hide resolved
Comment on lines 12 to 15
versionSuffix =
".${finalLib.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")}.${self.shortRev or "dirty"}";
version = finalLib.trivial.release + finalLib.trivial.versionSuffix;
revisionWithDefault = default: self.rev or default;
Copy link
Member

@infinisil infinisil Oct 30, 2023

Choose a reason for hiding this comment

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

This is partially duplicated code and is not very re-usable. Instead we can add attributes like these to proper lib.trivial:

  • lib.trivial.lastModifiedDate (no lastModified since now Flakes always provide lastModifiedDate), defaulting to null.
  • lib.trivial.revision (maybe also a shortRev, but not necessary since it can easily be computed), defaulting to what revisionWithDefault currently defaults to.

Then there's no need to have any implementation here, because it can be moved to the original definitions for versionSuffix and revisionWithDefault. You will have to remove the rec from lib/trivial.nix though in order for version to be updated correctly.

Then this here can just be

{
  lastModifiedDate = self.lastModifiedDate;
  revision = self.rev;
}

This also allows us to test and document this functionality in lib/tests, which I really think should be done.

Copy link
Member

Choose a reason for hiding this comment

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

trivial

I don't think this is insignificant or self-evident.

re-usable

Not sure if that should be a goal here.

test and document this functionality

Good point, but lib/tests can import a file like this to achieve that.

Copy link
Member Author

Choose a reason for hiding this comment

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

like these to proper lib.trivial:

To make sure I'm not misunderstanding you: you're talking about lib/trivial.nix itself, correct?

no lastModified since now Flakes always provide lastModifiedDate

Good point. Was there for historical reasons only I guess.

You will have to remove the rec from lib/trivial.nix though in order for version to be updated correctly.

That can be done independently of the other changes you suggested here IMHO.

That said, the downside is that you'll have to touch the entire code affecting .version-suffix because that's where the {lastmodified}.{shortrev} thing actually comes from in the non-flake case.

but not necessary since it can easily be computed

Not necessarily because git IIRC determines a length that makes each short rev unique (I think hardcoding a short-rev to e.g. 8 may cause a few collisions already).

Copy link
Member

Choose a reason for hiding this comment

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

you're talking about lib/trivial.nix itself, correct?

Yes.

That said, the downside is that you'll have to touch the entire code affecting .version-suffix because that's where the {lastmodified}.{shortrev} thing actually comes from in the non-flake case.

No I'm thinking to change the definition of revisionWithDefault

nixpkgs/lib/trivial.nix

Lines 212 to 221 in 0a1051c

revisionWithDefault =
# Default value to return if revision can not be determined
default:
let
revisionFile = "${toString ./..}/.git-revision";
gitRepo = "${toString ./..}/.git";
in if lib.pathIsGitRepo gitRepo
then lib.commitIdFromGitRepo gitRepo
else if lib.pathExists revisionFile then lib.fileContents revisionFile
else default;
to have an extra if condition to use lib.trivial.revision if it's not null. But I'm not insisting on that, I think it's okay the way this PR is now.

Not necessarily because git IIRC determines a length that makes each short rev unique (I think hardcoding a short-rev to e.g. 8 may cause a few collisions already).

Ah true, I guess the short revs would still be prone to collisions over longer time though. I'd prefer a sufficiently long constant short rev length that is reasonably collision resistant for the future.

Copy link
Member Author

Choose a reason for hiding this comment

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

to have an extra if condition to use lib.trivial.revision if it's not null. But I'm not insisting on that, I think it's okay the way this PR is now.

Hmm I don't think I like that: having an attribute that only works magically when using flakes and that provides a revision despite all the other attributes for that seems unintuitive to me at best.

IMHO redesigning this version code here is another topic and the what we have here is quite an improvement already, so I'd actually prefer the current version for now.

lib/__flake-version-info.nix Outdated Show resolved Hide resolved
@Ma27 Ma27 requested a review from infinisil October 31, 2023 12:44
@Ma27
Copy link
Member Author

Ma27 commented Oct 31, 2023

Implemented a few of the suggestions, namely

  • comment improvements from @roberth
  • dropped the rec in lib/trivial.nix to spare the version = expression.
  • dropped the __-prefix from the lib overlay's filename.
  • dropped the fallback to lastModified when generating the version suffix.

Re introducing lib.trivial.lastModifiedDate/lib.trivial.revision I left a comment above because that'd mean a more significant change to nixpkgs internals that I'd like to discuss first.

As mentioned above, I'll update the documentation about the corner cases of flake's versionSuffix when everything is done (in the default case it behaves the same as when using channel tarballs).

Copy link
Member

@infinisil infinisil left a comment

Choose a reason for hiding this comment

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

Just a minor detail, this looks good to me otherwise!

flake.nix Outdated Show resolved Hide resolved
Ma27 and others added 2 commits December 9, 2023 11:45
A lot of fetchers from Nix's own `libfetchers` also provide the
information that `lib.trivial` aims to expose with
`version`/`versionSuffix`/`revision`. In fact you don't even need a
`nixpkgs` channel to get a proper version suffix because of that!

Unfortunately this isn't used currently. When using the
nixpkgs flake, but not `nixpkgs.lib.nixosSystem` to build a NixOS
configuration, the version will always be `YY.MMpre-git`. One example is
e.g. `colmena` which evaluates configurations via
`import (npkgs.path + "/nixos/lib/eval-config.nix")`.

This patch ensures that the version suffix (i.e. the normalized last
modified date + git revision) is correctly exposed in `lib.trivial`.
Additionally, the change is injected into the following locations:

* `lib`: with that, something like

      $ nix eval nixpkgs#lib.trivial.version
      23.05.20230921.cf8bf79

  is working fine (i.e. rather than `23.05pre-git`).

* `legacyPackages` to make sure that e.g. `legacyPackages.<system>.nixos`
  has correct version info. This also applies to everything else using
  `pkgs.lib.trivial` for that purpose.

* `overlays.default` which can be applied to a `nixpkgs` and changes the
  previous `pkgs.lib` from said `nixpkgs` to also contain the correct
  `version`/`revision`/etc..

  This is useful for people using `nixpkgs` as flake input, but
  importing it manually with

      import inputs.nixpkgs { }

Co-authored-by: Linus Heckemann <git@sphalerite.org>
This effectively means that

    nixpkgs$ nix eval ./lib#lib.trivial.version
    "23.11.20231020.ee0d6b5"

now gives meaningful results as well.

See NixOS#257100 (comment)
for the discussion around this.
@Ma27 Ma27 force-pushed the version-info-lib branch from 16579eb to 29ede03 Compare December 9, 2023 10:59
@github-actions github-actions bot added the 6.topic: flakes The experimental Nix feature label Dec 9, 2023
@Ma27
Copy link
Member Author

Ma27 commented Dec 9, 2023

Fixed @infinisil's remark, rebased onto master and also fixed an evaluation error in trivial.nix (I dropped the rec in there and a newly added function (mirrorFunctionArgs) broke because of that).

Any final remarks or can we merge @roberth @lheckemann @infinisil ?

Copy link
Member

@roberth roberth left a comment

Choose a reason for hiding this comment

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

Can merge after implementing the suggestions.

Scoping out nixpkgs entrypoint problems for now.

lib/trivial.nix Outdated
@@ -446,7 +446,7 @@ rec {
annotated with function args.
*/
isFunction = f: builtins.isFunction f ||
(f ? __functor && isFunction (f.__functor f));
(f ? __functor && lib.trivial.isFunction (f.__functor f));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
(f ? __functor && lib.trivial.isFunction (f.__functor f));
(f ? __functor && isFunction (f.__functor f));

Performance regression. Use let inherit (lib) isFunction; near start of file.

Copy link
Member

Choose a reason for hiding this comment

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

Please do the same for the rest - at least for everything that doesn't perform I/O like warn.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

Btw I'm curious, is "dereferencing" an attribute-set really that more expensive? (not that deep into the evaluator I must admit 😅 )

Copy link
Member

@roberth roberth Dec 10, 2023

Choose a reason for hiding this comment

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

Generally no, it'd only be measurable if it's in a hot path, but functions like isFunction probably are. Not worth risking.
Also less noise.

flake.nix Outdated Show resolved Hide resolved
Ma27 and others added 2 commits December 10, 2023 13:25
That way each expression uses the final version of other lib.trivial
declarations.

For instance, when replacing `versionSuffix` with the string `"fnord"`
in a lib overlay, `trivial.version` uses `"fnord"` as suffix now rather
than `pre-git`.
* Improves the comments of `lib/flake-version-info.nix` and drops the
  `__`-prefix from the filename.
* `lib'` -> `lib0` in `nixpkgs/lib`.
* Drop the declaration of `trivial.version` in the overlay because this
  declaration already uses the final expressions of `versionSuffix` and
  `release` now.
* No need to fall back to `self.lastModified` anymore, this was a
  workaround for pre2.4 Nix.

Co-authored-by: Robert Hensing <robert@roberthensing.nl>
Co-authored-by: Silvan Mosberger <contact@infinisil.com>
Ma27 and others added 2 commits December 10, 2023 13:25
We cannot pass `overlays = ...` to `nixpkgs` directly because by default
overlays from `~/.config/nixpkgs` are loaded in there. This doesn't
happen by default, but when using `--impure`.

Explicitly specifying that ignores these overlays. By using `pkgs.extend`
the old behavior can be kept and the new overlay can be applied.

Co-authored-by: Silvan Mosberger <contact@infinisil.com>
It's not really a pkgs overlay, but a lib overlay.
@roberth roberth merged commit 067ac02 into NixOS:master Dec 11, 2023
6 checks passed
@Ma27 Ma27 deleted the version-info-lib branch December 11, 2023 13:17
github-actions bot pushed a commit to arcnmx/nixpkgs-lib that referenced this pull request Dec 12, 2023
This effectively means that

    nixpkgs$ nix eval ./lib#lib.trivial.version
    "23.11.20231020.ee0d6b5"

now gives meaningful results as well.

See NixOS/nixpkgs#257100 (comment)
for the discussion around this.
github-actions bot pushed a commit to nix-community/nixpkgs.lib that referenced this pull request Dec 17, 2023
This effectively means that

    nixpkgs$ nix eval ./lib#lib.trivial.version
    "23.11.20231020.ee0d6b5"

now gives meaningful results as well.

See NixOS/nixpkgs#257100 (comment)
for the discussion around this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: flakes The experimental Nix feature 6.topic: lib The Nixpkgs function library 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 1-10
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants