Implement invocation_directory function (#312)
This commit is contained in:
parent
ee7302c0e3
commit
cf3fde442f
18
README.adoc
18
README.adoc
@ -289,6 +289,24 @@ This is an x86_64 machine
|
|||||||
|
|
||||||
- `env_var_or_default(key, default)` – Retrieves the environment variable with name `key`, returning `default` if it is not present.
|
- `env_var_or_default(key, default)` – Retrieves the environment variable with name `key`, returning `default` if it is not present.
|
||||||
|
|
||||||
|
==== Invocation Directory
|
||||||
|
|
||||||
|
- `invocation_directory()` - Retrieves the path of the current working directory, before `just` changed it (chdir'd) prior to executing commands.
|
||||||
|
|
||||||
|
For example, to call `rustfmt` on files just under the "current directory" (from the user/invoker's perspective), use the following rule:
|
||||||
|
|
||||||
|
```
|
||||||
|
rustfmt:
|
||||||
|
find {{invocation_directory()}} -name \*.rs -exec rustfmt {} \;
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, if your command needs to be run from the current directory, you could use (e.g.):
|
||||||
|
|
||||||
|
```
|
||||||
|
build:
|
||||||
|
cd {{invocation_directory()}}; ./some_script_that_needs_to_be_run_from_here
|
||||||
|
```
|
||||||
|
|
||||||
==== Dotenv Integration
|
==== Dotenv Integration
|
||||||
|
|
||||||
`just` will load environment variables from a file named `.env`. This file can be located in the same directory as your justfile or in a parent directory. These variables are environment variables, not `just` variables, and so must be accessed using `$VARIABLE_NAME` in recipes and backticks.
|
`just` will load environment variables from a file named `.env`. This file can be located in the same directory as your justfile or in a parent directory. These variables are environment variables, not `just` variables, and so must be accessed using `$VARIABLE_NAME` in recipes and backticks.
|
||||||
|
4
justfile
4
justfile
@ -141,6 +141,10 @@ ruby:
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
puts "Hello from ruby!"
|
puts "Hello from ruby!"
|
||||||
|
|
||||||
|
# Print working directory, for demonstration purposes!
|
||||||
|
pwd:
|
||||||
|
echo {{invocation_directory()}}
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# mode: makefile
|
# mode: makefile
|
||||||
# End:
|
# End:
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
use brev;
|
use brev;
|
||||||
|
|
||||||
pub struct AssignmentEvaluator<'a: 'b, 'b> {
|
pub struct AssignmentEvaluator<'a: 'b, 'b> {
|
||||||
pub assignments: &'b Map<&'a str, Expression<'a>>,
|
pub assignments: &'b Map<&'a str, Expression<'a>>,
|
||||||
|
pub invocation_directory: &'b Result<PathBuf, String>,
|
||||||
pub dotenv: &'b Map<String, String>,
|
pub dotenv: &'b Map<String, String>,
|
||||||
pub dry_run: bool,
|
pub dry_run: bool,
|
||||||
pub evaluated: Map<&'a str, String>,
|
pub evaluated: Map<&'a str, String>,
|
||||||
@ -17,6 +20,7 @@ pub struct AssignmentEvaluator<'a: 'b, 'b> {
|
|||||||
impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
||||||
pub fn evaluate_assignments(
|
pub fn evaluate_assignments(
|
||||||
assignments: &Map<&'a str, Expression<'a>>,
|
assignments: &Map<&'a str, Expression<'a>>,
|
||||||
|
invocation_directory: &Result<PathBuf, String>,
|
||||||
dotenv: &'b Map<String, String>,
|
dotenv: &'b Map<String, String>,
|
||||||
overrides: &Map<&str, &str>,
|
overrides: &Map<&str, &str>,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
@ -28,6 +32,7 @@ impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
|||||||
exports: &empty(),
|
exports: &empty(),
|
||||||
scope: &empty(),
|
scope: &empty(),
|
||||||
assignments,
|
assignments,
|
||||||
|
invocation_directory,
|
||||||
dotenv,
|
dotenv,
|
||||||
dry_run,
|
dry_run,
|
||||||
overrides,
|
overrides,
|
||||||
@ -107,6 +112,7 @@ impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
|||||||
self.evaluate_expression(argument, arguments)
|
self.evaluate_expression(argument, arguments)
|
||||||
}).collect::<Result<Vec<String>, RuntimeError>>()?;
|
}).collect::<Result<Vec<String>, RuntimeError>>()?;
|
||||||
let context = FunctionContext {
|
let context = FunctionContext {
|
||||||
|
invocation_directory: &self.invocation_directory,
|
||||||
dotenv: self.dotenv,
|
dotenv: self.dotenv,
|
||||||
};
|
};
|
||||||
evaluate_function(token, name, &context, &call_arguments)
|
evaluate_function(token, name, &context, &call_arguments)
|
||||||
@ -161,10 +167,14 @@ mod test {
|
|||||||
use testing::parse_success;
|
use testing::parse_success;
|
||||||
use Configuration;
|
use Configuration;
|
||||||
|
|
||||||
|
fn no_cwd_err() -> Result<PathBuf, String> {
|
||||||
|
Err(String::from("no cwd in tests"))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn backtick_code() {
|
fn backtick_code() {
|
||||||
match parse_success("a:\n echo {{`f() { return 100; }; f`}}")
|
match parse_success("a:\n echo {{`f() { return 100; }; f`}}")
|
||||||
.run(&["a"], &Default::default()).unwrap_err() {
|
.run(no_cwd_err(), &["a"], &Default::default()).unwrap_err() {
|
||||||
RuntimeError::Backtick{token, output_error: OutputError::Code(code)} => {
|
RuntimeError::Backtick{token, output_error: OutputError::Code(code)} => {
|
||||||
assert_eq!(code, 100);
|
assert_eq!(code, 100);
|
||||||
assert_eq!(token.lexeme, "`f() { return 100; }; f`");
|
assert_eq!(token.lexeme, "`f() { return 100; }; f`");
|
||||||
@ -187,7 +197,7 @@ recipe:
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
match parse_success(text).run(&["recipe"], &configuration).unwrap_err() {
|
match parse_success(text).run(no_cwd_err(), &["recipe"], &configuration).unwrap_err() {
|
||||||
RuntimeError::Backtick{token, output_error: OutputError::Code(_)} => {
|
RuntimeError::Backtick{token, output_error: OutputError::Code(_)} => {
|
||||||
assert_eq!(token.lexeme, "`echo $exported_variable`");
|
assert_eq!(token.lexeme, "`echo $exported_variable`");
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
use target;
|
use target;
|
||||||
|
|
||||||
|
use platform::{Platform, PlatformInterface};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref FUNCTIONS: Map<&'static str, Function> = vec![
|
static ref FUNCTIONS: Map<&'static str, Function> = vec![
|
||||||
("arch", Function::Nullary(arch )),
|
("arch", Function::Nullary(arch )),
|
||||||
@ -8,6 +12,7 @@ lazy_static! {
|
|||||||
("os_family", Function::Nullary(os_family )),
|
("os_family", Function::Nullary(os_family )),
|
||||||
("env_var", Function::Unary (env_var )),
|
("env_var", Function::Unary (env_var )),
|
||||||
("env_var_or_default", Function::Binary (env_var_or_default)),
|
("env_var_or_default", Function::Binary (env_var_or_default)),
|
||||||
|
("invocation_directory", Function::Nullary(invocation_directory)),
|
||||||
].into_iter().collect();
|
].into_iter().collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,6 +34,7 @@ impl Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct FunctionContext<'a> {
|
pub struct FunctionContext<'a> {
|
||||||
|
pub invocation_directory: &'a Result<PathBuf, String>,
|
||||||
pub dotenv: &'a Map<String, String>,
|
pub dotenv: &'a Map<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +98,12 @@ pub fn os_family(_context: &FunctionContext) -> Result<String, String> {
|
|||||||
Ok(target::os_family().to_string())
|
Ok(target::os_family().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn invocation_directory(context: &FunctionContext) -> Result<String, String> {
|
||||||
|
context.invocation_directory.clone()
|
||||||
|
.and_then(|s| Platform::to_shell_path(&s)
|
||||||
|
.map_err(|e| format!("Error getting shell path: {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn env_var(context: &FunctionContext, key: &str) -> Result<String, String> {
|
pub fn env_var(context: &FunctionContext, key: &str) -> Result<String, String> {
|
||||||
use std::env::VarError::*;
|
use std::env::VarError::*;
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
use edit_distance::edit_distance;
|
use edit_distance::edit_distance;
|
||||||
@ -42,6 +44,7 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
|
|||||||
|
|
||||||
pub fn run(
|
pub fn run(
|
||||||
&'a self,
|
&'a self,
|
||||||
|
invocation_directory: Result<PathBuf, String>,
|
||||||
arguments: &[&'a str],
|
arguments: &[&'a str],
|
||||||
configuration: &Configuration<'a>,
|
configuration: &Configuration<'a>,
|
||||||
) -> RunResult<'a, ()> {
|
) -> RunResult<'a, ()> {
|
||||||
@ -57,6 +60,7 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
|
|||||||
|
|
||||||
let scope = AssignmentEvaluator::evaluate_assignments(
|
let scope = AssignmentEvaluator::evaluate_assignments(
|
||||||
&self.assignments,
|
&self.assignments,
|
||||||
|
&invocation_directory,
|
||||||
&dotenv,
|
&dotenv,
|
||||||
&configuration.overrides,
|
&configuration.overrides,
|
||||||
configuration.quiet,
|
configuration.quiet,
|
||||||
@ -115,7 +119,7 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
|
|||||||
|
|
||||||
let mut ran = empty();
|
let mut ran = empty();
|
||||||
for (recipe, arguments) in grouped {
|
for (recipe, arguments) in grouped {
|
||||||
self.run_recipe(recipe, arguments, &scope, &dotenv, configuration, &mut ran)?
|
self.run_recipe(&invocation_directory, recipe, arguments, &scope, &dotenv, configuration, &mut ran)?
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -123,6 +127,7 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
|
|||||||
|
|
||||||
fn run_recipe<'c>(
|
fn run_recipe<'c>(
|
||||||
&'c self,
|
&'c self,
|
||||||
|
invocation_directory: &Result<PathBuf, String>,
|
||||||
recipe: &Recipe<'a>,
|
recipe: &Recipe<'a>,
|
||||||
arguments: &[&'a str],
|
arguments: &[&'a str],
|
||||||
scope: &Map<&'c str, String>,
|
scope: &Map<&'c str, String>,
|
||||||
@ -132,10 +137,10 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
|
|||||||
) -> RunResult<()> {
|
) -> RunResult<()> {
|
||||||
for dependency_name in &recipe.dependencies {
|
for dependency_name in &recipe.dependencies {
|
||||||
if !ran.contains(dependency_name) {
|
if !ran.contains(dependency_name) {
|
||||||
self.run_recipe(&self.recipes[dependency_name], &[], scope, dotenv, configuration, ran)?;
|
self.run_recipe(invocation_directory, &self.recipes[dependency_name], &[], scope, dotenv, configuration, ran)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
recipe.run(arguments, scope, dotenv, &self.exports, configuration)?;
|
recipe.run(invocation_directory, arguments, scope, dotenv, &self.exports, configuration)?;
|
||||||
ran.insert(recipe.name);
|
ran.insert(recipe.name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -171,9 +176,13 @@ mod test {
|
|||||||
use testing::parse_success;
|
use testing::parse_success;
|
||||||
use RuntimeError::*;
|
use RuntimeError::*;
|
||||||
|
|
||||||
|
fn no_cwd_err() -> Result<PathBuf, String> {
|
||||||
|
Err(String::from("no cwd in tests"))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unknown_recipes() {
|
fn unknown_recipes() {
|
||||||
match parse_success("a:\nb:\nc:").run(&["a", "x", "y", "z"], &Default::default()).unwrap_err() {
|
match parse_success("a:\nb:\nc:").run(no_cwd_err(), &["a", "x", "y", "z"], &Default::default()).unwrap_err() {
|
||||||
UnknownRecipes{recipes, suggestion} => {
|
UnknownRecipes{recipes, suggestion} => {
|
||||||
assert_eq!(recipes, &["x", "y", "z"]);
|
assert_eq!(recipes, &["x", "y", "z"]);
|
||||||
assert_eq!(suggestion, None);
|
assert_eq!(suggestion, None);
|
||||||
@ -201,7 +210,7 @@ a:
|
|||||||
x
|
x
|
||||||
";
|
";
|
||||||
|
|
||||||
match parse_success(text).run(&["a"], &Default::default()).unwrap_err() {
|
match parse_success(text).run(no_cwd_err(), &["a"], &Default::default()).unwrap_err() {
|
||||||
Code{recipe, line_number, code} => {
|
Code{recipe, line_number, code} => {
|
||||||
assert_eq!(recipe, "a");
|
assert_eq!(recipe, "a");
|
||||||
assert_eq!(code, 200);
|
assert_eq!(code, 200);
|
||||||
@ -214,7 +223,7 @@ a:
|
|||||||
#[test]
|
#[test]
|
||||||
fn code_error() {
|
fn code_error() {
|
||||||
match parse_success("fail:\n @exit 100")
|
match parse_success("fail:\n @exit 100")
|
||||||
.run(&["fail"], &Default::default()).unwrap_err() {
|
.run(no_cwd_err(), &["fail"], &Default::default()).unwrap_err() {
|
||||||
Code{recipe, line_number, code} => {
|
Code{recipe, line_number, code} => {
|
||||||
assert_eq!(recipe, "fail");
|
assert_eq!(recipe, "fail");
|
||||||
assert_eq!(code, 100);
|
assert_eq!(code, 100);
|
||||||
@ -230,7 +239,7 @@ a:
|
|||||||
a return code:
|
a return code:
|
||||||
@x() { {{return}} {{code + "0"}}; }; x"#;
|
@x() { {{return}} {{code + "0"}}; }; x"#;
|
||||||
|
|
||||||
match parse_success(text).run(&["a", "return", "15"], &Default::default()).unwrap_err() {
|
match parse_success(text).run(no_cwd_err(), &["a", "return", "15"], &Default::default()).unwrap_err() {
|
||||||
Code{recipe, line_number, code} => {
|
Code{recipe, line_number, code} => {
|
||||||
assert_eq!(recipe, "a");
|
assert_eq!(recipe, "a");
|
||||||
assert_eq!(code, 150);
|
assert_eq!(code, 150);
|
||||||
@ -242,7 +251,7 @@ a return code:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_some_arguments() {
|
fn missing_some_arguments() {
|
||||||
match parse_success("a b c d:").run(&["a", "b", "c"], &Default::default()).unwrap_err() {
|
match parse_success("a b c d:").run(no_cwd_err(), &["a", "b", "c"], &Default::default()).unwrap_err() {
|
||||||
ArgumentCountMismatch{recipe, found, min, max} => {
|
ArgumentCountMismatch{recipe, found, min, max} => {
|
||||||
assert_eq!(recipe, "a");
|
assert_eq!(recipe, "a");
|
||||||
assert_eq!(found, 2);
|
assert_eq!(found, 2);
|
||||||
@ -255,7 +264,7 @@ a return code:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_some_arguments_variadic() {
|
fn missing_some_arguments_variadic() {
|
||||||
match parse_success("a b c +d:").run(&["a", "B", "C"], &Default::default()).unwrap_err() {
|
match parse_success("a b c +d:").run(no_cwd_err(), &["a", "B", "C"], &Default::default()).unwrap_err() {
|
||||||
ArgumentCountMismatch{recipe, found, min, max} => {
|
ArgumentCountMismatch{recipe, found, min, max} => {
|
||||||
assert_eq!(recipe, "a");
|
assert_eq!(recipe, "a");
|
||||||
assert_eq!(found, 2);
|
assert_eq!(found, 2);
|
||||||
@ -269,7 +278,7 @@ a return code:
|
|||||||
#[test]
|
#[test]
|
||||||
fn missing_all_arguments() {
|
fn missing_all_arguments() {
|
||||||
match parse_success("a b c d:\n echo {{b}}{{c}}{{d}}")
|
match parse_success("a b c d:\n echo {{b}}{{c}}{{d}}")
|
||||||
.run(&["a"], &Default::default()).unwrap_err() {
|
.run(no_cwd_err(), &["a"], &Default::default()).unwrap_err() {
|
||||||
ArgumentCountMismatch{recipe, found, min, max} => {
|
ArgumentCountMismatch{recipe, found, min, max} => {
|
||||||
assert_eq!(recipe, "a");
|
assert_eq!(recipe, "a");
|
||||||
assert_eq!(found, 0);
|
assert_eq!(found, 0);
|
||||||
@ -282,7 +291,7 @@ a return code:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_some_defaults() {
|
fn missing_some_defaults() {
|
||||||
match parse_success("a b c d='hello':").run(&["a", "b"], &Default::default()).unwrap_err() {
|
match parse_success("a b c d='hello':").run(no_cwd_err(), &["a", "b"], &Default::default()).unwrap_err() {
|
||||||
ArgumentCountMismatch{recipe, found, min, max} => {
|
ArgumentCountMismatch{recipe, found, min, max} => {
|
||||||
assert_eq!(recipe, "a");
|
assert_eq!(recipe, "a");
|
||||||
assert_eq!(found, 1);
|
assert_eq!(found, 1);
|
||||||
@ -295,7 +304,7 @@ a return code:
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_all_defaults() {
|
fn missing_all_defaults() {
|
||||||
match parse_success("a b c='r' d='h':").run(&["a"], &Default::default()).unwrap_err() {
|
match parse_success("a b c='r' d='h':").run(no_cwd_err(), &["a"], &Default::default()).unwrap_err() {
|
||||||
ArgumentCountMismatch{recipe, found, min, max} => {
|
ArgumentCountMismatch{recipe, found, min, max} => {
|
||||||
assert_eq!(recipe, "a");
|
assert_eq!(recipe, "a");
|
||||||
assert_eq!(found, 0);
|
assert_eq!(found, 0);
|
||||||
@ -312,7 +321,7 @@ a return code:
|
|||||||
configuration.overrides.insert("foo", "bar");
|
configuration.overrides.insert("foo", "bar");
|
||||||
configuration.overrides.insert("baz", "bob");
|
configuration.overrides.insert("baz", "bob");
|
||||||
match parse_success("a:\n echo {{`f() { return 100; }; f`}}")
|
match parse_success("a:\n echo {{`f() { return 100; }; f`}}")
|
||||||
.run(&["a"], &configuration).unwrap_err() {
|
.run(no_cwd_err(), &["a"], &configuration).unwrap_err() {
|
||||||
UnknownOverrides{overrides} => {
|
UnknownOverrides{overrides} => {
|
||||||
assert_eq!(overrides, &["baz", "foo"]);
|
assert_eq!(overrides, &["baz", "foo"]);
|
||||||
},
|
},
|
||||||
@ -337,7 +346,7 @@ wut:
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
match parse_success(text).run(&["wut"], &configuration).unwrap_err() {
|
match parse_success(text).run(no_cwd_err(), &["wut"], &configuration).unwrap_err() {
|
||||||
Code{code: _, line_number, recipe} => {
|
Code{code: _, line_number, recipe} => {
|
||||||
assert_eq!(recipe, "wut");
|
assert_eq!(recipe, "wut");
|
||||||
assert_eq!(line_number, Some(8));
|
assert_eq!(line_number, Some(8));
|
||||||
|
@ -15,8 +15,12 @@ pub trait PlatformInterface {
|
|||||||
|
|
||||||
/// Extract the signal from a process exit status, if it was terminated by a signal
|
/// Extract the signal from a process exit status, if it was terminated by a signal
|
||||||
fn signal_from_exit_status(exit_status: process::ExitStatus) -> Option<i32>;
|
fn signal_from_exit_status(exit_status: process::ExitStatus) -> Option<i32>;
|
||||||
|
|
||||||
|
/// Translate a path from a "native" path to a path the interpreter expects
|
||||||
|
fn to_shell_path(path: &Path) -> Result<String, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
impl PlatformInterface for Platform {
|
impl PlatformInterface for Platform {
|
||||||
fn make_shebang_command(path: &Path, _command: &str, _argument: Option<&str>)
|
fn make_shebang_command(path: &Path, _command: &str, _argument: Option<&str>)
|
||||||
@ -44,6 +48,12 @@ impl PlatformInterface for Platform {
|
|||||||
use std::os::unix::process::ExitStatusExt;
|
use std::os::unix::process::ExitStatusExt;
|
||||||
exit_status.signal()
|
exit_status.signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_shell_path(path: &Path) -> Result<String, String> {
|
||||||
|
path.to_str().map(str::to_string)
|
||||||
|
.ok_or_else(|| String::from(
|
||||||
|
"Error getting current directory: unicode decode error"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -75,4 +85,12 @@ impl PlatformInterface for Platform {
|
|||||||
// from a windows process exit status, so just return None
|
// from a windows process exit status, so just return None
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_shell_path(path: &Path) -> Result<String, String> {
|
||||||
|
// Translate path from windows style to unix style
|
||||||
|
let mut cygpath = Command::new("cygpath");
|
||||||
|
cygpath.arg("--unix");
|
||||||
|
cygpath.arg(path);
|
||||||
|
brev::output(cygpath).map_err(|e| format!("Error converting shell path: {}", e))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process::{ExitStatus, Command, Stdio};
|
use std::process::{ExitStatus, Command, Stdio};
|
||||||
|
|
||||||
use platform::{Platform, PlatformInterface};
|
use platform::{Platform, PlatformInterface};
|
||||||
@ -50,6 +51,7 @@ impl<'a> Recipe<'a> {
|
|||||||
|
|
||||||
pub fn run(
|
pub fn run(
|
||||||
&self,
|
&self,
|
||||||
|
invocation_directory: &Result<PathBuf, String>,
|
||||||
arguments: &[&'a str],
|
arguments: &[&'a str],
|
||||||
scope: &Map<&'a str, String>,
|
scope: &Map<&'a str, String>,
|
||||||
dotenv: &Map<String, String>,
|
dotenv: &Map<String, String>,
|
||||||
@ -86,6 +88,7 @@ impl<'a> Recipe<'a> {
|
|||||||
|
|
||||||
let mut evaluator = AssignmentEvaluator {
|
let mut evaluator = AssignmentEvaluator {
|
||||||
assignments: &empty(),
|
assignments: &empty(),
|
||||||
|
invocation_directory,
|
||||||
dry_run: configuration.dry_run,
|
dry_run: configuration.dry_run,
|
||||||
evaluated: empty(),
|
evaluated: empty(),
|
||||||
overrides: &empty(),
|
overrides: &empty(),
|
||||||
|
@ -47,6 +47,9 @@ pub fn run() {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
enable_ansi_support().ok();
|
enable_ansi_support().ok();
|
||||||
|
|
||||||
|
let invocation_directory = env::current_dir()
|
||||||
|
.map_err(|e| format!("Error getting current directory: {}", e));
|
||||||
|
|
||||||
let matches = App::new(env!("CARGO_PKG_NAME"))
|
let matches = App::new(env!("CARGO_PKG_NAME"))
|
||||||
.version(concat!("v", env!("CARGO_PKG_VERSION")))
|
.version(concat!("v", env!("CARGO_PKG_VERSION")))
|
||||||
.author(env!("CARGO_PKG_AUTHORS"))
|
.author(env!("CARGO_PKG_AUTHORS"))
|
||||||
@ -354,7 +357,11 @@ pub fn run() {
|
|||||||
overrides,
|
overrides,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(run_error) = justfile.run(&arguments, &configuration) {
|
if let Err(run_error) = justfile.run(
|
||||||
|
invocation_directory,
|
||||||
|
&arguments,
|
||||||
|
&configuration)
|
||||||
|
{
|
||||||
if !configuration.quiet {
|
if !configuration.quiet {
|
||||||
if color.stderr().active() {
|
if color.stderr().active() {
|
||||||
eprintln!("{:#}", run_error);
|
eprintln!("{:#}", run_error);
|
||||||
|
77
tests/invocation_directory.rs
Normal file
77
tests/invocation_directory.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
extern crate brev;
|
||||||
|
extern crate executable_path;
|
||||||
|
extern crate libc;
|
||||||
|
extern crate target;
|
||||||
|
extern crate tempdir;
|
||||||
|
|
||||||
|
use executable_path::executable_path;
|
||||||
|
use std::process;
|
||||||
|
use std::str;
|
||||||
|
use std::path::Path;
|
||||||
|
use tempdir::TempDir;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn to_shell_path(path: &Path) -> String {
|
||||||
|
use std::fs;
|
||||||
|
fs::canonicalize(path).expect("canonicalize failed")
|
||||||
|
.to_str().map(str::to_string).expect("unicode decode failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn to_shell_path(path: &Path) -> String {
|
||||||
|
// Translate path from windows style to unix style
|
||||||
|
let mut cygpath = process::Command::new("cygpath");
|
||||||
|
cygpath.arg("--unix");
|
||||||
|
cygpath.arg(path);
|
||||||
|
brev::output(cygpath).expect("converting cygwin path failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invocation_directory() {
|
||||||
|
let tmp = TempDir::new("just-integration")
|
||||||
|
.unwrap_or_else(
|
||||||
|
|err| panic!("integration test: failed to create temporary directory: {}", err));
|
||||||
|
|
||||||
|
let mut justfile_path = tmp.path().to_path_buf();
|
||||||
|
justfile_path.push("justfile");
|
||||||
|
brev::dump(justfile_path, "default:\n @cd {{invocation_directory()}}\n @echo {{invocation_directory()}}");
|
||||||
|
|
||||||
|
let mut subdir = tmp.path().to_path_buf();
|
||||||
|
subdir.push("subdir");
|
||||||
|
brev::mkdir(&subdir);
|
||||||
|
|
||||||
|
let output = process::Command::new(&executable_path("just"))
|
||||||
|
.current_dir(&subdir)
|
||||||
|
.args(&["--shell", "sh"])
|
||||||
|
.output()
|
||||||
|
.expect("just invocation failed");
|
||||||
|
|
||||||
|
let mut failure = false;
|
||||||
|
|
||||||
|
let expected_status = 0;
|
||||||
|
let expected_stdout =
|
||||||
|
to_shell_path(&subdir) + "\n";
|
||||||
|
let expected_stderr = "";
|
||||||
|
|
||||||
|
let status = output.status.code().unwrap();
|
||||||
|
if status != expected_status {
|
||||||
|
println!("bad status: {} != {}", status, expected_status);
|
||||||
|
failure = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stdout = str::from_utf8(&output.stdout).unwrap();
|
||||||
|
if stdout != expected_stdout {
|
||||||
|
println!("bad stdout:\ngot:\n{:?}\n\nexpected:\n{:?}", stdout, expected_stdout);
|
||||||
|
failure = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stderr = str::from_utf8(&output.stderr).unwrap();
|
||||||
|
if stderr != expected_stderr {
|
||||||
|
println!("bad stderr:\ngot:\n{:?}\n\nexpected:\n{:?}", stderr, expected_stderr);
|
||||||
|
failure = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if failure {
|
||||||
|
panic!("test failed");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user