seperate shell and internal commands in watch subcommand

This commit is contained in:
Moritz Hölting 2024-06-17 09:04:42 +02:00
parent 916901e81a
commit e8ac54f231
6 changed files with 73 additions and 69 deletions

View File

@ -13,7 +13,7 @@ pub struct Args {
/// Enable tracing output /// Enable tracing output
/// ///
/// When specified without a value, defaults to `info`. /// When specified without a value, defaults to `info`.
#[clap( #[arg(
long, long,
global = true, global = true,
default_missing_value = "info", default_missing_value = "info",

View File

@ -16,21 +16,21 @@ use std::{
#[derive(Debug, clap::Args, Clone)] #[derive(Debug, clap::Args, Clone)]
pub struct BuildArgs { pub struct BuildArgs {
/// The path of the project to build. /// The path of the project to build.
#[clap(default_value = ".")] #[arg(default_value = ".")]
pub path: PathBuf, pub path: PathBuf,
/// Path of output directory /// Path of output directory
/// ///
/// The path of the directory to place the compiled datapack. /// The path of the directory to place the compiled datapack.
#[clap(short, long, env = "DATAPACK_DIR")] #[arg(short, long, env = "DATAPACK_DIR")]
pub output: Option<PathBuf>, pub output: Option<PathBuf>,
/// Path of the assets folder /// Path of the assets folder
/// ///
/// The path of a folder which files and subfolders will be copied to the root of the datapack. /// The path of a folder which files and subfolders will be copied to the root of the datapack.
/// Overrides the `assets` field in the pack.toml file. /// Overrides the `assets` field in the pack.toml file.
#[clap(short, long)] #[arg(short, long)]
pub assets: Option<PathBuf>, pub assets: Option<PathBuf>,
/// Package the project to a zip file. /// Package the project to a zip file.
#[clap(short, long)] #[arg(short, long)]
pub zip: bool, pub zip: bool,
} }

View File

@ -8,19 +8,19 @@ use crate::terminal_output::{print_error, print_info, print_success};
#[derive(Debug, clap::Args, Clone)] #[derive(Debug, clap::Args, Clone)]
pub struct CleanArgs { pub struct CleanArgs {
/// The path of the project to clean. /// The path of the project to clean.
#[clap(default_value = ".")] #[arg(default_value = ".")]
pub path: PathBuf, pub path: PathBuf,
/// The path of the directory where the compiled datapacks are placed. /// The path of the directory where the compiled datapacks are placed.
#[clap(short, long, env = "DATAPACK_DIR")] #[arg(short, long, env = "DATAPACK_DIR")]
pub output: Option<PathBuf>, pub output: Option<PathBuf>,
/// Clean the whole output folder /// Clean the whole output folder
#[clap(short, long)] #[arg(short, long)]
pub all: bool, pub all: bool,
/// Force clean /// Force clean
#[clap(short, long)] #[arg(short, long)]
pub force: bool, pub force: bool,
/// Enable verbose output. /// Enable verbose output.
#[clap(short, long)] #[arg(short, long)]
verbose: bool, verbose: bool,
} }

View File

@ -19,25 +19,25 @@ use crate::{
#[derive(Debug, clap::Args, Clone)] #[derive(Debug, clap::Args, Clone)]
pub struct InitArgs { pub struct InitArgs {
/// The path of the folder to initialize in. /// The path of the folder to initialize in.
#[clap(default_value = ".")] #[arg(default_value = ".")]
pub path: PathBuf, pub path: PathBuf,
/// The name of the project. /// The name of the project.
#[clap(short, long)] #[arg(short, long)]
pub name: Option<String>, pub name: Option<String>,
/// The description of the project. /// The description of the project.
#[clap(short, long)] #[arg(short, long)]
pub description: Option<String>, pub description: Option<String>,
/// The pack format version. /// The pack format version.
#[clap(short, long, value_name = "FORMAT")] #[arg(short, long, value_name = "FORMAT")]
pub pack_format: Option<u8>, pub pack_format: Option<u8>,
/// Force initialization even if the directory is not empty. /// Force initialization even if the directory is not empty.
#[clap(short, long)] #[arg(short, long)]
pub force: bool, pub force: bool,
/// The version control system to initialize. /// The version control system to initialize.
#[clap(long, default_value = "git")] #[arg(long, default_value = "git")]
pub vcs: VersionControlSystem, pub vcs: VersionControlSystem,
/// Enable verbose output. /// Enable verbose output.
#[clap(short, long)] #[arg(short, long)]
verbose: bool, verbose: bool,
} }

View File

@ -6,15 +6,15 @@ use std::path::PathBuf;
#[derive(Debug, clap::Args, Clone)] #[derive(Debug, clap::Args, Clone)]
pub struct LangDebugArgs { pub struct LangDebugArgs {
/// The path of the project to compile. /// The path of the project to compile.
#[clap(default_value = ".")] #[arg(default_value = ".")]
pub path: PathBuf, pub path: PathBuf,
/// The state to dump. /// The state to dump.
/// ///
/// Output can be the raw tokens, the abstract syntax tree, or the transpiled datapack. /// Output can be the raw tokens, the abstract syntax tree, or the transpiled datapack.
#[clap(short, long, value_name = "STATE", default_value = "ast")] #[arg(short, long, value_name = "STATE", default_value = "ast")]
pub dump: DumpState, pub dump: DumpState,
/// Pretty-print the output. /// Pretty-print the output.
#[clap(short, long)] #[arg(short, long)]
pub pretty: bool, pub pretty: bool,
} }

View File

@ -18,33 +18,42 @@ use crate::{
#[derive(Debug, clap::Args, Clone)] #[derive(Debug, clap::Args, Clone)]
pub struct WatchArgs { pub struct WatchArgs {
/// The path of the project to watch. /// The path of the project to watch.
#[clap(default_value = ".")] #[arg(default_value = ".")]
pub path: PathBuf, pub path: PathBuf,
/// Only run after changes are detected. /// Only run after changes are detected.
/// ///
/// Skips the initial run of the commands. /// Skips the initial run of the commands.
#[clap(short, long)] #[arg(short, long)]
pub no_inital: bool, pub no_inital: bool,
/// The time to wait in ms before running the command after changes are detected. /// The time to wait in ms before running the command after changes are detected.
#[clap(short, long, value_name = "TIME_IN_MS", default_value = "2000")] #[arg(short, long, value_name = "TIME_IN_MS", default_value = "2000")]
pub debounce_time: u64, pub debounce_time: u64,
/// Additional paths to watch for changes. /// Additional paths to watch for changes.
/// ///
/// By default, the `src` directory, `pack.png`, and `pack.toml` as well as the defined /// By default, the `src` directory, `pack.png`, and `pack.toml` as well as the defined
/// assets directory in the config are watched. /// assets directory in the config are watched.
#[clap(short, long, value_name = "PATH")] #[arg(short, long, value_name = "PATH")]
pub watch: Vec<PathBuf>, pub watch: Vec<PathBuf>,
/// The commands to run in the project directory when changes are detected. /// The shulkerscript commands to run in the project directory when changes are detected.
/// ///
/// Use multiple times to run multiple commands. /// Use multiple times to run multiple commands.
#[clap(short = 'x', long, value_name = "COMMAND", default_value = "build .")] /// Internal commands will always run before shell commands and a command will only run if the
/// previous one exited successfully.
///
/// Use the `--no-execute` flag to disable running these commands, useful when only wanting to
/// run shell commands and not default build command.
#[arg(short = 'x', long, value_name = "COMMAND", default_value = "build .")]
pub execute: Vec<String>, pub execute: Vec<String>,
} /// Do not run the internal shulkerscript commands specified by `--execute` (and the default one).
#[arg(short = 'X', long)]
#[derive(Debug, Clone)] pub no_execute: bool,
enum WatchCommand { /// The shell commands to run in the project directory when changes are detected.
Internal(Args), ///
External(String), /// Use multiple times to run multiple commands.
/// Shell commands will always run after shulkerscript commands and a command will only run
/// if the previous one exited successfully.
#[arg(short, long, value_name = "COMMAND")]
pub shell: Vec<String>,
} }
pub fn watch(args: &WatchArgs) -> Result<()> { pub fn watch(args: &WatchArgs) -> Result<()> {
@ -58,13 +67,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
let prog_name = std::env::args() let prog_name = std::env::args()
.next() .next()
.unwrap_or(env!("CARGO_PKG_NAME").to_string()); .unwrap_or(env!("CARGO_PKG_NAME").to_string());
if let Ok(args) = Args::parse_from(iter::once(prog_name.as_str()).chain(split.clone()))
Args::try_parse_from(iter::once(prog_name.as_str()).chain(split.clone()))
{
WatchCommand::Internal(args)
} else {
WatchCommand::External(cmd.to_owned())
}
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -83,7 +86,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
#[allow(clippy::collapsible_if)] #[allow(clippy::collapsible_if)]
if !args.no_inital { if !args.no_inital {
run_cmds(&commands, true); run_cmds(&commands, args.no_execute, &args.shell, true);
} }
ctrlc::set_handler(move || { ctrlc::set_handler(move || {
@ -92,11 +95,14 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
}) })
.expect("Error setting Ctrl-C handler"); .expect("Error setting Ctrl-C handler");
let shell_commands = args.shell.clone();
let no_execute = args.no_execute;
let mut debouncer = new_debouncer( let mut debouncer = new_debouncer(
Duration::from_millis(args.debounce_time), Duration::from_millis(args.debounce_time),
move |res: DebounceEventResult| { move |res: DebounceEventResult| {
if res.is_ok() { if res.is_ok() {
run_cmds(&commands, false) run_cmds(&commands, no_execute, &shell_commands, false)
} else { } else {
process::exit(1); process::exit(1);
} }
@ -160,40 +166,38 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
} }
} }
fn run_cmds(cmds: &[WatchCommand], initial: bool) { fn run_cmds(cmds: &[Args], no_execute: bool, shell_cmds: &[String], initial: bool) {
if initial { if initial {
print_info("Running commands initially..."); print_info("Running commands initially...");
} else { } else {
print_info("Changes have been detected. Running commands..."); print_info("Changes have been detected. Running commands...");
} }
for (index, cmd) in cmds.iter().enumerate() { if !no_execute {
match cmd { for (index, args) in cmds.iter().enumerate() {
WatchCommand::Internal(args) => {
if args.run().is_err() { if args.run().is_err() {
print_error(format!("Error running command: {}", index + 1)); print_error(format!("Error running command: {}", index + 1));
print_error("Not running further commands."); print_error("Not running further commands.");
break; return;
} }
} }
WatchCommand::External(cmd) => { }
for (index, cmd) in shell_cmds.iter().enumerate() {
let status = run_shell_cmd(cmd); let status = run_shell_cmd(cmd);
match status { match status {
Ok(status) if !status.success() => { Ok(status) if !status.success() => {
print_error(format!( print_error(format!(
"Command {} exited unsuccessfully with status code {}", "Shell command {} exited unsuccessfully with status code {}",
index + 1, index + 1,
status.code().unwrap_or(1) status.code().unwrap_or(1)
)); ));
print_error("Not running further commands."); print_error("Not running further shell commands.");
break; return;
} }
Ok(_) => {} Ok(_) => {}
Err(_) => { Err(_) => {
print_error(format!("Error running command: {}", index + 1)); print_error(format!("Error running shell command: {}", index + 1));
print_error("Not running further commands."); print_error("Not running further shell commands.");
break; return;
}
}
} }
} }
} }