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