mirror of
https://github.com/ipetkov/crane.git
synced 2024-11-30 05:57:28 +03:00
148 lines
3.8 KiB
Nix
148 lines
3.8 KiB
Nix
{ downloadCargoPackageFromGit
|
|
, lib
|
|
, runCommandLocal
|
|
}:
|
|
|
|
{ lockPackages
|
|
}:
|
|
let
|
|
inherit (builtins)
|
|
any
|
|
attrNames
|
|
filter
|
|
hashString
|
|
head
|
|
isString
|
|
length
|
|
listToAttrs
|
|
placeholder
|
|
split;
|
|
|
|
inherit (lib)
|
|
concatMapStrings
|
|
concatStrings
|
|
concatStringsSep
|
|
escapeShellArg
|
|
groupBy
|
|
hasPrefix
|
|
last
|
|
mapAttrs'
|
|
mapAttrsToList
|
|
nameValuePair
|
|
removePrefix;
|
|
|
|
knownGitParams = [ "branch" "rev" "tag" ];
|
|
parseGitUrl = p:
|
|
let
|
|
lockUrl = removePrefix "git+" p.source;
|
|
revSplit = split "#" (removePrefix "git+" lockUrl);
|
|
# uniquely identifies the repo in terms of what cargo can address via
|
|
# source replacement (e.g. the url along with any branch/tag/rev).
|
|
id = head revSplit;
|
|
# NB: this is distict from the `rev` query param which may show up
|
|
# if the dependency is explicitly listed with a `rev` value.
|
|
lockedRev = if 3 == length revSplit then last revSplit else
|
|
throw ''
|
|
Cargo.lock is missing a locked revision for ${p.name}@${p.version}.
|
|
you can try to resolve this by running `cargo update -p ${lockUrl}#${p.name}@${p.version}`
|
|
'';
|
|
|
|
querySplit = split "\\?" (head revSplit);
|
|
git = head querySplit;
|
|
|
|
queryParamSplit = filter
|
|
(qp: (isString qp) && any (p: hasPrefix p qp) knownGitParams)
|
|
(split "&" (last querySplit));
|
|
extractedParams = listToAttrs (map
|
|
(qp:
|
|
let
|
|
kvSplit = (split "=" qp);
|
|
in
|
|
nameValuePair (head kvSplit) (last kvSplit)
|
|
)
|
|
queryParamSplit
|
|
);
|
|
in
|
|
extractedParams // {
|
|
inherit git id lockedRev;
|
|
};
|
|
|
|
hash = hashString "sha256";
|
|
|
|
# Local crates will show up in the lock file with no checksum/source
|
|
lockedPackagesFromGit = filter
|
|
(p: hasPrefix "git" (p.source or ""))
|
|
lockPackages;
|
|
lockedGitGroups = groupBy (p: p.id) (map
|
|
(p: (parseGitUrl p) // { package = p; })
|
|
lockedPackagesFromGit
|
|
);
|
|
|
|
sources = mapAttrs'
|
|
(id: ps:
|
|
let
|
|
p = head ps;
|
|
ref =
|
|
if p ? tag then "refs/tags/${p.tag}"
|
|
else if p ? branch then "refs/heads/${p.branch}"
|
|
else null;
|
|
|
|
extractedPackages = downloadCargoPackageFromGit {
|
|
inherit (p) git;
|
|
inherit ref;
|
|
rev = p.lockedRev;
|
|
};
|
|
|
|
# NB: we filter out any crates NOT in the lock file
|
|
# as the repo could have other crates we don't need
|
|
# (e.g. testing crates which might not even build properly)
|
|
# https://github.com/ipetkov/crane/issues/60
|
|
linkPsInLock = concatStringsSep "\n" (map
|
|
(p:
|
|
let
|
|
name = escapeShellArg p.package.name;
|
|
version = escapeShellArg p.package.version;
|
|
vendoredName = "${name}-${version}";
|
|
in
|
|
"ln -s ${extractedPackages}/${vendoredName} $out/${vendoredName}"
|
|
)
|
|
ps
|
|
);
|
|
in
|
|
nameValuePair (hash id) (runCommandLocal "linkLockedDeps" { } ''
|
|
mkdir -p $out
|
|
${linkPsInLock}
|
|
'')
|
|
)
|
|
lockedGitGroups;
|
|
|
|
configLocalSources = concatMapStrings
|
|
(hashedId: ''
|
|
[source.nix-sources-${hashedId}]
|
|
directory = "${placeholder "out"}/${hashedId}"
|
|
'')
|
|
(attrNames sources);
|
|
|
|
configReplaceGitSources = mapAttrsToList
|
|
(hashedId: ps:
|
|
let
|
|
p = head ps;
|
|
extractAttr = attr:
|
|
if p ? ${attr} then ''
|
|
${attr} = "${p.${attr}}"
|
|
'' else "";
|
|
sourceValues = concatMapStrings extractAttr ([ "git" ] ++ knownGitParams);
|
|
in
|
|
''
|
|
[source."${p.id}"]
|
|
replace-with = "nix-sources-${hash p.id}"
|
|
${sourceValues}
|
|
''
|
|
)
|
|
lockedGitGroups;
|
|
in
|
|
{
|
|
inherit sources;
|
|
config = configLocalSources + (concatStrings configReplaceGitSources);
|
|
}
|