at 18.03-beta 4.3 kB view raw
1# Functions for copying sources to the Nix store. 2{ lib }: 3 4rec { 5 6 # Returns the type of a path: regular (for file), symlink, or directory 7 pathType = p: with builtins; getAttr (baseNameOf p) (readDir (dirOf p)); 8 9 # Returns true if the path exists and is a directory, false otherwise 10 pathIsDirectory = p: if builtins.pathExists p then (pathType p) == "directory" else false; 11 12 # Bring in a path as a source, filtering out all Subversion and CVS 13 # directories, as well as backup files (*~). 14 cleanSourceFilter = name: type: let baseName = baseNameOf (toString name); in ! ( 15 # Filter out Subversion and CVS directories. 16 (type == "directory" && (baseName == ".git" || baseName == ".svn" || baseName == "CVS" || baseName == ".hg")) || 17 # Filter out editor backup / swap files. 18 lib.hasSuffix "~" baseName || 19 builtins.match "^\\.sw[a-z]$" baseName != null || 20 builtins.match "^\\..*\\.sw[a-z]$" baseName != null || 21 22 # Filter out generates files. 23 lib.hasSuffix ".o" baseName || 24 lib.hasSuffix ".so" baseName || 25 # Filter out nix-build result symlinks 26 (type == "symlink" && lib.hasPrefix "result" baseName) 27 ); 28 29 cleanSource = src: cleanSourceWith { filter = cleanSourceFilter; inherit src; }; 30 31 # Like `builtins.filterSource`, except it will compose with itself, 32 # allowing you to chain multiple calls together without any 33 # intermediate copies being put in the nix store. 34 # 35 # lib.cleanSourceWith f (lib.cleanSourceWith g ./.) # Succeeds! 36 # builtins.filterSource f (builtins.filterSource g ./.) # Fails! 37 cleanSourceWith = { filter, src }: 38 let 39 isFiltered = src ? _isLibCleanSourceWith; 40 origSrc = if isFiltered then src.origSrc else src; 41 filter' = if isFiltered then name: type: filter name type && src.filter name type else filter; 42 in { 43 inherit origSrc; 44 filter = filter'; 45 outPath = builtins.filterSource filter' origSrc; 46 _isLibCleanSourceWith = true; 47 }; 48 49 # Filter sources by a list of regular expressions. 50 # 51 # E.g. `src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]` 52 sourceByRegex = src: regexes: cleanSourceWith { 53 filter = (path: type: 54 let relPath = lib.removePrefix (toString src + "/") (toString path); 55 in lib.any (re: builtins.match re relPath != null) regexes); 56 inherit src; 57 }; 58 59 # Get all files ending with the specified suffices from the given 60 # directory or its descendants. E.g. `sourceFilesBySuffices ./dir 61 # [".xml" ".c"]'. 62 sourceFilesBySuffices = path: exts: 63 let filter = name: type: 64 let base = baseNameOf (toString name); 65 in type == "directory" || lib.any (ext: lib.hasSuffix ext base) exts; 66 in cleanSourceWith { inherit filter; src = path; }; 67 68 69 # Get the commit id of a git repo 70 # Example: commitIdFromGitRepo <nixpkgs/.git> 71 commitIdFromGitRepo = 72 let readCommitFromFile = path: file: 73 with builtins; 74 let fileName = toString path + "/" + file; 75 packedRefsName = toString path + "/packed-refs"; 76 in if lib.pathExists fileName 77 then 78 let fileContent = lib.fileContents fileName; 79 # Sometimes git stores the commitId directly in the file but 80 # sometimes it stores something like: «ref: refs/heads/branch-name» 81 matchRef = match "^ref: (.*)$" fileContent; 82 in if isNull matchRef 83 then fileContent 84 else readCommitFromFile path (lib.head matchRef) 85 # Sometimes, the file isn't there at all and has been packed away in the 86 # packed-refs file, so we have to grep through it: 87 else if lib.pathExists packedRefsName 88 then 89 let fileContent = readFile packedRefsName; 90 matchRef = match (".*\n([^\n ]*) " + file + "\n.*") fileContent; 91 in if isNull matchRef 92 then throw ("Could not find " + file + " in " + packedRefsName) 93 else lib.head matchRef 94 else throw ("Not a .git directory: " + path); 95 in lib.flip readCommitFromFile "HEAD"; 96 97 pathHasContext = builtins.hasContext or (lib.hasPrefix builtins.storeDir); 98 99 canCleanSource = src: src ? _isLibCleanSourceWith || !(pathHasContext (toString src)); 100}