mirror of
https://github.com/nix-community/dream2nix.git
synced 2024-12-23 06:21:30 +03:00
feat(rust): port crane builder
This commit is contained in:
parent
55b0141465
commit
b2ca3da052
93
modules/drv-parts/rust-crane/build.nix
Normal file
93
modules/drv-parts/rust-crane/build.nix
Normal file
@ -0,0 +1,93 @@
|
||||
{
|
||||
lib,
|
||||
crane,
|
||||
utils,
|
||||
vendoring,
|
||||
# lock data
|
||||
subsystemAttrs,
|
||||
packages,
|
||||
...
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
|
||||
buildPackage = pname: version: let
|
||||
replacePaths =
|
||||
utils.replaceRelativePathsWithAbsolute
|
||||
subsystemAttrs.relPathReplacements.${pname}.${version};
|
||||
writeGitVendorEntries = vendoring.writeGitVendorEntries "nix-sources";
|
||||
|
||||
# common args we use for both buildDepsOnly and buildPackage
|
||||
common = {
|
||||
inherit pname version;
|
||||
|
||||
src = utils.getRootSource pname version;
|
||||
cargoVendorDir = "$TMPDIR/nix-vendor";
|
||||
installCargoArtifactsMode = "use-zstd";
|
||||
|
||||
postUnpack = ''
|
||||
export CARGO_HOME=$(pwd)/.cargo_home
|
||||
export cargoVendorDir="$TMPDIR/nix-vendor"
|
||||
'';
|
||||
preConfigure = ''
|
||||
${writeGitVendorEntries}
|
||||
${replacePaths}
|
||||
'';
|
||||
|
||||
cargoTestProfile = "release";
|
||||
cargoBuildProfile = "release";
|
||||
|
||||
# Make sure cargo only builds & tests the package we want
|
||||
cargoBuildCommand = "cargo build \${cargoBuildFlags:-} --profile \${cargoBuildProfile} --package ${pname}";
|
||||
cargoTestCommand = "cargo test \${cargoTestFlags:-} --profile \${cargoTestProfile} --package ${pname}";
|
||||
};
|
||||
|
||||
# The deps-only derivation will use this as a prefix to the `pname`
|
||||
depsNameSuffix = "-deps";
|
||||
depsArgs =
|
||||
common
|
||||
// {
|
||||
# we pass cargoLock path to buildDepsOnly
|
||||
# so that crane's mkDummySrc adds it to the dummy source
|
||||
inherit (utils) cargoLock;
|
||||
pnameSuffix = depsNameSuffix;
|
||||
# Make sure cargo only checks the package we want
|
||||
cargoCheckCommand = "cargo check \${cargoBuildFlags:-} --profile \${cargoBuildProfile} --package ${pname}";
|
||||
dream2nixVendorDir = vendoring.vendoredDependencies;
|
||||
preUnpack = ''
|
||||
${vendoring.copyVendorDir "$dream2nixVendorDir" common.cargoVendorDir}
|
||||
'';
|
||||
# move the vendored dependencies folder to $out for main derivation to use
|
||||
postInstall = ''
|
||||
mv $TMPDIR/nix-vendor $out/nix-vendor
|
||||
'';
|
||||
};
|
||||
deps = crane.buildDepsOnly depsArgs;
|
||||
|
||||
buildArgs =
|
||||
common
|
||||
// {
|
||||
meta = utils.getMeta pname version;
|
||||
cargoArtifacts = deps;
|
||||
# link the vendor dir we used earlier to the correct place
|
||||
preUnpack = ''
|
||||
${vendoring.copyVendorDir "$cargoArtifacts/nix-vendor" common.cargoVendorDir}
|
||||
'';
|
||||
# write our cargo lock
|
||||
# note: we don't do this in buildDepsOnly since
|
||||
# that uses a cargoLock argument instead
|
||||
preConfigure = ''
|
||||
${common.preConfigure}
|
||||
${utils.writeCargoLock}
|
||||
'';
|
||||
passthru = {dependencies = deps;};
|
||||
};
|
||||
build = crane.buildPackage buildArgs;
|
||||
in
|
||||
build;
|
||||
|
||||
allPackages =
|
||||
l.mapAttrs
|
||||
(name: version: {"${version}" = buildPackage name version;})
|
||||
packages;
|
||||
in
|
||||
allPackages
|
104
modules/drv-parts/rust-crane/crane.nix
Normal file
104
modules/drv-parts/rust-crane/crane.nix
Normal file
@ -0,0 +1,104 @@
|
||||
{
|
||||
lib,
|
||||
craneSource,
|
||||
# nixpkgs
|
||||
cargo,
|
||||
makeSetupHook,
|
||||
runCommand,
|
||||
runCommandLocal,
|
||||
writeText,
|
||||
stdenv,
|
||||
zstd,
|
||||
jq,
|
||||
remarshal,
|
||||
}: let
|
||||
importLibFile = name: import "${craneSource}/lib/${name}.nix";
|
||||
|
||||
makeHook = attrs: name:
|
||||
makeSetupHook
|
||||
({inherit name;} // attrs)
|
||||
"${craneSource}/lib/setupHooks/${name}.sh";
|
||||
genHooks = names: attrs: lib.genAttrs names (makeHook attrs);
|
||||
|
||||
crane = rec {
|
||||
otherHooks =
|
||||
genHooks [
|
||||
"cargoHelperFunctionsHook"
|
||||
"configureCargoCommonVarsHook"
|
||||
"configureCargoVendoredDepsHook"
|
||||
"removeReferencesToVendoredSourcesHook"
|
||||
]
|
||||
{};
|
||||
installHooks =
|
||||
genHooks [
|
||||
"inheritCargoArtifactsHook"
|
||||
"installCargoArtifactsHook"
|
||||
]
|
||||
{
|
||||
substitutions = {
|
||||
zstd = "${zstd}/bin/zstd";
|
||||
};
|
||||
};
|
||||
installLogHook = genHooks ["installFromCargoBuildLogHook"] {
|
||||
substitutions = {
|
||||
cargo = "${cargo}/bin/cargo";
|
||||
jq = "${jq}/bin/jq";
|
||||
};
|
||||
};
|
||||
|
||||
# These aren't used by dream2nix
|
||||
crateNameFromCargoToml = null;
|
||||
vendorCargoDeps = null;
|
||||
|
||||
writeTOML = importLibFile "writeTOML" {
|
||||
inherit runCommand;
|
||||
pkgsBuildBuild = {inherit remarshal;};
|
||||
};
|
||||
cleanCargoToml = importLibFile "cleanCargoToml" {};
|
||||
findCargoFiles = importLibFile "findCargoFiles" {
|
||||
inherit lib;
|
||||
};
|
||||
mkDummySrc = importLibFile "mkDummySrc" {
|
||||
inherit writeText runCommandLocal lib;
|
||||
inherit writeTOML cleanCargoToml findCargoFiles;
|
||||
};
|
||||
|
||||
mkCargoDerivation = importLibFile "mkCargoDerivation" {
|
||||
inherit stdenv zstd cargo;
|
||||
inherit
|
||||
(installHooks)
|
||||
inheritCargoArtifactsHook
|
||||
installCargoArtifactsHook
|
||||
;
|
||||
inherit
|
||||
(otherHooks)
|
||||
configureCargoCommonVarsHook
|
||||
configureCargoVendoredDepsHook
|
||||
cargoHelperFunctionsHook
|
||||
;
|
||||
inherit crateNameFromCargoToml vendorCargoDeps;
|
||||
};
|
||||
buildDepsOnly = importLibFile "buildDepsOnly" {
|
||||
inherit lib;
|
||||
inherit
|
||||
mkCargoDerivation
|
||||
crateNameFromCargoToml
|
||||
vendorCargoDeps
|
||||
mkDummySrc
|
||||
;
|
||||
};
|
||||
buildPackage = importLibFile "buildPackage" {
|
||||
inherit lib jq;
|
||||
inherit (installLogHook) installFromCargoBuildLogHook;
|
||||
inherit
|
||||
buildDepsOnly
|
||||
crateNameFromCargoToml
|
||||
vendorCargoDeps
|
||||
mkCargoDerivation
|
||||
;
|
||||
inherit (otherHooks) removeReferencesToVendoredSourcesHook;
|
||||
};
|
||||
};
|
||||
in {
|
||||
inherit (crane) buildPackage buildDepsOnly;
|
||||
}
|
169
modules/drv-parts/rust-crane/default.nix
Normal file
169
modules/drv-parts/rust-crane/default.nix
Normal file
@ -0,0 +1,169 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
extendModules,
|
||||
...
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
|
||||
cfg = config.rust-crane;
|
||||
|
||||
dreamLock = config.rust-cargo-lock.dreamLock;
|
||||
|
||||
fetchDreamLockSources =
|
||||
import ../../../lib/internal/fetchDreamLockSources.nix
|
||||
{inherit lib;};
|
||||
getDreamLockSource = import ../../../lib/internal/getDreamLockSource.nix {inherit lib;};
|
||||
readDreamLock = import ../../../lib/internal/readDreamLock.nix {inherit lib;};
|
||||
hashPath = import ../../../lib/internal/hashPath.nix {
|
||||
inherit lib;
|
||||
inherit (config.deps) runCommandLocal nix;
|
||||
};
|
||||
hashFile = import ../../../lib/internal/hashFile.nix {
|
||||
inherit lib;
|
||||
inherit (config.deps) runCommandLocal nix;
|
||||
};
|
||||
|
||||
# fetchers
|
||||
fetchers = {
|
||||
git = import ../../../lib/internal/fetchers/git {
|
||||
inherit hashPath;
|
||||
inherit (config.deps) fetchgit;
|
||||
};
|
||||
crates-io = import ../../../lib/internal/fetchers/crates-io {
|
||||
inherit hashFile;
|
||||
inherit (config.deps) fetchurl runCommandLocal;
|
||||
};
|
||||
path = import ../../../lib/internal/fetchers/path {
|
||||
inherit hashPath;
|
||||
};
|
||||
};
|
||||
|
||||
dreamLockLoaded = readDreamLock {inherit dreamLock;};
|
||||
dreamLockInterface = dreamLockLoaded.interface;
|
||||
|
||||
inherit (dreamLockInterface) defaultPackageName defaultPackageVersion;
|
||||
|
||||
fetchedSources' = fetchDreamLockSources {
|
||||
inherit defaultPackageName defaultPackageVersion;
|
||||
inherit (dreamLockLoaded.lock) sources;
|
||||
inherit fetchers;
|
||||
};
|
||||
|
||||
fetchedSources =
|
||||
fetchedSources'
|
||||
// {
|
||||
${defaultPackageName}.${defaultPackageVersion} = config.mkDerivation.src;
|
||||
};
|
||||
|
||||
getSource = getDreamLockSource fetchedSources;
|
||||
|
||||
toTOML = import ../../../lib/internal/toTOML.nix {inherit lib;};
|
||||
|
||||
utils = import ./utils.nix {
|
||||
inherit dreamLock getSource lib toTOML;
|
||||
inherit
|
||||
(dreamLockInterface)
|
||||
getSourceSpec
|
||||
getRoot
|
||||
subsystemAttrs
|
||||
packages
|
||||
;
|
||||
inherit
|
||||
(config.deps)
|
||||
writeText
|
||||
;
|
||||
sourceRoot = config.mkDerivation.src;
|
||||
};
|
||||
|
||||
vendoring = import ./vendor.nix {
|
||||
inherit dreamLock getSource lib;
|
||||
inherit
|
||||
(dreamLockInterface)
|
||||
getSourceSpec
|
||||
subsystemAttrs
|
||||
;
|
||||
inherit
|
||||
(config.deps)
|
||||
cargo
|
||||
jq
|
||||
moreutils
|
||||
python3Packages
|
||||
runCommandLocal
|
||||
writePython3
|
||||
;
|
||||
};
|
||||
|
||||
allPackages = import ./build.nix {
|
||||
inherit lib utils vendoring;
|
||||
inherit (dreamLockInterface) subsystemAttrs packages;
|
||||
inherit (config.deps) crane;
|
||||
};
|
||||
|
||||
selectedPackage = allPackages.${config.name}.${config.version};
|
||||
in {
|
||||
public = lib.mkForce {
|
||||
type = "derivation";
|
||||
inherit config extendModules;
|
||||
inherit (config) name version;
|
||||
inherit
|
||||
(selectedPackage)
|
||||
drvPath
|
||||
outPath
|
||||
outputs
|
||||
outputName
|
||||
meta
|
||||
passthru
|
||||
;
|
||||
};
|
||||
|
||||
deps = {nixpkgs, ...}:
|
||||
(l.mapAttrs (_: l.mkDefault) {
|
||||
cargo = nixpkgs.cargo;
|
||||
craneSource = config.deps.fetchFromGitHub {
|
||||
owner = "ipetkov";
|
||||
repo = "crane";
|
||||
rev = "v0.12.2";
|
||||
sha256 = "sha256-looLH5MdY4erLiJw0XwQohGdr0fJL9y6TJY3898RA2U=";
|
||||
};
|
||||
crane = import ./crane.nix {
|
||||
inherit lib;
|
||||
inherit
|
||||
(config.deps)
|
||||
craneSource
|
||||
stdenv
|
||||
cargo
|
||||
jq
|
||||
zstd
|
||||
remarshal
|
||||
makeSetupHook
|
||||
writeText
|
||||
runCommand
|
||||
runCommandLocal
|
||||
;
|
||||
};
|
||||
})
|
||||
# maybe it would be better to put these under `options.rust-crane.deps` instead of this `deps`
|
||||
# since it conflicts with a lot of stuff?
|
||||
// (l.mapAttrs (_: l.mkOverride 999) {
|
||||
inherit
|
||||
(nixpkgs)
|
||||
stdenv
|
||||
fetchurl
|
||||
jq
|
||||
zstd
|
||||
remarshal
|
||||
moreutils
|
||||
python3Packages
|
||||
makeSetupHook
|
||||
runCommandLocal
|
||||
runCommand
|
||||
writeText
|
||||
fetchFromGitHub
|
||||
;
|
||||
inherit
|
||||
(nixpkgs.writers)
|
||||
writePython3
|
||||
;
|
||||
});
|
||||
}
|
81
modules/drv-parts/rust-crane/devshell.nix
Normal file
81
modules/drv-parts/rust-crane/devshell.nix
Normal file
@ -0,0 +1,81 @@
|
||||
{
|
||||
# args
|
||||
drvs,
|
||||
name,
|
||||
# nixpkgs
|
||||
lib,
|
||||
libiconv,
|
||||
mkShell,
|
||||
...
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
|
||||
# illegal env names to be removed and not be added to the devshell
|
||||
illegalEnvNames =
|
||||
[
|
||||
"src"
|
||||
"name"
|
||||
"pname"
|
||||
"version"
|
||||
"args"
|
||||
"stdenv"
|
||||
"builder"
|
||||
"outputs"
|
||||
"phases"
|
||||
# cargo artifact and vendoring derivations
|
||||
# we don't need these in the devshell
|
||||
"cargoArtifacts"
|
||||
"dream2nixVendorDir"
|
||||
"cargoVendorDir"
|
||||
]
|
||||
++ (
|
||||
l.map
|
||||
(phase: "${phase}Phase")
|
||||
["configure" "build" "check" "install" "fixup" "unpack"]
|
||||
)
|
||||
++ l.flatten (
|
||||
l.map
|
||||
(phase: ["pre${phase}" "post${phase}"])
|
||||
["Configure" "Build" "Check" "Install" "Fixup" "Unpack"]
|
||||
);
|
||||
isIllegalEnv = name: l.elem name illegalEnvNames;
|
||||
getEnvs = drv:
|
||||
# filter out attrsets, functions and illegal environment vars
|
||||
l.filterAttrs
|
||||
(name: env: (env != null) && (! isIllegalEnv name))
|
||||
(
|
||||
l.mapAttrs
|
||||
(
|
||||
n: v:
|
||||
if ! (l.isAttrs v || l.isFunction v)
|
||||
then v
|
||||
else null
|
||||
)
|
||||
drv.drvAttrs
|
||||
);
|
||||
combineEnvs = envs:
|
||||
l.foldl'
|
||||
(
|
||||
all: env: let
|
||||
mergeInputs = name: (all.${name} or []) ++ (env.${name} or []);
|
||||
in
|
||||
all
|
||||
// env
|
||||
// {
|
||||
buildInputs = mergeInputs "buildInputs";
|
||||
nativeBuildInputs = mergeInputs "nativeBuildInputs";
|
||||
propagatedBuildInputs = mergeInputs "propagatedBuildInputs";
|
||||
propagatedNativeBuildInputs = mergeInputs "propagatedNativeBuildInputs";
|
||||
}
|
||||
)
|
||||
{}
|
||||
envs;
|
||||
_shellEnv = combineEnvs (l.map getEnvs drvs);
|
||||
shellEnv =
|
||||
_shellEnv
|
||||
// {
|
||||
inherit name;
|
||||
passthru.env = _shellEnv;
|
||||
};
|
||||
in
|
||||
(mkShell.override {stdenv = (l.head drvs).stdenv;}) shellEnv
|
29
modules/drv-parts/rust-crane/interface.nix
Normal file
29
modules/drv-parts/rust-crane/interface.nix
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
t = l.types;
|
||||
in {
|
||||
options.deps = {
|
||||
cargo = l.mkOption {
|
||||
type = t.package;
|
||||
description = "The Cargo package to use";
|
||||
};
|
||||
craneSource = l.mkOption {
|
||||
type = t.path;
|
||||
};
|
||||
crane = {
|
||||
buildPackage = l.mkOption {
|
||||
type = t.functionTo t.package;
|
||||
};
|
||||
buildDepsOnly = l.mkOption {
|
||||
type = t.functionTo t.package;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
options.rust-crane = {
|
||||
};
|
||||
}
|
48
modules/drv-parts/rust-crane/patch-workspace-deps.jq
Normal file
48
modules/drv-parts/rust-crane/patch-workspace-deps.jq
Normal file
@ -0,0 +1,48 @@
|
||||
def normalizeWorkspaceDep:
|
||||
if ($workspaceDependencies."\(.key)" | type) == "object"
|
||||
then [.value, $workspaceDependencies."\(.key)"] | add
|
||||
else [.value, {"version":$workspaceDependencies."\(.key)"}] | add
|
||||
end
|
||||
# remove workspace option from the dependency
|
||||
| del(.workspace)
|
||||
;
|
||||
|
||||
# normalizes workspace inherited dependencies for one list
|
||||
def mapWorkspaceDepsFor(name):
|
||||
if has(name)
|
||||
then
|
||||
."\(name)" = (
|
||||
."\(name)"
|
||||
| to_entries
|
||||
| map(
|
||||
if (.value | type) == "object" and .value.workspace == true
|
||||
then .value = (. | normalizeWorkspaceDep)
|
||||
else .
|
||||
end
|
||||
)
|
||||
| from_entries
|
||||
)
|
||||
else .
|
||||
end
|
||||
;
|
||||
|
||||
# shorthand for normalizing all the dependencies list
|
||||
def mapWorkspaceDeps:
|
||||
mapWorkspaceDepsFor("dependencies")
|
||||
| mapWorkspaceDepsFor("dev-dependencies")
|
||||
| mapWorkspaceDepsFor("build-dependencies")
|
||||
;
|
||||
|
||||
# normalize workspace inherited deps
|
||||
mapWorkspaceDeps
|
||||
| if has("target")
|
||||
then
|
||||
# normalize workspace inherited deps in target specific deps
|
||||
.target = (
|
||||
.target
|
||||
| to_entries
|
||||
| map(.value = (.value | mapWorkspaceDeps))
|
||||
| from_entries
|
||||
)
|
||||
else .
|
||||
end
|
228
modules/drv-parts/rust-crane/utils.nix
Normal file
228
modules/drv-parts/rust-crane/utils.nix
Normal file
@ -0,0 +1,228 @@
|
||||
{
|
||||
dreamLock,
|
||||
getSourceSpec,
|
||||
getSource,
|
||||
getRoot,
|
||||
sourceRoot,
|
||||
subsystemAttrs,
|
||||
packages,
|
||||
lib,
|
||||
toTOML,
|
||||
writeText,
|
||||
...
|
||||
}: let
|
||||
l = lib // builtins;
|
||||
isInPackages = name: version: (packages.${name} or null) == version;
|
||||
# a make overridable for rust derivations specifically
|
||||
makeOverridable = f: origArgs: let
|
||||
result = f origArgs;
|
||||
|
||||
# Creates a functor with the same arguments as f
|
||||
copyArgs = g: l.setFunctionArgs g (l.functionArgs f);
|
||||
# Changes the original arguments with (potentially a function that returns) a set of new attributes
|
||||
overrideWith = newArgs:
|
||||
origArgs
|
||||
// (
|
||||
if l.isFunction newArgs
|
||||
then newArgs origArgs
|
||||
else newArgs
|
||||
);
|
||||
|
||||
# Re-call the function but with different arguments
|
||||
overrideArgs = copyArgs (newArgs: makeOverridable f (overrideWith newArgs));
|
||||
# Change the result of the function call by applying g to it
|
||||
overrideResult = g: makeOverridable (copyArgs (args: g (f args))) origArgs;
|
||||
in
|
||||
result.derivation
|
||||
// {
|
||||
override = args:
|
||||
overrideArgs {
|
||||
args =
|
||||
origArgs.args
|
||||
// (
|
||||
if l.isFunction args
|
||||
then args origArgs.args
|
||||
else args
|
||||
);
|
||||
};
|
||||
overrideRustToolchain = f: overrideArgs {toolchain = f origArgs.toolchain;};
|
||||
overrideAttrs = fdrv: overrideResult (x: {derivation = x.derivation.overrideAttrs fdrv;});
|
||||
};
|
||||
in rec {
|
||||
getMeta = pname: version: let
|
||||
meta = subsystemAttrs.meta.${pname}.${version};
|
||||
in
|
||||
meta
|
||||
// {
|
||||
license = l.map (name: l.licenses.${name}) meta.license;
|
||||
};
|
||||
|
||||
# Gets the root source for a package
|
||||
getRootSource = pname: version: let
|
||||
root = getRoot pname version;
|
||||
in
|
||||
getSource root.pname root.version;
|
||||
|
||||
# Generates a script that replaces relative path dependency paths with absolute
|
||||
# ones, if the path dependency isn't in the source dream2nix provides
|
||||
replaceRelativePathsWithAbsolute = replacements: let
|
||||
replace =
|
||||
l.concatStringsSep
|
||||
" \\\n"
|
||||
(
|
||||
l.mapAttrsToList
|
||||
(
|
||||
# TODO: this is not great, because it forces us to include the entire
|
||||
# sourceRoot here, which could possibly cause more rebuilds than necessary
|
||||
# when source is changed (although this mostly depends on how the project
|
||||
# repository is structured). doing this properly is pretty complex, but
|
||||
# it should still be done later.
|
||||
from: relPath: ''--replace "\"${from}\"" "\"${sourceRoot}/${relPath}\""''
|
||||
)
|
||||
replacements
|
||||
);
|
||||
in ''
|
||||
substituteInPlace ./Cargo.toml \
|
||||
${replace}
|
||||
'';
|
||||
|
||||
mkBuildWithToolchain = mkBuildFunc: let
|
||||
buildWithToolchain = args:
|
||||
makeOverridable
|
||||
(args: {
|
||||
derivation =
|
||||
(mkBuildFunc args.toolchain)
|
||||
(
|
||||
args.args
|
||||
// {
|
||||
passthru =
|
||||
(args.args.passthru or {})
|
||||
// {rustToolchain = args.toolchain;};
|
||||
}
|
||||
);
|
||||
})
|
||||
args;
|
||||
in
|
||||
buildWithToolchain;
|
||||
|
||||
# Backup original Cargo.lock if it exists and write our own one
|
||||
writeCargoLock = ''
|
||||
mv -f Cargo.lock Cargo.lock.orig || echo "no Cargo.lock"
|
||||
cat ${cargoLock} > Cargo.lock
|
||||
'';
|
||||
|
||||
# The Cargo.lock for this dreamLock.
|
||||
cargoLock = let
|
||||
mkPkgEntry = {
|
||||
name,
|
||||
version,
|
||||
...
|
||||
} @ args: let
|
||||
# constructs source string for dependency
|
||||
makeSource = sourceSpec: let
|
||||
source =
|
||||
if sourceSpec.type == "crates-io"
|
||||
then "registry+https://github.com/rust-lang/crates.io-index"
|
||||
else if sourceSpec.type == "git"
|
||||
then let
|
||||
gitSpec =
|
||||
l.findFirst
|
||||
(src: src.url == sourceSpec.url && src.sha == sourceSpec.rev)
|
||||
(throw "no git source: ${sourceSpec.url}#${sourceSpec.rev}")
|
||||
(subsystemAttrs.gitSources or {});
|
||||
refPart =
|
||||
l.optionalString
|
||||
(gitSpec ? type)
|
||||
"?${gitSpec.type}=${gitSpec.value}";
|
||||
in "git+${sourceSpec.url}${refPart}#${sourceSpec.rev}"
|
||||
else null;
|
||||
in
|
||||
source;
|
||||
# constructs source string for dependency entry
|
||||
makeDepSource = sourceSpec:
|
||||
if sourceSpec.type == "crates-io"
|
||||
then makeSource sourceSpec
|
||||
else if sourceSpec.type == "git"
|
||||
then l.concatStringsSep "#" (l.init (l.splitString "#" (makeSource sourceSpec)))
|
||||
else null;
|
||||
# removes source type information from the version
|
||||
normalizeVersion = version: srcType: l.removeSuffix ("$" + srcType) version;
|
||||
|
||||
sourceSpec = getSourceSpec name version;
|
||||
|
||||
normalizedVersion = normalizeVersion version sourceSpec.type;
|
||||
|
||||
source = let
|
||||
src = makeSource sourceSpec;
|
||||
in
|
||||
if src == null
|
||||
then throw "source type '${sourceSpec.type}' not supported"
|
||||
else src;
|
||||
dependencies =
|
||||
l.map
|
||||
(
|
||||
dep: let
|
||||
depSourceSpec = getSourceSpec dep.name dep.version;
|
||||
depSource = makeDepSource depSourceSpec;
|
||||
|
||||
normalizedDepVersion = normalizeVersion dep.version depSourceSpec.type;
|
||||
|
||||
hasMultipleVersions =
|
||||
l.length (l.attrValues dreamLock.sources.${dep.name}) > 1;
|
||||
hasDuplicateVersions = dep.version != normalizedDepVersion;
|
||||
|
||||
# only put version if there are different versions of the dep
|
||||
versionString =
|
||||
l.optionalString hasMultipleVersions " ${normalizedDepVersion}";
|
||||
# only put source if there are duplicate versions of the dep
|
||||
# cargo vendor does not support this anyway and so builds will fail
|
||||
# until https://github.com/rust-lang/cargo/issues/10310 is resolved.
|
||||
srcString =
|
||||
l.optionalString hasDuplicateVersions " (${depSource})";
|
||||
in "${dep.name}${versionString}${srcString}"
|
||||
)
|
||||
args.dependencies;
|
||||
|
||||
isMainPackage = isInPackages name version;
|
||||
in
|
||||
{
|
||||
name = sourceSpec.pname or name;
|
||||
version = sourceSpec.version or normalizedVersion;
|
||||
}
|
||||
# put dependencies like how cargo expects them
|
||||
// (
|
||||
l.optionalAttrs
|
||||
(l.length dependencies > 0)
|
||||
{inherit dependencies;}
|
||||
)
|
||||
// (
|
||||
l.optionalAttrs
|
||||
(sourceSpec.type != "path" && !isMainPackage)
|
||||
{inherit source;}
|
||||
)
|
||||
// (
|
||||
l.optionalAttrs
|
||||
(sourceSpec.type == "crates-io" && !isMainPackage)
|
||||
{checksum = sourceSpec.hash;}
|
||||
);
|
||||
package = l.flatten (
|
||||
l.mapAttrsToList
|
||||
(
|
||||
name: versions:
|
||||
l.mapAttrsToList
|
||||
(
|
||||
version: dependencies:
|
||||
mkPkgEntry {inherit name version dependencies;}
|
||||
)
|
||||
versions
|
||||
)
|
||||
dreamLock.dependencies
|
||||
);
|
||||
lockTOML = toTOML {
|
||||
# the lockfile we generate is of version 3
|
||||
version = 3;
|
||||
inherit package;
|
||||
};
|
||||
in
|
||||
writeText "Cargo.lock" lockTOML;
|
||||
}
|
145
modules/drv-parts/rust-crane/vendor.nix
Normal file
145
modules/drv-parts/rust-crane/vendor.nix
Normal file
@ -0,0 +1,145 @@
|
||||
{
|
||||
lib,
|
||||
getSource,
|
||||
getSourceSpec,
|
||||
subsystemAttrs,
|
||||
dreamLock,
|
||||
moreutils,
|
||||
writePython3,
|
||||
python3Packages,
|
||||
runCommandLocal,
|
||||
...
|
||||
} @ args: let
|
||||
l = lib // builtins;
|
||||
|
||||
allDependencies =
|
||||
l.flatten
|
||||
(
|
||||
l.mapAttrsToList
|
||||
(
|
||||
name: versions:
|
||||
l.map (version: {inherit name version;}) (l.attrNames versions)
|
||||
)
|
||||
dreamLock.dependencies
|
||||
);
|
||||
in rec {
|
||||
# Generates a shell script that writes git vendor entries to .cargo/config.
|
||||
# `replaceWith` is the name of the vendored source(s) to use.
|
||||
writeGitVendorEntries = replaceWith: let
|
||||
makeEntry = source: ''
|
||||
[source."${source.url}${l.optionalString (source ? type) "?${source.type}=${source.value}"}"]
|
||||
replace-with = "${replaceWith}"
|
||||
git = "${source.url}"
|
||||
${l.optionalString (source ? type) "${source.type} = \"${source.value}\""}
|
||||
'';
|
||||
entries = l.map makeEntry subsystemAttrs.gitSources;
|
||||
in ''
|
||||
echo "Writing git vendor entries to $CARGO_HOME/config.toml"
|
||||
mkdir -p $CARGO_HOME && touch $CARGO_HOME/config.toml
|
||||
cat >> $CARGO_HOME/config.toml <<EOF
|
||||
${l.concatStringsSep "\n" entries}
|
||||
EOF
|
||||
'';
|
||||
|
||||
# Vendors the dependencies passed as Cargo expects them
|
||||
vendorDependencies = deps: let
|
||||
makeSource = dep: let
|
||||
path = getSource dep.name dep.version;
|
||||
spec = getSourceSpec dep.name dep.version;
|
||||
normalizeVersion = version: l.removeSuffix ("$" + spec.type) version;
|
||||
in {
|
||||
inherit path spec dep;
|
||||
name = "${dep.name}-${normalizeVersion dep.version}";
|
||||
};
|
||||
sources = l.map makeSource deps;
|
||||
|
||||
findCrateSource = source: let
|
||||
cargo = "${args.cargo}/bin/cargo";
|
||||
jq = "${args.jq}/bin/jq";
|
||||
sponge = "${moreutils}/bin/sponge";
|
||||
|
||||
writeConvertScript = from: to:
|
||||
writePython3
|
||||
"${from}-to-${to}.py"
|
||||
{libraries = [python3Packages.toml];}
|
||||
''
|
||||
import toml
|
||||
import json
|
||||
import sys
|
||||
t = ${from}.loads(sys.stdin.read())
|
||||
sys.stdout.write(${to}.dumps(t))
|
||||
'';
|
||||
tomlToJson = writeConvertScript "toml" "json";
|
||||
jsonToToml = writeConvertScript "json" "toml";
|
||||
|
||||
pkg = source.dep;
|
||||
in ''
|
||||
# If the target package is in a workspace, or if it's the top-level
|
||||
# crate, we should find the crate path using `cargo metadata`.
|
||||
crateCargoTOML=$(${cargo} metadata --format-version 1 --no-deps --manifest-path $tree/Cargo.toml | \
|
||||
${jq} -r '.packages[] | select(.name == "${pkg.name}") | .manifest_path')
|
||||
# If the repository is not a workspace the package might be in a subdirectory.
|
||||
if [[ -z $crateCargoTOML ]]; then
|
||||
for manifest in $(find $tree -name "Cargo.toml"); do
|
||||
echo Looking at $manifest
|
||||
crateCargoTOML=$(${cargo} metadata --format-version 1 --no-deps --manifest-path "$manifest" | ${jq} -r '.packages[] | select(.name == "${pkg.name}") | .manifest_path' || :)
|
||||
if [[ ! -z $crateCargoTOML ]]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ -z $crateCargoTOML ]]; then
|
||||
>&2 echo "Cannot find path for crate '${pkg.name}-${pkg.version}' in the tree in: $tree"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# we need to patch dependencies with `workspace = true` (workspace inheritance)
|
||||
workspaceDependencies="$(cat "$tree/Cargo.toml" | ${tomlToJson} | ${jq} -cr '.workspace.dependencies')"
|
||||
if [[ "$workspaceDependencies" != "null" ]]; then
|
||||
tree="$(pwd)/${pkg.name}-${pkg.version}"
|
||||
cp -prd --no-preserve=mode,ownership "$(dirname $crateCargoTOML)" "$tree"
|
||||
crateCargoTOML="$tree/Cargo.toml"
|
||||
cat "$crateCargoTOML" \
|
||||
| ${tomlToJson} \
|
||||
| ${jq} -cr --argjson workspaceDependencies "$workspaceDependencies" \
|
||||
--from-file ${./patch-workspace-deps.jq} \
|
||||
| ${jsonToToml} \
|
||||
| ${sponge} "$crateCargoTOML"
|
||||
fi
|
||||
fi
|
||||
echo Found crate ${pkg.name} at $crateCargoTOML
|
||||
tree="$(dirname $crateCargoTOML)"
|
||||
'';
|
||||
makeScript = source: let
|
||||
isGit = source.spec.type == "git";
|
||||
isPath = source.spec.type == "path";
|
||||
in
|
||||
l.optionalString (!isPath) ''
|
||||
tree="${source.path}"
|
||||
${l.optionalString isGit (findCrateSource source)}
|
||||
echo Vendoring crate ${source.name}
|
||||
if [ -d $out/${source.name} ]; then
|
||||
echo Crate is already vendored
|
||||
echo Crates with duplicate versions cannot be vendored as Cargo does not support this behaviour
|
||||
exit 1
|
||||
else
|
||||
cp -prd "$tree" $out/${source.name}
|
||||
chmod u+w $out/${source.name}
|
||||
${l.optionalString isGit "printf '{\"files\":{},\"package\":null}' > $out/${source.name}/.cargo-checksum.json"}
|
||||
fi
|
||||
'';
|
||||
in
|
||||
runCommandLocal "vendor" {} ''
|
||||
mkdir -p $out
|
||||
|
||||
${
|
||||
l.concatMapStringsSep "\n"
|
||||
makeScript
|
||||
sources
|
||||
}
|
||||
'';
|
||||
|
||||
# All dependencies in the Cargo.lock file, vendored
|
||||
vendoredDependencies = vendorDependencies allDependencies;
|
||||
|
||||
copyVendorDir = from: to: ''cp -rs --no-preserve=mode,ownership ${from} ${to}'';
|
||||
}
|
@ -7,12 +7,11 @@
|
||||
in {
|
||||
imports = [
|
||||
../../drv-parts/rust-cargo-lock
|
||||
../../drv-parts/buildRustPackage
|
||||
../../drv-parts/rust-crane
|
||||
];
|
||||
|
||||
deps = {nixpkgs, ...}: {
|
||||
inherit (nixpkgs) fetchFromGitHub;
|
||||
inherit (nixpkgs) stdenv;
|
||||
};
|
||||
|
||||
name = l.mkForce "ripgrep";
|
||||
|
@ -8,7 +8,7 @@
|
||||
in {
|
||||
imports = [
|
||||
dream2nix.modules.drv-parts.rust-cargo-lock
|
||||
dream2nix.modules.drv-parts.buildRustPackage
|
||||
dream2nix.modules.drv-parts.rust-crane
|
||||
];
|
||||
|
||||
mkDerivation = {
|
||||
@ -23,5 +23,5 @@ in {
|
||||
};
|
||||
|
||||
name = "app";
|
||||
version = "1.0.0";
|
||||
version = "0.1.0";
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user