Unverified Commit f37dd68f authored by Silvan Mosberger's avatar Silvan Mosberger Committed by GitHub
Browse files

Merge pull request #265964 from tweag/fileset.optional

`lib.fileset.maybeMissing`: init
parents 0e23cb37 827232d6
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -253,7 +253,15 @@ The `fileFilter` function takes a path, and not a file set, as its second argume
      it would change the `subpath`/`components` value depending on which files are included.
- (+) If necessary, this restriction can be relaxed later, the opposite wouldn't be possible

## To update in the future

Here's a list of places in the library that need to be updated in the future:
- If/Once a function exists that can optionally include a path depending on whether it exists, the error message for the path not existing in `_coerce` should mention the new function
### Strict path existence checking

Coercing paths that don't exist to file sets always gives an error.

- (-) Sometimes you want to remove a file that may not always exist using `difference ./. ./does-not-exist`,
  but this does not work because coercion of `./does-not-exist` fails,
  even though its existence would have no influence on the result.
  - (+) This is dangerous, because you wouldn't be protected against typos anymore.
    E.g. when trying to prevent `./secret` from being imported, a typo like `difference ./. ./sercet` would import it regardless.
  - (+) `difference ./. (maybeMissing ./does-not-exist)` can be used to do this more explicitly.
  - (+) `difference ./. (difference ./foo ./foo/bar)` should report an error when `./foo/bar` does not exist ("double negation"). Unfortunately, the current internal representation does not lend itself to a behavior where both `difference x ./does-not-exists` and double negation are handled and checked correctly.
    This could be fixed, but would require significant changes to the internal representation that are not worth the effort and the risk of introducing implicit behavior.
+31 −0
Original line number Diff line number Diff line
@@ -11,6 +11,10 @@
  Basics:
  - [Implicit coercion from paths to file sets](#sec-fileset-path-coercion)

  - [`lib.fileset.maybeMissing`](#function-library-lib.fileset.maybeMissing):

    Create a file set from a path that may be missing.

  - [`lib.fileset.trace`](#function-library-lib.fileset.trace)/[`lib.fileset.traceVal`](#function-library-lib.fileset.trace):

    Pretty-print file sets for debugging.
@@ -105,6 +109,7 @@ let
    _difference
    _mirrorStorePath
    _fetchGitSubmodulesMinver
    _emptyWithoutBase
    ;

  inherit (builtins)
@@ -148,6 +153,32 @@ let

in {

  /*
    Create a file set from a path that may or may not exist:
    - If the path does exist, the path is [coerced to a file set](#sec-fileset-path-coercion).
    - If the path does not exist, a file set containing no files is returned.

    Type:
      maybeMissing :: Path -> FileSet

    Example:
      # All files in the current directory, but excluding main.o if it exists
      difference ./. (maybeMissing ./main.o)
  */
  maybeMissing =
    path:
    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.''
      else
        throw ''
          lib.fileset.maybeMissing: Argument is of type ${typeOf path}, but it should be a path instead.''
    else if ! pathExists path then
      _emptyWithoutBase
    else
      _singleton path;

  /*
    Incrementally evaluate and trace a file set in a pretty way.
    This function is only intended for debugging purposes.
+2 −1
Original line number Diff line number Diff line
@@ -181,7 +181,8 @@ rec {
          ${context} is of type ${typeOf value}, but it should be a file set or a path instead.''
    else if ! pathExists value then
      throw ''
        ${context} (${toString value}) is a path that does not exist.''
        ${context} (${toString value}) is a path that does not exist.
            To create a file set from a path that may not exist, use `lib.fileset.maybeMissing`.''
    else
      _singleton value;

+36 −1
Original line number Diff line number Diff line
@@ -413,7 +413,8 @@ expectFailure 'toSource { root = ./.; fileset = cleanSourceWith { src = ./.; };
\s*Note that this only works for sources created from paths.'

# Path coercion errors for non-existent paths
expectFailure 'toSource { root = ./.; fileset = ./a; }' 'lib.fileset.toSource: `fileset` \('"$work"'/a\) is a path that does not exist.'
expectFailure 'toSource { root = ./.; fileset = ./a; }' 'lib.fileset.toSource: `fileset` \('"$work"'/a\) is a path that does not exist.
\s*To create a file set from a path that may not exist, use `lib.fileset.maybeMissing`.'

# File sets cannot be evaluated directly
expectFailure 'union ./. ./.' 'lib.fileset: Directly evaluating a file set is not supported.
@@ -1450,6 +1451,40 @@ checkGitTracked

rm -rf -- *

## lib.fileset.maybeMissing

# Argument must be a path
expectFailure 'maybeMissing "someString"' 'lib.fileset.maybeMissing: Argument \("someString"\) is a string-like value, but it should be a path instead.'
expectFailure 'maybeMissing null' 'lib.fileset.maybeMissing: Argument is of type null, but it should be a path instead.'

tree=(
)
checkFileset 'maybeMissing ./a'
checkFileset 'maybeMissing ./b'
checkFileset 'maybeMissing ./b/c'

# Works on single files
tree=(
    [a]=1
    [b/c]=0
    [b/d]=0
)
checkFileset 'maybeMissing ./a'
tree=(
    [a]=0
    [b/c]=1
    [b/d]=0
)
checkFileset 'maybeMissing ./b/c'

# Works on directories
tree=(
    [a]=0
    [b/c]=1
    [b/d]=1
)
checkFileset 'maybeMissing ./b'

# TODO: Once we have combinators and a property testing library, derive property tests from https://en.wikipedia.org/wiki/Algebra_of_sets

echo >&2 tests ok