mirror of
https://github.com/nix-community/dream2nix.git
synced 2025-01-07 07:09:26 +03:00
port buildRustPackage to drv-parts
This commit is contained in:
parent
8843ecf03d
commit
9e2129d053
@ -1,6 +1,7 @@
|
||||
{
|
||||
pkgs,
|
||||
utils,
|
||||
runCommandLocal,
|
||||
fetchurl,
|
||||
hashFile,
|
||||
...
|
||||
}: {
|
||||
inputs = ["pname" "version"];
|
||||
@ -17,18 +18,18 @@
|
||||
url = "https://crates.io/api/v1/crates/${pname}/${version}/download";
|
||||
in {
|
||||
calcHash = algo:
|
||||
utils.hashFile algo (b.fetchurl {
|
||||
hashFile algo (b.fetchurl {
|
||||
inherit url;
|
||||
});
|
||||
|
||||
fetched = hash: let
|
||||
fetched = pkgs.fetchurl {
|
||||
fetched = fetchurl {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
name = "download-${pname}-${version}";
|
||||
};
|
||||
in
|
||||
pkgs.runCommandLocal "unpack-${pname}-${version}" {}
|
||||
runCommandLocal "unpack-${pname}-${version}" {}
|
||||
''
|
||||
mkdir -p $out
|
||||
tar --strip-components 1 -xzf ${fetched} -C $out
|
||||
|
145
lib/internal/toTOML.nix
Normal file
145
lib/internal/toTOML.nix
Normal file
@ -0,0 +1,145 @@
|
||||
{lib, ...}: let
|
||||
inherit
|
||||
(lib)
|
||||
length
|
||||
elemAt
|
||||
concatMap
|
||||
concatLists
|
||||
concatStringsSep
|
||||
concatMapStringsSep
|
||||
mapAttrsToList
|
||||
foldl
|
||||
isDerivation
|
||||
;
|
||||
|
||||
inherit
|
||||
(builtins)
|
||||
abort
|
||||
match
|
||||
typeOf
|
||||
;
|
||||
|
||||
quoteKey = k:
|
||||
if match "[a-zA-Z]+" k == []
|
||||
then k
|
||||
else quoteString k;
|
||||
|
||||
quoteString = builtins.toJSON;
|
||||
|
||||
outputValInner = v: let
|
||||
ty = tomlTy v;
|
||||
in
|
||||
if ty == "set"
|
||||
then let
|
||||
vals =
|
||||
mapAttrsToList
|
||||
(k': v': "${quoteKey k'} = ${outputValInner v'}")
|
||||
v;
|
||||
valsStr = concatStringsSep ", " vals;
|
||||
in "{ ${valsStr} }"
|
||||
else outputVal v;
|
||||
|
||||
outputVal = v: let
|
||||
ty = tomlTy v;
|
||||
in
|
||||
if (ty == "bool" || ty == "int")
|
||||
then builtins.toJSON v
|
||||
else if ty == "string"
|
||||
then quoteString v
|
||||
else if ty == "list" || ty == "list_of_attrs"
|
||||
then let
|
||||
vals = map quoteString v;
|
||||
valsStr = concatStringsSep ", " vals;
|
||||
in "[ ${valsStr} ]"
|
||||
else if ty == "set"
|
||||
then abort "unsupported set for not-inner value"
|
||||
else abort "Not implemented: type ${ty}";
|
||||
|
||||
outputKeyValInner = k: v: let
|
||||
ty = tomlTy v;
|
||||
in
|
||||
if ty == "set"
|
||||
then let
|
||||
vals =
|
||||
mapAttrsToList
|
||||
(k': v': "${quoteKey k'} = ${outputValInner v'}")
|
||||
v;
|
||||
valsStr = concatStringsSep ", " vals;
|
||||
in ["${quoteKey k} = { ${valsStr} }"]
|
||||
else outputKeyVal k v;
|
||||
|
||||
# Returns a list of strings; one string per line
|
||||
outputKeyVal = k: v: let
|
||||
ty = tomlTy v;
|
||||
in
|
||||
if ty == "bool" || ty == "int"
|
||||
then ["${quoteKey k} = ${outputValInner v}"]
|
||||
else if ty == "string"
|
||||
then ["${quoteKey k} = ${quoteString v}"]
|
||||
else if ty == "list_of_attrs"
|
||||
then
|
||||
concatMap (
|
||||
inner:
|
||||
["[[${k}]]"] ++ (concatLists (mapAttrsToList outputKeyValInner inner))
|
||||
)
|
||||
v
|
||||
else if ty == "list"
|
||||
then let
|
||||
vals = map quoteString v;
|
||||
valsStr = concatStringsSep ", " vals;
|
||||
in ["${quoteKey k} = [ ${valsStr} ]"]
|
||||
else if ty == "set"
|
||||
then ["[${k}]"] ++ (concatLists (mapAttrsToList outputKeyValInner v))
|
||||
else abort "Not implemented: type ${ty} for key ${k}";
|
||||
|
||||
tomlTy = x:
|
||||
if typeOf x == "string"
|
||||
then "string"
|
||||
else if typeOf x == "bool"
|
||||
then "bool"
|
||||
else if typeOf x == "int"
|
||||
then "int"
|
||||
else if typeOf x == "float"
|
||||
then "float"
|
||||
else if typeOf x == "set"
|
||||
then
|
||||
if isDerivation x
|
||||
then "string"
|
||||
else "set"
|
||||
else if typeOf x == "list"
|
||||
then
|
||||
if length x == 0
|
||||
then "list"
|
||||
else let
|
||||
ty = typeOf (elemAt x 0);
|
||||
in
|
||||
#assert (all (v: typeOf v == ty) x);
|
||||
if ty == "set"
|
||||
then "list_of_attrs"
|
||||
else "list"
|
||||
else abort "Not implemented: toml type for ${typeOf x}";
|
||||
|
||||
toTOML = attrs:
|
||||
assert (typeOf attrs == "set"); let
|
||||
byTy =
|
||||
foldl
|
||||
(
|
||||
acc: x: let
|
||||
ty = tomlTy x.v;
|
||||
in
|
||||
acc // {"${ty}" = (acc.${ty} or []) ++ [x];}
|
||||
)
|
||||
{} (mapAttrsToList (k: v: {inherit k v;}) attrs);
|
||||
in
|
||||
concatMapStringsSep "\n"
|
||||
(kv: concatStringsSep "\n" (outputKeyVal kv.k kv.v))
|
||||
(
|
||||
(byTy.string or [])
|
||||
++ (byTy.int or [])
|
||||
++ (byTy.float or [])
|
||||
++ (byTy.list or [])
|
||||
++ (byTy.list_of_attrs or [])
|
||||
++ (byTy.set or [])
|
||||
);
|
||||
in
|
||||
toTOML
|
213
v1/nix/modules/drv-parts/buildRustPackage/default.nix
Normal file
213
v1/nix/modules/drv-parts/buildRustPackage/default.nix
Normal file
@ -0,0 +1,213 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
} @ topArgs: let
|
||||
l = lib // builtins;
|
||||
|
||||
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;
|
||||
};
|
||||
http = import ../../../lib/internal/fetchers/http {
|
||||
inherit hashFile lib;
|
||||
inherit (config.deps.stdenv) mkDerivation;
|
||||
inherit (config.deps) fetchurl;
|
||||
};
|
||||
crates-io = import ../../../lib/internal/fetchers/crates-io {
|
||||
inherit hashFile;
|
||||
inherit (config.deps) fetchurl runCommandLocal;
|
||||
};
|
||||
};
|
||||
|
||||
dreamLockLoaded =
|
||||
readDreamLock {inherit (config.rust-cargo-lock) dreamLock;};
|
||||
dreamLockInterface = dreamLockLoaded.interface;
|
||||
|
||||
fetchedSources' = fetchDreamLockSources {
|
||||
inherit (dreamLockInterface) defaultPackageName defaultPackageVersion;
|
||||
inherit (dreamLockLoaded.lock) sources;
|
||||
inherit fetchers;
|
||||
};
|
||||
|
||||
fetchedSources =
|
||||
fetchedSources'
|
||||
// {
|
||||
${defaultPackageName}.${defaultPackageVersion} = config.mkDerivation.src;
|
||||
};
|
||||
|
||||
# name: version: -> store-path
|
||||
getSource = getDreamLockSource fetchedSources;
|
||||
|
||||
inherit
|
||||
(dreamLockInterface)
|
||||
getDependencies # name: version: -> [ {name=; version=; } ]
|
||||
# Attributes
|
||||
|
||||
subsystemAttrs # attrset
|
||||
packageVersions
|
||||
defaultPackageName
|
||||
defaultPackageVersion
|
||||
;
|
||||
|
||||
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
|
||||
;
|
||||
};
|
||||
|
||||
buildWithToolchain =
|
||||
utils.mkBuildWithToolchain
|
||||
(toolchain: (config.deps.makeRustPlatform toolchain).buildRustPackage);
|
||||
|
||||
defaultToolchain = {
|
||||
inherit (config.deps) cargo rustc;
|
||||
};
|
||||
|
||||
buildPackage = pname: version: let
|
||||
src = utils.getRootSource pname version;
|
||||
replacePaths =
|
||||
utils.replaceRelativePathsWithAbsolute
|
||||
subsystemAttrs.relPathReplacements.${pname}.${version};
|
||||
writeGitVendorEntries = vendoring.writeGitVendorEntries "vendored-sources";
|
||||
|
||||
cargoBuildFlags = "--package ${pname}";
|
||||
buildArgs = {
|
||||
inherit pname version src;
|
||||
|
||||
meta = utils.getMeta pname version;
|
||||
|
||||
cargoBuildFlags = cargoBuildFlags;
|
||||
cargoTestFlags = cargoBuildFlags;
|
||||
|
||||
cargoVendorDir = "../nix-vendor";
|
||||
dream2nixVendorDir = vendoring.vendoredDependencies;
|
||||
|
||||
postUnpack = ''
|
||||
${vendoring.copyVendorDir "$dream2nixVendorDir" "./nix-vendor"}
|
||||
export CARGO_HOME=$(pwd)/.cargo_home
|
||||
'';
|
||||
|
||||
preConfigure = ''
|
||||
mkdir -p $CARGO_HOME
|
||||
if [ -f ../.cargo/config ]; then
|
||||
mv ../.cargo/config $CARGO_HOME/config.toml
|
||||
fi
|
||||
${writeGitVendorEntries}
|
||||
${replacePaths}
|
||||
${utils.writeCargoLock}
|
||||
'';
|
||||
};
|
||||
in
|
||||
buildWithToolchain {
|
||||
toolchain = defaultToolchain;
|
||||
args = buildArgs;
|
||||
};
|
||||
|
||||
allPackages =
|
||||
l.mapAttrs
|
||||
(name: version: {"${version}" = buildPackage name version;})
|
||||
dreamLockInterface.packages;
|
||||
|
||||
mkShellForDrvs = drvs:
|
||||
import ./devshell.nix {
|
||||
inherit drvs lib;
|
||||
inherit (config.deps) mkShell;
|
||||
name = "devshell";
|
||||
};
|
||||
|
||||
pkgShells =
|
||||
l.mapAttrs
|
||||
(
|
||||
name: version: let
|
||||
pkg = allPackages.${name}.${version};
|
||||
in
|
||||
mkShellForDrvs [pkg]
|
||||
)
|
||||
dreamLockInterface.packages;
|
||||
|
||||
allPackagesList =
|
||||
l.mapAttrsToList
|
||||
(name: version: allPackages.${name}.${version})
|
||||
dreamLockInterface.packages;
|
||||
|
||||
packages = allPackages;
|
||||
|
||||
devShells =
|
||||
pkgShells
|
||||
// {
|
||||
default = mkShellForDrvs allPackagesList;
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
# dream2nix.modules.drv-parts.mkDerivation
|
||||
];
|
||||
|
||||
public = lib.mkForce packages.${dreamLockInterface.defaultPackageName}.${dreamLockInterface.defaultPackageVersion};
|
||||
|
||||
deps = {nixpkgs, ...}: {
|
||||
inherit
|
||||
(nixpkgs)
|
||||
cargo
|
||||
fetchurl
|
||||
jq
|
||||
makeRustPlatform
|
||||
moreutils
|
||||
python3Packages
|
||||
runCommandLocal
|
||||
rustc
|
||||
;
|
||||
inherit
|
||||
(nixpkgs.writers)
|
||||
writePython3
|
||||
;
|
||||
};
|
||||
}
|
79
v1/nix/modules/drv-parts/buildRustPackage/devshell.nix
Normal file
79
v1/nix/modules/drv-parts/buildRustPackage/devshell.nix
Normal file
@ -0,0 +1,79 @@
|
||||
{
|
||||
# args
|
||||
drvs,
|
||||
name,
|
||||
# nixpkgs
|
||||
lib,
|
||||
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
|
227
v1/nix/modules/drv-parts/buildRustPackage/utils.nix
Normal file
227
v1/nix/modules/drv-parts/buildRustPackage/utils.nix
Normal file
@ -0,0 +1,227 @@
|
||||
{
|
||||
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;
|
||||
}
|
147
v1/nix/modules/drv-parts/buildRustPackage/vendor.nix
Normal file
147
v1/nix/modules/drv-parts/buildRustPackage/vendor.nix
Normal file
@ -0,0 +1,147 @@
|
||||
{
|
||||
lib,
|
||||
getSource,
|
||||
getSourceSpec,
|
||||
subsystemAttrs,
|
||||
dreamLock,
|
||||
# pkgs
|
||||
cargo,
|
||||
jq,
|
||||
moreutils,
|
||||
python3Packages,
|
||||
runCommandLocal,
|
||||
writePython3,
|
||||
} @ 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,6 +7,7 @@
|
||||
in {
|
||||
imports = [
|
||||
../../drv-parts/rust-cargo-lock
|
||||
../../drv-parts/buildRustPackage
|
||||
];
|
||||
|
||||
deps = {nixpkgs, ...}: {
|
||||
|
Loading…
Reference in New Issue
Block a user