Add justfile_directory() and justfile() (#569)

Add `justfile()` function, returning the current justfile, and
`justfile_directory(), returning its parent directory.
This commit is contained in:
Casey Rodarmor 2019-12-25 06:12:06 -08:00 committed by GitHub
parent eeb603160a
commit 61ab53dbc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 109 additions and 70 deletions

View File

@ -402,13 +402,11 @@ impl Config {
match &self.subcommand {
Dump => self.dump(justfile),
Evaluate { overrides } => {
self.run(justfile, &search.working_directory, overrides, &Vec::new())
}
Evaluate { overrides } => self.run(justfile, &search, overrides, &Vec::new()),
Run {
arguments,
overrides,
} => self.run(justfile, &search.working_directory, overrides, arguments),
} => self.run(justfile, &search, overrides, arguments),
List => self.list(justfile),
Show { ref name } => self.show(&name, justfile),
Summary => self.summary(justfile),
@ -561,7 +559,7 @@ impl Config {
fn run(
&self,
justfile: Justfile,
working_directory: &Path,
search: &Search,
overrides: &BTreeMap<String, String>,
arguments: &[String],
) -> Result<(), i32> {
@ -569,7 +567,7 @@ impl Config {
warn!("Failed to set CTRL-C handler: {}", error)
}
let result = justfile.run(&self, working_directory, overrides, arguments);
let result = justfile.run(&self, search, overrides, arguments);
if !self.quiet {
result.eprint(self.color)

View File

@ -6,7 +6,7 @@ pub(crate) struct Evaluator<'src: 'run, 'run> {
dotenv: &'run BTreeMap<String, String>,
scope: Scope<'src, 'run>,
settings: &'run Settings<'run>,
working_directory: &'run Path,
search: &'run Search,
}
impl<'src, 'run> Evaluator<'src, 'run> {
@ -16,7 +16,7 @@ impl<'src, 'run> Evaluator<'src, 'run> {
dotenv: &'run BTreeMap<String, String>,
overrides: Scope<'src, 'run>,
settings: &'run Settings<'run>,
working_directory: &'run Path,
search: &'run Search,
) -> RunResult<'src, Scope<'src, 'run>> {
let mut evaluator = Evaluator {
scope: overrides,
@ -24,7 +24,7 @@ impl<'src, 'run> Evaluator<'src, 'run> {
config,
dotenv,
settings,
working_directory,
search,
};
for assignment in assignments.values() {
@ -67,9 +67,9 @@ impl<'src, 'run> Evaluator<'src, 'run> {
}
Expression::Call { thunk } => {
let context = FunctionContext {
invocation_directory: &self.config.invocation_directory,
working_directory: &self.working_directory,
dotenv: self.dotenv,
invocation_directory: &self.config.invocation_directory,
search: self.search,
};
use Thunk::*;
@ -127,7 +127,7 @@ impl<'src, 'run> Evaluator<'src, 'run> {
cmd.arg(raw);
cmd.current_dir(self.working_directory);
cmd.current_dir(&self.search.working_directory);
cmd.export(self.dotenv, &self.scope);
@ -167,15 +167,15 @@ impl<'src, 'run> Evaluator<'src, 'run> {
arguments: &[&str],
scope: &'run Scope<'src, 'run>,
settings: &'run Settings,
working_directory: &'run Path,
search: &'run Search,
) -> RunResult<'src, Scope<'src, 'run>> {
let mut evaluator = Evaluator {
assignments: None,
scope: Scope::child(scope),
search,
settings,
dotenv,
config,
working_directory,
};
let mut scope = Scope::child(scope);
@ -211,15 +211,15 @@ impl<'src, 'run> Evaluator<'src, 'run> {
dotenv: &'run BTreeMap<String, String>,
scope: &'run Scope<'src, 'run>,
settings: &'run Settings,
working_directory: &'run Path,
search: &'run Search,
) -> Evaluator<'src, 'run> {
Evaluator {
assignments: None,
scope: Scope::child(scope),
search,
settings,
dotenv,
config,
working_directory,
}
}
}

View File

@ -1,6 +1,7 @@
use crate::common::*;
use target;
use Function::*;
pub(crate) enum Function {
Nullary(fn(&FunctionContext) -> Result<String, String>),
@ -10,15 +11,14 @@ pub(crate) enum Function {
lazy_static! {
pub(crate) static ref TABLE: BTreeMap<&'static str, Function> = vec![
("arch", Function::Nullary(arch)),
("os", Function::Nullary(os)),
("os_family", Function::Nullary(os_family)),
("env_var", Function::Unary(env_var)),
("env_var_or_default", Function::Binary(env_var_or_default)),
(
"invocation_directory",
Function::Nullary(invocation_directory)
),
("arch", Nullary(arch)),
("os", Nullary(os)),
("os_family", Nullary(os_family)),
("justfile_directory", Nullary(justfile_directory)),
("justfile", Nullary(justfile)),
("invocation_directory", Nullary(invocation_directory)),
("env_var", Unary(env_var)),
("env_var_or_default", Binary(env_var_or_default)),
]
.into_iter()
.collect();
@ -26,7 +26,6 @@ lazy_static! {
impl Function {
pub(crate) fn argc(&self) -> usize {
use self::Function::*;
match *self {
Nullary(_) => 0,
Unary(_) => 1,
@ -48,8 +47,44 @@ fn os_family(_context: &FunctionContext) -> Result<String, String> {
}
fn invocation_directory(context: &FunctionContext) -> Result<String, String> {
Platform::to_shell_path(context.working_directory, context.invocation_directory)
.map_err(|e| format!("Error getting shell path: {}", e))
Platform::to_shell_path(
&context.search.working_directory,
context.invocation_directory,
)
.map_err(|e| format!("Error getting shell path: {}", e))
}
fn justfile(context: &FunctionContext) -> Result<String, String> {
context
.search
.justfile
.to_str()
.map(str::to_owned)
.ok_or_else(|| {
format!(
"Justfile path is not valid unicode: {}",
context.search.justfile.to_string_lossy()
)
})
}
fn justfile_directory(context: &FunctionContext) -> Result<String, String> {
let justfile_directory = context.search.justfile.parent().ok_or_else(|| {
format!(
"Could not resolve justfile directory. Justfile `{}` had no parent.",
context.search.justfile.display()
)
})?;
justfile_directory
.to_str()
.map(str::to_owned)
.ok_or_else(|| {
format!(
"Justfile directory is not valid unicode: {}",
justfile_directory.to_string_lossy()
)
})
}
fn env_var(context: &FunctionContext, key: &str) -> Result<String, String> {

View File

@ -1,7 +1,7 @@
use crate::common::*;
pub(crate) struct FunctionContext<'run> {
pub(crate) invocation_directory: &'run Path,
pub(crate) working_directory: &'run Path,
pub(crate) dotenv: &'run BTreeMap<String, String>,
pub(crate) invocation_directory: &'run Path,
pub(crate) search: &'run Search,
}

View File

@ -43,13 +43,13 @@ impl<'src> Justfile<'src> {
None
}
pub(crate) fn run(
&'src self,
config: &'src Config,
working_directory: &'src Path,
overrides: &'src BTreeMap<String, String>,
arguments: &'src [String],
) -> RunResult<'src, ()> {
pub(crate) fn run<'run>(
&'run self,
config: &'run Config,
search: &'run Search,
overrides: &'run BTreeMap<String, String>,
arguments: &'run [String],
) -> RunResult<'run, ()> {
let argvec: Vec<&str> = if !arguments.is_empty() {
arguments.iter().map(|argument| argument.as_str()).collect()
} else if let Some(recipe) = self.first() {
@ -105,7 +105,7 @@ impl<'src> Justfile<'src> {
&dotenv,
scope,
&self.settings,
working_directory,
search,
)?
};
@ -172,12 +172,12 @@ impl<'src> Justfile<'src> {
settings: &self.settings,
config,
scope,
working_directory,
search,
};
let mut ran = BTreeSet::new();
for (recipe, arguments) in grouped {
self.run_recipe(&context, recipe, arguments, &dotenv, &mut ran)?
self.run_recipe(&context, recipe, arguments, &dotenv, &search, &mut ran)?
}
Ok(())
@ -203,6 +203,7 @@ impl<'src> Justfile<'src> {
recipe: &Recipe<'src>,
arguments: &[&'run str],
dotenv: &BTreeMap<String, String>,
search: &'run Search,
ran: &mut BTreeSet<Vec<String>>,
) -> RunResult<'src, ()> {
let scope = Evaluator::evaluate_parameters(
@ -212,16 +213,11 @@ impl<'src> Justfile<'src> {
arguments,
&context.scope,
context.settings,
context.working_directory,
search,
)?;
let mut evaluator = Evaluator::recipe_evaluator(
context.config,
dotenv,
&scope,
context.settings,
context.working_directory,
);
let mut evaluator =
Evaluator::recipe_evaluator(context.config, dotenv, &scope, context.settings, search);
for Dependency { recipe, arguments } in &recipe.dependencies {
let mut invocation = vec![recipe.name().to_owned()];
@ -236,11 +232,11 @@ impl<'src> Justfile<'src> {
.skip(1)
.map(String::as_ref)
.collect::<Vec<&str>>();
self.run_recipe(context, recipe, &arguments, dotenv, ran)?;
self.run_recipe(context, recipe, &arguments, dotenv, search, ran)?;
}
}
recipe.run(context, dotenv, scope)?;
recipe.run(context, dotenv, scope, search)?;
let mut invocation = Vec::new();
invocation.push(recipe.name().to_owned());

View File

@ -69,6 +69,7 @@ impl<'src, D> Recipe<'src, D> {
context: &RecipeContext<'src, 'run>,
dotenv: &BTreeMap<String, String>,
scope: Scope<'src, 'run>,
search: &'run Search,
) -> RunResult<'src, ()> {
let config = &context.config;
@ -82,13 +83,8 @@ impl<'src, D> Recipe<'src, D> {
);
}
let mut evaluator = Evaluator::recipe_evaluator(
context.config,
dotenv,
&scope,
context.settings,
context.working_directory,
);
let mut evaluator =
Evaluator::recipe_evaluator(context.config, dotenv, &scope, context.settings, search);
if self.shebang {
let mut evaluated_lines = vec![];
@ -166,12 +162,16 @@ impl<'src, D> Recipe<'src, D> {
})?;
// create a command to run the script
let mut command =
Platform::make_shebang_command(&path, context.working_directory, interpreter, argument)
.map_err(|output_error| RuntimeError::Cygpath {
recipe: self.name(),
output_error,
})?;
let mut command = Platform::make_shebang_command(
&path,
&context.search.working_directory,
interpreter,
argument,
)
.map_err(|output_error| RuntimeError::Cygpath {
recipe: self.name(),
output_error,
})?;
command.export(dotenv, &scope);
@ -248,7 +248,7 @@ impl<'src, D> Recipe<'src, D> {
let mut cmd = context.settings.shell_command(config);
cmd.current_dir(context.working_directory);
cmd.current_dir(&context.search.working_directory);
cmd.arg(command);

View File

@ -3,6 +3,6 @@ use crate::common::*;
pub(crate) struct RecipeContext<'src: 'run, 'run> {
pub(crate) config: &'run Config,
pub(crate) scope: Scope<'src, 'run>,
pub(crate) working_directory: &'run Path,
pub(crate) search: &'run Search,
pub(crate) settings: &'run Settings<'src>,
}

View File

@ -2,7 +2,7 @@ use crate::common::*;
use std::path::Component;
const FILENAME: &str = "justfile";
pub(crate) const FILENAME: &str = "justfile";
const PROJECT_ROOT_CHILDREN: &[&str] = &[".bzr", ".git", ".hg", ".svn", "_darcs"];
pub(crate) struct Search {

View File

@ -20,6 +20,16 @@ pub(crate) fn config(args: &[&str]) -> Config {
Config::from_matches(&matches).unwrap()
}
pub(crate) fn search(config: &Config) -> Search {
let working_directory = config.invocation_directory.clone();
let justfile = working_directory.join(crate::search::FILENAME);
Search {
working_directory,
justfile,
}
}
pub(crate) use test_utilities::{tempdir, unindent};
macro_rules! analysis_error {
@ -80,15 +90,15 @@ macro_rules! run_error {
} => {
#[test]
fn $name() {
let config = &$crate::testing::config(&$args);
let current_dir = std::env::current_dir().unwrap();
let config = $crate::testing::config(&$args);
let search = $crate::testing::search(&config);
if let Subcommand::Run{ overrides, arguments } = &config.subcommand {
match $crate::compiler::Compiler::compile(&$crate::testing::unindent($src))
.expect("Expected successful compilation")
.run(
config,
&current_dir,
&config,
&search,
&overrides,
&arguments,
).expect_err("Expected runtime error") {