LTB4YNHF75FTVQG6S5PL46CGS4CMDWZRAEXWEIXUHQHIWVYVKFKAC ("mkdir -p $DESTDIR; tar -xf " ^ List.hd zipped.destdir ^ " -C $DESTDIR")
("mkdir -p $DESTDIR; tar -xf " ^ List.hd zipped.destdir^ " -C $DESTDIR; cd $DESTDIR/*; echo -n \\{\\\"files\\\":\\{ \>.cargo-checksum.json\n\n=0\n\for f in $(find . -type f -printf '%P\\n'); do\n\if [[ $n -gt 0 ]]; then\n\echo -n , >>.cargo-checksum.json\n\fi\n\echo -n \\\"$f\\\":\\\"$(sha256sum $f | cut -d\" \" -f 1)\\\" >> \.cargo-checksum.json;\n\n=$((n+1))\n\done\n\echo -n \\},\\\"package\\\":\\\"" ^ hash^ "\\\"\\} >> .cargo-checksum.json")
let packages toml =
(* Parse the Cargo.lock file, returning a hash table of all packagesthat have a `source` field, i.e. packages that come from aregistry. *)let parse_cargo_lock destdir =let lock = Stdlib.open_in (Filename.concat destdir "Cargo.lock") inlet toml =match Toml.Parser.from_channel lock with| `Ok toml -> toml| `Error (err, _) -> failwith ("Error: " ^ err)in
let metadata rust_version cargo rustc platform src n_packages packages =
(* Run `cargo metadata` in a derivation. This derivation doesn'tproduce anything and only forwards the stdandard output of `cargometadata`. *)class metadata rust_version cargo rustc platform src n_packages packages =
let compile_crate rust_version rustc platform package path deps features =let target_platform = "x86_64-unknown-linux-gnu" in
let underscorize = String.map (fun c -> if c = '-' then '_' else c)type deps = { build_dependencies : string; dependencies : string }(* A derivation building a crate, created from the crate's resolvedparameters. *)class compiled_crate rust_version rustc cc platform package path deps features =
method! build_phase =let platform =match platform with Some s -> " --filter-platform " ^ s | None -> ""inlet features =String.concat ", " (List.map (fun x -> "\"" ^ x ^ "\"") features)
(* Rustc has the option of generating extra filenames todisambiguate things. We keep track of these in the `hash`parameter of built derivations. *)val hash =let id = package |> member "id" |> to_string inlet f =List.fold_left(fun acc x -> acc ^ " --cfg 'feature=\"" ^ x ^ "\"'")"" features
let setup = ref "set -x\nrustc --print sysroot\n" inlet dependencies = "" inlet compile_target target kind =let src_path = target |> member "src_path" |> to_string inlet name = target |> member "name" |> to_string inlet edition =try " --edition=" ^ (target |> member "edition" |> to_string) ^ " "with Not_found -> (try " --edition=" ^ (package |> member "edition" |> to_string) ^ " "with Not_found -> " ")in
method hash = hash(* If this src_path comes from a vendored directory (i.e. if it'sa dependency), remove the "vendor" prefix. *)method private strip_src_path src_path =let prefix = "/src/vendor/" ^ self#name ^ "-" ^ self#version ^ "/" inif String.starts_with ~prefix src_path thenString.sub src_path (String.length prefix)(String.length src_path - String.length prefix)elselet prefix_ = "/src/vendor/" ^ self#name ^ "/" inif String.starts_with ~prefix:prefix_ src_path thenString.sub src_path (String.length prefix_)(String.length src_path - String.length prefix_)else src_path(* Concatenation of `--cfg feature=…`. *)val features_args =List.fold_left(fun acc x -> acc ^ " --cfg 'feature=\"" ^ x ^ "\"'")"" features
method private compile_target setup platform target kind dependencies out =let initial_src_path = target |> member "src_path" |> to_string inlet src_path = self#strip_src_path initial_src_path inlet name = target |> member "name" |> to_string inlet under = underscorize name inlet edition =try " --edition=" ^ (target |> member "edition" |> to_string) ^ " "with Not_found -> (try " --edition=" ^ (package |> member "edition" |> to_string) ^ " "with Not_found -> " ")inlet platform =match platform with Some p -> " --target " ^ p | None -> ""inif kind = "bin" then
!setup ^ "rustc --crate-name " ^ name ^ edition ^ src_path^ " --crate-type " ^ kind^ " --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 \--cfg 'feature=\"cargo-build \"' --cfg 'feature=\"default\"' \--check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values("^ features^ "))' -C metadata=db5f6b051938318f -C \extra-filename=-99d0a40c2aab0586 --out-dir $DESTDIR/lib "^ dependencies ^ " --cap-lints allow\n"
!setup ^ "rustc --crate-name " ^ under ^ edition ^ src_path ^ platform^ " --crate-type bin -C linker=gcc" ^ features_args ^ " -C metadata="^ hash ^ " --out-dir " ^ out ^ dependencies ^ " --cap-lints allow\n"elsesetup :=!setup ^ "rustc --crate-name " ^ under ^ edition ^ src_path^ " --crate-type " ^ kind ^ platform^ " --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2"^ features_args ^ " -C metadata=" ^ hash ^ " --out-dir " ^ out^ " -C extra-filename=-" ^ hash ^ dependencies^ " --cap-lints allow\n";under(* The `dependencies` method below computes the build and regulardependencies in one go, caching them in the`computed_dependencies` value. *)val computed_dependencies = ref Nonemethod private dependencies =match !computed_dependencies with| Some d -> Lwt.return d| None ->let package_deps =let d = package |> member "dependencies" |> to_list inlet h = Hashtbl.create (List.length d) inList.iter(fun d -> Hashtbl.add h (d |> member "name" |> to_string) d)d;hinlet de = ref "" inlet build_de = ref "" inlet* deps =Lwt_list.map_p(fun x ->let* b = x#build inLwt.return (x#name, x#hash, b))depsinList.iter(fun (x_name, x_hash, b) ->let d = Hashtbl.find package_deps x_name inlet is_build =d |> member "kind" |> to_option to_string = Some "build"inList.iter self#add_path b.destdir;let name =match d |> member "rename" |> to_option to_string with| Some rename -> rename| None -> x_nameinlet r = if is_build then build_de else de inr :=!r ^ " -L dependency=target/deps --extern " ^ name ^ "="^ List.hd b.destdir ^ "/lib/lib" ^ x_name ^ "-" ^ x_hash^ ".rlib")deps;let result = { build_dependencies = !build_de; dependencies = !de } incomputed_dependencies := Some result;Lwt.return resultmethod! build_inputs = Lwt.return [ ubuntu "coreutils"; cc ](* Run the build script, if any. Also `cd` to the correctdirectory. *)method! configure_phase =let setup =ref ("set -x\nmkdir -p target/build-" ^ hash ^ "\nexport RUSTC=rustc\n")inlet has_source =trylet _ = package |> member "source" |> to_string intruewith Not_found | Yojson.Basic.Util.Type_error _ -> falseinlet* d = self#dependencies in(* The following fold does two things in one pass: *)let _, build_script =List.fold_left(fun (is_first_target, build_script) target ->if is_first_target && has_source thensetup := !setup ^ "cd " ^ self#name ^ "-" ^ self#version ^ "\n"else ();(* The other task is to add the build script if there isone, and return its name. *)( false,List.fold_left(fun has_it kind ->match kind with| "custom-build" ->Some(self#compile_target setup None target "bin"d.build_dependencies ("target/build-" ^ hash))| _ -> has_it)build_script(target |> member "kind" |> to_list |> filter_string) ))(true, None)(package |> member "targets" |> to_list)in(* If there is a build script, call it. *)let _ =match build_script with| Some bs_name ->setup := !setup ^ "target/build-" ^ hash ^ "/" ^ bs_name ^ "\n"| None -> ()
let lock =Stdlib.open_in (Filename.concat (List.hd src_built.destdir) "Cargo.lock")inlet parsed =match Toml.Parser.from_channel lock with| `Ok toml -> toml| `Error (err, _) -> failwith ("Error: " ^ err)inlet* packages_drv, packages = packages parsed in
let* packages_drv, packages = parse_cargo_lock (List.hd src_built.destdir) in
let c =match !backend_conn with None -> failwith "no conn" | Some c -> cinlet* index =Lwt_list.map_p(fun repository ->let* res = ubuntu_release c ~release ~arch:Amd64 ~repository inlet res, _ = Result.get_ok res inmatch res with| `Ok r -> Lwt.return r.destdir| `Error e -> failwith e| _ -> assert false)[ "main"; "universe" ]inlet index = List.concat index inlet* res = ubuntu_package c ~index ~name inlet res, _ = Result.get_ok res inmatch res with| `Ok r -> Lwt.return { destdir = r.destdir; paths = r.paths }| `Error e -> failwith e| _ -> assert false
match !cached_build with| Some x -> Lwt.return x| None ->Lwt_mutex.with_lock build_lock (fun () ->let c =match !backend_conn with| None -> failwith "no conn"| Some c -> cinlet* index =Lwt_list.map_p(fun repository ->let arch =match arch with| Amd64 -> Elpegrpc.Elpe.Arch.Amd64| Aarch64 -> Elpegrpc.Elpe.Arch.Aarch64inlet* res = ubuntu_release c ~release ~arch ~repository inlet res, _ = Result.get_ok res inmatch res with| `Ok r -> Lwt.return r.destdir| `Error e -> raise (DerivationError e)| _ -> assert false)[ "main"; "universe" ]inlet index = List.concat index inlet* res = ubuntu_package c ~index ~name inlet r = Result.get_ok res inlet x = { destdir = r.destdir; paths = r.paths } incached_build := Some x;Lwt.return x)
let* all = Lwt.all [ self#pre_unpack; self#post_unpack ] inmatch all with| pre :: post :: _ ->Lwt.return(pre ^ "\ncp -R " ^ List.hd src_built.destdir ^ "/. .\n" ^ post)| _ -> assert false
Lwt.return(pre_unpack ^ "\ncp -R " ^ List.hd src_built.destdir ^ "/. .\n"^ post_unpack)
let* all = Lwt.all [ self#pre_configure; self#post_configure ] inmatch all with| pre :: post :: _ ->Lwt.return(pre ^ "\nif [[ -e configure ]]; then ./configure; fi\n" ^ post)| _ -> assert false
Lwt.return(pre_configure ^ "\nif [[ -e configure ]]; then ./configure; fi\n"^ post_configure)
let* all = Lwt.all [ self#pre_build; self#post_build ] inmatch all with| pre :: post :: _ ->Lwt.return (pre ^ "\nif [[ -e Makefile ]]; then make; fi\n" ^ post)| _ -> assert false
Lwt.return(pre_build ^ "\nif [[ -e Makefile ]]; then make; fi\n" ^ post_build)
let* all = Lwt.all [ self#pre_install; self#post_install ] inmatch all with| pre :: post :: _ ->Lwt.return(pre ^ "\nif [[ -e Makefile ]]; then make install; fi\n" ^ post)| _ -> assert false
Lwt.return(pre_install ^ "\nif [[ -e Makefile ]]; then make install; fi\n"^ post_install)
match !cached_build with| Some cached -> Lwt.return cached| None -> (let* phases =Lwt.all[self#setup;self#unpack_phase;self#configure_phase;self#build_phase;self#install_phase;]inlet builder = String.concat "\n" phases inlet c =match !backend_conn with None -> failwith "no conn" | Some c -> cinlet* output_hash = self#output_hash inlet* r =derivation c ~name:self#name ~builder ~paths:!extra_paths~stdout:!(self#stdout) ~stderr:!(self#stderr) ~target:self#target~output_hashinmatch r with| `Ok r ->let c = { destdir = r.destdir; paths = r.paths } incached_build := Some c;Lwt.return c| `Error e -> failwith e| _ -> assert false)
Lwt_mutex.with_lock build_lock (fun () ->match !cached_build with| Some cached -> Lwt.return cached| None -> (let* setup = self#setup inlet* unpack_phase = self#unpack_phase inlet* configure_phase = self#configure_phase inlet* build_phase = self#build_phase inlet* install_phase = self#install_phase inlet phases =[setup;unpack_phase;configure_phase;build_phase;install_phase;]inlet builder = String.concat "\n" phases inlet c =match !backend_conn with| None -> failwith "no conn"| Some c -> cinlet* output_hash = self#output_hash inlet* r =derivation c ~name:self#name ~builder ~paths:!extra_paths~stdout:!(self#stdout) ~stderr:!(self#stderr)~target:self#target ~output_hashinmatch r with| `Ok r ->let c = { destdir = r.destdir; paths = r.paths } incached_build := Some c;Lwt.return c| `Error e -> failwith e| _ -> assert false))
let unzip pkg =object (self)inherit std_derivationmethod name = "rust"method! unpack_phase = Lwt.return ""method! build_inputs =Lwt.return[(ubuntu "libc6-dev" :> derivation);(ubuntu "coreutils" :> derivation);(ubuntu "tar" :> derivation);(ubuntu "gzip" :> derivation);]method! build_phase =let* zipped = self#derivation pkg inLwt.return("mkdir -p $DESTDIR; tar -xf " ^ List.hd zipped.destdir ^ " -C $DESTDIR")end