fork
Configure Feed
Select the types of activity you want to include in your feed.
lol
fork
Configure Feed
Select the types of activity you want to include in your feed.
1{
2 callPackage,
3 fetchgit,
4 fontconfig,
5 git,
6 lib,
7 makeWrapper,
8 python3,
9 runCommand,
10 system,
11 writeText,
12 writeTextFile,
13
14 # Artifacts dependencies
15 fetchurl,
16 glibc,
17 pkgs,
18 stdenv,
19
20 julia,
21
22 # Special registry which is equal to JuliaRegistries/General, but every Versions.toml
23 # entry is augmented with a Nix sha256 hash
24 augmentedRegistry ? callPackage ./registry.nix { },
25
26 # Other overridable arguments
27 extraLibs ? [ ],
28 juliaCpuTarget ? null,
29 makeTransitiveDependenciesImportable ? false, # Used to support symbol indexing
30 makeWrapperArgs ? "",
31 packageOverrides ? { },
32 precompile ? true,
33 setDefaultDepot ? true,
34}:
35
36packageNames:
37
38let
39 util = callPackage ./util.nix { };
40
41 # Some Julia packages require access to Python. Provide a Nixpkgs version so it
42 # doesn't try to install its own.
43 pythonToUse =
44 let
45 extraPythonPackages = (
46 (callPackage ./extra-python-packages.nix { inherit python3; }).getExtraPythonPackages packageNames
47 );
48 in
49 (
50 if extraPythonPackages == [ ] then
51 python3
52 else
53 util.addPackagesToPython python3 (map (pkg: lib.getAttr pkg python3.pkgs) extraPythonPackages)
54 );
55
56 # Start by wrapping Julia so it has access to Python and any other extra libs.
57 # Also, prevent various packages (CondaPkg.jl, PythonCall.jl) from trying to do network calls.
58 juliaWrapped =
59 runCommand "julia-${julia.version}-wrapped"
60 {
61 nativeBuildInputs = [ makeWrapper ];
62 inherit makeWrapperArgs;
63 }
64 ''
65 mkdir -p $out/bin
66 makeWrapper ${julia}/bin/julia $out/bin/julia \
67 --suffix LD_LIBRARY_PATH : "${lib.makeLibraryPath extraLibs}" \
68 --set FONTCONFIG_FILE ${fontconfig.out}/etc/fonts/fonts.conf \
69 --set PYTHONHOME "${pythonToUse}" \
70 --prefix PYTHONPATH : "${pythonToUse}/${pythonToUse.sitePackages}" \
71 --set PYTHON ${pythonToUse}/bin/python $makeWrapperArgs \
72 --set JULIA_CONDAPKG_OFFLINE yes \
73 --set JULIA_CONDAPKG_BACKEND Null \
74 --set JULIA_PYTHONCALL_EXE "@PyCall"
75 '';
76
77 # If our closure ends up with certain packages, add others.
78 packageImplications = {
79 # Because we want to put PythonCall in PyCall mode so it doesn't try to download
80 # Python packages
81 PythonCall = [ "PyCall" ];
82 };
83
84 # Invoke Julia resolution logic to determine the full dependency closure
85 packageOverridesRepoified = lib.mapAttrs util.repoifySimple packageOverrides;
86 closureYaml = callPackage ./package-closure.nix {
87 inherit
88 augmentedRegistry
89 julia
90 packageNames
91 packageImplications
92 ;
93 packageOverrides = packageOverridesRepoified;
94 };
95
96 # Generate a Nix file consisting of a map from dependency UUID --> package info with fetchgit call:
97 # {
98 # "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" = {
99 # src = fetchgit {...};
100 # name = "...";
101 # version = "...";
102 # treehash = "...";
103 # };
104 # ...
105 # }
106 dependencies =
107 runCommand "julia-sources.nix"
108 {
109 buildInputs = [
110 (python3.withPackages (
111 ps: with ps; [
112 toml
113 pyyaml
114 ]
115 ))
116 git
117 ];
118 }
119 ''
120 python ${./python}/sources_nix.py \
121 "${augmentedRegistry}" \
122 '${lib.generators.toJSON { } packageOverridesRepoified}' \
123 "${closureYaml}" \
124 "$out"
125 '';
126
127 # Import the Nix file from the previous step (IFD) and turn each dependency repo into
128 # a dummy Git repository, as Julia expects. Format the results as a YAML map from
129 # dependency UUID -> Nix store location:
130 # {
131 # "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3":"/nix/store/...-NaNMath.jl-0877504",
132 # ...
133 # }
134 # This is also the point where we apply the packageOverrides.
135 dependencyUuidToInfo = import dependencies { inherit fetchgit; };
136 fillInOverrideSrc =
137 uuid: info:
138 if lib.hasAttr info.name packageOverrides then
139 (info // { src = lib.getAttr info.name packageOverrides; })
140 else
141 info;
142 dependencyUuidToRepo = lib.mapAttrs util.repoifyInfo (
143 lib.mapAttrs fillInOverrideSrc dependencyUuidToInfo
144 );
145 dependencyUuidToRepoYaml = writeTextFile {
146 name = "dependency-uuid-to-repo.yml";
147 text = lib.generators.toYAML { } dependencyUuidToRepo;
148 };
149
150 # Given the augmented registry, closure info yaml, and dependency path yaml, construct a complete
151 # Julia registry containing all the necessary packages
152 dependencyUuidToInfoYaml = writeTextFile {
153 name = "dependency-uuid-to-info.yml";
154 text = lib.generators.toYAML { } dependencyUuidToInfo;
155 };
156 fillInOverrideSrc' =
157 uuid: info:
158 if lib.hasAttr info.name packageOverridesRepoified then
159 (info // { src = lib.getAttr info.name packageOverridesRepoified; })
160 else
161 info;
162 overridesOnly = lib.mapAttrs fillInOverrideSrc' (
163 lib.filterAttrs (uuid: info: info.src == null) dependencyUuidToInfo
164 );
165 minimalRegistry =
166 runCommand "minimal-julia-registry"
167 {
168 buildInputs = [
169 (python3.withPackages (
170 ps: with ps; [
171 toml
172 pyyaml
173 ]
174 ))
175 git
176 ];
177 }
178 ''
179 python ${./python}/minimal_registry.py \
180 "${augmentedRegistry}" \
181 "${closureYaml}" \
182 '${lib.generators.toJSON { } overridesOnly}' \
183 "${dependencyUuidToRepoYaml}" \
184 "$out"
185 '';
186
187 # Next, deal with artifacts. Scan each artifacts file individually and generate a Nix file that
188 # produces the desired Overrides.toml.
189 artifactsNix =
190 runCommand "julia-artifacts.nix"
191 {
192 buildInputs = [
193 (python3.withPackages (
194 ps: with ps; [
195 toml
196 pyyaml
197 ]
198 ))
199 ];
200 }
201 ''
202 python ${./python}/extract_artifacts.py \
203 "${dependencyUuidToRepoYaml}" \
204 "${closureYaml}" \
205 "${juliaWrapped}/bin/julia" \
206 "${
207 if lib.versionAtLeast julia.version "1.7" then ./extract_artifacts.jl else ./extract_artifacts_16.jl
208 }" \
209 '${lib.generators.toJSON { } (import ./extra-libs.nix)}' \
210 '${lib.generators.toJSON { } (stdenv.hostPlatform.isDarwin)}' \
211 "$out"
212 '';
213
214 # Import the artifacts Nix to build Overrides.toml (IFD)
215 artifacts = import artifactsNix (
216 {
217 inherit
218 lib
219 fetchurl
220 pkgs
221 stdenv
222 ;
223 }
224 // lib.optionalAttrs (!stdenv.targetPlatform.isDarwin) {
225 inherit glibc;
226 }
227 );
228 overridesJson = writeTextFile {
229 name = "Overrides.json";
230 text = lib.generators.toJSON { } artifacts;
231 };
232 overridesToml =
233 runCommand "Overrides.toml" { buildInputs = [ (python3.withPackages (ps: with ps; [ toml ])) ]; }
234 ''
235 python ${./python}/format_overrides.py \
236 "${overridesJson}" \
237 "$out"
238 '';
239
240 # Build a Julia project and depot. The project contains Project.toml/Manifest.toml, while the
241 # depot contains package build products (including the precompiled libraries, if precompile=true)
242 projectAndDepot = callPackage ./depot.nix {
243 inherit
244 closureYaml
245 extraLibs
246 juliaCpuTarget
247 overridesToml
248 packageImplications
249 precompile
250 ;
251 julia = juliaWrapped;
252 registry = minimalRegistry;
253 packageNames =
254 if makeTransitiveDependenciesImportable then
255 lib.mapAttrsToList (uuid: info: info.name) dependencyUuidToInfo
256 else
257 packageNames;
258 };
259
260in
261
262runCommand "julia-${julia.version}-env"
263 {
264 nativeBuildInputs = [ makeWrapper ];
265
266 passthru = {
267 inherit julia;
268 inherit juliaWrapped;
269 inherit (julia) pname version meta;
270
271 # Expose the steps we used along the way in case the user wants to use them, for example to build
272 # expressions and build them separately to avoid IFD.
273 inherit dependencies;
274 inherit closureYaml;
275 inherit dependencyUuidToInfoYaml;
276 inherit dependencyUuidToRepoYaml;
277 inherit minimalRegistry;
278 inherit artifactsNix;
279 inherit overridesJson;
280 inherit overridesToml;
281 inherit projectAndDepot;
282 };
283 }
284 (
285 ''
286 mkdir -p $out/bin
287 makeWrapper ${juliaWrapped}/bin/julia $out/bin/julia \
288 --suffix JULIA_DEPOT_PATH : "${projectAndDepot}/depot" \
289 --set-default JULIA_PROJECT "${projectAndDepot}/project" \
290 --set-default JULIA_LOAD_PATH '@:${projectAndDepot}/project/Project.toml:@v#.#:@stdlib'
291 ''
292 + lib.optionalString setDefaultDepot ''
293 sed -i '2 i\JULIA_DEPOT_PATH=''${JULIA_DEPOT_PATH-"$HOME/.julia"}' $out/bin/julia
294 ''
295 )