From cc683cbb04280940922b042abe9d72c33dd77559 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sun, 30 Oct 2016 13:14:39 -0700 Subject: [PATCH] Bump version, add --debug --- Cargo.toml | 2 +- notes | 19 ++++++--------- src/app.rs | 23 +++++++++--------- src/integration.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 43 +++++++++++++++++++++++++-------- src/unit.rs | 16 ++++++------- 6 files changed, 120 insertions(+), 42 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8c5b621..34f2ea9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "j" -version = "0.2.7" +version = "0.2.8" authors = ["Casey Rodarmor "] license = "WTFPL/MIT/Apache-2.0" description = "a command runner" diff --git a/notes b/notes index 83789de..c69f202 100644 --- a/notes +++ b/notes @@ -1,15 +1,8 @@ -notes ------ +todo +---- -- --debug tests that: - - should consider renaming it to --evaluate if it actually evaluates stuff - - test values of assignments - - test values of interpolations - - test results of concatination - - test string escape parsing - - should it evaluate `` in recipes? - -- before release: +before release +-------------- - where can users get help? - irc, email, github, mailing list @@ -54,7 +47,8 @@ notes . irc . r/rust -enhancements: +enhancements +------------ - lazy assignment: don't evaluate unused assignments - use cow strings where we currently use String @@ -66,6 +60,7 @@ enhancements: . just ../foo # ../justfile:foo . just xyz/foo # xyz/justfile:foo . just xyz/ # xyz/justfile:DEFAULT + . path prefix is starting dir, so just ../foo can run ../../justfile:foo - allow setting and exporting environment variables . export a as "HELLO_BAR" . export a diff --git a/src/app.rs b/src/app.rs index 10d39d9..0af4865 100644 --- a/src/app.rs +++ b/src/app.rs @@ -23,16 +23,19 @@ macro_rules! die { pub fn app() { let matches = App::new("j") - .version("0.2.7") - .author("Casey R. ") + .version("0.2.8") + .author("Casey Rodarmor ") .about("Just a command runner - https://github.com/casey/j") .arg(Arg::with_name("list") .short("l") .long("list") .help("Lists available recipes")) - .arg(Arg::with_name("debug") - .long("debug") - .help("Prints the justfile with debugging information, such as evaluated expression and assignment")) + .arg(Arg::with_name("dry-run") + .long("dry-run") + .help("Print recipe text without executing")) + .arg(Arg::with_name("evaluate") + .long("evaluate") + .help("Print evaluated variables")) .arg(Arg::with_name("show") .short("s") .long("show") @@ -108,11 +111,6 @@ pub fn app() { let justfile = super::parse(&text).unwrap_or_else(|error| die!("{}", error)); - if matches.is_present("debug") { - println!("{:#}", justfile); - process::exit(0); - } - if matches.is_present("list") { if justfile.count() == 0 { warn!("Justfile contains no recipes"); @@ -162,7 +160,10 @@ pub fn app() { die!("Justfile contains no recipes"); }; - if let Err(run_error) = justfile.run(&overrides, &arguments) { + let dry_run = matches.is_present("dry-run"); + let evaluate = matches.is_present("evaluate"); + + if let Err(run_error) = justfile.run(&overrides, &arguments, dry_run, evaluate) { warn!("{}", run_error); match run_error { super::RunError::Code{code, .. } => process::exit(code), diff --git a/src/integration.rs b/src/integration.rs index 027a451..f0f3e6c 100644 --- a/src/integration.rs +++ b/src/integration.rs @@ -398,3 +398,62 @@ recipe arg: "echo arg=baz=bar\necho barbbaz\n", ); } + +// shebangs are printed + +#[test] +fn dry_run() { + integration_test( + "dry_run", + &["--dry-run", "shebang", "command"], + r#" +var = `echo stderr 1>&2; echo backtick` + +command: + @touch /this/is/not/a/file + {{var}} + echo {{`echo command interpolation`}} + +shebang: + #!/bin/sh + touch /this/is/not/a/file + {{var}} + echo {{`echo shebang interpolation`}}"#, + 0, + "", + "stderr +#!/bin/sh +touch /this/is/not/a/file +backtick +echo shebang interpolation +touch /this/is/not/a/file +backtick +echo command interpolation +", + ); +} + +#[test] +fn evaluate() { + integration_test( + "evaluate", + &["--evaluate"], + r#" +foo = "a\t" +baz = "c" +bar = "b\t" +abc = foo + bar + baz + +wut: + touch /this/is/not/a/file +"#, + 0, + r#"abc = "a b c" +bar = "b " +baz = "c" +foo = "a " +"#, + "", + ); +} + diff --git a/src/lib.rs b/src/lib.rs index 6b8330d..b0104ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -188,7 +188,8 @@ impl<'a> Recipe<'a> { fn run( &self, arguments: &[&'a str], - scope: &BTreeMap<&'a str, String> + scope: &BTreeMap<&'a str, String>, + dry_run: bool, ) -> Result<(), RunError<'a>> { let argument_map = arguments .iter().enumerate() .map(|(i, argument)| (self.arguments[i], *argument)).collect(); @@ -206,6 +207,13 @@ impl<'a> Recipe<'a> { evaluated_lines.push(try!(evaluator.evaluate_line(&line, &argument_map))); } + if dry_run { + for line in evaluated_lines { + warn!("{}", line); + } + return Ok(()); + } + let tmp = try!( tempdir::TempDir::new("j") .map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error}) @@ -266,10 +274,15 @@ impl<'a> Recipe<'a> { for line in &self.lines { let evaluated = &try!(evaluator.evaluate_line(&line, &argument_map)); let mut command = evaluated.as_str(); - if !command.starts_with('@') { + let quiet = command.starts_with('@'); + if quiet { + command = &command[1..]; + } + if dry_run || !quiet { warn!("{}", command); - } else { - command = &command[1..]; + } + if dry_run { + continue; } let status = process::Command::new("sh") .arg("-cu") @@ -809,7 +822,9 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b { fn run( &'a self, overrides: &BTreeMap<&'a str, &'a str>, - arguments: &[&'a str] + arguments: &[&'a str], + dry_run: bool, + evaluate: bool, ) -> Result<(), RunError<'a>> { let unknown_overrides = overrides.keys().cloned() .filter(|name| !self.assignments.contains_key(name)) @@ -820,6 +835,13 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b { } let scope = try!(evaluate_assignments(&self.assignments, overrides)); + if evaluate { + for (name, value) in scope { + println!("{} = \"{}\"", name, value); + } + return Ok(()); + } + let mut ran = HashSet::new(); for (i, argument) in arguments.iter().enumerate() { @@ -836,7 +858,7 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b { expected: recipe.arguments.len(), }); } - try!(self.run_recipe(recipe, rest, &scope, &mut ran)); + try!(self.run_recipe(recipe, rest, &scope, &mut ran, dry_run)); return Ok(()); } } else { @@ -854,7 +876,7 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b { return Err(RunError::UnknownRecipes{recipes: missing}); } for recipe in arguments.iter().map(|name| &self.recipes[name]) { - try!(self.run_recipe(recipe, &[], &scope, &mut ran)); + try!(self.run_recipe(recipe, &[], &scope, &mut ran, dry_run)); } Ok(()) } @@ -864,14 +886,15 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b { recipe: &Recipe<'a>, arguments: &[&'a str], scope: &BTreeMap<&'c str, String>, - ran: &mut HashSet<&'a str> + ran: &mut HashSet<&'a str>, + dry_run: bool, ) -> Result<(), RunError> { for dependency_name in &recipe.dependencies { if !ran.contains(dependency_name) { - try!(self.run_recipe(&self.recipes[dependency_name], &[], scope, ran)); + try!(self.run_recipe(&self.recipes[dependency_name], &[], scope, ran, dry_run)); } } - try!(recipe.run(arguments, &scope)); + try!(recipe.run(arguments, &scope, dry_run)); ran.insert(recipe.name); Ok(()) } diff --git a/src/unit.rs b/src/unit.rs index 0f11795..17e2e30 100644 --- a/src/unit.rs +++ b/src/unit.rs @@ -579,7 +579,7 @@ fn conjoin_and() { #[test] fn unknown_recipes() { - match parse_success("a:\nb:\nc:").run(&BTreeMap::new(), &["a", "x", "y", "z"]).unwrap_err() { + match parse_success("a:\nb:\nc:").run(&BTreeMap::new(), &["a", "x", "y", "z"], false, false).unwrap_err() { RunError::UnknownRecipes{recipes} => assert_eq!(recipes, &["x", "y", "z"]), other => panic!("expected an unknown recipe error, but got: {}", other), } @@ -747,7 +747,7 @@ a: x "; - match parse_success(text).run(&BTreeMap::new(), &["a"]).unwrap_err() { + match parse_success(text).run(&BTreeMap::new(), &["a"], false, false).unwrap_err() { RunError::Code{recipe, code} => { assert_eq!(recipe, "a"); assert_eq!(code, 200); @@ -758,7 +758,7 @@ a: #[test] fn code_error() { - match parse_success("fail:\n @function x { return 100; }; x").run(&BTreeMap::new(), &["fail"]).unwrap_err() { + match parse_success("fail:\n @function x { return 100; }; x").run(&BTreeMap::new(), &["fail"], false, false).unwrap_err() { RunError::Code{recipe, code} => { assert_eq!(recipe, "fail"); assert_eq!(code, 100); @@ -773,7 +773,7 @@ fn run_args() { a return code: @function x { {{return}} {{code + "0"}}; }; x"#; - match parse_success(text).run(&BTreeMap::new(), &["a", "return", "15"]).unwrap_err() { + match parse_success(text).run(&BTreeMap::new(), &["a", "return", "15"], false, false).unwrap_err() { RunError::Code{recipe, code} => { assert_eq!(recipe, "a"); assert_eq!(code, 150); @@ -784,7 +784,7 @@ a return code: #[test] fn missing_args() { - match parse_success("a b c d:").run(&BTreeMap::new(), &["a", "b", "c"]).unwrap_err() { + match parse_success("a b c d:").run(&BTreeMap::new(), &["a", "b", "c"], false, false).unwrap_err() { RunError::ArgumentCountMismatch{recipe, found, expected} => { assert_eq!(recipe, "a"); assert_eq!(found, 2); @@ -796,7 +796,7 @@ fn missing_args() { #[test] fn missing_default() { - match parse_success("a b c d:\n echo {{b}}{{c}}{{d}}").run(&BTreeMap::new(), &["a"]).unwrap_err() { + match parse_success("a b c d:\n echo {{b}}{{c}}{{d}}").run(&BTreeMap::new(), &["a"], false, false).unwrap_err() { RunError::ArgumentCountMismatch{recipe, found, expected} => { assert_eq!(recipe, "a"); assert_eq!(found, 0); @@ -808,7 +808,7 @@ fn missing_default() { #[test] fn backtick_code() { - match parse_success("a:\n echo {{`function f { return 100; }; f`}}").run(&BTreeMap::new(), &["a"]).unwrap_err() { + match parse_success("a:\n echo {{`function f { return 100; }; f`}}").run(&BTreeMap::new(), &["a"], false, false).unwrap_err() { RunError::BacktickCode{code, token} => { assert_eq!(code, 100); assert_eq!(token.lexeme, "`function f { return 100; }; f`"); @@ -823,7 +823,7 @@ fn unknown_overrides() { overrides.insert("foo", "bar"); overrides.insert("baz", "bob"); match parse_success("a:\n echo {{`function f { return 100; }; f`}}") - .run(&overrides, &["a"]).unwrap_err() { + .run(&overrides, &["a"], false, false).unwrap_err() { RunError::UnknownOverrides{overrides} => { assert_eq!(overrides, &["baz", "foo"]); },