Skip to content

Commit

Permalink
feat: Add support for executing cargo commands with @ prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
Lupus committed Nov 4, 2024
1 parent 0384af2 commit f901d77
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 20 deletions.
26 changes: 17 additions & 9 deletions bin/Cmdline.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ type build_target =
| Crate_name of string
| Manifest_path of string

type action =
| Build of build_target
| Cargo_command of string

type t =
{ profile : string
; workspace_root : string option
; cargo_args : string list
; target : build_target
; action : action
; output_dir : string option
}

Expand Down Expand Up @@ -34,15 +38,19 @@ let parse () =
in
Arg.parse speclist anon_fun usage_msg;
let args = List.rev !args in
let target, output_dir =
let action, output_dir =
match args with
| [ arg ] ->
let target =
if Filename.check_suffix arg "Cargo.toml"
then Manifest_path arg
else Crate_name arg
let action =
if String.get arg 0 = '@'
then (
let cmd = String.sub arg 1 (String.length arg - 1) in
Cargo_command cmd)
else if Filename.check_suffix arg "Cargo.toml"
then Build (Manifest_path arg)
else Build (Crate_name arg)
in
target, None
action, None
| [ arg; output_dir ] ->
let target =
if Filename.check_suffix arg "Cargo.toml"
Expand All @@ -51,14 +59,14 @@ let parse () =
in
if not (Sys.file_exists output_dir && Sys.is_directory output_dir)
then failwith "Error: Output directory does not exist or is not a directory";
target, Some output_dir
Build target, Some output_dir
| [] -> print_usage ()
| _ -> print_usage ()
in
{ profile = !profile
; workspace_root = !workspace_root
; cargo_args = !cargo_args
; target
; action
; output_dir
}
;;
6 changes: 5 additions & 1 deletion bin/Cmdline.mli
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ type build_target =
| Crate_name of string
| Manifest_path of string

type action =
| Build of build_target
| Cargo_command of string

type t =
{ profile : string
; workspace_root : string option
; cargo_args : string list
; target : build_target
; action : action
; output_dir : string option
}

Expand Down
92 changes: 82 additions & 10 deletions bin/Dune_cargo_build.ml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,67 @@ let cargo_read_lines input =
aux []
;;

let run_cargo_build cmdline =
let profile_flag = if cmdline.Cmdline.profile = "dev" then "" else "--release" in
let offline_flag = cargo_offline_flag () in
(* Commands that support the --offline flag *)
let allowed_offline_commands =
[ "build" (* https://doc.rust-lang.org/cargo/commands/cargo-build.html *)
; "check" (* https://doc.rust-lang.org/cargo/commands/cargo-check.html *)
; "run" (* https://doc.rust-lang.org/cargo/commands/cargo-run.html *)
; "test" (* https://doc.rust-lang.org/cargo/commands/cargo-test.html *)
; "bench" (* https://doc.rust-lang.org/cargo/commands/cargo-bench.html *)
; "doc" (* https://doc.rust-lang.org/cargo/commands/cargo-doc.html *)
; "generate-lockfile"
(* https://doc.rust-lang.org/cargo/commands/cargo-generate-lockfile.html
- With --offline, it can only generate a lockfile based on locally
available information *)
; "install" (* https://doc.rust-lang.org/cargo/commands/cargo-install.html *)
; "uninstall"
(* https://doc.rust-lang.org/cargo/commands/cargo-uninstall.html
- --offline flag is valid but typically not necessary for this
operation *)
; "clean"
(* https://doc.rust-lang.org/cargo/commands/cargo-clean.html
- --offline flag is valid but typically not necessary for this
operation *)
; "fetch"
(* https://doc.rust-lang.org/cargo/commands/cargo-fetch.html
- While it supports --offline, it primarily downloads dependencies,
so using it with --offline limits functionality *)
; "update"
(* https://doc.rust-lang.org/cargo/commands/cargo-update.html
- With --offline, it can only update based on locally cached
information *)
]
;;

(* Commands that support the --release flag *)
let allowed_release_commands =
[ "build" (* https://doc.rust-lang.org/cargo/commands/cargo-build.html *)
; "run" (* https://doc.rust-lang.org/cargo/commands/cargo-run.html *)
; "test" (* https://doc.rust-lang.org/cargo/commands/cargo-test.html *)
; "doc" (* https://doc.rust-lang.org/cargo/commands/cargo-doc.html *)
; "install"
(* https://doc.rust-lang.org/cargo/commands/cargo-install.html
- Uses release profile by default, so --release is usually redundant *)
]
;;

let build_flags cmdline command =
let profile_flag =
if List.mem command allowed_release_commands
then if cmdline.Cmdline.profile = "dev" then "" else "--release"
else ""
in
let offline_flag =
if List.mem command allowed_offline_commands then cargo_offline_flag () else ""
in
let cargo_args_str = String.concat " " (List.rev cmdline.cargo_args) in
profile_flag, offline_flag, cargo_args_str
;;

let run_cargo_build cmdline target =
let profile_flag, offline_flag, cargo_args_str = build_flags cmdline "build" in
let target_flag =
match cmdline.target with
match target with
| Cmdline.Crate_name crate_name -> Printf.sprintf "--package %s" crate_name
| Cmdline.Manifest_path manifest_path ->
Printf.sprintf "--manifest-path %s" manifest_path
Expand All @@ -59,34 +114,49 @@ let run_cargo_build cmdline =
| WSTOPPED signal -> failwith ("Cargo build stopped by signal " ^ string_of_int signal)
;;

let run_cargo_command cmdline cmd =
let profile_flag, offline_flag, cargo_args_str = build_flags cmdline cmd in
let command =
Printf.sprintf "cargo %s %s %s %s" cmd profile_flag offline_flag cargo_args_str
in
let command = Util.simplify_whitespace command in
let in_source_workspace_root = Workspace_root.get () in
Printf.printf
"Changing dir to in-source workspace root: %s\n%!"
in_source_workspace_root.dir;
Sys.chdir in_source_workspace_root.dir;
Printf.printf "Running cargo command: %s\n%!" command;
Unix.execvp "cargo" (Array.of_list (String.split_on_char ' ' command))
;;

(* Function to replace '-' with '_' in crate name *)
let rustify_crate_name crate_name =
String.map (fun c -> if c = '-' then '_' else c) crate_name
;;

let process_cargo_output cmdline output_dir =
let process_cargo_output cmdline target output_dir =
let in_source_workspace_root = Workspace_root.get () in
let cd_to =
match cmdline.Cmdline.workspace_root with
| Some root ->
let relative_path = Util.reconstruct_relative_path root in
Filename.concat in_source_workspace_root.dir relative_path
| None ->
(match cmdline.target with
(match target with
| Cmdline.Crate_name _ -> ()
| Cmdline.Manifest_path _ ->
failwith "Error: please provide -workspace-root when building by manifest path");
in_source_workspace_root.dir
in
let lines =
Util.temporarily_change_directory cd_to ~f:(fun () -> run_cargo_build cmdline)
Util.temporarily_change_directory cd_to ~f:(fun () -> run_cargo_build cmdline target)
in
let buffer = Buffer.create 256 in
let pf fmt = Printf.bprintf buffer ("[process_cargo_output] " ^^ fmt ^^ "\n") in
let filter =
let open Cargo_json in
match cmdline.target with
| Crate_name name ->
match target with
| Cmdline.Crate_name name ->
let orig_crate_name = name in
let crate_name = rustify_crate_name name in
fun json ->
Expand Down Expand Up @@ -178,7 +248,9 @@ let main () =
| Some dir -> dir
| None -> Sys.getcwd ()
in
process_cargo_output cmdline output_dir
match cmdline.Cmdline.action with
| Cmdline.Cargo_command cmd -> run_cargo_command cmdline cmd
| Build target -> process_cargo_output cmdline target output_dir
;;

let () = main ()

0 comments on commit f901d77

Please sign in to comment.