Skip to content

Commit

Permalink
feat: add --argc-run to run the script (#331)
Browse files Browse the repository at this point in the history
  • Loading branch information
sigoden authored May 24, 2024
1 parent e9678f4 commit aa0f67f
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/bin/argc/completion.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# @option --argc-eval~ <FILE> <ARGS> Use `eval "$(argc --argc-eval "$0" "$@")"`
# @option --argc-create~ <RECIPES> Create a boilerplate argcfile
# @option --argc-run~ <FILE> <ARGS> Run an argc-based script
# @option --argc-build <FILE> <OUTPATH?> Generate bashscript without argc dependency
# @option --argc-mangen <FILE> <OUTDIR> Generate man pages
# @option --argc-completions <SHELL> <CMDS> Generate shell completion scripts
Expand Down
59 changes: 52 additions & 7 deletions src/bin/argc/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn main() {
}
}
Err(err) => {
eprintln!("{}", err);
eprintln!("{err:?}");
process::exit(1);
}
}
Expand Down Expand Up @@ -83,12 +83,43 @@ fn run() -> Result<i32> {
println!("{dir_vars}{export_vars}{code}")
}
}
"--argc-run" => {
if args.len() < 3 {
bail!("No script file provided");
}
let shell = runtime.shell_path()?;
let script_path = normalize_script_path(&args[2]);
let (script_dir, script_path) = {
let script_path = fs::canonicalize(&script_path)
.with_context(|| format!("Failed to run '{script_path}'"))?;
let script_dir = script_path.parent().unwrap();
let script_path = {
let path = script_path.display().to_string();
if cfg!(windows) && path.starts_with(r"\\?\") {
path[4..].to_string()
} else {
path
}
};
(script_dir.to_path_buf(), script_path)
};
let mut envs = HashMap::new();
if is_runner_script(&script_path) {
if let Some(cwd) = runtime.current_dir() {
if env::var("ARGC_PWD").is_err() {
envs.insert("ARGC_PWD".to_string(), escape_shell_words(&cwd));
}
}
}
let args = [vec![&script_path], args.iter().skip(3).collect()].concat();
return run_command(&script_path, &shell, &args, envs, Some(&script_dir));
}
"--argc-create" => {
if let Some((_, script_file)) = get_script_path(false) {
bail!("Already exist {}", script_file.display());
}
let content = generate_boilerplate(&args[2..]);
let names = candidate_script_names();
let names = runner_script_names();
fs::write(&names[0], content)
.with_context(|| format!("Failed to create {}", &names[0]))?;
println!("{} has been successfully created.", &names[0]);
Expand Down Expand Up @@ -181,7 +212,9 @@ fn run() -> Result<i32> {
.ok_or_else(|| anyhow!("Argcfile not found, try `argc --argc-help` for help."))?;
let mut envs = HashMap::new();
if let Some(cwd) = runtime.current_dir() {
envs.insert("ARGC_PWD".to_string(), escape_shell_words(&cwd));
if env::var("ARGC_PWD").is_err() {
envs.insert("ARGC_PWD".to_string(), escape_shell_words(&cwd));
}
}
let script_file = script_file.display().to_string();
let args = [vec![&script_file], args[1..].iter().collect()].concat();
Expand Down Expand Up @@ -360,7 +393,7 @@ fn export_dir_vars(path: &str) -> String {
}

fn get_argc_script_dir(path: &str) -> Option<String> {
if candidate_script_names().iter().all(|v| !path.ends_with(v)) {
if runner_script_names().iter().all(|v| !path.ends_with(v)) {
return None;
}
let path = Path::new(path);
Expand All @@ -376,7 +409,7 @@ fn get_argc_script_dir(path: &str) -> Option<String> {

fn parse_script_args(args: &[String]) -> Result<(String, String, Vec<String>)> {
if args.is_empty() {
bail!("No script provided");
bail!("No script file provided");
}
let script_file = args[0].as_str();
let script_file = normalize_script_path(script_file);
Expand Down Expand Up @@ -425,7 +458,7 @@ eval "$(argc --argc-eval "$0" "$@")"
}

fn get_script_path(recursive: bool) -> Option<(PathBuf, PathBuf)> {
let candidates = candidate_script_names();
let candidates = runner_script_names();
let mut dir = env::current_dir().ok()?;
loop {
for name in candidates.iter() {
Expand All @@ -441,7 +474,7 @@ fn get_script_path(recursive: bool) -> Option<(PathBuf, PathBuf)> {
}
}

fn candidate_script_names() -> Vec<String> {
fn runner_script_names() -> Vec<String> {
let mut names = vec![];
if let Ok(name) = env::var("ARGC_SCRIPT_NAME") {
names.push(name.clone());
Expand All @@ -453,6 +486,18 @@ fn candidate_script_names() -> Vec<String> {
names
}

fn is_runner_script(script_file: &str) -> bool {
let name = match get_script_name(script_file) {
Ok(v) => v,
Err(_) => return false,
};
let name = name.strip_suffix(".sh").unwrap_or(name);
let expect_name = env::var("ARGC_SCRIPT_NAME")
.map(|v| v.to_lowercase())
.unwrap_or_else(|_| "argcfile".to_string());
name.to_lowercase() == expect_name
}

fn search_completion_script(args: &mut Vec<String>) -> Option<PathBuf> {
let search_paths = env::var("ARGC_COMPLETIONS_PATH").ok()?;
let cmd = Path::new(&args[4])
Expand Down
14 changes: 14 additions & 0 deletions tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ fn create_with_tasks() {
.success();
}

#[test]
fn run() {
let path_env_var = get_path_env_var();
let path = locate_script("examples/demo.sh");
Command::cargo_bin("argc")
.unwrap()
.arg("--argc-run")
.arg(path)
.env("PATH", path_env_var)
.assert()
.stderr(predicates::str::contains("USAGE: demo"))
.success();
}

#[test]
fn build_stdout() {
let path = locate_script("examples/demo.sh");
Expand Down

0 comments on commit aa0f67f

Please sign in to comment.