nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 mitm-cache,
3 lib,
4 pkgs,
5 stdenv,
6 callPackage,
7}:
8
9let
10 getPkg = attrPath: lib.getAttrFromPath (lib.splitString "." (toString attrPath)) pkgs;
11in
12# the derivation to fetch/update deps for
13{
14 pkg ? getPkg attrPath,
15 pname ? null,
16 attrPath ? pname,
17 # bwrap flags for the update script (this will be put in bash as-is)
18 # this is relevant for downstream users
19 bwrapFlags ? "--ro-bind \"$PWD\" \"$PWD\"",
20 # deps path (relative to the package directory, or absolute)
21 data,
22 # redirect stdout to stderr to allow the update script to be used with update script combinators
23 silent ? true,
24 useBwrap ? stdenv.hostPlatform.isLinux,
25}@attrs:
26
27let
28 data' =
29 removeAttrs
30 (
31 if builtins.isPath data then
32 lib.importJSON data
33 else if builtins.isString data then
34 lib.importJSON "${dirOf pkg.meta.position}/${data}"
35 else
36 data
37 )
38 [
39 "!comment"
40 "!version"
41 ];
42
43 parseArtifactUrl =
44 url:
45 let
46 extension = lib.last (lib.splitString "." url);
47 splitUrl = lib.splitString "/" url;
48 artifactId = builtins.elemAt splitUrl (builtins.length splitUrl - 3);
49 baseVer = builtins.elemAt splitUrl (builtins.length splitUrl - 2);
50 filename = builtins.elemAt splitUrl (builtins.length splitUrl - 1);
51 filenameNoExt = lib.removeSuffix ".${extension}" filename;
52 verCls = lib.removePrefix "${artifactId}-" filenameNoExt;
53 in
54 rec {
55 inherit
56 artifactId
57 baseVer
58 filename
59 extension
60 ;
61 isSnapshot = lib.hasSuffix "-SNAPSHOT" baseVer;
62 version =
63 if isSnapshot && !lib.hasPrefix "SNAPSHOT" verCls then
64 builtins.concatStringsSep "-" (lib.take 3 (lib.splitString "-" verCls))
65 else
66 baseVer;
67 classifier = if verCls == version then null else lib.removePrefix "${version}-" verCls;
68 # for snapshots
69 timestamp = builtins.elemAt (lib.splitString "-" version) 1;
70 buildNum = builtins.elemAt (lib.splitString "-" version) 2;
71 };
72
73 parseMetadataUrl =
74 url:
75 let
76 xmlBase = lib.removeSuffix "/maven-metadata.xml" url;
77 vMeta = lib.hasSuffix "-SNAPSHOT" xmlBase;
78 splitBase = lib.splitString "/" xmlBase;
79 in
80 if vMeta then
81 {
82 vMeta = true;
83 baseVer = builtins.elemAt splitBase (builtins.length splitBase - 1);
84 artifactId = builtins.elemAt splitBase (builtins.length splitBase - 2);
85 }
86 else
87 {
88 vMeta = false;
89 baseVer = null;
90 artifactId = builtins.elemAt splitBase (builtins.length splitBase - 1);
91 };
92
93 extractHashArtifact =
94 afterHash:
95 let
96 nameVer = builtins.match "([^/]*)/([^/]*)(/SNAPSHOT)?(/.*)?" afterHash;
97 artifactId = builtins.elemAt nameVer 0;
98 version = builtins.elemAt nameVer 1;
99 isSnapshot = builtins.elemAt nameVer 2 != null;
100 cls = builtins.elemAt nameVer 3;
101 in
102 rec {
103 inherit artifactId version isSnapshot;
104 baseVer =
105 if !isSnapshot then
106 version
107 else
108 builtins.head (builtins.match "(.*)-([^-]*)-([^-]*)" version) + "-SNAPSHOT";
109 classifier = if cls == null then null else lib.removePrefix "/" cls;
110 clsSuf = if classifier == null then "" else "-${classifier}";
111 };
112
113 # replace base#name/ver with base/name/ver/name-ver
114 decompressNameVer =
115 prefix:
116 let
117 splitHash = lib.splitString "#" (builtins.concatStringsSep "/" prefix);
118 inherit (extractHashArtifact (lib.last splitHash))
119 artifactId
120 baseVer
121 version
122 clsSuf
123 ;
124 in
125 if builtins.length splitHash == 1 then
126 builtins.head splitHash
127 else
128 builtins.concatStringsSep "/${artifactId}/${baseVer}/" (
129 lib.init splitHash ++ [ "${artifactId}-${version}${clsSuf}" ]
130 );
131
132 # `visit` all elements in attrs and merge into a set
133 # attrs will be passed as parent1, parent1 will be passed as parent2
134 visitAttrs =
135 parent1: prefix: attrs:
136 builtins.foldl' (a: b: a // b) { } (lib.mapAttrsToList (visit parent1 attrs prefix) attrs);
137
138 # convert a compressed deps.json into an uncompressed json used for mitm-cache.fetch
139 visit =
140 parent2: parent1: prefix: k: v:
141 # groupId being present means this is a metadata xml "leaf" and we shouldn't descend further
142 if builtins.isAttrs v && !v ? groupId then
143 visitAttrs parent1 (prefix ++ [ k ]) v
144 else
145 let
146 url = "${decompressNameVer prefix}.${k}";
147 in
148 {
149 ${url} =
150 if builtins.isString v then
151 { hash = v; }
152 else
153 {
154 text =
155 let
156 xmlBase = lib.removeSuffix "/maven-metadata.xml" url;
157 meta = parseMetadataUrl url // v;
158 inherit (meta)
159 groupId
160 vMeta
161 artifactId
162 baseVer
163 ;
164
165 fileList = builtins.filter (x: lib.hasPrefix xmlBase x && x != url) (builtins.attrNames finalData);
166 jarPomList = map parseArtifactUrl fileList;
167
168 sortByVersion = a: b: (builtins.compareVersions a.version b.version) < 0;
169 sortedJarPomList = lib.sort sortByVersion jarPomList;
170
171 uniqueVersionFiles = map ({ i, x }: x) (
172 builtins.filter (
173 { i, x }: i == 0 || (builtins.elemAt sortedJarPomList (i - 1)).version != x.version
174 ) (lib.imap0 (i: x: { inherit i x; }) sortedJarPomList)
175 );
176 uniqueVersions' = map (x: x.version) uniqueVersionFiles;
177 releaseVersions = map (x: x.version) (builtins.filter (x: !x.isSnapshot) uniqueVersionFiles);
178 latestVer = v.latest or v.release or (lib.last uniqueVersions');
179 releaseVer = v.release or (lib.last releaseVersions);
180
181 # The very latest version isn't necessarily used by Gradle, so it may not be present in the MITM data.
182 # In order to generate better metadata xml, if the latest version is known but wasn't fetched by Gradle,
183 # add it anyway.
184 uniqueVersions =
185 uniqueVersions'
186 ++ lib.optional (!builtins.elem releaseVer uniqueVersions') releaseVer
187 ++ lib.optional (!builtins.elem latestVer uniqueVersions' && releaseVer != latestVer) latestVer;
188
189 lastUpdated =
190 v.lastUpdated
191 or (if vMeta then builtins.replaceStrings [ "." ] [ "" ] snapshotTs else "20240101123456");
192
193 # the following are only used for snapshots
194 snapshotTsAndNum = lib.splitString "-" latestVer;
195 snapshotTs = builtins.elemAt snapshotTsAndNum 1;
196 snapshotNum = lib.last snapshotTsAndNum;
197
198 indent = x: s: builtins.concatStringsSep "\n" (map (s: x + s) (lib.splitString "\n" s));
199 containsSpecialXmlChars = s: builtins.match ''.*[<>"'&].*'' s != null;
200 in
201 # make sure all user-provided data is safe
202 assert lib.hasInfix "${builtins.replaceStrings [ "." ] [ "/" ] groupId}/${artifactId}" url;
203 assert !containsSpecialXmlChars groupId;
204 assert !containsSpecialXmlChars lastUpdated;
205 if vMeta then
206 ''
207 <?xml version="1.0" encoding="UTF-8"?>
208 <metadata modelVersion="1.1.0">
209 <groupId>${groupId}</groupId>
210 <artifactId>${artifactId}</artifactId>
211 <version>${baseVer}</version>
212 <versioning>
213 <snapshot>
214 <timestamp>${snapshotTs}</timestamp>
215 <buildNumber>${snapshotNum}</buildNumber>
216 </snapshot>
217 <lastUpdated>${lastUpdated}</lastUpdated>
218 <snapshotVersions>
219 ${builtins.concatStringsSep "\n" (
220 map (
221 x:
222 indent " " ''
223 <snapshotVersion>${
224 lib.optionalString (x.classifier != null) "\n <classifier>${x.classifier}</classifier>"
225 }
226 <extension>${x.extension}</extension>
227 <value>${x.version}</value>
228 <updated>${builtins.replaceStrings [ "." ] [ "" ] x.timestamp}</updated>
229 </snapshotVersion>''
230 ) sortedJarPomList
231 )}
232 </snapshotVersions>
233 </versioning>
234 </metadata>
235 ''
236 else
237 assert !containsSpecialXmlChars latestVer;
238 assert !containsSpecialXmlChars releaseVer;
239 ''
240 <?xml version="1.0" encoding="UTF-8"?>
241 <metadata modelVersion="1.1.0">
242 <groupId>${groupId}</groupId>
243 <artifactId>${artifactId}</artifactId>
244 <versioning>
245 <latest>${latestVer}</latest>
246 <release>${releaseVer}</release>
247 <versions>
248 ${builtins.concatStringsSep "\n" (map (x: " <version>${x}</version>") uniqueVersions)}
249 </versions>
250 <lastUpdated>${lastUpdated}</lastUpdated>
251 </versioning>
252 </metadata>
253 '';
254 };
255 };
256
257 finalData = visitAttrs { } [ ] data';
258in
259mitm-cache.fetch {
260 name = "${pkg.pname or pkg.name}-deps";
261 data = finalData // {
262 "!version" = 1;
263 };
264 passthru = lib.optionalAttrs (!builtins.isAttrs data) {
265 updateScript = callPackage ./update-deps.nix { } {
266 inherit
267 pkg
268 pname
269 attrPath
270 bwrapFlags
271 data
272 silent
273 useBwrap
274 ;
275 };
276 };
277}