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

lib.fileset.fromSource: init #261732

Merged
merged 3 commits into from
Nov 10, 2023
Merged

lib.fileset.fromSource: init #261732

merged 3 commits into from
Nov 10, 2023

Conversation

infinisil
Copy link
Member

@infinisil infinisil commented Oct 17, 2023

Description of changes

Another split off from #222981, motivated by @alyssais's comment here. This introduces one new function:

  • lib.fileset.fromSource: Create a file set from a filtered local source as produced by the lib.sources functions.
    lib.fileset.toSource {
      root = ./.;
      fileset = lib.fileset.intersection
        (lib.fileset.fromSource (lib.sources.cleanSource ./.))
        (lib.fileset.unions [
          ./Makefile
          ./src
        ]);
    }

This is mainly useful for migration from lib.sources-based filtering. In the future we should have a convenience function in lib.fileset that could take over.

This work is sponsored by Antithesis

Things done

  • Tests
  • Clean code
  • Documentation

@github-actions github-actions bot added the 6.topic: lib The Nixpkgs function library label Oct 17, 2023
This was referenced Oct 17, 2023
@infinisil infinisil requested a review from alyssais October 17, 2023 22:50
@ofborg ofborg bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 1-10 labels Oct 18, 2023
@infinisil infinisil changed the title lib.fileset.fromSource: init lib.fileset.fromSource: init Nov 1, 2023
@infinisil
Copy link
Member Author

I'm wondering if this will still be necessary with #264891 🤔

@alyssais
Copy link
Member

alyssais commented Nov 2, 2023

Definitely is IMO. Not everything is or should be a git repository.

@alyssais
Copy link
Member

alyssais commented Nov 5, 2023

Another reason I can't switch from sources to filesets yet:

I want to be able to do, essentially: src = fileset.difference ./. ./generated.o, where generated.o is some generated file that may or may not exist in my development tree, but that shouldn't be input to the derivation. This is not currently possible, because filesets require all files to exist. So there needs to be a way to filter a fileset that doesn't require the files in the negative set to exist.

@infinisil infinisil mentioned this pull request Nov 7, 2023
3 tasks
@infinisil
Copy link
Member Author

It is possible to do this already with

difference ./.
  (unions
    (lib.optional (builtins.pathExists ./generated.o) ./generated.o)
  )

But I think a convenient shorthand for this would be appropriate, I also had that in #222981, so I just created #265964 which adds a lib.fileset.optional!

Copy link
Contributor

@fricklerhandwerk fricklerhandwerk left a comment

Choose a reason for hiding this comment

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

That's a really valuable addition to the library, as you said because it would ease migration a lot. We may want to note that in the docstring, along the lines of

use this to gradually migrate builds relying on lib.sources to lib.fileset

but that's no reason to block this PR.

PS: Not sure why it's still in draft mode, looks ready to me.

if ! source._isLibCleanSourceWith or false || ! source ? origSrc || ! source ? filter then
throw "lib.fileset.fromSource: Expected the argument to be a value produced from `lib.sources`, but got a ${typeOf source} instead."
else if ! isPath source.origSrc then
throw "lib.fileset.fromSource: Expected the argument to be source-like value of a local path."
Copy link
Contributor

Choose a reason for hiding this comment

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

What's a source-like value? What's a source?

Copy link
Member

Choose a reason for hiding this comment

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

"Very" good question unfortunately. Basically a path value or the "source attrset" returned by the lib.sources functions. Can we write introductions for sublibraries yet? It'd be great to have a sensible place to document the unique types of each sublibrary.

Copy link
Member Author

Choose a reason for hiding this comment

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

Can we write introductions for sublibraries yet?

Almost

fromSource :: SourceLike -> FileSet

Example:
fromSource (lib.sources.cleanSource ./.)
Copy link
Contributor

Choose a reason for hiding this comment

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

The example in the PR description is also relevant, because it shows a bit of integration.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added some more practical examples now

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.

Remember to test that directories for which the predicate is false are not read. This is part of the (implicit) contract.
Other than that, I think the tests will "write themselves" if that makes sense.

lib/fileset/internal.nix Outdated Show resolved Hide resolved
fromSource (lib.sources.cleanSource ./.)
*/
fromSource = source:
if ! source._isLibCleanSourceWith or false || ! source ? origSrc || ! source ? filter then
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't seem to actually take SourceLike (although I didn't define that in words in lib.sources, you could perhaps tell from the code or behavior).

That type was meant to cover all source-coercible types, similar to how you allow both paths and filesets as arguments to fileset functions. In fact, it seems to be pretty much exactly that.

So what I meant to say is lib.sources users will probably expect to be able to use any source here, whether that's an _isLibCleanSourceWith, or a path value. Rejecting path values makes libraries (e.g. lang2nix) that use this fragile.

Not simplifying fromSource ./. to ./. is harmless, while { src, ... }: f (fromSource src) would be a bug waiting to happen.

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 now!

@infinisil
Copy link
Member Author

PS: Not sure why it's still in draft mode, looks ready to me.

See the checklist in the PR description 🙂. Generally I recommend not taking close looks at the code of draft PRs. If I request you for a review it's because I'd like feedback to the approach only. I'll mark PRs as ready to review when I think their implementation is ready to review.

The review comments you both left are very helpful though, will incorporate!

@infinisil infinisil force-pushed the fileset.fromSource branch 3 times, most recently from 4133f7a to 3dfaf15 Compare November 8, 2023 04:32
@infinisil
Copy link
Member Author

Other than that, I think the tests will "write themselves" if that makes sense.

It didn't make sense to me, but I wrote tests anyways and pushed them now :)

Still need to clean up the code and docs a bit, including addressing the review comments. I'll mark it as ready when everything is addressed.

@infinisil infinisil marked this pull request as ready for review November 8, 2023 20:24
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.

One question; otherwise lgtm.

Comment on lines +157 to +160
throw ''
lib.fileset.toSource: `root` is a `lib.sources`-based value, but it should be a path instead.
To use a `lib.sources`-based value, convert it to a file set using `lib.fileset.fromSource` and pass it as `fileset`.
Note that this only works for sources created from paths.''
Copy link
Member

Choose a reason for hiding this comment

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

Any reason not to just call it for them?

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'm not 100% convinced it's a good idea, just minor ideas like

  • The operation this function does is somewhat expensive, so it being explicit makes people aware of that. This is different from the implicit path coercion, which is very cheap
  • Do we want to deprecate this at some point? Probably not
  • Source filters can be impure by changing behavior based on the project directory, does this impurity leak into file sets? Probably not a problem
  • Is it a problem to have a lack of symmetry regarding toSource/fromSource? Probably not, these aren't symmetric, fromSource discard's the root and toSource has to add it
  • Would it be a problem to have cases like toSource { root = ./.; fileset = toSource { root = ./.; fileset = toSource { ...? Probably also no

Furthermore this being an error for now means that we could still do this later.

@roberth roberth merged commit cfd83c9 into NixOS:master Nov 10, 2023
19 checks passed
@infinisil infinisil deleted the fileset.fromSource branch November 10, 2023 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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