diff --git a/CHANGELOG.md b/CHANGELOG.md index e30a046e..59906c2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ in case a crate is used as `bin` artifact dependency. * Add `cargoLlvmCov` to run `cargo llvm-cov` * Add `cargoLockParsed` option to `vendorCargoDeps` to support `Cargo.lock` files parsed as nix attribute sets. +* `craneLib.path` can now be used as a convenience wrapper on (or drop in + replacement of) `builtins.path` to ensure reproducible results whenever paths + like `./.` or `./..` are used directly. ## [0.11.3] - 2023-02-19 diff --git a/docs/API.md b/docs/API.md index 3f1a4ad9..73278bb4 100644 --- a/docs/API.md +++ b/docs/API.md @@ -618,7 +618,7 @@ written (which may want to also call `lib.filterCargoSources`) to achieve the desired behavior. ```nix -lib.cleanCargoSource ./. +lib.cleanCargoSource (lib.path ./.) ``` ### `lib.cleanCargoToml` @@ -761,7 +761,7 @@ will retain the following files from a given source: ```nix cleanSourceWith { - src = ./.; + src = lib.path ./.; filter = lib.filterCargoSources; } ``` @@ -777,7 +777,7 @@ let (markdownFilter path type) || (lib.filterCargoSources path type); in cleanSourceWith { - src = ./.; + src = lib.path ./.; filter = markdownOrCargo; } ``` @@ -928,7 +928,7 @@ build caches. More specifically: mkDummySrc { # The _entire_ source of the project. mkDummySrc will automatically # filter out irrelevant files as described above - src = ./.; + src = lib.path ./.; # Note that here we scope the path to just `./.cargo` and not any other # directories which may exist at the root of the project. Also note that @@ -959,6 +959,40 @@ can be the output of `oxalica/rust-overlay`. crane.lib.${system}.overrideToolchain myCustomToolchain ``` +### `lib.path` + +`path :: path -> drv` + +`path :: set -> drv` + +A convenience wrapper around `builtins.path` which will automatically set the +path's `name` to the workspace's package name (or a placeholder value of +`"source"` if a name cannot be determined). + +It should be used anywhere a relative path like `./.` or `./..` is needed so +that the result is reproducible and caches can be reused. Otherwise the store +path [will depend on the name of the parent +directory](https://nix.dev/anti-patterns/language#reproducibility-referencing-top-level-directory-with) which may cause unnecessary rebuilds. + +```nix +crane.lib.${system}.path ./. +# "/nix/store/wbhf6c7wiw9z53hsn487a8wswivwdw81-source" +``` + +```nix +lib.path ./checks/simple +# "/nix/store/s9scn97c86kqskf7yv5n2k85in5y5cmy-simple" +``` + +It is also possible to use as a drop in replacement for `builtins.path`: +```nix +lib.path { + path = ./.; + name = "asdf"; +} +# "/nix/store/23zy3c68v789cg8sysgba0rbgbfcjfhn-asdf" +``` + ### `lib.registryFromDownloadUrl` `registryFromDownloadUrl :: set -> set` diff --git a/docs/custom_cargo_commands.md b/docs/custom_cargo_commands.md index 6bfc5361..13947218 100644 --- a/docs/custom_cargo_commands.md +++ b/docs/custom_cargo_commands.md @@ -46,6 +46,6 @@ let }); in cargoAwesome { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); } ``` diff --git a/docs/customizing_builds.md b/docs/customizing_builds.md index 177b3030..0a2b7b11 100644 --- a/docs/customizing_builds.md +++ b/docs/customizing_builds.md @@ -34,7 +34,7 @@ and hooks to customize a particular build: ```nix craneLib.buildPackage { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); # Define a list of function names to execute before the `configurePhase` runs preConfigurePhases = [ diff --git a/docs/faq/patching-cargo-lock.md b/docs/faq/patching-cargo-lock.md index dacf1f99..7bf82a76 100644 --- a/docs/faq/patching-cargo-lock.md +++ b/docs/faq/patching-cargo-lock.md @@ -29,7 +29,7 @@ craneLib.buildPackage { src = patchedCargoLock; }; - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); patches = [ ./update-cargo-lock.patch diff --git a/docs/faq/workspace-not-at-source-root.md b/docs/faq/workspace-not-at-source-root.md index f516b085..d5b58e1e 100644 --- a/docs/faq/workspace-not-at-source-root.md +++ b/docs/faq/workspace-not-at-source-root.md @@ -13,7 +13,7 @@ deeper directory: # ./nested/Cargo.lock # ./nested/src/*.rs craneLib.buildPackage { - src = myLib.cleanCargoSource ./.; + src = myLib.cleanCargoSource (craneLib.path ./.); cargoLock = ./nested/Cargo.lock; cargoToml = ./nested/Cargo.toml; # Use a postUnpack hook to jump into our nested directory. This will work diff --git a/docs/getting-started.md b/docs/getting-started.md index edec1c22..6fc3da06 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -41,7 +41,7 @@ following contents at the root of your cargo workspace: in { packages.default = craneLib.buildPackage { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); # Add extra inputs here or any other derivation settings # doCheck = true; diff --git a/docs/introduction/artifact-reuse.md b/docs/introduction/artifact-reuse.md index 77b58cbb..5aa23b83 100644 --- a/docs/introduction/artifact-reuse.md +++ b/docs/introduction/artifact-reuse.md @@ -35,7 +35,7 @@ Here's how we can set up our flake to achieve our goals: # Common derivation arguments used for all builds commonArgs = { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); buildInputs = with pkgs; [ # Add extra build inputs here, etc. diff --git a/docs/introduction/sequential-builds.md b/docs/introduction/sequential-builds.md index b3a8b506..5fe3da96 100644 --- a/docs/introduction/sequential-builds.md +++ b/docs/introduction/sequential-builds.md @@ -26,7 +26,7 @@ build. craneLib = crane.lib.${system}; # Common derivation arguments used for all builds commonArgs = { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); buildInputs = with pkgs; [ # Add extra build inputs here, etc. diff --git a/docs/local_development.md b/docs/local_development.md index ebb70ef3..675044ea 100644 --- a/docs/local_development.md +++ b/docs/local_development.md @@ -34,7 +34,7 @@ Sample `flake.nix`: craneLib = crane.lib.${system}; my-crate = craneLib.buildPackage { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); buildInputs = [ # Add additional build inputs here diff --git a/docs/source-filtering.md b/docs/source-filtering.md index 1698db05..fc2641ca 100644 --- a/docs/source-filtering.md +++ b/docs/source-filtering.md @@ -17,7 +17,7 @@ non-Rust/non-cargo related files. It can be used like so: ```nix craneLib.buildPackage { # other attributes omitted - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); } ``` @@ -37,7 +37,7 @@ in craneLib.buildPackage { # other attributes omitted src = lib.cleanSourceWith { - src = ./.; # The original, unfiltered source + src = craneLib.path ./.; # The original, unfiltered source filter = markdownOrCargo; }; } diff --git a/examples/alt-registry/flake.nix b/examples/alt-registry/flake.nix index 236d3be0..a578128c 100644 --- a/examples/alt-registry/flake.nix +++ b/examples/alt-registry/flake.nix @@ -52,7 +52,7 @@ ]; my-crate = craneLib.buildPackage { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); buildInputs = [ # Add additional build inputs here diff --git a/examples/cross-musl/flake.nix b/examples/cross-musl/flake.nix index b0a8e2e5..95399345 100644 --- a/examples/cross-musl/flake.nix +++ b/examples/cross-musl/flake.nix @@ -35,7 +35,7 @@ craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; my-crate = craneLib.buildPackage { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); CARGO_BUILD_TARGET = "x86_64-unknown-linux-musl"; CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static"; diff --git a/examples/cross-rust-overlay/flake.nix b/examples/cross-rust-overlay/flake.nix index 8a87d323..ab6119eb 100644 --- a/examples/cross-rust-overlay/flake.nix +++ b/examples/cross-rust-overlay/flake.nix @@ -57,7 +57,7 @@ , stdenv }: craneLib.buildPackage { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); # Build-time tools which are target agnostic. build = host = target = your-machine. # Emulators should essentially also go `nativeBuildInputs`. But with some packaging issue, diff --git a/examples/cross-windows/flake.nix b/examples/cross-windows/flake.nix index 81b94496..b2a41bba 100644 --- a/examples/cross-windows/flake.nix +++ b/examples/cross-windows/flake.nix @@ -35,7 +35,7 @@ in { packages.default = craneLib.buildPackage { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); strictDeps = true; doCheck = false; diff --git a/examples/custom-toolchain/flake.nix b/examples/custom-toolchain/flake.nix index 9885c3af..d193dc52 100644 --- a/examples/custom-toolchain/flake.nix +++ b/examples/custom-toolchain/flake.nix @@ -39,7 +39,7 @@ craneLib = (crane.mkLib pkgs).overrideToolchain rustWithWasiTarget; my-crate = craneLib.buildPackage { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); cargoExtraArgs = "--target wasm32-wasi"; diff --git a/examples/quick-start-simple/flake.nix b/examples/quick-start-simple/flake.nix index 456c4396..8bce96a6 100644 --- a/examples/quick-start-simple/flake.nix +++ b/examples/quick-start-simple/flake.nix @@ -21,7 +21,7 @@ craneLib = crane.lib.${system}; my-crate = craneLib.buildPackage { - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); buildInputs = [ # Add additional build inputs here diff --git a/examples/quick-start/flake.nix b/examples/quick-start/flake.nix index a55995f3..33a219fb 100644 --- a/examples/quick-start/flake.nix +++ b/examples/quick-start/flake.nix @@ -34,7 +34,7 @@ inherit (pkgs) lib; craneLib = crane.lib.${system}; - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource (craneLib.path ./.); # Common arguments can be set here to avoid repeating them later commonArgs = { diff --git a/lib/crateNameFromCargoToml.nix b/lib/crateNameFromCargoToml.nix index 68d6c934..40a08e9b 100644 --- a/lib/crateNameFromCargoToml.nix +++ b/lib/crateNameFromCargoToml.nix @@ -1,4 +1,5 @@ -{ lib +{ internalCrateNameFromCargoToml +, lib }: args: @@ -29,35 +30,10 @@ let traceMsg = tomlName: drvName: placeholder: lib.trivial.warn "crane cannot find ${tomlName} attribute in ${debugPath}, consider setting `${drvName} = \"...\";` explicitly" placeholder; + + internalName = internalCrateNameFromCargoToml toml; in { - # Now that cargo supports workspace inheritance we attempt to select a name - # with the following priorities: - # - choose `[package.name]` if the value is present and a string - # (i.e. it isn't `[package.name] = { workspace = "true" }`) - # - choose `[workspace.package.name]` if it is present (and a string for good measure) - # - otherwise, fall back to a placeholder - pname = - let - packageName = toml.package.name or null; - workspacePackageName = toml.workspace.package.name or null; - in - if lib.isString packageName then packageName - else if lib.isString workspacePackageName then workspacePackageName - else traceMsg "name" "pname" "cargo-package"; - - # Now that cargo supports workspace inheritance we attempt to select a version - # string with the following priorities: - # - choose `[package.version]` if the value is present and a string - # (i.e. it isn't `[package.version] = { workspace = "true" }`) - # - choose `[workspace.package.version]` if it is present (and a string for good measure) - # - otherwise, fall back to a placeholder - version = - let - packageVersion = toml.package.version or null; - workspacePackageVersion = toml.workspace.package.version or null; - in - if lib.isString packageVersion then packageVersion - else if lib.isString workspacePackageVersion then workspacePackageVersion - else traceMsg "version" "version" "0.0.1"; + pname = internalName.pname or (traceMsg "name" "pname" "cargo-package"); + version = internalName.version or (traceMsg "version" "version" "0.0.1"); } diff --git a/lib/default.nix b/lib/default.nix index cc86dd13..42114d49 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -5,6 +5,8 @@ lib.makeScope newScope (self: let inherit (self) callPackage; + + internalCrateNameFromCargoToml = callPackage ./internalCrateNameFromCargoToml.nix { }; in { appendCrateRegistries = input: self.overrideScope' (_final: prev: { @@ -28,7 +30,10 @@ in configureCargoCommonVarsHook = callPackage ./setupHooks/configureCargoCommonVars.nix { }; configureCargoVendoredDepsHook = callPackage ./setupHooks/configureCargoVendoredDeps.nix { }; craneUtils = callPackage ../pkgs/crane-utils { }; - crateNameFromCargoToml = callPackage ./crateNameFromCargoToml.nix { }; + + crateNameFromCargoToml = callPackage ./crateNameFromCargoToml.nix { + inherit internalCrateNameFromCargoToml; + }; crateRegistries = self.registryFromDownloadUrl { dl = "https://crates.io/api/v1/crates"; @@ -52,6 +57,10 @@ in rustfmt = toolchain; }); + path = callPackage ./path.nix { + inherit internalCrateNameFromCargoToml; + }; + registryFromDownloadUrl = callPackage ./registryFromDownloadUrl.nix { }; registryFromGitIndex = callPackage ./registryFromGitIndex.nix { }; removeReferencesToVendoredSourcesHook = callPackage ./setupHooks/removeReferencesToVendoredSources.nix { }; diff --git a/lib/internalCrateNameFromCargoToml.nix b/lib/internalCrateNameFromCargoToml.nix new file mode 100644 index 00000000..0f2be14d --- /dev/null +++ b/lib/internalCrateNameFromCargoToml.nix @@ -0,0 +1,35 @@ +{ lib +}: + +toml: +lib.filterAttrs (_: v: v != null) { + # Now that cargo supports workspace inheritance we attempt to select a name + # with the following priorities: + # - choose `[package.name]` if the value is present and a string + # (i.e. it isn't `[package.name] = { workspace = "true" }`) + # - choose `[workspace.package.name]` if it is present (and a string for good measure) + # - otherwise, fall back to a placeholder + pname = + let + packageName = toml.package.name or null; + workspacePackageName = toml.workspace.package.name or null; + in + if lib.isString packageName then packageName + else if lib.isString workspacePackageName then workspacePackageName + else null; + + # Now that cargo supports workspace inheritance we attempt to select a version + # string with the following priorities: + # - choose `[package.version]` if the value is present and a string + # (i.e. it isn't `[package.version] = { workspace = "true" }`) + # - choose `[workspace.package.version]` if it is present (and a string for good measure) + # - otherwise, fall back to a placeholder + version = + let + packageVersion = toml.package.version or null; + workspacePackageVersion = toml.workspace.package.version or null; + in + if lib.isString packageVersion then packageVersion + else if lib.isString workspacePackageVersion then workspacePackageVersion + else null; +} diff --git a/lib/path.nix b/lib/path.nix new file mode 100644 index 00000000..716f1e7e --- /dev/null +++ b/lib/path.nix @@ -0,0 +1,24 @@ +{ internalCrateNameFromCargoToml +, lib +}: + +input: +let + pathArgs = if lib.isAttrs input then input else { path = input; }; + + cargoTomlContents = + let + emptyToml = { }; + cargoToml = pathArgs.path + "/Cargo.toml"; + cargoTomlContents = builtins.readFile cargoToml; + toml = builtins.tryEval (builtins.fromTOML cargoTomlContents); + in + if builtins.pathExists cargoToml + then + if toml.success then toml.value else emptyToml + else + emptyToml; + + name = (internalCrateNameFromCargoToml cargoTomlContents).pname or "source"; +in +builtins.path ({ inherit name; } // pathArgs) diff --git a/pkgs/crane-utils/default.nix b/pkgs/crane-utils/default.nix index f5dd832e..9f5a9a3f 100644 --- a/pkgs/crane-utils/default.nix +++ b/pkgs/crane-utils/default.nix @@ -3,10 +3,11 @@ , cargoClippy , cargoFmt , cleanCargoSource +, path }: let - src = cleanCargoSource ./.; + src = cleanCargoSource (path ./.); cargoArtifacts = buildDepsOnly { inherit src; diff --git a/pkgs/default.nix b/pkgs/default.nix index 3dd763fc..082ea577 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -4,7 +4,7 @@ book = let inherit (pkgs) lib; - root = ./..; + root = myLib.path ./..; rootPrefix = toString root; cleanedSrc = lib.cleanSourceWith { src = root; diff --git a/shell.nix b/shell.nix index 061d3726..daec5c99 100644 --- a/shell.nix +++ b/shell.nix @@ -6,6 +6,11 @@ let sha256 = locked.narHash; }; - flake = import compat { src = ./.; }; + flake = import compat { + src = builtins.path { + path = ./.; + name = "crane"; + }; + }; in flake.shellNix