summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/input_foreman.ml234
-rw-r--r--lib/prefetch.ml164
2 files changed, 198 insertions, 200 deletions
diff --git a/lib/input_foreman.ml b/lib/input_foreman.ml
index 4b8b3f1..f30fd12 100644
--- a/lib/input_foreman.ml
+++ b/lib/input_foreman.ml
@@ -253,169 +253,41 @@ let prefetch ~env ~proc_mgr ~name () : (unit, error) result =
let open Input in
let (let*) = Result.bind in
let* input = get name in
- let hash_algo_type_val = Input.Hash.algorithm_to_string_lower input.hash.algorithm in
- let proc_env =
- let unix_env = Unix.environment () in
- Array.append unix_env [|"NIX_HASH_ALGO=" ^ hash_algo_type_val|]
- in
- let run_and_gather ?(buffer_size = 1024) method' cmd =
- let stdout_buf = Buffer.create buffer_size
- and stderr_buf = Buffer.create buffer_size
- in
- let stdout_sink = Eio.Flow.buffer_sink stdout_buf
- and stderr_sink = Eio.Flow.buffer_sink stderr_buf
- in
- let* () =
- try
- Eio.Process.run proc_mgr ~env: proc_env ~stdout: stdout_sink ~stderr: stderr_sink cmd;
- Ok ()
- with
- | exn ->
- Error (`Run_exception (method', exn, String.trim (Buffer.contents stdout_buf)))
- in
- Ok (String.trim (Buffer.contents stdout_buf))
- in
- let models = Input.jg_models2 input in
- let prefetch_file (f : File.t) : (Input.t * string, Error.prefetch_error) result =
- let method' = `URL
- and url = Uri.of_string (Input.Template.fill f.url ~models)
- in
- let cmd = [
- "nix-prefetch-url";
- Uri.to_string url;
- "--print-path";
- "--type";
- hash_algo_type_val;
- ]
- in
- Logs.debug (fun m -> m "Running file cmd: %a" (Fmt.list ~sep: Fmt.sp Fmt.string) cmd);
- match run_and_gather method' cmd with
- | Ok "" ->
- Error (`Empty_output method')
- | Ok stdout ->
- begin
- Logs.debug (fun m -> m "Command output: %s" stdout);
- match Prefetch.File.of_stdout ~env stdout with
- | None -> Error (`Bad_output (method', stdout))
- | Some {path; hash_value} ->
- Ok (
- {input with hash = {input.hash with value = Some hash_value}},
- path
- )
- end
- | Error err -> Error err
-
- and prefetch_archive (a : Archive.t) : (Input.t * string, Error.prefetch_error) result =
- let method' = `URL
- and url = Uri.of_string (Input.Template.fill a.url ~models)
- in
- let cmd = [
- "nix-prefetch-url";
- Uri.to_string url;
- "--print-path";
- "--unpack";
- "--type";
- hash_algo_type_val;
- ]
- in
- Logs.debug (fun m -> m "Running archive cmd: %a" (Fmt.list ~sep: Fmt.sp Fmt.string) cmd);
- match run_and_gather method' cmd with
- | Ok "" ->
- Error (`Empty_output method')
- | Ok stdout ->
- begin
- Logs.debug (fun m -> m "Command output: %s" stdout);
- match Prefetch.Archive.of_stdout ~env stdout with
- | None -> Error (`Bad_output (method', stdout))
- | Some {path; hash_value} ->
- Ok (
- {input with hash = {input.hash with value = Some hash_value}},
- path
- )
- end
- | Error err -> Error err
-
- and prefetch_git (g : Git.t) : (Input.t * string, Error.prefetch_error) result =
- let method' = `Git
- and repository = Uri.of_string (Input.Template.fill g.repository ~models)
- in
- let cmd = [
- "nix-prefetch-git";
- "--no-deepClone";
- "--quiet";
- "--url";
- Uri.to_string repository;
- ]
- in
- let cmd =
- List.concat [
- cmd;
- (
- match g.reference with
- | `Branch b -> ["--branch-name"; b]
- | `Ref r -> ["--rev"; r]
- );
- if g.submodules then ["--fetch-submodules"] else [];
- if g.lfs then ["--fetch-lfs"] else [];
- ];
- in
- Logs.debug (fun m -> m "Running Git cmd: %a" (Fmt.list ~sep: Fmt.sp Fmt.string) cmd);
- match run_and_gather method' cmd with
- | Ok "" ->
- Error (`Empty_output method')
- | Ok stdout ->
- begin
- Logs.debug (fun m -> m "Command output: %s" stdout);
- let* data =
- Jsont_bytesrw.decode_string Prefetch.Git.jsont stdout
- |> Result.map_error (fun err -> `JSON_parsing (method', err))
- in
+ let* (new_input, new_silo_link) : Input.t * string =
+ Result.map_error (fun err -> `Prefetch (input.name, err)) @@ begin
+ let* latest_result = Prefetch.get_latest ~env ~proc_mgr input in
+ match input.kind, latest_result with
+ | `File _, `File f_data ->
+ Ok (
+ {input with hash = {input.hash with value = Some f_data.hash_value}},
+ f_data.path
+ )
+ | `Archive _, `Archive a_data ->
+ Ok (
+ {input with hash = {input.hash with value = Some a_data.hash_value}},
+ a_data.path
+ )
+ | `Git g, `Git g_data ->
Ok (
{input with
kind =
`Git {g with
- latest_revision = Some data.rev;
- datetime = data.datetime;
+ latest_revision = Some g_data.rev;
+ datetime = g_data.datetime;
};
hash = {input.hash with
- algorithm = data.hash.algorithm;
- value = Some data.hash.value;
+ algorithm = g_data.hash.algorithm;
+ value = Some g_data.hash.value;
};
},
- data.path
+ g_data.path
)
- end
- | Error err -> Error err
-
- and prefetch_darcs (d : Darcs.t) : (Input.t * string, Error.prefetch_error) result =
- let method' = `Darcs
- and repository = Input.Template.fill d.repository ~models
- in
- let cmd = ["nix-prefetch-darcs"] in
- (* formatter looks ugly so doing cmd = cmd @ […] *)
- let cmd =
- match d.reference with
- | `Context (`Assumed _) -> cmd
- | `Context (`Stated sc) -> cmd @ ["--context"; sc]
- | `Tag t -> cmd @ ["--tag"; t]
- in
- let cmd = cmd @ [repository] in
- Logs.debug (fun m -> m "Running Darcs cmd: %a" (Fmt.list ~sep: Fmt.sp Fmt.string) cmd);
- match run_and_gather method' cmd with
- | Ok "" ->
- Error (`Empty_output method')
- | Ok stdout ->
- begin
- Logs.debug (fun m -> m "Command output: %s" stdout);
- let* data =
- Jsont_bytesrw.decode_string Prefetch.Darcs.jsont stdout
- |> Result.map_error (fun err -> `JSON_parsing (method', err))
- in
+ | `Darcs d, `Darcs d_data ->
let* reference =
match d.reference with
| `Context (`Assumed _) ->
let* new_ctx =
- cp_darcs_context ~env ~name ~context: data.context
+ cp_darcs_context ~env ~name ~context: d_data.context
|> Result.map_error (fun err -> `Darcs_context err)
in
Ok (`Context (`Assumed (Some new_ctx)))
@@ -427,70 +299,32 @@ let prefetch ~env ~proc_mgr ~name () : (unit, error) result =
kind =
`Darcs {d with
reference;
- datetime = data.datetime;
- latest_weak_hash = Some data.weak_hash;
+ datetime = d_data.datetime;
+ latest_weak_hash = Some d_data.weak_hash;
};
hash = {input.hash with
- algorithm = data.hash.algorithm;
- value = Some data.hash.value;
+ algorithm = d_data.hash.algorithm;
+ value = Some d_data.hash.value;
};
},
- data.path
+ d_data.path
)
- end
- | Error err -> Error err
-
- and prefetch_pijul (p : Pijul.t) : (Input.t * string, Error.prefetch_error) result =
- let method' = `Pijul
- and cmd = [
- "nix-prefetch-pijul";
- "--remote";
- Input.Template.fill p.remote ~models;
- ]
- in
- let cmd =
- cmd @
- match p.reference with
- | `Change c -> ["--change"; c]
- | `Channel c -> ["--channel"; c]
- | `State s -> ["--state"; s]
- in
- Logs.debug (fun m -> m "Running Pijul cmd: %a" (Fmt.list ~sep: Fmt.sp Fmt.string) cmd);
- match run_and_gather method' cmd with
- | Ok "" ->
- Error (`Empty_output method')
- | Ok stdout ->
- begin
- Logs.debug (fun m -> m "Command output: %s" stdout);
- let* data =
- Jsont_bytesrw.decode_string Prefetch.Pijul.jsont stdout
- |> Result.map_error (fun err -> `JSON_parsing (method', err))
- in
+ | `Pijul p, `Pijul p_data ->
Ok (
{input with
kind =
`Pijul {p with
- datetime = data.datetime;
- latest_state = Some data.state;
+ datetime = p_data.datetime;
+ latest_state = Some p_data.state;
};
hash = {input.hash with
- algorithm = data.hash.algorithm;
- value = Some data.hash.value;
+ algorithm = p_data.hash.algorithm;
+ value = Some p_data.hash.value;
};
},
- data.path
+ p_data.path
)
- end
- | Error err -> Error err
- in
- let* (new_input, new_silo_link) : Input.t * string =
- Result.map_error (fun err -> `Prefetch (input.name, err)) @@ begin
- match input.kind with
- | `File f -> prefetch_file f
- | `Archive a -> prefetch_archive a
- | `Git g -> prefetch_git g
- | `Darcs d -> prefetch_darcs d
- | `Pijul p -> prefetch_pijul p
+ | _, _ -> failwith "Prefetch kind mismatch"
end
in
Logs.app (fun m -> m "Prefetched %a." Name.pp input.name);
diff --git a/lib/prefetch.ml b/lib/prefetch.ml
index c4685b8..f4923f5 100644
--- a/lib/prefetch.ml
+++ b/lib/prefetch.ml
@@ -2,6 +2,31 @@
│ SPDX-FileCopyrightText: 2025 toastal <https://toast.al/contact/> │
│ SPDX-License-Identifier: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception │
└─────────────────────────────────────────────────────────────────────────────*)
+type error = Error.prefetch_error
+
+let run_and_gather ~proc_mgr ~(proc_env : string array) ?(buffer_size = 1024) method' cmd : (string, error) result =
+ Logs.debug (fun m -> m "Running %a cmd: %a" Error.pp_prefetch_method method' (Fmt.list ~sep: Fmt.sp Fmt.string) cmd);
+ let (let*) = Result.bind in
+ let stdout_buf = Buffer.create buffer_size
+ and stderr_buf = Buffer.create buffer_size
+ in
+ let stdout_sink = Eio.Flow.buffer_sink stdout_buf
+ and stderr_sink = Eio.Flow.buffer_sink stderr_buf
+ in
+ let* () =
+ try
+ Eio.Process.run proc_mgr ~env: proc_env ~stdout: stdout_sink ~stderr: stderr_sink cmd;
+ Ok ()
+ with
+ | exn ->
+ Error (`Run_exception (method', exn, String.trim (Buffer.contents stdout_buf)))
+ in
+ match String.trim (Buffer.contents stdout_buf) with
+ | "" -> Error (`Empty_output method')
+ | stdout ->
+ Logs.debug (fun m -> m "Command %a output: %s" Error.pp_prefetch_method method' stdout);
+ Ok stdout
+
module Hash = struct
type t = {
algorithm: Input.Hash.algorithm;
@@ -42,6 +67,24 @@ module File = struct
Some {path; hash_value}
| _ ->
None
+
+ let latest_cmd (f : Input.File.t) ~(hash_algo : string) ~models =
+ let url = URI.of_string (Input.Template.fill f.url ~models) in
+ [
+ "nix-prefetch-url";
+ URI.to_string url;
+ "--print-path";
+ "--type";
+ hash_algo;
+ ]
+
+ let get_latest ~env ~proc_mgr ~proc_env (f : Input.File.t) ~(hash_algo : string) ~models =
+ let (let*) = Result.bind in
+ let method' = `URL in
+ let* stdout = run_and_gather ~proc_mgr ~proc_env method' (latest_cmd f ~hash_algo ~models) in
+ match of_stdout ~env stdout with
+ | None -> Error (`Bad_output (method', stdout))
+ | Some t -> Ok t
end
module Archive = struct
@@ -59,6 +102,25 @@ module Archive = struct
Some {path; hash_value}
| _ ->
None
+
+ let latest_cmd (a : Input.Archive.t) ~(hash_algo : string) ~models =
+ let url = URI.of_string (Input.Template.fill a.url ~models) in
+ [
+ "nix-prefetch-url";
+ URI.to_string url;
+ "--print-path";
+ "--unpack";
+ "--type";
+ hash_algo;
+ ]
+
+ let get_latest ~env ~proc_mgr ~proc_env (a : Input.Archive.t) ~(hash_algo : string) ~models =
+ let (let*) = Result.bind in
+ let method' = `URL in
+ let* stdout = run_and_gather ~proc_mgr ~proc_env method' (latest_cmd a ~hash_algo ~models) in
+ match of_stdout ~env stdout with
+ | None -> Error (`Bad_output (method', stdout))
+ | Some t -> Ok t
end
module Git = struct
@@ -83,6 +145,33 @@ module Git = struct
|> Object.mem "rev" string ~enc: (fun i -> i.rev)
|> Hash.add_jsont_case
|> Object.finish
+
+ let latest_cmd (g : Input.Git.t) ~models =
+ let cmd = [
+ "nix-prefetch-git";
+ "--no-deepClone";
+ "--quiet";
+ "--url";
+ URI.to_string (URI.of_string (Input.Template.fill g.repository ~models));
+ ]
+ in
+ List.concat [
+ cmd;
+ (
+ match g.reference with
+ | `Branch b -> ["--branch-name"; b]
+ | `Ref r -> ["--rev"; r]
+ );
+ if g.submodules then ["--fetch-submodules"] else [];
+ if g.lfs then ["--fetch-lfs"] else [];
+ ]
+
+ let get_latest ~proc_mgr ~proc_env (g : Input.Git.t) ~models =
+ let (let*) = Result.bind in
+ let method' = `Git in
+ let* stdout = run_and_gather ~proc_mgr ~proc_env method' (latest_cmd g ~models) in
+ Jsont_bytesrw.decode_string jsont stdout
+ |> Result.map_error (fun err -> `JSON_parsing (method', err))
end
module Darcs = struct
@@ -109,6 +198,26 @@ module Darcs = struct
|> Object.mem "weak-hash" string ~enc: (fun i -> i.weak_hash)
|> Hash.add_jsont_case
|> Object.finish
+
+ let latest_cmd (d : Input.Darcs.t) ~models =
+ (* formatter looks ugly so doing cmd = cmd @ […] *)
+ let cmd = ["nix-prefetch-darcs"] in
+ let cmd =
+ match d.reference with
+ | `Context (`Assumed _) -> cmd
+ | `Context (`Stated sc) -> cmd @ ["--context"; sc]
+ | `Tag t -> cmd @ ["--tag"; t]
+ in
+ cmd @ [
+ URI.to_string (URI.of_string (Input.Template.fill d.repository ~models));
+ ]
+
+ let get_latest ~proc_mgr ~proc_env (d : Input.Darcs.t) ~models =
+ let (let*) = Result.bind in
+ let method' = `Darcs in
+ let* stdout = run_and_gather ~proc_mgr ~proc_env method' (latest_cmd d ~models) in
+ Jsont_bytesrw.decode_string jsont stdout
+ |> Result.map_error (fun err -> `JSON_parsing (method', err))
end
module Pijul = struct
@@ -133,4 +242,59 @@ module Pijul = struct
|> Object.mem "state" string ~enc: (fun i -> i.state)
|> Hash.add_jsont_case
|> Object.finish
+
+ let latest_cmd (p : Input.Pijul.t) ~models =
+ let cmd = [
+ "nix-prefetch-pijul";
+ "--remote";
+ URI.to_string (URI.of_string (Input.Template.fill p.remote ~models));
+ ]
+ in
+ cmd @
+ match p.reference with
+ | `Change c -> ["--change"; c]
+ | `Channel c -> ["--channel"; c]
+ | `State s -> ["--state"; s]
+
+ let get_latest ~proc_mgr ~proc_env (p : Input.Pijul.t) ~models =
+ let (let*) = Result.bind in
+ let method' = `Pijul in
+ let* stdout = run_and_gather ~proc_mgr ~proc_env method' (latest_cmd p ~models) in
+ Jsont_bytesrw.decode_string jsont stdout
+ |> Result.map_error (fun err -> `JSON_parsing (method', err))
end
+
+type prefetch_kind_result = (
+ [
+ | `File of File.t
+ | `Archive of Archive.t
+ | `Git of Git.t
+ | `Darcs of Darcs.t
+ | `Pijul of Pijul.t
+ ],
+ error
+) result
+
+let get_latest ~env ~proc_mgr (input : Input.t) : prefetch_kind_result =
+ let hash_algo = Input.Hash.algorithm_to_string_lower input.hash.algorithm in
+ let proc_env =
+ let unix_env = Unix.environment () in
+ Array.append unix_env [|"NIX_HASH_ALGO=" ^ hash_algo|]
+ in
+ let models = Input.jg_models2 input in
+ match input.kind with
+ | `File file ->
+ File.get_latest ~env ~proc_mgr ~proc_env file ~hash_algo ~models
+ |> Result.map (fun f -> `File f)
+ | `Archive archive ->
+ Archive.get_latest ~env ~proc_mgr ~proc_env archive ~hash_algo ~models
+ |> Result.map (fun a -> `Archive a)
+ | `Git git ->
+ Git.get_latest ~proc_mgr ~proc_env git ~models
+ |> Result.map (fun g -> `Git g)
+ | `Darcs darcs ->
+ Darcs.get_latest ~proc_mgr ~proc_env darcs ~models
+ |> Result.map (fun d -> `Darcs d)
+ | `Pijul pijul ->
+ Pijul.get_latest ~proc_mgr ~proc_env pijul ~models
+ |> Result.map (fun p -> `Pijul p)