diff --git a/src/check/mod.rs b/src/check/mod.rs new file mode 100644 index 00000000..cd2be762 --- /dev/null +++ b/src/check/mod.rs @@ -0,0 +1,75 @@ +use crate::build::run_command; +use color_eyre::eyre::{eyre, Result}; +use fs_err as fs; +use std::path::Path; +use std::process::Command; +use tracing::{info, instrument}; + +#[instrument(level = "trace", skip_all)] +pub fn execute( + package_dir: &Path, + release: bool, + profile: Option<&str>, + targets: Vec, + packages: Vec, + features: Vec, + all_features: bool, + no_default_features: bool, + verbose: bool, +) -> Result<()> { + let package_dir = fs::canonicalize(package_dir)?; + + if !package_dir.exists() { + let error = format!("Directory {:?} doesnt exists.", package_dir); + return Err(eyre!(error)); + } + + info!("Checking package in {:?}...", package_dir); + + let mut args: Vec = vec!["check", "--target-dir", "target"] + .iter() + .map(|v| v.to_string()) + .collect(); + + if release { + args.push("--release".to_string()); + } + + if let Some(prof) = profile { + args.push("--profile".to_string()); + args.push(prof.to_string()); + } + + for target in targets { + args.push("--target".to_string()); + args.push(target); + } + + for package in packages { + args.push("--package".to_string()); + args.push(package); + } + + if all_features { + args.push("--all-features".to_string()); + } + + if no_default_features { + args.push("--no-default-features".to_string()); + } + + if !features.is_empty() { + args.push("--features".to_string()); + args.push(features.join(",")); + } + + run_command( + Command::new("cargo") + .args(&args[..]) + .current_dir(&package_dir), + verbose, + )?; + + info!("Done checking package in {:?}.", package_dir); + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 0dc17a8c..7c659e29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ pub mod boot_real_node; pub mod build; pub mod build_start_package; pub mod chain; +pub mod check; pub mod connect; pub mod dev_ui; pub mod inject_message; diff --git a/src/main.rs b/src/main.rs index 50957dd2..196786fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use tracing_subscriber::{ }; use kit::{ - boot_fake_node, boot_real_node, build, build_start_package, chain, connect, dev_ui, + boot_fake_node, boot_real_node, build, build_start_package, chain, check, connect, dev_ui, inject_message, new, publish, remove_package, reset_cache, run_tests, setup, start_package, update, view_api, KIT_LOG_PATH_DEFAULT, }; @@ -206,6 +206,41 @@ async fn execute( ) .await } + Some(("check", matches)) => { + let package_dir = PathBuf::from(matches.get_one::("DIR").unwrap()); + let release = matches.get_one::("RELEASE").unwrap(); + let profile = matches.get_one::("PROFILE"); + let targets: Vec = matches + .get_many::("TARGET") + .unwrap_or_default() + .map(|s| s.to_string()) + .collect(); + let packages: Vec = matches + .get_many::("PACKAGE") + .unwrap_or_default() + .map(|s| s.to_string()) + .collect(); + let features: Vec = matches + .get_many::("FEATURES") + .unwrap_or_default() + .map(|s| s.to_string()) + .collect(); + let all_features = matches.get_one::("ALL_FEATURES").unwrap(); + let no_default_features = matches.get_one::("NO_DEFAULT_FEATURES").unwrap(); + let verbose = matches.get_one::("VERBOSE").unwrap(); + + check::execute( + &package_dir, + *release, + profile.map(|s| s.as_str()), + targets, + packages, + features, + *all_features, + *no_default_features, + *verbose, + ) + } Some(("build", matches)) => { let package_dir = PathBuf::from(matches.get_one::("DIR").unwrap()); let no_ui = matches.get_one::("NO_UI").unwrap(); @@ -704,6 +739,76 @@ async fn make_app(current_dir: &std::ffi::OsString) -> Result { .required(false) ) ) + .subcommand(Command::new("check") + .about("Check a Kinode package for errors") + .arg( + Arg::new("DIR") + .action(ArgAction::Set) + .help("The package directory to check") + .default_value(current_dir) + .required(false), + ) + .arg( + Arg::new("RELEASE") + .action(ArgAction::SetTrue) + .short('r') + .long("release") + .help("Check artifacts in release mode, with optimizations") + .required(false), + ) + .arg( + Arg::new("PROFILE") + .action(ArgAction::Set) + .long("profile") + .help("Check artifacts with the specified profile") + .required(false), + ) + .arg( + Arg::new("TARGET") + .action(ArgAction::Append) + .long("target") + .help("Check for the target triple (can specify multiple times)") + .required(false), + ) + .arg( + Arg::new("PACKAGE") + .action(ArgAction::Append) + .short('p') + .long("package") + .help("Package(s) to check (can specify multiple times)") + .required(false), + ) + .arg( + Arg::new("FEATURES") + .action(ArgAction::Append) + .short('F') + .long("features") + .help("Space or comma separated list of features to activate") + .required(false), + ) + .arg( + Arg::new("ALL_FEATURES") + .action(ArgAction::SetTrue) + .long("all-features") + .help("Activate all available features") + .required(false), + ) + .arg( + Arg::new("NO_DEFAULT_FEATURES") + .action(ArgAction::SetTrue) + .long("no-default-features") + .help("Do not activate the `default` feature") + .required(false), + ) + .arg( + Arg::new("VERBOSE") + .action(ArgAction::SetTrue) + .short('v') + .long("verbose") + .help("If set, output stdout and stderr") + .required(false), + ), + ) .subcommand(Command::new("build") .about("Build a Hyperware package") .visible_alias("b")