summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorelseym <elseym@me.com>2020-01-10 21:24:31 +0100
committerelseym <elseym@me.com>2020-01-10 22:29:48 +0100
commitc9214c394b248e1f26e45dbe1be2bd82363af3a6 (patch)
treef28e88086f844a4d781fc9eb23bf7c078814b963 /lib
parentb74c26a17f1856735577c29d92939721d542f0f5 (diff)
downloadnixpkgs-c9214c394b248e1f26e45dbe1be2bd82363af3a6.tar
nixpkgs-c9214c394b248e1f26e45dbe1be2bd82363af3a6.tar.gz
nixpkgs-c9214c394b248e1f26e45dbe1be2bd82363af3a6.tar.bz2
nixpkgs-c9214c394b248e1f26e45dbe1be2bd82363af3a6.tar.lz
nixpkgs-c9214c394b248e1f26e45dbe1be2bd82363af3a6.tar.xz
nixpkgs-c9214c394b248e1f26e45dbe1be2bd82363af3a6.tar.zst
nixpkgs-c9214c394b248e1f26e45dbe1be2bd82363af3a6.zip
lib.commitIdFromGitRepo: support git-worktree
lib.commitIdFromGitRepo now resolves the refs from the
parent repository in case the supplied path is a file
containing the path to said repository. this adds support
for git-worktree and things alike. see gitrepository-layout(5).

this also:
- adds a new boolean function lib.pathIsRegularFile to
  check whether a path is a regular file
- patches lib.revisionWithDefault and
  the revision and versionSuffix attributes in
  config.system.nixos in order to support git-worktrees
Diffstat (limited to 'lib')
-rw-r--r--lib/default.nix2
-rw-r--r--lib/sources.nix34
-rw-r--r--lib/trivial.nix2
3 files changed, 30 insertions, 8 deletions
diff --git a/lib/default.nix b/lib/default.nix
index 9f7a088d792..77dda17f3b4 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -100,7 +100,7 @@ let
     inherit (sources) pathType pathIsDirectory cleanSourceFilter
       cleanSource sourceByRegex sourceFilesBySuffices
       commitIdFromGitRepo cleanSourceWith pathHasContext
-      canCleanSource;
+      canCleanSource pathIsRegularFile;
     inherit (modules) evalModules unifyModuleSyntax
       applyIfFunction mergeModules
       mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions
diff --git a/lib/sources.nix b/lib/sources.nix
index 51bcf5559e3..0fd172c42b7 100644
--- a/lib/sources.nix
+++ b/lib/sources.nix
@@ -9,6 +9,9 @@ rec {
   # Returns true if the path exists and is a directory, false otherwise
   pathIsDirectory = p: if builtins.pathExists p then (pathType p) == "directory" else false;
 
+  # Returns true if the path exists and is a regular file, false otherwise
+  pathIsRegularFile = p: if builtins.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 ! (
@@ -110,24 +113,43 @@ rec {
       with builtins;
         let fileName       = toString path + "/" + file;
             packedRefsName = toString path + "/packed-refs";
-        in if lib.pathExists fileName
+        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     = lib.head m;
+                      commonDir' = if pathIsRegularFile "${gitDir}/commondir"
+                                   then lib.fileContents "${gitDir}/commondir"
+                                   else gitDir;
+                      commonDir  = if lib.hasPrefix "/" commonDir'
+                                   then commonDir'
+                                   else toString (/. + "${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;
-                 # Sometimes git stores the commitId directly in the file but
-                 # sometimes it stores something like: «ref: refs/heads/branch-name»
                  matchRef    = match "^ref: (.*)$" fileContent;
-             in if   matchRef == null
+             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:
-           else if lib.pathExists packedRefsName
            then
              let fileContent = readFile packedRefsName;
                  matchRef    = match (".*\n([^\n ]*) " + file + "\n.*") fileContent;
-             in if   matchRef == null
+             in if  matchRef == null
                 then throw ("Could not find " + file + " in " + packedRefsName)
                 else lib.head matchRef
+
            else throw ("Not a .git directory: " + path);
     in readCommitFromFile "HEAD";
 
diff --git a/lib/trivial.nix b/lib/trivial.nix
index 3a25e31fb05..940ec1a3d59 100644
--- a/lib/trivial.nix
+++ b/lib/trivial.nix
@@ -191,7 +191,7 @@ rec {
     let
       revisionFile = "${toString ./..}/.git-revision";
       gitRepo      = "${toString ./..}/.git";
-    in if lib.pathIsDirectory gitRepo
+    in if builtins.pathExists gitRepo
        then lib.commitIdFromGitRepo gitRepo
        else if lib.pathExists revisionFile then lib.fileContents revisionFile
        else default;