@@ -0,0 +1,223 @@
1+{ javaVersion
2+, graalVersion
3+, defaultVersion
4+, config
5+, sourcesFilename
6+, name
7+, lib
8+, writeShellScript
9+, jq
10+, gnused
11+}:
12+
13+/*
14+ How to use:
15+ run `nix-shell maintainers/scripts/update.nix --argstr package graalvmXX-ce`
16+ to update the graalvmXX-ce-sources.json file.
17+ E.g: nix-shell maintainers/scripts/update.nix --argstr package graalvm17-ce
18+
19+ Basic idea:
20+ If we know the platform, product, javaVersion and graalVersion
21+ we can create the url. This leads to the following json structure:
22+ {
23+ "platform/arch1": {
24+ "product1|javaVersion|graalVersion": { "sha256": "...", "url": "..."},
25+ "product2|javaVersion|graalVersion": { "sha256": "...", "url": "..."},
26+ ...
27+ },
28+ "platform/arch2": {
29+ ...
30+ }
31+ }
32+*/
33+
34+let
35+ separator = "|";
36+
37+ # isDev :: String -> Boolean
38+ isDev = version:
39+ lib.hasInfix "dev" version;
40+
41+ # getLatestVersion :: String -> String
42+ getLatestVersion = currentVersion:
43+ let
44+ dev = if isDev currentVersion then "dev-" else "";
45+ url = "https://api.github.com/repos/graalvm/graalvm-ce-${dev}builds/releases/latest";
46+ file = builtins.fetchurl url;
47+ json = builtins.fromJSON (builtins.readFile file);
48+ in
49+ lib.removePrefix "vm-" json.tag_name;
50+
51+ # getArchString :: String -> String
52+ getArchString = nixArchString:
53+ {
54+ "aarch64-linux" = "linux-aarch64";
55+ "x86_64-linux" = "linux-amd64";
56+ "x86_64-darwin" = "darwin-amd64";
57+ }.${nixArchString};
58+
59+
60+ # getProductSuffix :: String -> String
61+ getProductSuffix = productName:
62+ {
63+ "graalvm-ce" = ".tar.gz";
64+ "native-image-installable-svm" = ".jar";
65+ "ruby-installable-svm" = ".jar";
66+ "wasm-installable-svm" = ".jar";
67+ "python-installable-svm" = ".jar";
68+ }.${productName};
69+
70+ # getProductSuffix :: String -> String
71+ getProductBaseUrl = productName:
72+ {
73+ "graalvm-ce" = "https://github.com/graalvm/graalvm-ce-builds/releases/download";
74+ "native-image-installable-svm" = "https://github.com/graalvm/graalvm-ce-builds/releases/download";
75+ "ruby-installable-svm" = "https://github.com/oracle/truffleruby/releases/download";
76+ "wasm-installable-svm" = "https://github.com/graalvm/graalvm-ce-builds/releases/download";
77+ "python-installable-svm" = "https://github.com/graalvm/graalpython/releases/download";
78+ }.${productName};
79+
80+ # getDevUrl :: String
81+ getDevUrl = { arch, graalVersion, product, javaVersion }:
82+ let
83+ baseUrl = https://github.com/graalvm/graalvm-ce-dev-builds/releases/download;
84+ in
85+ "${baseUrl}/${graalVersion}/${product}-${javaVersion}-${arch}-dev${getProductSuffix product}";
86+
87+ # getReleaseUrl :: AttrSet -> String
88+ getReleaseUrl = { arch, graalVersion, product, javaVersion }:
89+ let baseUrl = getProductBaseUrl product;
90+ in
91+ "${baseUrl}/vm-${graalVersion}/${product}-${javaVersion}-${arch}-${graalVersion}${getProductSuffix product}";
92+
93+ # getUrl :: AttrSet -> String
94+ getUrl = args@{ arch, graalVersion, product, javaVersion }:
95+ if isDev graalVersion
96+ then getDevUrl args
97+ else getReleaseUrl args;
98+
99+ # computeSha256 :: String -> String
100+ computeSha256 = url:
101+ builtins.hashFile "sha256" (builtins.fetchurl url);
102+
103+ # downloadSha256 :: String -> String
104+ downloadSha256 = url:
105+ let sha256Url = url + ".sha256";
106+ in
107+ builtins.readFile (builtins.fetchurl sha256Url);
108+
109+ # getSha256 :: String -> String -> String
110+ getSha256 = graalVersion: url:
111+ if isDev graalVersion
112+ then computeSha256 url
113+ else downloadSha256 url;
114+
115+ # cartesianZipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c]
116+ cartesianZipListsWith = f: fst: snd:
117+ let
118+ cartesianProduct = lib.cartesianProductOfSets { a = fst; b = snd; };
119+ fst' = builtins.catAttrs "a" cartesianProduct;
120+ snd' = builtins.catAttrs "b" cartesianProduct;
121+ in
122+ lib.zipListsWith f fst' snd';
123+
124+ # zipListsToAttrs :: [a] -> [b] -> AttrSet
125+ zipListsToAttrs = names: values:
126+ lib.listToAttrs (
127+ lib.zipListsWith (name: value: { inherit name value; }) names values
128+ );
129+
130+ # genProductJavaVersionGraalVersionAttrSet :: String -> AttrSet
131+ genProductJavaVersionGraalVersionAttrSet = product_javaVersion_graalVersion:
132+ let
133+ attrNames = [ "product" "javaVersion" "graalVersion" ];
134+ attrValues = lib.splitString separator product_javaVersion_graalVersion;
135+ in
136+ zipListsToAttrs attrNames attrValues;
137+
138+ # genUrlAndSha256 :: String -> String -> AttrSet
139+ genUrlAndSha256 = arch: product_javaVersion_graalVersion:
140+ let
141+ productJavaVersionGraalVersion =
142+ (genProductJavaVersionGraalVersionAttrSet product_javaVersion_graalVersion)
143+ // { inherit arch; };
144+ url = getUrl productJavaVersionGraalVersion;
145+ sha256 = getSha256 productJavaVersionGraalVersion.graalVersion url;
146+ in
147+ {
148+ ${arch} = {
149+ ${product_javaVersion_graalVersion} = {
150+ inherit sha256 url;
151+ };
152+ };
153+ };
154+
155+ # genArchProductVersionPairs :: String -> -> String -> AttrSet -> [AttrSet]
156+ genArchProductVersionList = javaVersion: graalVersion: archProducts:
157+ let
158+ arch = archProducts.arch;
159+ products = archProducts.products;
160+ javaGraalVersion = javaVersion + separator + (getLatestVersion (archProducts.version or graalVersion));
161+ productJavaGraalVersionList =
162+ cartesianZipListsWith (a: b: a + separator + b)
163+ products [ javaGraalVersion ];
164+ in
165+ cartesianZipListsWith (genUrlAndSha256) [ arch ] productJavaGraalVersionList;
166+
167+
168+ # genSources :: String -> String -> AttrSet -> Path String
169+ genSources = javaVersion: defaultVersion: config:
170+ let
171+ archProducts = builtins.attrValues config;
172+ sourcesList = builtins.concatMap (genArchProductVersionList javaVersion defaultVersion) archProducts;
173+ sourcesAttr = builtins.foldl' (lib.recursiveUpdate) { } sourcesList;
174+ in
175+ builtins.toFile "sources.json" (builtins.toJSON sourcesAttr);
176+
177+ # isNew :: String -> String -> Boolean
178+ isNew = newVersion: currentVersion:
179+ {
180+ "-1" = false;
181+ "0" = false;
182+ "1" = true;
183+ }.${builtins.toString (builtins.compareVersions newVersion currentVersion)};
184+
185+ newVersion = getLatestVersion graalVersion;
186+ sourcesJson = genSources javaVersion defaultVersion config;
187+ sourcesJsonPath = lib.strings.escapeShellArg ./. + "/${sourcesFilename}";
188+
189+ # versionKeyInDefaultNix String -> String
190+ versionKeyInDefaultNix = graalVersion:
191+ if isDev graalVersion
192+ then "${name}-dev-version"
193+ else "${name}-release-version";
194+
195+ /*
196+ updateScriptText :: String -> String -> String
197+ Writes the json file and updates the version in default.nix using sed
198+ because update-source-version does not work srcs.
199+ */
200+ updateScriptText = newVersion: currentVersion:
201+
202+ if isNew newVersion currentVersion
203+ then
204+ let
205+ versionKey = versionKeyInDefaultNix currentVersion;
206+ in
207+ ''
208+ echo "New version found. Updating ${currentVersion} -> ${newVersion}".
209+ export PATH="${lib.makeBinPath [ jq gnused ]}:$PATH"
210+ jq . ${sourcesJson} > ${sourcesJsonPath}
211+ sed -i 's|${versionKey} = "${currentVersion}";|${versionKey} = "${newVersion}";|' \
212+ ${lib.strings.escapeShellArg ./default.nix}
213+ ''
214+ else ''echo "No new version found. Skip updating."'';
215+
216+in
217+writeShellScript "update-graal.sh" ''
218+ set -o errexit
219+ set -o nounset
220+ set -o pipefail
221+
222+ ${updateScriptText newVersion graalVersion}
223+''