at 24.11-pre 3.9 kB view raw
1 2import json 3from pathlib import Path 4import multiprocessing 5import subprocess 6import sys 7import toml 8from urllib.parse import urlparse 9import yaml 10 11import dag 12 13# This should match the behavior of the default unpackPhase. 14# See https://github.com/NixOS/nixpkgs/blob/59fa082abdbf462515facc8800d517f5728c909d/pkgs/stdenv/generic/setup.sh#L1044 15archive_extensions = [ 16 # xz extensions 17 ".tar.xz", 18 ".tar.lzma", 19 ".txz", 20 21 # *.tar or *.tar.* 22 ".tar", 23 ".tar.Z", 24 ".tar.bz2", 25 ".tar.gz", 26 27 # Other tar extensions 28 ".tgz", 29 ".tbz2", 30 ".tbz", 31 32 ".zip" 33 ] 34 35dependencies_path = Path(sys.argv[1]) 36closure_yaml_path = Path(sys.argv[2]) 37julia_path = Path(sys.argv[3]) 38extract_artifacts_script = Path(sys.argv[4]) 39extra_libs = json.loads(sys.argv[5]) 40out_path = Path(sys.argv[6]) 41 42with open(dependencies_path, "r") as f: 43 dependencies = yaml.safe_load(f) 44 dependency_uuids = dependencies.keys() 45 46with open(closure_yaml_path, "r") as f: 47 # Build up a map of UUID -> closure information 48 closure_yaml_list = yaml.safe_load(f) or [] 49 closure_yaml = {} 50 for item in closure_yaml_list: 51 closure_yaml[item["uuid"]] = item 52 53 # Build up a dependency graph of UUIDs 54 closure_dependencies_dag = dag.DAG() 55 for uuid, contents in closure_yaml.items(): 56 if contents.get("depends_on"): 57 closure_dependencies_dag.add_node(uuid, dependencies=contents["depends_on"].values()) 58 59def get_archive_derivation(uuid, artifact_name, url, sha256): 60 depends_on = set() 61 if closure_dependencies_dag.has_node(uuid): 62 depends_on = set(closure_dependencies_dag.get_dependencies(uuid)).intersection(dependency_uuids) 63 64 other_libs = extra_libs.get(uuid, []) 65 66 fixup = f"""fixupPhase = let 67 libs = lib.concatMap (lib.mapAttrsToList (k: v: v.path)) 68 [{" ".join(["uuid-" + x for x in depends_on])}]; 69 in '' 70 find $out -type f -executable -exec \ 71 patchelf --set-rpath \$ORIGIN:\$ORIGIN/../lib:${{lib.makeLibraryPath (["$out" glibc] ++ libs ++ (with pkgs; [{" ".join(other_libs)}]))}} {{}} \; 72 find $out -type f -executable -exec \ 73 patchelf --set-interpreter ${{glibc}}/lib/ld-linux-x86-64.so.2 {{}} \; 74 ''""" 75 76 return f"""stdenv.mkDerivation {{ 77 name = "{artifact_name}"; 78 src = fetchurl {{ 79 url = "{url}"; 80 sha256 = "{sha256}"; 81 }}; 82 preUnpack = '' 83 mkdir unpacked 84 cd unpacked 85 ''; 86 sourceRoot = "."; 87 dontConfigure = true; 88 dontBuild = true; 89 installPhase = "cp -r . $out"; 90 {fixup}; 91 }}""" 92 93def get_plain_derivation(url, sha256): 94 return f"""fetchurl {{ 95 url = "{url}"; 96 sha256 = "{sha256}"; 97 }}""" 98 99with open(out_path, "w") as f: 100 f.write("{ lib, fetchurl, glibc, pkgs, stdenv }:\n\n") 101 f.write("rec {\n") 102 103 def process_item(item): 104 uuid, src = item 105 lines = [] 106 artifacts = toml.loads(subprocess.check_output([julia_path, extract_artifacts_script, uuid, src]).decode()) 107 if not artifacts: return f' uuid-{uuid} = {{}};\n' 108 109 lines.append(f' uuid-{uuid} = {{') 110 111 for artifact_name, details in artifacts.items(): 112 if len(details["download"]) == 0: continue 113 download = details["download"][0] 114 url = download["url"] 115 sha256 = download["sha256"] 116 117 git_tree_sha1 = details["git-tree-sha1"] 118 119 parsed_url = urlparse(url) 120 if any(parsed_url.path.endswith(x) for x in archive_extensions): 121 derivation = get_archive_derivation(uuid, artifact_name, url, sha256) 122 else: 123 derivation = get_plain_derivation(url, sha256) 124 125 lines.append(f""" "{artifact_name}" = {{ 126 sha1 = "{git_tree_sha1}"; 127 path = {derivation}; 128 }};\n""") 129 130 lines.append(' };\n') 131 132 return "\n".join(lines) 133 134 with multiprocessing.Pool(10) as pool: 135 for s in pool.map(process_item, dependencies.items()): 136 f.write(s) 137 138 f.write(f""" 139}}\n""")