diff --git a/README.md b/README.md
index bdd10bb..ae3214a 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,7 @@ it is converted to an attribute set equivalent to `{ root = theArg; }`.
| `version` | The version of the derivation. |
| `src` | Used by `naersk` as source input to the derivation. When `root` is not set, `src` is also used to discover the `Cargo.toml` and `Cargo.lock`. |
| `root` | Used by `naersk` to read the `Cargo.toml` and `Cargo.lock` files. May be different from `src`. When `src` is not set, `root` is (indirectly) used as `src`. |
+| `allRefs` | Whether to fetch all refs while fetching Git dependencies. Useful if the wanted revision isn't in the default branch. |
| `cargoBuild` | The command to use for the build. The argument must be a function modifying the default value.
Default: `''cargo $cargo_options build $cargo_build_options >> $cargo_build_output_json''` |
| `cargoBuildOptions` | Options passed to cargo build, i.e. `cargo build `. These options can be accessed during the build through the environment variable `cargo_build_options`.
Note: naersk relies on the `--out-dir out` option and the `--message-format` option. The `$cargo_message_format` variable is set based on the cargo version.
Note: these values are not (shell) escaped, meaning that you can use environment variables but must be careful when introducing e.g. spaces.
The argument must be a function modifying the default value.
Default: `[ "$cargo_release" ''-j "$NIX_BUILD_CORES"'' "--out-dir" "out" "--message-format=$cargo_message_format" ]` |
| `remapPathPrefix` | When `true`, rustc remaps the (`/nix/store`) source paths to `/sources` to reduce the number of dependencies in the closure. Default: `true` |
diff --git a/build.nix b/build.nix
index 74a6b01..f8c6511 100644
--- a/build.nix
+++ b/build.nix
@@ -65,10 +65,6 @@ let
builtins // import ./builtins
{ inherit lib writeText remarshal runCommand; };
- # All the git dependencies, as a list
- gitDependenciesList =
- lib.concatLists (lib.mapAttrsToList (_: ds: ds) gitDependencies);
-
# This unpacks all git dependencies:
# $out/rand
# $out/rand/Cargo.toml
@@ -127,7 +123,7 @@ let
fi
done <<< "$tomls"
done < <(cat ${
- builtins.toFile "git-deps-json" (builtins.toJSON gitDependenciesList)
+ builtins.toFile "git-deps-json" (builtins.toJSON gitDependencies)
} | jq -cMr '.[]')
'';
@@ -173,7 +169,7 @@ let
};
}
)
- gitDependenciesList
+ gitDependencies
);
};
diff --git a/config.nix b/config.nix
index c412f87..1f2d7d8 100644
--- a/config.nix
+++ b/config.nix
@@ -25,6 +25,10 @@ let
# used as `src`.
root = attrs0.root or null;
+ # Whether to fetch all refs while fetching Git dependencies. Useful if
+ # the wanted revision isn't in the default branch.
+ allRefs = attrs0.allRefs or false;
+
# The command to use for the build.
cargoBuild =
allowFun attrs0 "cargoBuild"
@@ -234,7 +238,7 @@ let
# Whether we skip pre-building the deps
isSingleStep = attrs.singleStep;
- inherit (attrs) overrideMain;
+ inherit (attrs) overrideMain allRefs;
# The members we want to build
# (list of directory names)
diff --git a/default.nix b/default.nix
index 2aa3cee..3065785 100644
--- a/default.nix
+++ b/default.nix
@@ -26,7 +26,7 @@ let
let
config = mkConfig arg;
gitDependencies =
- libb.findGitDependencies { inherit (config) cargotomls cargolock; };
+ libb.findGitDependencies { inherit (config) cargolock allRefs; };
cargoconfig =
if builtinz.pathExists (toString config.root + "/.cargo/config")
then builtins.readFile (config.root + "/.cargo/config")
diff --git a/lib.nix b/lib.nix
index c42fcb6..e317f4c 100644
--- a/lib.nix
+++ b/lib.nix
@@ -64,99 +64,56 @@ rec
mkMetadataKey = name: version:
"checksum ${name} ${version} (registry+https://github.com/rust-lang/crates.io-index)";
- # a record:
- # { "." = # '.' is the directory of the cargotoml
- # [
- # {
- # name = "rand";
- # url = "https://github.com/...";
- # checkout = "/nix/store/checkout"
- # }
- # ]
+ # Gets all git dependencies in Cargo.lock as a list.
+ # [
+ # {
+ # name = "rand";
+ # url = "https://github.com/...";
+ # checkout = "/nix/store/checkout"
# }
+ # ]
findGitDependencies =
- { cargotomls
- , cargolock
- }:
- let
- # This returns all the git dependencies of a particular Cargo.toml.
- # tomlDependencies : Cargo.toml ->
- # [
- # {
- # checkout = { rev = "abcd"; shortRev = "abcd"; outPath = ...; ... };
- # key = "abcd";
- # name = "rand";
- # url = "https://github.com/...";
- # }
- # ...
- # ]
- #
- # NOTE: this is terribly inefficient _and_ confusing:
- # * the lockfile is read once for every cargo toml entry (n^2)
- # * 'fromLockfile' is odd, instead of returning the first matched
- # revision it'll return a pseudo lockfile entry
- tomlDependencies = cargotoml:
- lib.filter (x: ! isNull x) (
- lib.mapAttrsToList
- (entryName: v: # The dependecy name + the entry from the cargo toml
- if ! (lib.isAttrs v && builtins.hasAttr "git" v)
- then null
- else
- let
- # Use the 'package' attribute if it exists, which means this is a renamed dependency
- # https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml
- depName = v.package or entryName;
- # predicate that holds if the given lockfile entry is the
- # Cargo.toml dependency being looked at (depName)
- pred = entry: entry.name == depName && (lib.substring 0 (4 + lib.stringLength v.git) entry.source) == "git+${v.git}";
-
- # extract the revision from a Cargo.lock "package.source"
- # entry
- # git+https://gi.../rand?rev=703452...#703452
- # ^^^^^^
- extractRevision = url: lib.last (lib.splitString "#" url);
-
- # parse a lockfile entry:
- # { name = "rand";
- # version = ...;
- # source = "git+https://...rev=703452...#703452";
- # } ->
- # { name = "rand";
- # source = "git+https://...rev=703452...#703452";
- # revision = "703452";
- # }
- parseLockfileEntry = entry: rec { inherit (entry) name source; revision = extractRevision source; };
-
- # List of all entries: [ { name, source, revision } ]
- packageLocks = builtins.map parseLockfileEntry (lib.filter pred cargolock.package);
+ { cargolock, allRefs }:
+ let
+ query = p: (lib.substring 0 4 (p.source or "")) == "git+";
- # Find the first revision from the lockfile that:
- # * has the same name as the cargo toml entry _if_ the cargo toml does not specify a revision, or
- # * has the same name and revision as the cargo toml entry
- fromLockfile = lib.findFirst (p: p.name == depName && ((! v?rev) || v.rev == p.revision)) null packageLocks;
+ extractRevision = source: lib.last (lib.splitString "#" source);
+ extractPart = part: source: if lib.hasInfix part source then lib.last (lib.splitString part (lib.head (lib.splitString "#" source))) else null;
+ extractRepoUrl = source: let splitted = lib.head (lib.splitString "?" source); in lib.substring 4 (lib.stringLength splitted) splitted;
- # Cargo.lock revision is prioritized, because in Cargo.toml short revisions are allowed
- val = v // { rev = fromLockfile.revision or v.rev or null; };
- in
- lib.filterAttrs (n: _: n == "rev" || n == "tag" || n == "branch") val //
- {
- name = depName;
- url = val.git;
- key = val.rev or val.tag or val.branch or
- (throw "No 'rev', 'tag' or 'branch' available to specify key, nor a git revision was found in Cargo.lock");
- checkout = builtins.fetchGit ({
- url = val.git;
- } // lib.optionalAttrs (val ? rev) {
- rev = val.rev;
- } // lib.optionalAttrs (val ? branch) {
- ref = val.branch;
- } // lib.optionalAttrs (val ? tag) {
- ref = val.tag;
- });
- }
- ) cargotoml.dependencies or { });
+ parseLock = lock:
+ let
+ source = lock.source;
+ rev = extractPart "?rev=" source;
+ tag = extractPart "?tag=" source;
+ branch = extractPart "?branch=" source;
in
- lib.mapAttrs (_: x: tomlDependencies x) cargotomls;
+ {
+ inherit (lock) name;
+ revision = extractRevision source;
+ url = extractRepoUrl source;
+ } // (lib.optionalAttrs (! isNull branch) { inherit branch; })
+ // (lib.optionalAttrs (! isNull tag) { inherit tag; })
+ // (lib.optionalAttrs (! isNull rev) { inherit rev; });
+ packageLocks = builtins.map parseLock (lib.filter query cargolock.package);
+
+ mkFetch = lock: {
+ key = lock.revision or lock.rev or lock.tag or lock.branch
+ or (throw "No 'rev', 'tag' or 'branch' available to specify key, nor a git revision was found in Cargo.lock");
+ checkout = builtins.fetchGit ({
+ url = lock.url;
+ rev = lock.revision;
+ } // lib.optionalAttrs (lock ? rev) {
+ rev = lock.rev;
+ } // lib.optionalAttrs (lock ? branch) {
+ ref = lock.branch;
+ } // lib.optionalAttrs (lock ? tag) {
+ ref = lock.tag;
+ } // lib.optionalAttrs allRefs {
+ allRefs = true;
+ });
+ } // lock;
+ in lib.foldl' (acc: e: if lib.any (oe: (oe.url == e.url) && (oe.key == e.key)) acc then acc else acc ++ [e]) [] (builtins.map mkFetch packageLocks);
# A very minimal 'src' which makes cargo happy nonetheless
dummySrc =