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.maybeMissing: init #265964

Merged
merged 2 commits into from
Nov 22, 2023
Merged

lib.fileset.maybeMissing: init #265964

merged 2 commits into from
Nov 22, 2023

Conversation

infinisil
Copy link
Member

@infinisil infinisil commented Nov 7, 2023

Description of changes

Another split-off from #222981, motivated by @alyssais comment describing a use case. This PR adds a new function to lib.fileset:

  • lib.fileset.maybeMissing :: Path -> FileSet: Create a file set from a path that may or may not exist.
    lib.fileset.maybeMissing ./generated.o

An alternative is #267091, but we decided against that

This work is sponsored by Antithesis

Things done

  • Tests
  • Documentation
  • Update related documentation

@github-actions github-actions bot added the 6.topic: lib The Nixpkgs function library label Nov 7, 2023
@infinisil infinisil mentioned this pull request Nov 7, 2023
3 tasks
@infinisil infinisil changed the title lib.fileset.optional: init lib.fileset.optional: init Nov 7, 2023
@infinisil infinisil mentioned this pull request Nov 7, 2023
7 tasks
@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 Nov 7, 2023
@roberth
Copy link
Member

roberth commented Nov 7, 2023

The name suggests a parallel with lib.optional : Bool -> a -> List a, but there isn't one.
How about unchecked instead?

OT: I would quite like to have fileset.optional : Bool -> FileSet -> FileSet such that optional false x == fileset.empty. Example:

mkDerivation(finalAttrs: {
  src = fileset.unions [
    ./src
    (fileset.optional finalAttrs.doCheck ./tests)
  ];
})

@infinisil
Copy link
Member Author

The name suggests a parallel with lib.optional : Bool -> a -> List a, but there isn't one.
How about unchecked instead?

Hmm good point, not a fan of unchecked though, makes me ask the question what property is not being checked, and whether this is an unsafe operation.

Some other ideas:

  • lib.fileset.optionalIfExists ./generated.o -> Meh, it's not optional if it does exist, then it's definitely included
  • lib.fileset.ifExists ./generated.o -> If it exists then what? Does this return a bool?
  • lib.fileset.try ./generated.o -> Doesn't say what is being tried
  • lib.fileset.tryCoerce ./generated.o -> Does make sense, but maybe a bit too odd of a word
  • lib.fileset.tryFrom ./generated.o -> Not bad imo, nicer word than coerce
  • lib.fileset.maybe ./generated.o -> Not bad imo, though it doesn't match Haskell's maybe
  • lib.fileset.maybeMissing ./generated.o -> A bit more explicit, but a bit long

I think I like lib.fileset.tryFrom the most, which could also lead to a lib.fileset.from that does coercion but fails for missing files in case that's ever needed.

OT: I would quite like to have fileset.optional : Bool -> FileSet -> FileSet such that optional false x == fileset.empty.

Oh that sounds nice, should be fairly easy to add too.

@alyssais
Copy link
Member

alyssais commented Nov 7, 2023

OT: I would quite like to have fileset.optional : Bool -> FileSet -> FileSet such that optional false x == fileset.empty

Is this actually required? You can already use lib.optional(s) and have the result coerced to a fileset.

@infinisil
Copy link
Member Author

infinisil commented Nov 7, 2023

@roberth @alyssais I migrated (and replied to) our discussion on lib.fileset.optional :: Bool -> FileSet -> FileSet to a new issue: #266106

@roberth
Copy link
Member

roberth commented Nov 7, 2023

  • lib.fileset.maybe ./generated.o -> Not bad imo, though it doesn't match Haskell's maybe
  • We don't have Haskell's Maybe in the first place. nullOr might feel similar but is very very different (in the context of a standard library).
  • maybe is kinda bad, for reasons that point-free is bad.

So I wouldn't be too concerned about this name in general, but I don't think it's specific enough.

  • lib.fileset.tryFrom ./generated.o

Still doesn't say what's tried.

My favorite from your list is maybeMissing.

What about whenExists?

@infinisil
Copy link
Member Author

What about whenExists?

Also doesn't indicate what happens when it exists.

I'll just go for maybeMissing (though should it be mayBeMissing instead?), seems like the least evil.

@infinisil infinisil changed the title lib.fileset.optional: init lib.fileset.maybeMissing: init Nov 7, 2023
@roberth
Copy link
Member

roberth commented Nov 7, 2023

What about whenExists?

Also doesn't indicate what happens when it exists.

I'm used to Haskell's when which "does" nothing when false. It could be read as "only when exists", with the implied alternative of nothing (empty).

mayBeMissing

Correct, but I predict 50% will mistype.

@fricklerhandwerk
Copy link
Contributor

I'm worried the interface is growing faster than adoption of the library warrants. This issue could be stop-gapped with an example in the documentation, because the use case can be implemented with what's already there.

If it turns out to be a heavily used pattern one can still add a convenience layer.

Right now I'd prefer efforts being directed to making good use of existing facilities, evolving some usage patterns, and adding more practical examples to the docs.

@infinisil
Copy link
Member Author

This particular use case I also encountered while working on the original WIP, and @alyssais being one of the first users and immediately running into it too gives me the feeling we should support this. The alternative without this function is too verbose:

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

# With this PR:
maybeMissing ./generated.o

Even just the fact that the path needs to be repeated will make anybody needing this want to write a function for it! I think lib.fileset should be a batteries-included library that just lets you do what you need to do, without having to create extra functions or write boilerplate.

@alyssais
Copy link
Member

FWIW: all I'm trying to do is replace this very simple use of cleanSource(With), and then add some additional filtering on top for individual components. I'd consider this a fairly basic use case.

@alyssais
Copy link
Member

@infinisil how would you feel about having lib.fileset.difference implicitly handle missing files in its second argument? It's used for filtering out files you don't want, so I'm not sure when you'd ever care that they didn't exist, and otherwise IIUC you need to lib.fileset.difference set (lib.unions (map lib.fileset.maybeMissing [ … ])), which is pretty boilerplate-y. I'd understand if it felt like too much magic to you, though.

@ofborg ofborg bot added the 2.status: merge conflict This PR has merge conflicts with the target branch label Nov 10, 2023
@infinisil
Copy link
Member Author

Hmm that doesn't always make sense though, because you can also do difference ./. (difference ./foo ./foo/bar), where ./foo/bar would be included in the end and so has to exist.

Maybe the check for files existing could be pushed further down generally though, I'll look into that.

@roberth
Copy link
Member

roberth commented Nov 11, 2023

Right! That reminds me of the function type operator, which also have a binary property that flips in one of the operands, and flips back when the operator is nested: covariance/contravariance aka positive/negative.

Seems to reinforce the idea that you can negate a contextual boolean (ie argument to some internal function) whenever you process a difference rhs.

@infinisil
Copy link
Member Author

Unfortunately the difference ./. (difference ./foo ./foo/bar) case doesn't work out with the current internal representation, but otherwise it's totally doable, check out #267091!

@infinisil
Copy link
Member Author

Since we decided against doing #267091, we should have maybeMissing after all.

I rebased on top of master, this would be ready from my side.

@ofborg ofborg bot removed the 2.status: merge conflict This PR has merge conflicts with the target branch label Nov 16, 2023
@infinisil
Copy link
Member Author

Rebased again, still good from my side :)

if ! isPath path then
if isStringLike path then
throw ''
lib.fileset.maybeMissing: Argument ("${toString path}") is a string-like value, but it should be a path instead.''
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
lib.fileset.maybeMissing: Argument ("${toString path}") is a string-like value, but it should be a path instead.''
lib.fileset.maybeMissing: Argument ("${toString path}") is a string-like value, but it should be a path instead. See https://nixos.org/manual/nix/stable/language/values#type-path''

I don't think the word "path" is enough for novices.

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 in 701cff3!

lib.fileset.maybeMissing: Argument ("${toString path}") is a string-like value, but it should be a path instead.''
else
throw ''
lib.fileset.maybeMissing: Argument is of type ${typeOf path}, but it should be a path instead.''
Copy link
Member

Choose a reason for hiding this comment

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

Same here.
Might be helpful to have a function that generates an explanation or something. Or just a let binding with the url?

Copy link
Member Author

Choose a reason for hiding this comment

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

Just for the sake of consistency I'd prefer just copying it to all the error messages for now. We could consider having a dedicated lib/fileset/errors.nix in the future to collect and abstract over all error messages together.

Copy link
Member

Choose a reason for hiding this comment

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

Could you document the rationale for maybeMissing here, as opposed to non-strict by default?

Copy link
Member Author

@infinisil infinisil Nov 20, 2023

Choose a reason for hiding this comment

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

Done in 4594aa0!

@ofborg ofborg bot added the 2.status: merge conflict This PR has merge conflicts with the target branch label Nov 20, 2023
@ofborg ofborg bot removed the 2.status: merge conflict This PR has merge conflicts with the target branch label Nov 20, 2023
@infinisil
Copy link
Member Author

Ready to be merged again from my side

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.

The implementation is good, but I suggest cutting down on the other diff noise.

lib.fileset.maybeMissing: Argument ("${toString path}") is a string-like value, but it should be a path instead, see https://nixos.org/manual/nix/stable/language/values#type-path.''
else
throw ''
lib.fileset.maybeMissing: Argument is of type ${typeOf path}, but it should be a path instead, see https://nixos.org/manual/nix/stable/language/values#type-path.''
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need links to the manual. It's spammy and doesn't exactly make things easier with maintaining that web stuff in the long run.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fair enough, removed them again!

lib/fileset/README.md Outdated Show resolved Hide resolved
lib/fileset/README.md Outdated Show resolved Hide resolved
@infinisil
Copy link
Member Author

I'll soon merge this myself so we can unblock NixOS/nix.dev#802 :)

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 suggestion, then lgtm.

lib/fileset/README.md Outdated Show resolved Hide resolved
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
@infinisil infinisil merged commit f37dd68 into NixOS:master Nov 22, 2023
6 checks passed
@infinisil infinisil deleted the fileset.optional branch November 22, 2023 18:46
Copy link
Contributor

Successfully created backport PR for release-23.11:

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