Skip to content

Commit 7025c2d

Browse files
authored
Use correct backtick and shell() expression working directory in submodules (#2285)
1 parent 23a53fb commit 7025c2d

13 files changed

+130
-79
lines changed

src/analyzer.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ impl<'src> Analyzer<'src> {
3535
let mut assignments = Vec::new();
3636

3737
let mut stack = Vec::new();
38-
stack.push(asts.get(root).unwrap());
38+
let ast = asts.get(root).unwrap();
39+
stack.push(ast);
3940

4041
let mut warnings = Vec::new();
4142

@@ -232,6 +233,7 @@ impl<'src> Analyzer<'src> {
232233
unexports,
233234
unstable_features,
234235
warnings,
236+
working_directory: ast.working_directory.clone(),
235237
})
236238
}
237239

src/ast.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ use super::*;
55
/// are performed by the `Analyzer`, which produces a `Justfile` from an `Ast`.
66
#[derive(Debug, Clone)]
77
pub(crate) struct Ast<'src> {
8-
/// Items in the justfile
98
pub(crate) items: Vec<Item<'src>>,
10-
/// Non-fatal warnings encountered during parsing
119
pub(crate) warnings: Vec<Warning>,
10+
pub(crate) working_directory: PathBuf,
1211
}
1312

1413
impl<'src> Display for Ast<'src> {

src/compiler.rs

-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ impl Compiler {
2424
&current.path,
2525
&current.import_offsets,
2626
&current.namepath,
27-
current.submodule_depth,
2827
&tokens,
2928
&current.working_directory,
3029
)?;
@@ -220,7 +219,6 @@ impl Compiler {
220219
&PathBuf::new(),
221220
&[],
222221
&Namepath::default(),
223-
0,
224222
&tokens,
225223
&PathBuf::new(),
226224
)?;

src/evaluator.rs

+9-17
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@ impl<'src, 'run> Evaluator<'src, 'run> {
2222
let context = ExecutionContext {
2323
config,
2424
dotenv,
25-
module_source: &module.source,
25+
module,
2626
scope: parent,
2727
search,
28-
settings: &module.settings,
29-
unexports: &module.unexports,
3028
};
3129

3230
let mut scope = context.scope.child();
@@ -236,25 +234,19 @@ impl<'src, 'run> Evaluator<'src, 'run> {
236234
}
237235

238236
pub(crate) fn run_command(&self, command: &str, args: &[&str]) -> Result<String, OutputError> {
239-
let mut cmd = self.context.settings.shell_command(self.context.config);
237+
let mut cmd = self
238+
.context
239+
.module
240+
.settings
241+
.shell_command(self.context.config);
240242
cmd.arg(command);
241243
cmd.args(args);
242-
if let Some(working_directory) = &self.context.settings.working_directory {
243-
cmd.current_dir(
244-
self
245-
.context
246-
.search
247-
.working_directory
248-
.join(working_directory),
249-
)
250-
} else {
251-
cmd.current_dir(&self.context.search.working_directory)
252-
};
244+
cmd.current_dir(self.context.working_directory());
253245
cmd.export(
254-
self.context.settings,
246+
&self.context.module.settings,
255247
self.context.dotenv,
256248
&self.scope,
257-
self.context.unexports,
249+
&self.context.module.unexports,
258250
);
259251
cmd.stdin(Stdio::inherit());
260252
cmd.stderr(if self.context.config.verbosity.quiet() {

src/execution_context.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,23 @@ use super::*;
44
pub(crate) struct ExecutionContext<'src: 'run, 'run> {
55
pub(crate) config: &'run Config,
66
pub(crate) dotenv: &'run BTreeMap<String, String>,
7-
pub(crate) module_source: &'run Path,
7+
pub(crate) module: &'run Justfile<'src>,
88
pub(crate) scope: &'run Scope<'src, 'run>,
99
pub(crate) search: &'run Search,
10-
pub(crate) settings: &'run Settings<'src>,
11-
pub(crate) unexports: &'run HashSet<String>,
10+
}
11+
12+
impl<'src: 'run, 'run> ExecutionContext<'src, 'run> {
13+
pub(crate) fn working_directory(&self) -> PathBuf {
14+
let base = if self.module.is_submodule() {
15+
&self.module.working_directory
16+
} else {
17+
&self.search.working_directory
18+
};
19+
20+
if let Some(setting) = &self.module.settings.working_directory {
21+
base.join(setting)
22+
} else {
23+
base.into()
24+
}
25+
}
1226
}

src/function.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ fn module_directory(context: Context) -> FunctionResult {
458458
.justfile
459459
.parent()
460460
.unwrap()
461-
.join(context.evaluator.context.module_source)
461+
.join(&context.evaluator.context.module.source)
462462
.parent()
463463
.unwrap()
464464
.to_str()
@@ -469,7 +469,8 @@ fn module_directory(context: Context) -> FunctionResult {
469469
context
470470
.evaluator
471471
.context
472-
.module_source
472+
.module
473+
.source
473474
.parent()
474475
.unwrap()
475476
.display(),
@@ -485,13 +486,13 @@ fn module_file(context: Context) -> FunctionResult {
485486
.justfile
486487
.parent()
487488
.unwrap()
488-
.join(context.evaluator.context.module_source)
489+
.join(&context.evaluator.context.module.source)
489490
.to_str()
490491
.map(str::to_owned)
491492
.ok_or_else(|| {
492493
format!(
493494
"Module file path is not valid unicode: {}",
494-
context.evaluator.context.module_source.display(),
495+
context.evaluator.context.module.source.display(),
495496
)
496497
})
497498
}

src/justfile.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ use {super::*, serde::Serialize};
33
#[derive(Debug)]
44
struct Invocation<'src: 'run, 'run> {
55
arguments: Vec<&'run str>,
6-
module_source: &'run Path,
6+
module: &'run Justfile<'src>,
77
recipe: &'run Recipe<'src>,
88
scope: &'run Scope<'src, 'run>,
9-
settings: &'run Settings<'src>,
109
}
1110

1211
#[derive(Debug, PartialEq, Serialize)]
@@ -30,6 +29,8 @@ pub(crate) struct Justfile<'src> {
3029
#[serde(skip)]
3130
pub(crate) unstable_features: BTreeSet<UnstableFeature>,
3231
pub(crate) warnings: Vec<Warning>,
32+
#[serde(skip)]
33+
pub(crate) working_directory: PathBuf,
3334
}
3435

3536
impl<'src> Justfile<'src> {
@@ -204,11 +205,9 @@ impl<'src> Justfile<'src> {
204205
let context = ExecutionContext {
205206
config,
206207
dotenv: &dotenv,
207-
module_source: invocation.module_source,
208+
module: invocation.module,
208209
scope: invocation.scope,
209210
search,
210-
settings: invocation.settings,
211-
unexports: &self.unexports,
212211
};
213212

214213
Self::run_recipe(
@@ -267,10 +266,9 @@ impl<'src> Justfile<'src> {
267266
if position + 1 == path.len() {
268267
let recipe = self.get_recipe(&path[position]).unwrap();
269268
Ok(Invocation {
270-
recipe,
271-
module_source: &self.source,
272269
arguments: arguments.into(),
273-
settings: &self.settings,
270+
module: self,
271+
recipe,
274272
scope: parent,
275273
})
276274
} else {
@@ -306,6 +304,10 @@ impl<'src> Justfile<'src> {
306304
}
307305
}
308306

307+
pub(crate) fn is_submodule(&self) -> bool {
308+
self.name.is_some()
309+
}
310+
309311
pub(crate) fn name(&self) -> &'src str {
310312
self.name.map(|name| name.lexeme()).unwrap_or_default()
311313
}

src/parser.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ pub(crate) struct Parser<'run, 'src> {
3131
module_namepath: &'run Namepath<'src>,
3232
next_token: usize,
3333
recursion_depth: usize,
34-
submodule_depth: u32,
3534
tokens: &'run [Token<'src>],
3635
working_directory: &'run Path,
3736
}
@@ -43,7 +42,6 @@ impl<'run, 'src> Parser<'run, 'src> {
4342
file_path: &'run Path,
4443
import_offsets: &[usize],
4544
module_namepath: &'run Namepath<'src>,
46-
submodule_depth: u32,
4745
tokens: &'run [Token<'src>],
4846
working_directory: &'run Path,
4947
) -> CompileResult<'src, Ast<'src>> {
@@ -55,7 +53,6 @@ impl<'run, 'src> Parser<'run, 'src> {
5553
module_namepath,
5654
next_token: 0,
5755
recursion_depth: 0,
58-
submodule_depth,
5956
tokens,
6057
working_directory,
6158
}
@@ -446,8 +443,9 @@ impl<'run, 'src> Parser<'run, 'src> {
446443

447444
if self.next_token == self.tokens.len() {
448445
Ok(Ast {
449-
warnings: Vec::new(),
450446
items,
447+
warnings: Vec::new(),
448+
working_directory: self.working_directory.into(),
451449
})
452450
} else {
453451
Err(self.internal_error(format!(
@@ -838,8 +836,6 @@ impl<'run, 'src> Parser<'run, 'src> {
838836
priors,
839837
private: name.lexeme().starts_with('_'),
840838
quiet,
841-
submodule_depth: self.submodule_depth,
842-
working_directory: self.working_directory.into(),
843839
})
844840
}
845841

@@ -1089,7 +1085,6 @@ mod tests {
10891085
&PathBuf::new(),
10901086
&[],
10911087
&Namepath::default(),
1092-
0,
10931088
&tokens,
10941089
&PathBuf::new(),
10951090
)
@@ -1136,7 +1131,6 @@ mod tests {
11361131
&PathBuf::new(),
11371132
&[],
11381133
&Namepath::default(),
1139-
0,
11401134
&tokens,
11411135
&PathBuf::new(),
11421136
) {

src/recipe.rs

+23-27
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ pub(crate) struct Recipe<'src, D = Dependency<'src>> {
3636
pub(crate) private: bool,
3737
pub(crate) quiet: bool,
3838
pub(crate) shebang: bool,
39-
#[serde(skip)]
40-
pub(crate) submodule_depth: u32,
41-
#[serde(skip)]
42-
pub(crate) working_directory: PathBuf,
4339
}
4440

4541
impl<'src, D> Recipe<'src, D> {
@@ -137,20 +133,10 @@ impl<'src, D> Recipe<'src, D> {
137133
}
138134

139135
fn working_directory<'a>(&'a self, context: &'a ExecutionContext) -> Option<PathBuf> {
140-
if !self.change_directory() {
141-
return None;
142-
}
143-
144-
let base = if self.submodule_depth > 0 {
145-
&self.working_directory
136+
if self.change_directory() {
137+
Some(context.working_directory())
146138
} else {
147-
&context.search.working_directory
148-
};
149-
150-
if let Some(setting) = &context.settings.working_directory {
151-
Some(base.join(setting))
152-
} else {
153-
Some(base.into())
139+
None
154140
}
155141
}
156142

@@ -205,8 +191,8 @@ impl<'src, D> Recipe<'src, D> {
205191
let quiet_line = lines.peek().map_or(false, |line| line.is_quiet());
206192
let infallible_line = lines.peek().map_or(false, |line| line.is_infallible());
207193

208-
let comment_line =
209-
context.settings.ignore_comments && lines.peek().map_or(false, |line| line.is_comment());
194+
let comment_line = context.module.settings.ignore_comments
195+
&& lines.peek().map_or(false, |line| line.is_comment());
210196

211197
loop {
212198
if lines.peek().is_none() {
@@ -242,7 +228,7 @@ impl<'src, D> Recipe<'src, D> {
242228
if config.dry_run
243229
|| config.verbosity.loquacious()
244230
|| !((quiet_line ^ self.quiet)
245-
|| (context.settings.quiet && !self.no_quiet())
231+
|| (context.module.settings.quiet && !self.no_quiet())
246232
|| config.verbosity.quiet())
247233
{
248234
let color = config
@@ -269,15 +255,15 @@ impl<'src, D> Recipe<'src, D> {
269255
continue;
270256
}
271257

272-
let mut cmd = context.settings.shell_command(config);
258+
let mut cmd = context.module.settings.shell_command(config);
273259

274260
if let Some(working_directory) = self.working_directory(context) {
275261
cmd.current_dir(working_directory);
276262
}
277263

278264
cmd.arg(command);
279265

280-
if self.takes_positional_arguments(context.settings) {
266+
if self.takes_positional_arguments(&context.module.settings) {
281267
cmd.arg(self.name.lexeme());
282268
cmd.args(positional);
283269
}
@@ -287,7 +273,12 @@ impl<'src, D> Recipe<'src, D> {
287273
cmd.stdout(Stdio::null());
288274
}
289275

290-
cmd.export(context.settings, context.dotenv, scope, context.unexports);
276+
cmd.export(
277+
&context.module.settings,
278+
context.dotenv,
279+
scope,
280+
&context.module.unexports,
281+
);
291282

292283
match InterruptHandler::guard(|| cmd.status()) {
293284
Ok(exit_status) => {
@@ -356,7 +347,7 @@ impl<'src, D> Recipe<'src, D> {
356347
Executor::Command(
357348
interpreter
358349
.as_ref()
359-
.or(context.settings.script_interpreter.as_ref())
350+
.or(context.module.settings.script_interpreter.as_ref())
360351
.unwrap_or_else(|| Interpreter::default_script_interpreter()),
361352
)
362353
} else {
@@ -372,7 +363,7 @@ impl<'src, D> Recipe<'src, D> {
372363

373364
let mut tempdir_builder = tempfile::Builder::new();
374365
tempdir_builder.prefix("just-");
375-
let tempdir = match &context.settings.tempdir {
366+
let tempdir = match &context.module.settings.tempdir {
376367
Some(tempdir) => tempdir_builder.tempdir_in(context.search.working_directory.join(tempdir)),
377368
None => {
378369
if let Some(runtime_dir) = dirs::runtime_dir() {
@@ -420,11 +411,16 @@ impl<'src, D> Recipe<'src, D> {
420411
self.working_directory(context).as_deref(),
421412
)?;
422413

423-
if self.takes_positional_arguments(context.settings) {
414+
if self.takes_positional_arguments(&context.module.settings) {
424415
command.args(positional);
425416
}
426417

427-
command.export(context.settings, context.dotenv, scope, context.unexports);
418+
command.export(
419+
&context.module.settings,
420+
context.dotenv,
421+
scope,
422+
&context.module.unexports,
423+
);
428424

429425
// run it!
430426
match InterruptHandler::guard(|| command.status()) {

0 commit comments

Comments
 (0)