diff options
author | Mx Kookie <kookie@spacekookie.de> | 2020-12-21 06:05:12 +0100 |
---|---|---|
committer | Mx Kookie <kookie@spacekookie.de> | 2020-12-21 06:05:12 +0100 |
commit | f107be784e6d5da5f90735765a68fdff96acfbb4 (patch) | |
tree | 145573a598009fb6adbd5ef7fbce0a850681f5f0 /infra/libkookie/nixpkgs/lib/sources.nix | |
parent | 2e04b35e5ac3a9123cafffbc84494fa4d389cca0 (diff) | |
parent | e9158eca70ae59e73fae23be5d13d3fa0cfc78b4 (diff) |
Add 'infra/libkookie/nixpkgs/' from commit 'e9158eca70ae59e73fae23be5d13d3fa0cfc78b4'
git-subtree-dir: infra/libkookie/nixpkgs
git-subtree-mainline: 2e04b35e5ac3a9123cafffbc84494fa4d389cca0
git-subtree-split: e9158eca70ae59e73fae23be5d13d3fa0cfc78b4
Diffstat (limited to 'infra/libkookie/nixpkgs/lib/sources.nix')
-rw-r--r-- | infra/libkookie/nixpkgs/lib/sources.nix | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/infra/libkookie/nixpkgs/lib/sources.nix b/infra/libkookie/nixpkgs/lib/sources.nix new file mode 100644 index 000000000000..1a3afcae67da --- /dev/null +++ b/infra/libkookie/nixpkgs/lib/sources.nix @@ -0,0 +1,179 @@ +# Functions for copying sources to the Nix store. +{ lib }: + +let + inherit (builtins) + hasContext + match + readDir + split + storeDir + tryEval + ; + inherit (lib) + filter + getAttr + isString + pathExists + readFile + ; +in +rec { + + # Returns the type of a path: regular (for file), symlink, or directory + pathType = p: getAttr (baseNameOf p) (readDir (dirOf p)); + + # Returns true if the path exists and is a directory, false otherwise + pathIsDirectory = p: if pathExists p then (pathType p) == "directory" else false; + + # Returns true if the path exists and is a regular file, false otherwise + pathIsRegularFile = p: if pathExists p then (pathType p) == "regular" else false; + + # Bring in a path as a source, filtering out all Subversion and CVS + # directories, as well as backup files (*~). + cleanSourceFilter = name: type: let baseName = baseNameOf (toString name); in ! ( + # Filter out version control software files/directories + (baseName == ".git" || type == "directory" && (baseName == ".svn" || baseName == "CVS" || baseName == ".hg")) || + # Filter out editor backup / swap files. + lib.hasSuffix "~" baseName || + match "^\\.sw[a-z]$" baseName != null || + match "^\\..*\\.sw[a-z]$" baseName != null || + + # Filter out generates files. + lib.hasSuffix ".o" baseName || + lib.hasSuffix ".so" baseName || + # Filter out nix-build result symlinks + (type == "symlink" && lib.hasPrefix "result" baseName) + ); + + # Filters a source tree removing version control files and directories using cleanSourceWith + # + # Example: + # cleanSource ./. + cleanSource = src: cleanSourceWith { filter = cleanSourceFilter; inherit src; }; + + # Like `builtins.filterSource`, except it will compose with itself, + # allowing you to chain multiple calls together without any + # intermediate copies being put in the nix store. + # + # lib.cleanSourceWith { + # filter = f; + # src = lib.cleanSourceWith { + # filter = g; + # src = ./.; + # }; + # } + # # Succeeds! + # + # builtins.filterSource f (builtins.filterSource g ./.) + # # Fails! + # + # Parameters: + # + # src: A path or cleanSourceWith result to filter and/or rename. + # + # filter: A function (path -> type -> bool) + # Optional with default value: constant true (include everything) + # The function will be combined with the && operator such + # that src.filter is called lazily. + # For implementing a filter, see + # https://nixos.org/nix/manual/#builtin-filterSource + # + # name: Optional name to use as part of the store path. + # This defaults to `src.name` or otherwise `"source"`. + # + cleanSourceWith = { filter ? _path: _type: true, src, name ? null }: + let + isFiltered = src ? _isLibCleanSourceWith; + origSrc = if isFiltered then src.origSrc else src; + filter' = if isFiltered then name: type: filter name type && src.filter name type else filter; + name' = if name != null then name else if isFiltered then src.name else "source"; + in { + inherit origSrc; + filter = filter'; + outPath = builtins.path { filter = filter'; path = origSrc; name = name'; }; + _isLibCleanSourceWith = true; + name = name'; + }; + + # Filter sources by a list of regular expressions. + # + # E.g. `src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]` + sourceByRegex = src: regexes: + let + isFiltered = src ? _isLibCleanSourceWith; + origSrc = if isFiltered then src.origSrc else src; + in lib.cleanSourceWith { + filter = (path: type: + let relPath = lib.removePrefix (toString origSrc + "/") (toString path); + in lib.any (re: match re relPath != null) regexes); + inherit src; + }; + + # Get all files ending with the specified suffices from the given + # directory or its descendants. E.g. `sourceFilesBySuffices ./dir + # [".xml" ".c"]'. + sourceFilesBySuffices = path: exts: + let filter = name: type: + let base = baseNameOf (toString name); + in type == "directory" || lib.any (ext: lib.hasSuffix ext base) exts; + in cleanSourceWith { inherit filter; src = path; }; + + pathIsGitRepo = path: (tryEval (commitIdFromGitRepo path)).success; + + # Get the commit id of a git repo + # Example: commitIdFromGitRepo <nixpkgs/.git> + commitIdFromGitRepo = + let readCommitFromFile = file: path: + let fileName = toString path + "/" + file; + packedRefsName = toString path + "/packed-refs"; + absolutePath = base: path: + if lib.hasPrefix "/" path + then path + else toString (/. + "${base}/${path}"); + in if pathIsRegularFile path + # Resolve git worktrees. See gitrepository-layout(5) + then + let m = match "^gitdir: (.*)$" (lib.fileContents path); + in if m == null + then throw ("File contains no gitdir reference: " + path) + else + let gitDir = absolutePath (dirOf path) (lib.head m); + commonDir' = if pathIsRegularFile "${gitDir}/commondir" + then lib.fileContents "${gitDir}/commondir" + else gitDir; + commonDir = absolutePath gitDir commonDir'; + refFile = lib.removePrefix "${commonDir}/" "${gitDir}/${file}"; + in readCommitFromFile refFile commonDir + + else if pathIsRegularFile fileName + # Sometimes git stores the commitId directly in the file but + # sometimes it stores something like: «ref: refs/heads/branch-name» + then + let fileContent = lib.fileContents fileName; + matchRef = match "^ref: (.*)$" fileContent; + in if matchRef == null + then fileContent + else readCommitFromFile (lib.head matchRef) path + + else if pathIsRegularFile packedRefsName + # Sometimes, the file isn't there at all and has been packed away in the + # packed-refs file, so we have to grep through it: + then + let fileContent = readFile packedRefsName; + matchRef = match "([a-z0-9]+) ${file}"; + isRef = s: isString s && (matchRef s) != null; + # there is a bug in libstdc++ leading to stackoverflow for long strings: + # https://github.com/NixOS/nix/issues/2147#issuecomment-659868795 + refs = filter isRef (split "\n" fileContent); + in if refs == [] + then throw ("Could not find " + file + " in " + packedRefsName) + else lib.head (matchRef (lib.head refs)) + + else throw ("Not a .git directory: " + path); + in readCommitFromFile "HEAD"; + + pathHasContext = builtins.hasContext or (lib.hasPrefix storeDir); + + canCleanSource = src: src ? _isLibCleanSourceWith || !(pathHasContext (toString src)); +} |