Merge pull request #270774 from emilytrau/libbacktrace-musl
[NixPkgs.git] / lib / filesystem.nix
blob5569b8ac80fd1c8853b6cdd55265fe555e204484
1 /*
2   Functions for querying information about the filesystem
3   without copying any files to the Nix store.
4 */
5 { lib }:
7 # Tested in lib/tests/filesystem.sh
8 let
9   inherit (builtins)
10     readDir
11     pathExists
12     ;
14   inherit (lib.filesystem)
15     pathType
16     ;
21   /*
22     The type of a path. The path needs to exist and be accessible.
23     The result is either "directory" for a directory, "regular" for a regular file, "symlink" for a symlink, or "unknown" for anything else.
25     Type:
26       pathType :: Path -> String
28     Example:
29       pathType /.
30       => "directory"
32       pathType /some/file.nix
33       => "regular"
34   */
35   pathType =
36     builtins.readFileType or
37     # Nix <2.14 compatibility shim
38     (path:
39       if ! pathExists path
40       # Fail irrecoverably to mimic the historic behavior of this function and
41       # the new builtins.readFileType
42       then abort "lib.filesystem.pathType: Path ${toString path} does not exist."
43       # The filesystem root is the only path where `dirOf / == /` and
44       # `baseNameOf /` is not valid. We can detect this and directly return
45       # "directory", since we know the filesystem root can't be anything else.
46       else if dirOf path == path
47       then "directory"
48       else (readDir (dirOf path)).${baseNameOf path}
49     );
51   /*
52     Whether a path exists and is a directory.
54     Type:
55       pathIsDirectory :: Path -> Bool
57     Example:
58       pathIsDirectory /.
59       => true
61       pathIsDirectory /this/does/not/exist
62       => false
64       pathIsDirectory /some/file.nix
65       => false
66   */
67   pathIsDirectory = path:
68     pathExists path && pathType path == "directory";
70   /*
71     Whether a path exists and is a regular file, meaning not a symlink or any other special file type.
73     Type:
74       pathIsRegularFile :: Path -> Bool
76     Example:
77       pathIsRegularFile /.
78       => false
80       pathIsRegularFile /this/does/not/exist
81       => false
83       pathIsRegularFile /some/file.nix
84       => true
85   */
86   pathIsRegularFile = path:
87     pathExists path && pathType path == "regular";
89   /*
90     A map of all haskell packages defined in the given path,
91     identified by having a cabal file with the same name as the
92     directory itself.
94     Type: Path -> Map String Path
95   */
96   haskellPathsInDir =
97     # The directory within to search
98     root:
99     let # Files in the root
100         root-files = builtins.attrNames (builtins.readDir root);
101         # Files with their full paths
102         root-files-with-paths =
103           map (file:
104             { name = file; value = root + "/${file}"; }
105           ) root-files;
106         # Subdirectories of the root with a cabal file.
107         cabal-subdirs =
108           builtins.filter ({ name, value }:
109             builtins.pathExists (value + "/${name}.cabal")
110           ) root-files-with-paths;
111     in builtins.listToAttrs cabal-subdirs;
112   /*
113     Find the first directory containing a file matching 'pattern'
114     upward from a given 'file'.
115     Returns 'null' if no directories contain a file matching 'pattern'.
117     Type: RegExp -> Path -> Nullable { path : Path; matches : [ MatchResults ]; }
118   */
119   locateDominatingFile =
120     # The pattern to search for
121     pattern:
122     # The file to start searching upward from
123     file:
124     let go = path:
125           let files = builtins.attrNames (builtins.readDir path);
126               matches = builtins.filter (match: match != null)
127                           (map (builtins.match pattern) files);
128           in
129             if builtins.length matches != 0
130               then { inherit path matches; }
131               else if path == /.
132                 then null
133                 else go (dirOf path);
134         parent = dirOf file;
135         isDir =
136           let base = baseNameOf file;
137               type = (builtins.readDir parent).${base} or null;
138           in file == /. || type == "directory";
139     in go (if isDir then file else parent);
142   /*
143     Given a directory, return a flattened list of all files within it recursively.
145     Type: Path -> [ Path ]
146   */
147   listFilesRecursive =
148     # The path to recursively list
149     dir:
150     lib.flatten (lib.mapAttrsToList (name: type:
151     if type == "directory" then
152       lib.filesystem.listFilesRecursive (dir + "/${name}")
153     else
154       dir + "/${name}"
155   ) (builtins.readDir dir));