Skip to content

Commit 23a53fb

Browse files
authored
Add working-directory setting (#2283)
1 parent b70546a commit 23a53fb

File tree

11 files changed

+165
-14
lines changed

11 files changed

+165
-14
lines changed

GRAMMAR.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ setting : 'allow-duplicate-recipes' boolean?
8080
| 'unstable' boolean?
8181
| 'windows-powershell' boolean?
8282
| 'windows-shell' ':=' string_list
83+
| 'working-directory' ':=' string
8384
8485
boolean : ':=' ('true' | 'false')
8586

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,7 @@ foo:
824824
| `unstable`<sup>1.31.0</sup> | boolean | `false` | Enable unstable features. |
825825
| `windows-powershell` | boolean | `false` | Use PowerShell on Windows as default shell. (Deprecated. Use `windows-shell` instead. |
826826
| `windows-shell` | `[COMMAND, ARGS…]` | - | Set the command used to invoke recipes and evaluate backticks. |
827+
| `working-directory`<sup>master</sup> | string | - | Set the working directory for recipes and backticks, relative to the default working directory. |
827828

828829
Boolean settings can be written as:
829830

src/evaluator.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,17 @@ impl<'src, 'run> Evaluator<'src, 'run> {
239239
let mut cmd = self.context.settings.shell_command(self.context.config);
240240
cmd.arg(command);
241241
cmd.args(args);
242-
cmd.current_dir(&self.context.search.working_directory);
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+
};
243253
cmd.export(
244254
self.context.settings,
245255
self.context.dotenv,

src/keyword.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub(crate) enum Keyword {
3030
Unstable,
3131
WindowsPowershell,
3232
WindowsShell,
33+
WorkingDirectory,
3334
X,
3435
}
3536

src/node.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,10 @@ impl<'src> Node<'src> for Set<'src> {
307307
set.push_mut(Tree::string(&argument.cooked));
308308
}
309309
}
310-
Setting::DotenvFilename(value) | Setting::DotenvPath(value) | Setting::Tempdir(value) => {
310+
Setting::DotenvFilename(value)
311+
| Setting::DotenvPath(value)
312+
| Setting::Tempdir(value)
313+
| Setting::WorkingDirectory(value) => {
311314
set.push_mut(Tree::string(&value.cooked));
312315
}
313316
}

src/parser.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,7 @@ impl<'run, 'src> Parser<'run, 'src> {
967967
Keyword::Shell => Some(Setting::Shell(self.parse_interpreter()?)),
968968
Keyword::Tempdir => Some(Setting::Tempdir(self.parse_string_literal()?)),
969969
Keyword::WindowsShell => Some(Setting::WindowsShell(self.parse_interpreter()?)),
970+
Keyword::WorkingDirectory => Some(Setting::WorkingDirectory(self.parse_string_literal()?)),
970971
_ => None,
971972
};
972973

@@ -2146,6 +2147,12 @@ mod tests {
21462147
tree: (justfile (set windows_powershell false)),
21472148
}
21482149

2150+
test! {
2151+
name: set_working_directory,
2152+
text: "set working-directory := 'foo'",
2153+
tree: (justfile (set working_directory "foo")),
2154+
}
2155+
21492156
test! {
21502157
name: conditional,
21512158
text: "a := if b == c { d } else { e }",

src/recipe.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,21 @@ impl<'src, D> Recipe<'src, D> {
136136
!self.attributes.contains(&Attribute::NoExitMessage)
137137
}
138138

139-
fn working_directory<'a>(&'a self, search: &'a Search) -> Option<&Path> {
140-
if self.change_directory() {
141-
Some(if self.submodule_depth > 0 {
142-
&self.working_directory
143-
} else {
144-
&search.working_directory
145-
})
139+
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
146+
} else {
147+
&context.search.working_directory
148+
};
149+
150+
if let Some(setting) = &context.settings.working_directory {
151+
Some(base.join(setting))
146152
} else {
147-
None
153+
Some(base.into())
148154
}
149155
}
150156

@@ -265,7 +271,7 @@ impl<'src, D> Recipe<'src, D> {
265271

266272
let mut cmd = context.settings.shell_command(config);
267273

268-
if let Some(working_directory) = self.working_directory(context.search) {
274+
if let Some(working_directory) = self.working_directory(context) {
269275
cmd.current_dir(working_directory);
270276
}
271277

@@ -408,8 +414,11 @@ impl<'src, D> Recipe<'src, D> {
408414
io_error: error,
409415
})?;
410416

411-
let mut command =
412-
executor.command(&path, self.name(), self.working_directory(context.search))?;
417+
let mut command = executor.command(
418+
&path,
419+
self.name(),
420+
self.working_directory(context).as_deref(),
421+
)?;
413422

414423
if self.takes_positional_arguments(context.settings) {
415424
command.args(positional);

src/setting.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub(crate) enum Setting<'src> {
1919
Unstable(bool),
2020
WindowsPowerShell(bool),
2121
WindowsShell(Interpreter<'src>),
22+
WorkingDirectory(StringLiteral<'src>),
2223
}
2324

2425
impl<'src> Display for Setting<'src> {
@@ -38,7 +39,10 @@ impl<'src> Display for Setting<'src> {
3839
Self::ScriptInterpreter(shell) | Self::Shell(shell) | Self::WindowsShell(shell) => {
3940
write!(f, "[{shell}]")
4041
}
41-
Self::DotenvFilename(value) | Self::DotenvPath(value) | Self::Tempdir(value) => {
42+
Self::DotenvFilename(value)
43+
| Self::DotenvPath(value)
44+
| Self::Tempdir(value)
45+
| Self::WorkingDirectory(value) => {
4246
write!(f, "{value}")
4347
}
4448
}

src/settings.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub(crate) struct Settings<'src> {
2525
pub(crate) unstable: bool,
2626
pub(crate) windows_powershell: bool,
2727
pub(crate) windows_shell: Option<Interpreter<'src>>,
28+
pub(crate) working_directory: Option<PathBuf>,
2829
}
2930

3031
impl<'src> Settings<'src> {
@@ -84,6 +85,9 @@ impl<'src> Settings<'src> {
8485
Setting::Tempdir(tempdir) => {
8586
settings.tempdir = Some(tempdir.cooked);
8687
}
88+
Setting::WorkingDirectory(working_directory) => {
89+
settings.working_directory = Some(working_directory.cooked.into());
90+
}
8791
}
8892
}
8993

tests/json.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ fn alias() {
6262
"unstable": false,
6363
"windows_powershell": false,
6464
"windows_shell": null,
65+
"working_directory" : null,
6566
},
6667
"unexports": [],
6768
"warnings": [],
@@ -105,6 +106,7 @@ fn assignment() {
105106
"unstable": false,
106107
"windows_powershell": false,
107108
"windows_shell": null,
109+
"working_directory" : null,
108110
},
109111
"unexports": [],
110112
"warnings": [],
@@ -162,6 +164,7 @@ fn body() {
162164
"unstable": false,
163165
"windows_powershell": false,
164166
"windows_shell": null,
167+
"working_directory" : null,
165168
},
166169
"unexports": [],
167170
"warnings": [],
@@ -231,6 +234,7 @@ fn dependencies() {
231234
"unstable": false,
232235
"windows_powershell": false,
233236
"windows_shell": null,
237+
"working_directory" : null,
234238
},
235239
"unexports": [],
236240
"warnings": [],
@@ -338,6 +342,7 @@ fn dependency_argument() {
338342
"unstable": false,
339343
"windows_powershell": false,
340344
"windows_shell": null,
345+
"working_directory" : null,
341346
},
342347
"unexports": [],
343348
"warnings": [],
@@ -407,6 +412,7 @@ fn duplicate_recipes() {
407412
"unstable": false,
408413
"windows_powershell": false,
409414
"windows_shell": null,
415+
"working_directory" : null,
410416
},
411417
"unexports": [],
412418
"warnings": [],
@@ -454,6 +460,7 @@ fn duplicate_variables() {
454460
"unstable": false,
455461
"windows_powershell": false,
456462
"windows_shell": null,
463+
"working_directory" : null,
457464
},
458465
"unexports": [],
459466
"warnings": [],
@@ -504,6 +511,7 @@ fn doc_comment() {
504511
"unstable": false,
505512
"windows_powershell": false,
506513
"windows_shell": null,
514+
"working_directory" : null,
507515
},
508516
"unexports": [],
509517
"warnings": [],
@@ -540,6 +548,7 @@ fn empty_justfile() {
540548
"unstable": false,
541549
"windows_powershell": false,
542550
"windows_shell": null,
551+
"working_directory" : null,
543552
},
544553
"unexports": [],
545554
"warnings": [],
@@ -697,6 +706,7 @@ fn parameters() {
697706
"unstable": false,
698707
"windows_powershell": false,
699708
"windows_shell": null,
709+
"working_directory" : null,
700710
},
701711
"unexports": [],
702712
"warnings": [],
@@ -787,6 +797,7 @@ fn priors() {
787797
"unstable": false,
788798
"windows_powershell": false,
789799
"windows_shell": null,
800+
"working_directory" : null,
790801
},
791802
"unexports": [],
792803
"warnings": [],
@@ -837,6 +848,7 @@ fn private() {
837848
"unstable": false,
838849
"windows_powershell": false,
839850
"windows_shell": null,
851+
"working_directory" : null,
840852
},
841853
"unexports": [],
842854
"warnings": [],
@@ -887,6 +899,7 @@ fn quiet() {
887899
"unstable": false,
888900
"windows_powershell": false,
889901
"windows_shell": null,
902+
"working_directory" : null,
890903
},
891904
"unexports": [],
892905
"warnings": [],
@@ -952,6 +965,7 @@ fn settings() {
952965
"unstable": false,
953966
"windows_powershell": false,
954967
"windows_shell": null,
968+
"working_directory" : null,
955969
},
956970
"unexports": [],
957971
"warnings": [],
@@ -1005,6 +1019,7 @@ fn shebang() {
10051019
"unstable": false,
10061020
"windows_powershell": false,
10071021
"windows_shell": null,
1022+
"working_directory" : null,
10081023
},
10091024
"unexports": [],
10101025
"warnings": [],
@@ -1055,6 +1070,7 @@ fn simple() {
10551070
"unstable": false,
10561071
"windows_powershell": false,
10571072
"windows_shell": null,
1073+
"working_directory" : null,
10581074
},
10591075
"unexports": [],
10601076
"warnings": [],
@@ -1108,6 +1124,7 @@ fn attribute() {
11081124
"ignore_comments": false,
11091125
"windows_powershell": false,
11101126
"windows_shell": null,
1127+
"working_directory" : null,
11111128
},
11121129
"unexports": [],
11131130
"warnings": [],
@@ -1176,6 +1193,7 @@ fn module() {
11761193
"ignore_comments": false,
11771194
"windows_powershell": false,
11781195
"windows_shell": null,
1196+
"working_directory" : null,
11791197
},
11801198
"unexports": [],
11811199
"warnings": [],
@@ -1199,6 +1217,7 @@ fn module() {
11991217
"ignore_comments": false,
12001218
"windows_powershell": false,
12011219
"windows_shell": null,
1220+
"working_directory" : null,
12021221
},
12031222
"unexports": [],
12041223
"warnings": [],
@@ -1269,6 +1288,7 @@ fn module_group() {
12691288
"ignore_comments": false,
12701289
"windows_powershell": false,
12711290
"windows_shell": null,
1291+
"working_directory" : null,
12721292
},
12731293
"unexports": [],
12741294
"warnings": [],
@@ -1292,6 +1312,7 @@ fn module_group() {
12921312
"ignore_comments": false,
12931313
"windows_powershell": false,
12941314
"windows_shell": null,
1315+
"working_directory" : null,
12951316
},
12961317
"unexports": [],
12971318
"warnings": [],

0 commit comments

Comments
 (0)