From 4491221f5b9f5080d5c67df8d318d1ccd15c01bc Mon Sep 17 00:00:00 2001 From: BrettMayson Date: Tue, 21 Nov 2023 12:38:10 -0600 Subject: [PATCH] support for --just in dev and build (#605) --- bin/src/commands/build.rs | 51 ++++++++++++++++++++++++++++++++++--- bin/src/commands/dev.rs | 31 +++++++++++++++++++--- bin/src/commands/release.rs | 6 ++++- bin/src/commands/script.rs | 7 ++++- bin/src/context.rs | 17 +++++++++++-- bin/src/lib.rs | 5 +--- bin/src/link.rs | 15 +++++++++++ bin/src/modules/pbo.rs | 7 ++++- book/commands/build.md | 3 +++ book/commands/dev.md | 3 +++ book/commands/index.md | 17 +++++++++++++ 11 files changed, 147 insertions(+), 15 deletions(-) diff --git a/bin/src/commands/build.rs b/bin/src/commands/build.rs index faf266cb..bec197bd 100644 --- a/bin/src/commands/build.rs +++ b/bin/src/commands/build.rs @@ -1,6 +1,7 @@ use clap::{ArgAction, ArgMatches, Command}; use crate::{ + context::{self, Context}, error::Error, executor::Executor, modules::{pbo::Collapse, Binarize, Files, Hooks, Lint, Rapifier}, @@ -8,13 +9,13 @@ use crate::{ #[must_use] pub fn cli() -> Command { - add_args( + add_just(add_args( Command::new("build") .about("Build the project for final testing") .long_about( "Build your project in release mode for testing, without signing for full release.", ), - ) + )) } #[must_use] @@ -33,7 +34,51 @@ pub fn add_args(cmd: Command) -> Command { ) } -/// Execute the build command +#[must_use] +pub fn add_just(cmd: Command) -> Command { + cmd.arg( + clap::Arg::new("just") + .long("just") + .help("Only build the given addon") + .action(ArgAction::Append), + ) +} + +/// Execute the build command, build a new executor +/// +/// # Errors +/// [`Error`] depending on the modules +pub fn pre_execute(matches: &ArgMatches) -> Result<(), Error> { + let just = matches + .get_many::("just") + .unwrap_or_default() + .map(std::string::String::as_str) + .collect::>(); + let mut ctx = Context::new( + std::env::current_dir()?, + "build", + if just.is_empty() { + context::PreservePrevious::Remove + } else { + warn!("keeping previous build artifacts"); + context::PreservePrevious::Keep + }, + )?; + if !just.is_empty() { + ctx = ctx.filter(|a, _| just.contains(&a.name())); + } + let mut executor = Executor::new(&ctx); + + execute(matches, &mut executor)?; + + if !just.is_empty() { + warn!("Use of `--just` is not recommended, only use it if you know what you're doing"); + } + + Ok(()) +} + +/// Execute the build command, with a given executor /// /// # Errors /// [`Error`] depending on the modules diff --git a/bin/src/commands/dev.rs b/bin/src/commands/dev.rs index ea695e9e..3daf8a6d 100644 --- a/bin/src/commands/dev.rs +++ b/bin/src/commands/dev.rs @@ -8,13 +8,15 @@ use crate::{ modules::{pbo::Collapse, Binarize, FilePatching, Files, Hooks, Lint, Rapifier}, }; +use super::build::add_just; + #[must_use] pub fn cli() -> Command { - add_args( + add_just(add_args( Command::new("dev") .about("Build the project for development") .long_about("Build your project for local development and testing. It is built without binarization of .p3d and .rtm files."), - ) + )) } #[must_use] @@ -54,7 +56,26 @@ pub fn execute(matches: &ArgMatches, launch_optionals: &[String]) -> Result>(); - let ctx = Context::new(std::env::current_dir()?, "dev")?.filter(|a, config| { + let just = matches + .get_many::("just") + .unwrap_or_default() + .map(std::string::String::as_str) + .collect::>(); + + let ctx = Context::new( + std::env::current_dir()?, + "dev", + if just.is_empty() { + crate::context::PreservePrevious::Remove + } else { + warn!("keeping previous build artifacts"); + crate::context::PreservePrevious::Keep + }, + )? + .filter(|a, config| { + if !just.is_empty() && !just.contains(&a.name()) { + return false; + } if launch_optionals.iter().any(|o| o == a.name()) { return true; } @@ -96,5 +117,9 @@ pub fn execute(matches: &ArgMatches, launch_optionals: &[String]) -> Result Command { /// # Errors /// [`Error`] depending on the modules pub fn execute(matches: &ArgMatches) -> Result<(), Error> { - let ctx = Context::new(std::env::current_dir()?, "release")?; + let ctx = Context::new( + std::env::current_dir()?, + "release", + crate::context::PreservePrevious::Remove, + )?; let mut executor = Executor::new(&ctx); if matches.get_one::("no-sign") != Some(&true) && ctx.config().hemtt().release().sign() { diff --git a/bin/src/commands/script.rs b/bin/src/commands/script.rs index 8e2e9314..6b262e8a 100644 --- a/bin/src/commands/script.rs +++ b/bin/src/commands/script.rs @@ -48,7 +48,12 @@ pub fn execute(matches: &ArgMatches) -> Result<(), Error> { .map(std::string::String::as_str) .collect::>(); - let ctx = Context::new(std::env::current_dir()?, "script")?.filter(|a, config| { + let ctx = Context::new( + std::env::current_dir()?, + "script", + crate::context::PreservePrevious::Remove, + )? + .filter(|a, config| { if a.location() == &Location::Optionals && !all_optionals && !optionals.contains(&a.name()) { debug!("ignoring optional {}", a.name()); diff --git a/bin/src/context.rs b/bin/src/context.rs index d62d4b02..d44d7cd8 100644 --- a/bin/src/context.rs +++ b/bin/src/context.rs @@ -9,6 +9,15 @@ use hemtt_common::workspace::{Workspace, WorkspacePath}; use crate::{addons::Addon, error::Error}; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// Should the current contents of .hemttout\{} be preserved +pub enum PreservePrevious { + /// The contents should be removed + Remove, + /// The contents should be preserved + Keep, +} + #[derive(Debug, Clone)] pub struct Context { config: ProjectConfig, @@ -33,7 +42,11 @@ impl Context { /// /// # Panics /// If the project folder is not a valid [`OsStr`] (UTF-8) - pub fn new(root: PathBuf, folder: &str) -> Result { + pub fn new( + root: PathBuf, + folder: &str, + preserve_previous: PreservePrevious, + ) -> Result { let config = { let path = root.join(".hemtt").join("project.toml"); if !path.exists() { @@ -66,7 +79,7 @@ impl Context { std::fs::File::create(out_folder.join("ci_annotation.txt"))?; let build_folder = out_folder.join(folder); trace!("using build folder: {:?}", build_folder.display()); - if build_folder.exists() { + if preserve_previous == PreservePrevious::Remove && build_folder.exists() { remove_dir_all(&build_folder)?; } create_dir_all(&build_folder)?; diff --git a/bin/src/lib.rs b/bin/src/lib.rs index 8bb06cde..31a92f8d 100644 --- a/bin/src/lib.rs +++ b/bin/src/lib.rs @@ -1,5 +1,4 @@ use clap::{ArgAction, ArgMatches, Command}; -use context::Context; pub use error::Error; #[macro_use] @@ -115,9 +114,7 @@ pub fn execute(matches: &ArgMatches) -> Result<(), Error> { Ok(()) } Some(("build", matches)) => { - let ctx = Context::new(std::env::current_dir()?, "build")?; - let mut executor = executor::Executor::new(&ctx); - commands::build::execute(matches, &mut executor).map_err(std::convert::Into::into) + commands::build::pre_execute(matches).map_err(std::convert::Into::into) } Some(("release", matches)) => { commands::release::execute(matches).map_err(std::convert::Into::into) diff --git a/bin/src/link.rs b/bin/src/link.rs index 4a9885c5..90851fda 100644 --- a/bin/src/link.rs +++ b/bin/src/link.rs @@ -12,6 +12,14 @@ use crate::error::Error; pub fn create_link(link: &PathBuf, target: &PathBuf) -> Result<(), Error> { use std::process::Command; + if link.exists() { + warn!( + "link {:?} already exists, intended to point to {:?}", + link, target + ); + return Ok(()); + } + // attempt junction trace!("junction link {:?} => {:?}", link, target); let mut out = Command::new("cmd") @@ -49,6 +57,13 @@ pub fn create_link(link: &PathBuf, target: &PathBuf) -> Result<(), Error> { /// # Errors /// - [`std::io::Error`] if the link could not be created pub fn create_link(link: &PathBuf, target: &PathBuf) -> Result<(), Error> { + if link.exists() { + warn!( + "link {:?} already exists, intended to point to {:?}", + link, target + ); + return Ok(()); + } trace!("symlink {:?} => {:?}", link, target); std::os::unix::fs::symlink(target, link)?; Ok(()) diff --git a/bin/src/modules/pbo.rs b/bin/src/modules/pbo.rs index 6a5a8c16..c75f78e0 100644 --- a/bin/src/modules/pbo.rs +++ b/bin/src/modules/pbo.rs @@ -92,7 +92,12 @@ fn _build( path.set_extension("pbo"); path }; - create_dir_all(target_pbo.parent().unwrap())?; + if target_pbo.parent().unwrap().exists() { + debug!("{:?} already exists", target_pbo.parent().unwrap()); + } else { + debug!("creating {:?}", target_pbo.parent().unwrap()); + create_dir_all(target_pbo.parent().unwrap())?; + } debug!( "building {:?} => {:?}", addon.folder(), diff --git a/book/commands/build.md b/book/commands/build.md index 1cb89e0d..8fa5f1d2 100644 --- a/book/commands/build.md +++ b/book/commands/build.md @@ -11,6 +11,9 @@ Options: --no-rap Do not rapify files + --just <just> + Only build the specified addon + -t, --threads <threads> Number of threads, defaults to # of CPUs diff --git a/book/commands/dev.md b/book/commands/dev.md index 5931d198..3c497e35 100644 --- a/book/commands/dev.md +++ b/book/commands/dev.md @@ -14,6 +14,9 @@ Options: -O, --all-optionals Include all optional addon folders + --just <just> + Only build the specified addon + -t, --threads <threads> Number of threads, defaults to # of CPUs diff --git a/book/commands/index.md b/book/commands/index.md index ac93b2bf..3ec79c41 100644 --- a/book/commands/index.md +++ b/book/commands/index.md @@ -11,6 +11,23 @@ - [hemtt release](./release.md) - Build the project for release +## Options + +### --just + +The [`build`](./build.md) and [`dev`](./dev.md) commands can be used to build a single addon. It can be used multiple times to build multiple addons. + +```bash +hemtt build --just myAddon +``` + +```admonish danger +It is advised to only use this on very large projects that take a long time to build. +It is advised to only use this after running the command once without `--just` to ensure all addons are built. +Anytime you run any git commands that can modify files, you should run without `--just` to ensure all addons are up to date. +Before reporting any unexpected behavior, try running without `--just` first. +``` + ## Global Options ### -t, --threads