mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 11:38:30 +00:00
feat: host-target config resolution and cargo-style run args
This commit is contained in:
@@ -25,16 +25,25 @@ pub struct BuildRunFlags {
|
||||
pub force: bool,
|
||||
pub clean: bool,
|
||||
pub verbose: bool,
|
||||
pub bin_args: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn split_double_dash(args: &[String]) -> (&[String], &[String]) {
|
||||
match args.iter().position(|a| a == "--") {
|
||||
Some(i) => (&args[..i], &args[i + 1..]),
|
||||
None => (args, &[]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
||||
let (dcr_args, bin_args_slice) = split_double_dash(args);
|
||||
let mut profile = PROFILE.to_string();
|
||||
let mut target = None;
|
||||
let mut workspace = None;
|
||||
let mut force = false;
|
||||
let mut clean = false;
|
||||
let mut verbose = false;
|
||||
let mut iter = args.iter();
|
||||
let mut iter = dcr_args.iter();
|
||||
|
||||
while let Some(arg) = iter.next() {
|
||||
if !arg.starts_with("--") {
|
||||
@@ -91,5 +100,38 @@ pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
||||
force,
|
||||
clean,
|
||||
verbose,
|
||||
bin_args: bin_args_slice.to_vec(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn s(args: &[&str]) -> Vec<String> {
|
||||
args.iter().map(|a| a.to_string()).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_double_dash_empty_tail() {
|
||||
let args = s(&["--release", "--force"]);
|
||||
let (left, right) = split_double_dash(&args);
|
||||
assert_eq!(left, &s(&["--release", "--force"]));
|
||||
assert!(right.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_double_dash_with_bin_args() {
|
||||
let args = s(&["--release", "--", "--test_help", "x"]);
|
||||
let (left, right) = split_double_dash(&args);
|
||||
assert_eq!(left, &s(&["--release"]));
|
||||
assert_eq!(right, &s(&["--test_help", "x"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_run_flags_forwards_after_double_dash() {
|
||||
let flags = parse_build_run_flags(&s(&["--release", "--", "--test_help"])).unwrap();
|
||||
assert_eq!(flags.profile, "release");
|
||||
assert_eq!(flags.bin_args, s(&["--test_help"]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,12 +59,13 @@ pub fn run(args: &[String]) -> i32 {
|
||||
if args.first().is_some_and(|a| a == "--help") {
|
||||
printc("USAGE:", BOLD_GREEN);
|
||||
printc(
|
||||
" dcr run [--debug | --release] [--target <triple>] [--force] [--clean] [--verbose]",
|
||||
" dcr run [--debug | --release] [--target <triple>] [--force] [--clean] [--verbose] [-- <args>...]",
|
||||
BOLD_CYAN,
|
||||
);
|
||||
println!();
|
||||
printc("DESCRIPTION:", BOLD_GREEN);
|
||||
println!(" Builds and runs the project. Only available for kind = \"bin\".");
|
||||
println!(" Arguments after `--` are passed to the built binary (cargo-style).");
|
||||
println!();
|
||||
printc("OPTIONS:", BOLD_GREEN);
|
||||
println!(" --debug Run with debug profile (default)");
|
||||
@@ -73,6 +74,7 @@ pub fn run(args: &[String]) -> i32 {
|
||||
println!(" --force Force a full rebuild");
|
||||
println!(" --clean Clean before building");
|
||||
println!(" --verbose Print detailed build output");
|
||||
println!(" -- <args>... Arguments forwarded to the binary");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -112,12 +114,13 @@ pub fn run(args: &[String]) -> i32 {
|
||||
if let Some(cmd) = get_run_cmd(&config, &flags.profile, flags.target.as_deref(), "") {
|
||||
let build_status = build(&args_for_build(&flags));
|
||||
if build_status == 0 {
|
||||
let display = display_run_cmd(&cmd, &flags.bin_args);
|
||||
println!(
|
||||
" {} {}",
|
||||
colored(&format!("{:<9}", "run"), BOLD_GREEN),
|
||||
cmd
|
||||
display
|
||||
);
|
||||
return run_shell(&cmd);
|
||||
return run_shell_with_args(&cmd, &flags.bin_args);
|
||||
}
|
||||
return build_status;
|
||||
}
|
||||
@@ -250,32 +253,36 @@ fn run_project(
|
||||
);
|
||||
if build_status == 0 {
|
||||
if let Some(cmd) = run_cmd {
|
||||
let display = display_run_cmd(&cmd, &flags.bin_args);
|
||||
println!(
|
||||
" {} {}",
|
||||
colored(&format!("{:<9}", "run"), BOLD_GREEN),
|
||||
cmd
|
||||
display
|
||||
);
|
||||
return Ok(run_shell(&cmd));
|
||||
return Ok(run_shell_with_args(&cmd, &flags.bin_args));
|
||||
}
|
||||
let display = display_bin_run(&bin_path, &flags.bin_args);
|
||||
println!(
|
||||
" {} {}",
|
||||
colored(&format!("{:<9}", "run"), BOLD_GREEN),
|
||||
bin_path
|
||||
display
|
||||
);
|
||||
return Ok(run_binary(
|
||||
project_name,
|
||||
&flags.profile,
|
||||
normalized_target_dir.as_deref(),
|
||||
&flags.bin_args,
|
||||
));
|
||||
}
|
||||
|
||||
let fallback_code = if let Some(cmd) = run_cmd {
|
||||
run_shell(&cmd)
|
||||
run_shell_with_args(&cmd, &flags.bin_args)
|
||||
} else {
|
||||
run_binary(
|
||||
project_name,
|
||||
&flags.profile,
|
||||
normalized_target_dir.as_deref(),
|
||||
&flags.bin_args,
|
||||
)
|
||||
};
|
||||
if fallback_code != 1 {
|
||||
@@ -345,6 +352,62 @@ fn run_shell(cmd: &str) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_shell_with_args(cmd: &str, bin_args: &[String]) -> i32 {
|
||||
if bin_args.is_empty() {
|
||||
return run_shell(cmd);
|
||||
}
|
||||
let mut full = cmd.to_string();
|
||||
for arg in bin_args {
|
||||
full.push(' ');
|
||||
full.push_str(&shell_escape(arg));
|
||||
}
|
||||
run_shell(&full)
|
||||
}
|
||||
|
||||
fn display_run_cmd(cmd: &str, bin_args: &[String]) -> String {
|
||||
if bin_args.is_empty() {
|
||||
return cmd.to_string();
|
||||
}
|
||||
let mut display = cmd.to_string();
|
||||
for arg in bin_args {
|
||||
display.push(' ');
|
||||
display.push_str(arg);
|
||||
}
|
||||
display
|
||||
}
|
||||
|
||||
fn display_bin_run(bin_path: &str, bin_args: &[String]) -> String {
|
||||
if bin_args.is_empty() {
|
||||
return bin_path.to_string();
|
||||
}
|
||||
let mut display = bin_path.to_string();
|
||||
for arg in bin_args {
|
||||
display.push(' ');
|
||||
display.push_str(arg);
|
||||
}
|
||||
display
|
||||
}
|
||||
|
||||
fn shell_escape(arg: &str) -> String {
|
||||
if cfg!(target_os = "windows") {
|
||||
// cmd.exe: wrap in double quotes and escape embedded quotes.
|
||||
let escaped = arg.replace('"', "\\\"");
|
||||
format!("\"{escaped}\"")
|
||||
} else {
|
||||
// POSIX sh: single-quote and escape embedded single quotes as '\''.
|
||||
let mut out = String::from("'");
|
||||
for ch in arg.chars() {
|
||||
if ch == '\'' {
|
||||
out.push_str("'\\''");
|
||||
} else {
|
||||
out.push(ch);
|
||||
}
|
||||
}
|
||||
out.push('\'');
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
fn substitute_run_vars(cmd: &str, profile: &str, version: &str) -> String {
|
||||
let info = parse_version_info(version);
|
||||
substitute_vars(cmd, &info, profile, "")
|
||||
|
||||
Reference in New Issue
Block a user