7e47f3658e
GitOrigin-RevId: 1925c603f17fc89f4c8f6bf6f631a802ad85d784
221 lines
8.8 KiB
Nix
221 lines
8.8 KiB
Nix
{ mitm-cache
|
|
, lib
|
|
, pkgs
|
|
, stdenv
|
|
, callPackage
|
|
}:
|
|
|
|
let
|
|
getPkg = attrPath:
|
|
lib.getAttrFromPath
|
|
(lib.splitString "." (toString attrPath))
|
|
pkgs;
|
|
in
|
|
# the derivation to fetch/update deps for
|
|
{ pkg ? getPkg attrPath
|
|
, pname ? null
|
|
, attrPath ? pname
|
|
# bwrap flags for the update script (this will be put in bash as-is)
|
|
# this is relevant for downstream users
|
|
, bwrapFlags ? "--ro-bind \"$PWD\" \"$PWD\""
|
|
# deps path (relative to the package directory, or absolute)
|
|
, data
|
|
# redirect stdout to stderr to allow the update script to be used with update script combinators
|
|
, silent ? true
|
|
, useBwrap ? stdenv.hostPlatform.isLinux
|
|
} @ attrs:
|
|
|
|
let
|
|
data' = builtins.removeAttrs
|
|
(if builtins.isPath data then lib.importJSON data
|
|
else if builtins.isString data then lib.importJSON "${dirOf pkg.meta.position}/${data}"
|
|
else data)
|
|
[ "!comment" "!version" ];
|
|
|
|
parseArtifactUrl = url: let
|
|
extension = lib.last (lib.splitString "." url);
|
|
splitUrl = lib.splitString "/" url;
|
|
artifactId = builtins.elemAt splitUrl (builtins.length splitUrl - 3);
|
|
baseVer = builtins.elemAt splitUrl (builtins.length splitUrl - 2);
|
|
filename = builtins.elemAt splitUrl (builtins.length splitUrl - 1);
|
|
filenameNoExt = lib.removeSuffix ".${extension}" filename;
|
|
verCls = lib.removePrefix "${artifactId}-" filenameNoExt;
|
|
in rec {
|
|
inherit artifactId baseVer filename extension;
|
|
isSnapshot = lib.hasSuffix "-SNAPSHOT" baseVer;
|
|
version =
|
|
if isSnapshot && !lib.hasPrefix "SNAPSHOT" verCls
|
|
then builtins.concatStringsSep "-" (lib.take 3 (lib.splitString "-" verCls))
|
|
else baseVer;
|
|
classifier =
|
|
if verCls == version then null
|
|
else lib.removePrefix "${version}-" verCls;
|
|
# for snapshots
|
|
timestamp = builtins.elemAt (lib.splitString "-" version) 1;
|
|
buildNum = builtins.elemAt (lib.splitString "-" version) 2;
|
|
};
|
|
|
|
parseMetadataUrl = url: let
|
|
xmlBase = lib.removeSuffix "/maven-metadata.xml" url;
|
|
vMeta = lib.hasSuffix "-SNAPSHOT" xmlBase;
|
|
splitBase = lib.splitString "/" xmlBase;
|
|
in
|
|
if vMeta then {
|
|
vMeta = true;
|
|
baseVer = builtins.elemAt splitBase (builtins.length splitBase - 1);
|
|
artifactId = builtins.elemAt splitBase (builtins.length splitBase - 2);
|
|
} else {
|
|
vMeta = false;
|
|
baseVer = null;
|
|
artifactId = builtins.elemAt splitBase (builtins.length splitBase - 1);
|
|
};
|
|
|
|
extractHashArtifact = afterHash: let
|
|
nameVer = builtins.match "([^/]*)/([^/]*)(/SNAPSHOT)?(/.*)?" afterHash;
|
|
artifactId = builtins.elemAt nameVer 0;
|
|
version = builtins.elemAt nameVer 1;
|
|
isSnapshot = builtins.elemAt nameVer 2 != null;
|
|
cls = builtins.elemAt nameVer 3;
|
|
in rec {
|
|
inherit artifactId version isSnapshot;
|
|
baseVer =
|
|
if !isSnapshot then version
|
|
else builtins.head (builtins.match "(.*)-([^-]*)-([^-]*)" version) + "-SNAPSHOT";
|
|
classifier =
|
|
if cls == null then null
|
|
else lib.removePrefix "/" cls;
|
|
clsSuf =
|
|
if classifier == null then ""
|
|
else "-${classifier}";
|
|
};
|
|
|
|
# replace base#name/ver with base/name/ver/name-ver
|
|
decompressNameVer = prefix: let
|
|
splitHash = lib.splitString "#" (builtins.concatStringsSep "/" prefix);
|
|
inherit (extractHashArtifact (lib.last splitHash)) artifactId baseVer version clsSuf;
|
|
in
|
|
if builtins.length splitHash == 1 then builtins.head splitHash
|
|
else builtins.concatStringsSep "/${artifactId}/${baseVer}/" (lib.init splitHash ++ [ "${artifactId}-${version}${clsSuf}" ]);
|
|
|
|
# `visit` all elements in attrs and merge into a set
|
|
# attrs will be passed as parent1, parent1 will be passed as parent2
|
|
visitAttrs = parent1: prefix: attrs:
|
|
builtins.foldl'
|
|
(a: b: a // b)
|
|
{}
|
|
(lib.mapAttrsToList (visit parent1 attrs prefix) attrs);
|
|
|
|
# convert a compressed deps.json into an uncompressed json used for mitm-cache.fetch
|
|
visit = parent2: parent1: prefix: k: v:
|
|
# groupId being present means this is a metadata xml "leaf" and we shouldn't descend further
|
|
if builtins.isAttrs v && !v?groupId
|
|
then visitAttrs parent1 (prefix ++ [k]) v
|
|
else let
|
|
url = "${decompressNameVer prefix}.${k}";
|
|
in {
|
|
${url} =
|
|
if builtins.isString v then { hash = v; }
|
|
else {
|
|
text = let
|
|
xmlBase = lib.removeSuffix "/maven-metadata.xml" url;
|
|
meta = parseMetadataUrl url // v;
|
|
inherit (meta) groupId vMeta artifactId baseVer;
|
|
|
|
fileList = builtins.filter (x: lib.hasPrefix xmlBase x && x != url) (builtins.attrNames finalData);
|
|
jarPomList = map parseArtifactUrl fileList;
|
|
|
|
sortByVersion = a: b: (builtins.compareVersions a.version b.version) < 0;
|
|
sortedJarPomList = lib.sort sortByVersion jarPomList;
|
|
|
|
uniqueVersionFiles =
|
|
builtins.map ({ i, x }: x)
|
|
(builtins.filter ({ i, x }: i == 0 || (builtins.elemAt sortedJarPomList (i - 1)).version != x.version)
|
|
(lib.imap0 (i: x: { inherit i x; }) sortedJarPomList));
|
|
uniqueVersions' = map (x: x.version) uniqueVersionFiles;
|
|
releaseVersions = map (x: x.version) (builtins.filter (x: !x.isSnapshot) uniqueVersionFiles);
|
|
latestVer = v.latest or v.release or (lib.last uniqueVersions');
|
|
releaseVer = v.release or (lib.last releaseVersions);
|
|
|
|
# The very latest version isn't necessarily used by Gradle, so it may not be present in the MITM data.
|
|
# In order to generate better metadata xml, if the latest version is known but wasn't fetched by Gradle,
|
|
# add it anyway.
|
|
uniqueVersions =
|
|
uniqueVersions'
|
|
++ lib.optional (!builtins.elem releaseVer uniqueVersions') releaseVer
|
|
++ lib.optional (!builtins.elem latestVer uniqueVersions' && releaseVer != latestVer) latestVer;
|
|
|
|
lastUpdated = v.lastUpdated or
|
|
(if vMeta then builtins.replaceStrings ["."] [""] snapshotTs
|
|
else "20240101123456");
|
|
|
|
# the following are only used for snapshots
|
|
snapshotTsAndNum = lib.splitString "-" latestVer;
|
|
snapshotTs = builtins.elemAt snapshotTsAndNum 1;
|
|
snapshotNum = lib.last snapshotTsAndNum;
|
|
|
|
indent = x: s: builtins.concatStringsSep "\n" (map (s: x + s) (lib.splitString "\n" s));
|
|
containsSpecialXmlChars = s: builtins.match ''.*[<>"'&].*'' s != null;
|
|
in
|
|
# make sure all user-provided data is safe
|
|
assert lib.hasInfix "${builtins.replaceStrings ["."] ["/"] groupId}/${artifactId}" url;
|
|
assert !containsSpecialXmlChars groupId;
|
|
assert !containsSpecialXmlChars lastUpdated;
|
|
if vMeta then ''
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<metadata modelVersion="1.1.0">
|
|
<groupId>${groupId}</groupId>
|
|
<artifactId>${artifactId}</artifactId>
|
|
<version>${baseVer}</version>
|
|
<versioning>
|
|
<snapshot>
|
|
<timestamp>${snapshotTs}</timestamp>
|
|
<buildNumber>${snapshotNum}</buildNumber>
|
|
</snapshot>
|
|
<lastUpdated>${lastUpdated}</lastUpdated>
|
|
<snapshotVersions>
|
|
${builtins.concatStringsSep "\n" (map (x: indent " " ''
|
|
<snapshotVersion>${
|
|
lib.optionalString
|
|
(x.classifier != null)
|
|
"\n <classifier>${x.classifier}</classifier>"
|
|
}
|
|
<extension>${x.extension}</extension>
|
|
<value>${x.version}</value>
|
|
<updated>${builtins.replaceStrings ["."] [""] x.timestamp}</updated>
|
|
</snapshotVersion>'') sortedJarPomList)}
|
|
</snapshotVersions>
|
|
</versioning>
|
|
</metadata>
|
|
''
|
|
else
|
|
assert !containsSpecialXmlChars latestVer;
|
|
assert !containsSpecialXmlChars releaseVer;
|
|
''
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<metadata modelVersion="1.1.0">
|
|
<groupId>${groupId}</groupId>
|
|
<artifactId>${artifactId}</artifactId>
|
|
<versioning>
|
|
<latest>${latestVer}</latest>
|
|
<release>${releaseVer}</release>
|
|
<versions>
|
|
${builtins.concatStringsSep "\n" (map (x: " <version>${x}</version>") uniqueVersions)}
|
|
</versions>
|
|
<lastUpdated>${lastUpdated}</lastUpdated>
|
|
</versioning>
|
|
</metadata>
|
|
'';
|
|
};
|
|
};
|
|
|
|
finalData = visitAttrs {} [] data';
|
|
in
|
|
mitm-cache.fetch {
|
|
name = "${pkg.pname or pkg.name}-deps";
|
|
data = finalData // { "!version" = 1; };
|
|
passthru = lib.optionalAttrs (!builtins.isAttrs data) {
|
|
updateScript = callPackage ./update-deps.nix { } {
|
|
inherit pkg pname attrPath bwrapFlags data silent useBwrap;
|
|
};
|
|
};
|
|
}
|