+ open Derivation
+ open Lwt.Syntax
+
+ let fetch_crate source checksum crate version =
+ let registry_dl =
+ if source = "registry+https://github.com/rust-lang/crates.io-index" then
+ "https://crates.io/api/v1/crates"
+ else failwith "Not implemented"
+ in
+ http
+ ~url:(registry_dl ^ "/" ^ crate ^ "/" ^ version ^ "/download")
+ ~hash_algorithm:Elpegrpc.Elpe.Hash.Sha256
+ ~hash:(Hex.to_bytes (`Hex checksum))
+
+ let str_from_toml_table k toml =
+ match Toml.Types.Table.find (Toml.Types.Table.Key.of_string k) toml with
+ | Toml.Types.TString s -> s
+ | _ -> raise Not_found
+
+ let unzip pkg =
+ object (self)
+ inherit std_derivation
+ method 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 in
+ Lwt.return
+ ("mkdir -p $DESTDIR; tar -xf " ^ List.hd zipped.destdir ^ " -C $DESTDIR")
+ end
+
+ let rust ?(version = "1.84") src =
+ object (self)
+ inherit std_derivation
+ method name = "rust"
+ method! src = Lwt.return src
+ method! build_inputs = Lwt.return [ (ubuntu "coreutils" :> derivation) ]
+
+ method packages toml =
+ let packages =
+ match
+ Toml.Types.Table.find (Toml.Types.Table.Key.of_string "package") toml
+ with
+ | Toml.Types.TArray (Toml.Types.NodeTable arr) -> arr
+ | _ -> failwith "Unexpected type"
+ in
+
+ let* packages =
+ Lwt.all
+ (List.map
+ (fun pkg ->
+ try
+ let source = str_from_toml_table "source" pkg in
+ let checksum = str_from_toml_table "checksum" pkg in
+ let name = str_from_toml_table "name" pkg in
+ let version = str_from_toml_table "version" pkg in
+ let h = fetch_crate source checksum name version in
+ let* drv = self#derivation (unzip h :> derivation) in
+ Lwt.return (Some (name, version, h, drv))
+ with Not_found -> Lwt.return None)
+ packages)
+ in
+ let h = Hashtbl.create 16 in
+ Lwt.return
+ (List.fold_left
+ (fun acc x ->
+ match x with
+ | Some (crate_name, version, _, drv) ->
+ let target =
+ if Hashtbl.find_opt h crate_name = None then
+ let _ = Hashtbl.add h crate_name () in
+ crate_name ^ "-" ^ version
+ else crate_name
+ in
+ acc ^ "ln -s " ^ List.hd drv.destdir ^ "/" ^ crate_name ^ "-"
+ ^ version ^ " vendor/" ^ target ^ "\n"
+ | None -> acc)
+ "" packages)
+
+ method! build_phase =
+ let* src = self#src in
+ let* src_built = src#build in
+ let lock =
+ Stdlib.open_in
+ (Filename.concat (List.hd src_built.destdir) "Cargo.lock")
+ in
+ let parsed =
+ match Toml.Parser.from_channel lock with
+ | `Ok toml -> toml
+ | `Error (err, _) -> failwith ("Error: " ^ err)
+ in
+ let* packages = self#packages parsed in
+ let metadata =
+ object (self)
+ inherit std_derivation
+ method name = "test"
+ method! src = Lwt.return src
+
+ method! build_phase =
+ let* rustc = self#derivation (ubuntu ("rustc-" ^ version)) in
+ let rustc = List.hd rustc.destdir in
+ let* cargo = self#derivation (ubuntu ("cargo-" ^ version)) in
+ let cargo = List.hd cargo.destdir in
+ let setup =
+ "export HOME=/home/me\nmkdir -p $HOME\nexport PATH=" ^ rustc
+ ^ "/usr/lib/rust-" ^ version ^ "/bin:" ^ cargo ^ "/usr/lib/rust-"
+ ^ version ^ "/bin:$PATH\nmkdir -p vendor .cargo\n" ^ packages
+ ^ "\n\
+ cat <<EOF >> .cargo/config.toml\n\
+ [source.crates-io]\n\
+ replace-with = \"vendored-sources\"\n\n\
+ [source.vendored-sources]\n\
+ directory = \"vendor\"\n\
+ EOF\n\
+ cargo metadata --offline --format-version 1"
+ in
+ Lwt.return setup
+
+ method! build_inputs =
+ Lwt.return [ (ubuntu "coreutils" :> derivation) ]
+ end
+ in
+
+ let buf = metadata#set_stdout in
+ let* _ = metadata#build in
+ let meta_json = Yojson.Basic.from_string (Buffer.contents buf) in
+ let open Yojson.Basic.Util in
+ let members =
+ meta_json |> member "workspace_members" |> to_list |> filter_string
+ in
+ let _ = List.map (fun x -> print_endline x) members in
+
+ Lwt.return ""
+ end