Read commands in the order they’re given, regardless of shell/cargo-ness (#177)

This commit is contained in:
Félix Saparelli 2022-01-22 17:32:45 +13:00 committed by GitHub
parent 00205380f9
commit 089122821d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 47 deletions

View File

@ -2,7 +2,7 @@ use clap::{App, AppSettings, Arg, ArgMatches, ErrorKind, SubCommand};
use std::{env, process};
pub fn parse() -> ArgMatches<'static> {
let footnote = "Cargo commands (-x) are always executed before shell commands (-s). You can use the `-- command` style instead, note you'll need to use full commands, it won't prefix `cargo` for you.\n\nBy default, your entire project is watched, except for the target/ and .git/ folders, and your .ignore and .gitignore files are used to filter paths.".to_owned();
let footnote = "You can use the `-- command` style instead, note you'll need to use full commands, it won't prefix `cargo` for you.\n\nBy default, your entire project is watched, except for the target/ and .git/ folders, and your .ignore and .gitignore files are used to filter paths.".to_owned();
#[cfg(windows)] let footnote = format!("{}\n\nOn Windows, patterns given to -i have forward slashes (/) automatically converted to backward ones (\\) to ease command portability.", footnote);

View File

@ -1,4 +1,4 @@
use std::{path::MAIN_SEPARATOR, time::Duration};
use std::{env, path::MAIN_SEPARATOR, time::Duration};
use clap::{value_t, values_t, ArgMatches};
use log::{debug, warn};
@ -15,51 +15,6 @@ pub fn set_commands(builder: &mut ConfigBuilder, matches: &ArgMatches) {
// and before the remaining arguments
let features = value_t!(matches, "features", String).ok();
// Cargo commands are in front of the rest
if matches.is_present("cmd:cargo") {
for cargo in values_t!(matches, "cmd:cargo", String).unwrap_or_else(|e| e.exit()) {
let mut cmd: String = "cargo ".into();
let cargo = cargo.trim_start();
// features are supported for the following
// (b)uild, bench, doc, (r)un, test, install
if let Some(features) = features.as_ref() {
if cargo.starts_with('b')
|| cargo.starts_with("check")
|| cargo.starts_with("doc")
|| cargo.starts_with('r')
|| cargo.starts_with("test")
|| cargo.starts_with("install")
{
// Split command into first word and the arguments
let word_boundary = cargo
.find(|c: char| c.is_whitespace())
.unwrap_or_else(|| cargo.len());
// Find returns the byte index, and split_at takes a byte offset.
// This means the splitting is unicode-safe.
let (subcommand, args) = cargo.split_at(word_boundary);
cmd.push_str(subcommand);
cmd.push_str(" --features ");
cmd.push_str(features);
cmd.push(' ');
cmd.push_str(args)
} else {
cmd.push_str(cargo);
}
} else {
cmd.push_str(cargo);
}
commands.push(cmd);
}
}
// Shell commands go last
if matches.is_present("cmd:shell") {
for shell in values_t!(matches, "cmd:shell", String).unwrap_or_else(|e| e.exit()) {
commands.push(shell);
}
}
if matches.is_present("cmd:trail") {
debug!("trailing command is present, ignore all other command options");
commands = vec![values_t!(matches, "cmd:trail", String)
@ -68,6 +23,46 @@ pub fn set_commands(builder: &mut ConfigBuilder, matches: &ArgMatches) {
.map(|arg| shell_escape::escape(arg.into()))
.collect::<Vec<_>>()
.join(" ")];
} else {
let command_order = env::args().filter_map(|arg| match arg.as_str() {
"-x" | "--exec" => Some("cargo"),
"-s" | "--shell" => Some("shell"),
_ => None,
});
let mut cargos = if matches.is_present("cmd:cargo") {
values_t!(matches, "cmd:cargo", String).unwrap_or_else(|e| e.exit())
} else {
Vec::new()
}
.into_iter();
let mut shells = if matches.is_present("cmd:shell") {
values_t!(matches, "cmd:shell", String).unwrap_or_else(|e| e.exit())
} else {
Vec::new()
}
.into_iter();
for c in command_order {
match c {
"cargo" => {
commands.push(cargo_command(
cargos
.next()
.expect("Argument-order mismatch, this is a bug"),
&features,
));
}
"shell" => {
commands.push(
shells
.next()
.expect("Argument-order mismatch, this is a bug"),
);
}
_ => {}
}
}
}
// Default to `cargo check`
@ -84,6 +79,41 @@ pub fn set_commands(builder: &mut ConfigBuilder, matches: &ArgMatches) {
builder.cmd(commands);
}
fn cargo_command(cargo: String, features: &Option<String>) -> String {
let mut cmd = String::from("cargo ");
let cargo = cargo.trim_start();
if let Some(features) = features.as_ref() {
if cargo.starts_with('b')
|| cargo.starts_with("check")
|| cargo.starts_with("doc")
|| cargo.starts_with('r')
|| cargo.starts_with("test")
|| cargo.starts_with("install")
{
// Split command into first word and the arguments
let word_boundary = cargo
.find(|c: char| c.is_whitespace())
.unwrap_or_else(|| cargo.len());
// Find returns the byte index, and split_at takes a byte offset.
// This means the splitting is unicode-safe.
let (subcommand, args) = cargo.split_at(word_boundary);
cmd.push_str(subcommand);
cmd.push_str(" --features ");
cmd.push_str(features);
cmd.push(' ');
cmd.push_str(args);
} else {
cmd.push_str(&cargo);
}
} else {
cmd.push_str(&cargo);
}
cmd
}
pub fn set_ignores(builder: &mut ConfigBuilder, matches: &ArgMatches) {
if matches.is_present("ignore-nothing") {
debug!("Ignoring nothing");