2023-08-17 00:55:32 +02:00
{ lib }:
let
inherit ( import ./internal.nix { inherit lib ; } )
_coerce
2023-09-13 23:29:28 +02:00
_coerceMany
2023-08-17 00:55:32 +02:00
_toSourceFilter
2023-09-13 23:29:28 +02:00
_unionMany
2023-08-17 00:55:32 +02:00
;
inherit ( builtins )
2023-09-13 23:29:57 +02:00
isList
2023-08-17 00:55:32 +02:00
isPath
pathExists
typeOf
;
2023-09-13 23:29:57 +02:00
inherit ( lib . lists )
imap0
;
2023-08-17 00:55:32 +02:00
inherit ( lib . path )
hasPrefix
splitRoot
;
inherit ( lib . strings )
isStringLike
;
inherit ( lib . filesystem )
pathType
;
inherit ( lib . sources )
cleanSourceWith
;
2023-09-15 00:08:04 +02:00
inherit ( lib . trivial )
pipe
;
2023-08-17 00:55:32 +02:00
in {
/*
Add the local files contained in ` fileset ` to the store as a single [ store path ] ( https://nixos.org/manual/nix/stable/glossary #gloss-store-path) rooted at `root`.
The result is the store path as a string-like value , making it usable e . g . as the ` src ` of a derivation , or in string interpolation :
` ` ` nix
stdenv . mkDerivation {
src = lib . fileset . toSource { . . . } ;
# ...
}
` ` `
The name of the store path is always ` source ` .
Type :
toSource : : {
root : : Path ,
fileset : : FileSet ,
} -> SourceLike
Example :
2023-09-13 23:31:02 +02:00
# Import the current directory into the store
# but only include files under ./src
toSource {
root = ./. ;
fileset = ./src ;
}
2023-08-17 00:55:32 +02:00
= > " / n i x / s t o r e / . . . - s o u r c e "
2023-09-13 23:31:02 +02:00
# Import the current directory into the store
# but only include ./Makefile and all files under ./src
toSource {
root = ./. ;
fileset = union
./Makefile
./src ;
}
= > " / n i x / s t o r e / . . . - s o u r c e "
# Trying to include a file outside the root will fail
toSource {
root = ./. ;
fileset = unions [
./Makefile
./src
../LICENSE
] ;
}
2023-08-17 00:55:32 +02:00
= > <error>
2023-09-13 23:31:02 +02:00
# The root needs to point to a directory that contains all the files
toSource {
root = ../. ;
fileset = unions [
./Makefile
./src
../LICENSE
] ;
}
= > " / n i x / s t o r e / . . . - s o u r c e "
2023-08-17 00:55:32 +02:00
# The root has to be a local filesystem path
2023-09-13 23:31:02 +02:00
toSource {
root = " / n i x / s t o r e / . . . - s o u r c e " ;
fileset = ./. ;
}
2023-08-17 00:55:32 +02:00
= > <error>
* /
toSource = {
/*
( required ) The local directory [ path ] ( https://nixos.org/manual/nix/stable/language/values.html #type-path) that will correspond to the root of the resulting store path.
Paths in [ strings ] ( https://nixos.org/manual/nix/stable/language/values.html #type-string), including Nix store paths, cannot be passed as `root`.
` root ` has to be a directory .
2023-09-15 00:08:04 +02:00
< ! - - Ignore the indentation here , this is a nixdoc rendering bug that needs to be fixed : https://github.com/nix-community/nixdoc/issues/75 - ->
2023-08-17 00:55:32 +02:00
: : : { . note }
Changing ` root ` only affects the directory structure of the resulting store path , it does not change which files are added to the store .
The only way to change which files get added to the store is by changing the ` fileset ` attribute .
: : :
* /
root ,
/*
( required ) The file set whose files to import into the store .
2023-09-13 23:31:02 +02:00
File sets can be created using other functions in this library .
This argument can also be a path ,
which gets [ implicitly coerced to a file set ] ( #sec-fileset-path-coercion).
2023-09-15 00:08:04 +02:00
< ! - - Ignore the indentation here , this is a nixdoc rendering bug that needs to be fixed : https://github.com/nix-community/nixdoc/issues/75 - ->
2023-09-13 23:31:02 +02:00
: : : { . note }
If a directory does not recursively contain any file , it is omitted from the store path contents .
: : :
2023-08-17 00:55:32 +02:00
* /
fileset ,
} :
let
# We cannot rename matched attribute arguments, so let's work around it with an extra `let in` statement
2023-09-15 00:08:04 +02:00
filesetArg = fileset ;
2023-08-17 00:55:32 +02:00
in
let
2023-09-15 00:08:04 +02:00
fileset = _coerce " l i b . f i l e s e t . t o S o u r c e : ` f i l e s e t ` " filesetArg ;
2023-08-17 00:55:32 +02:00
rootFilesystemRoot = ( splitRoot root ) . root ;
filesetFilesystemRoot = ( splitRoot fileset . _internalBase ) . root ;
2023-09-15 00:08:04 +02:00
sourceFilter = _toSourceFilter fileset ;
2023-08-17 00:55:32 +02:00
in
if ! isPath root then
if isStringLike root then
throw ''
2023-09-15 00:08:04 +02:00
lib . fileset . toSource : ` root ` ( " ${ toString root } " ) is a string-like value , but it should be a path instead .
2023-08-17 00:55:32 +02:00
Paths in strings are not supported by ` lib . fileset ` , use ` lib . sources ` or derivations instead . ''
else
throw ''
lib . fileset . toSource : ` root ` is of type $ { typeOf root } , but it should be a path instead . ''
# Currently all Nix paths have the same filesystem root, but this could change in the future.
# See also ../path/README.md
2023-09-26 00:26:00 +02:00
else if ! fileset . _internalIsEmptyWithoutBase && rootFilesystemRoot != filesetFilesystemRoot then
2023-08-17 00:55:32 +02:00
throw ''
2023-09-15 00:08:04 +02:00
lib . fileset . toSource : Filesystem roots are not the same for ` fileset ` and ` root ` ( " ${ toString root } " ) :
2023-08-17 00:55:32 +02:00
` root ` : root " ${ toString rootFilesystemRoot } "
` fileset ` : root " ${ toString filesetFilesystemRoot } "
Different roots are not supported . ''
else if ! pathExists root then
throw ''
2023-09-15 00:08:04 +02:00
lib . fileset . toSource : ` root ` ( $ { toString root } ) does not exist . ''
2023-08-17 00:55:32 +02:00
else if pathType root != " d i r e c t o r y " then
throw ''
2023-09-15 00:08:04 +02:00
lib . fileset . toSource : ` root ` ( $ { toString root } ) is a file , but it should be a directory instead . Potential solutions :
2023-08-17 00:55:32 +02:00
- If you want to import the file into the store _without_ a containing directory , use string interpolation or ` builtins . path ` instead of this function .
- If you want to import the file into the store _with_ a containing directory , set ` root ` to the containing directory , such as $ { toString ( dirOf root ) } , and set ` fileset ` to the file path . ''
2023-09-26 00:26:00 +02:00
else if ! fileset . _internalIsEmptyWithoutBase && ! hasPrefix root fileset . _internalBase then
2023-08-17 00:55:32 +02:00
throw ''
2023-09-15 00:08:04 +02:00
lib . fileset . toSource : ` fileset ` could contain files in $ { toString fileset . _internalBase } , which is not under the ` root ` ( $ { toString root } ) . Potential solutions :
2023-08-17 00:55:32 +02:00
- Set ` root ` to $ { toString fileset . _internalBase } or any directory higher up . This changes the layout of the resulting store path .
2023-09-15 00:08:04 +02:00
- Set ` fileset ` to a file set that cannot contain files outside the ` root ` ( $ { toString root } ) . This could change the files included in the result . ''
2023-08-17 00:55:32 +02:00
else
2023-09-15 00:08:04 +02:00
builtins . seq sourceFilter
2023-08-17 00:55:32 +02:00
cleanSourceWith {
name = " s o u r c e " ;
src = root ;
2023-09-15 00:08:04 +02:00
filter = sourceFilter ;
2023-08-17 00:55:32 +02:00
} ;
2023-09-13 23:29:28 +02:00
/*
The file set containing all files that are in either of two given file sets .
2023-09-13 23:29:57 +02:00
This is the same as [ ` unions ` ] ( #function-library-lib.fileset.unions),
but takes just two file sets instead of a list .
2023-09-13 23:29:28 +02:00
See also [ Union ( set theory ) ] ( https://en.wikipedia.org/wiki/Union_ ( set_theory ) ) .
The given file sets are evaluated as lazily as possible ,
with the first argument being evaluated first if needed .
Type :
union : : FileSet -> FileSet -> FileSet
Example :
# Create a file set containing the file `Makefile`
# and all files recursively in the `src` directory
union ./Makefile ./src
# Create a file set containing the file `Makefile`
# and the LICENSE file from the parent directory
union ./Makefile ../LICENSE
* /
union =
# The first file set.
# This argument can also be a path,
# which gets [implicitly coerced to a file set](#sec-fileset-path-coercion).
fileset1 :
# The second file set.
# This argument can also be a path,
# which gets [implicitly coerced to a file set](#sec-fileset-path-coercion).
fileset2 :
2023-09-15 00:08:04 +02:00
_unionMany
( _coerceMany " l i b . f i l e s e t . u n i o n " [
2023-09-13 23:29:28 +02:00
{
context = " f i r s t a r g u m e n t " ;
value = fileset1 ;
}
{
context = " s e c o n d a r g u m e n t " ;
value = fileset2 ;
}
2023-09-15 00:08:04 +02:00
] ) ;
2023-09-13 23:29:28 +02:00
2023-09-13 23:29:57 +02:00
/*
The file set containing all files that are in any of the given file sets .
This is the same as [ ` union ` ] ( #function-library-lib.fileset.unions),
but takes a list of file sets instead of just two .
See also [ Union ( set theory ) ] ( https://en.wikipedia.org/wiki/Union_ ( set_theory ) ) .
The given file sets are evaluated as lazily as possible ,
with earlier elements being evaluated first if needed .
Type :
unions : : [ FileSet ] -> FileSet
Example :
# Create a file set containing selected files
unions [
# Include the single file `Makefile` in the current directory
# This errors if the file doesn't exist
./Makefile
# Recursively include all files in the `src/code` directory
# If this directory is empty this has no effect
./src/code
# Include the files `run.sh` and `unit.c` from the `tests` directory
./tests/run.sh
./tests/unit.c
# Include the `LICENSE` file from the parent directory
../LICENSE
]
* /
unions =
# A list of file sets.
# Must contain at least 1 element.
# The elements can also be paths,
# which get [implicitly coerced to file sets](#sec-fileset-path-coercion).
filesets :
2023-09-15 00:08:04 +02:00
if ! isList filesets then
throw " l i b . f i l e s e t . u n i o n s : E x p e c t e d a r g u m e n t t o b e a l i s t , b u t g o t a ${ typeOf filesets } . "
2023-09-13 23:29:57 +02:00
else
2023-09-15 00:08:04 +02:00
pipe filesets [
# Annotate the elements with context, used by _coerceMany for better errors
( imap0 ( i : el : {
context = " e l e m e n t ${ toString i } " ;
value = el ;
} ) )
( _coerceMany " l i b . f i l e s e t . u n i o n s " )
_unionMany
] ;
2023-09-13 23:29:57 +02:00
2023-08-17 00:55:32 +02:00
}