mirror of
https://github.com/ipetkov/crane.git
synced 2024-11-22 14:10:16 +03:00
139 lines
4.4 KiB
Nix
139 lines
4.4 KiB
Nix
{ downloadCargoPackage
|
|
, lib
|
|
, pkgsBuildBuild
|
|
}:
|
|
|
|
let
|
|
inherit (pkgsBuildBuild)
|
|
runCommandLocal;
|
|
|
|
inherit (builtins)
|
|
attrNames
|
|
concatStringsSep
|
|
filter
|
|
hasAttr
|
|
hashString
|
|
head
|
|
length
|
|
mapAttrs
|
|
placeholder
|
|
readFile;
|
|
|
|
inherit (lib)
|
|
concatMapStrings
|
|
concatStrings
|
|
escapeShellArg
|
|
filterAttrs
|
|
flatten
|
|
foldl
|
|
groupBy
|
|
hasPrefix
|
|
mapAttrs'
|
|
mapAttrsToList
|
|
nameValuePair
|
|
removePrefix;
|
|
|
|
inherit (lib.lists) unique;
|
|
|
|
hash = hashString "sha256";
|
|
|
|
hasRegistryProtocolPrefix = s: hasPrefix "registry+" s || hasPrefix "sparse+" s;
|
|
|
|
removeProtocol = s: removePrefix "registry+" (removePrefix "sparse+" s);
|
|
in
|
|
{ cargoConfigs ? [ ]
|
|
, lockPackages
|
|
, overrideVendorCargoPackage ? _: drv: drv
|
|
, ...
|
|
}@args:
|
|
let
|
|
# Local crates will show up in the lock file with no checksum/source,
|
|
# so should filter them out without trying to download them
|
|
lockedPackagesFromRegistry = filter
|
|
(p: p ? checksum && hasRegistryProtocolPrefix (p.source or ""))
|
|
lockPackages;
|
|
lockedRegistryGroups = groupBy (p: p.source) lockedPackagesFromRegistry;
|
|
|
|
vendorCrate = p: overrideVendorCargoPackage p (downloadCargoPackage p);
|
|
vendorSingleRegistry = packages: runCommandLocal "vendor-registry" { } ''
|
|
mkdir -p $out
|
|
${concatMapStrings (p: ''
|
|
ln -s ${escapeShellArg (vendorCrate p)} $out/${escapeShellArg "${p.name}-${p.version}"}
|
|
'') packages}
|
|
'';
|
|
|
|
# Registries configured in cargo config
|
|
parsedCargoConfigTomls = map (p: builtins.fromTOML (readFile p)) cargoConfigs;
|
|
allCargoRegistries = flatten (map (c: c.registries or [ ]) parsedCargoConfigTomls);
|
|
allCargoRegistryPairs = flatten (map (mapAttrsToList (name: value: { inherit name value; })) allCargoRegistries);
|
|
allCargoRegistryPairsWithIndex = filter (r: r ? value.index) allCargoRegistryPairs;
|
|
configuredRegistries = mapAttrs (_: map (r: r.value.index)) (groupBy (x: x.name) allCargoRegistryPairsWithIndex);
|
|
|
|
# Registries referenced in Cargo.lock that are missing from cargo config
|
|
existingRegistries = foldl (acc: r: acc // { ${removeProtocol r.value.index} = true; }) { "https://github.com/rust-lang/crates.io-index" = true; } allCargoRegistryPairsWithIndex;
|
|
allPackageRegistries = foldl (acc: p: if p ? source then acc // { ${removeProtocol p.source} = [ p.source ]; } else acc) { } lockPackages;
|
|
missingPackageRegistries = filterAttrs (name: _: !(existingRegistries ? ${name})) allPackageRegistries;
|
|
|
|
# Append the default crates.io registry, but allow it to be overridden
|
|
registries = {
|
|
"crates-io" = [ "https://github.com/rust-lang/crates.io-index" ];
|
|
} // (
|
|
if args ? registries
|
|
then mapAttrs (_: val: [ val ]) args.registries
|
|
else configuredRegistries // missingPackageRegistries
|
|
);
|
|
|
|
sources = mapAttrs'
|
|
(url: packages: nameValuePair (hash url) (vendorSingleRegistry packages))
|
|
lockedRegistryGroups;
|
|
|
|
configLocalSources = concatMapStrings
|
|
(hashedUrl: ''
|
|
[source.nix-sources-${hashedUrl}]
|
|
directory = "${placeholder "out"}/${hashedUrl}"
|
|
'')
|
|
(attrNames sources);
|
|
|
|
# e.g. hasSparse x if either has sparse+x, or x starts with sparse+ and has x.
|
|
hasRegistryWithProtocol = (lrg: protocol: u:
|
|
(hasAttr "${protocol}+${u}" lrg) || ((lib.hasPrefix protocol u) && (hasAttr u lrg))
|
|
);
|
|
hasSparseRegistry = hasRegistryWithProtocol lockedRegistryGroups "sparse";
|
|
hasLegacyRegistry = hasRegistryWithProtocol lockedRegistryGroups "registry";
|
|
|
|
hasRegistry = (u: (hasSparseRegistry u) || (hasLegacyRegistry u));
|
|
|
|
configReplaceRegistries = mapAttrsToList
|
|
(name: urls:
|
|
let
|
|
actuallyConfigured = unique (filter hasRegistry urls);
|
|
numConfigured = length actuallyConfigured;
|
|
in
|
|
if numConfigured == 0 then ""
|
|
else if numConfigured > 1 then
|
|
throw ''
|
|
there are multiple distinct registries configured with the same name.
|
|
please ensure that each unique registry name is used with exactly one registry url.
|
|
${name} is used with:
|
|
${concatStringsSep "\n" urls}
|
|
''
|
|
else
|
|
let
|
|
url = head actuallyConfigured;
|
|
prefixedUrl = if hasRegistryProtocolPrefix url then url else "registry+${url}";
|
|
hashed = hash prefixedUrl;
|
|
in
|
|
''
|
|
[source.${escapeShellArg name}]
|
|
registry = "${url}"
|
|
replace-with = "nix-sources-${hashed}"
|
|
''
|
|
)
|
|
registries;
|
|
in
|
|
{
|
|
inherit sources;
|
|
|
|
config = configLocalSources + (concatStrings configReplaceRegistries);
|
|
}
|