diff --git a/Cargo.lock b/Cargo.lock index 15220ac963..fcbbe7c8be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "ab_glyph" diff --git a/Cargo.toml b/Cargo.toml index 8f50dd794a..2bfd07ec62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,7 +90,7 @@ build_script_helpers = { path = "crates/build_script_helpers" } byteorder = "1.4.3" calibration = { path = "crates/calibration" } chrono = "0.4.23" -clap = { version = "4.2.4", features = ["derive"] } +clap = { version = "4.2.4", features = ["derive", "env"] } clap_complete = "4.2.1" code_generation = { path = "crates/code_generation" } color-eyre = "0.6.2" diff --git a/crates/repository/src/cargo.rs b/crates/repository/src/cargo.rs index f1a1cc61d1..a3b213d402 100644 --- a/crates/repository/src/cargo.rs +++ b/crates/repository/src/cargo.rs @@ -1,154 +1,55 @@ -use std::path::Path; +use std::{path::Path, process::Command, str::FromStr}; use color_eyre::{ eyre::{bail, Context, ContextCompat}, Result, }; -use log::info; -use tokio::process::Command; use crate::data_home::get_data_home; -pub enum Executor { - Native, - Docker, -} - -pub struct Environment { - pub executor: Executor, - pub version: String, +#[derive(Debug, Clone)] +pub enum Sdk { + Installed { version: String }, + Docker { image: String }, } -pub enum Cargo { +pub enum Environment { Native, - Sdk { environment: Environment }, + Sdk(Sdk), } -impl Cargo { - pub fn native() -> Self { - Cargo::Native - } - - pub fn sdk(environment: Environment) -> Self { - Cargo::Sdk { environment } - } - - pub fn command<'a>( - self, - sub_command: &'a str, - repository_root: &'a Path, - ) -> Result> { - Ok(CargoCommand { - cargo: self, - sub_command, - repository_root, - manifest_path: None, - profile: None, - workspace: false, - all_features: false, - all_targets: false, - features: None, - passthrough_arguments: None, - }) - } +pub enum Host { + Local, + Remote, } -pub struct CargoCommand<'a> { - cargo: Cargo, - sub_command: &'a str, - repository_root: &'a Path, - manifest_path: Option<&'a Path>, - profile: Option<&'a str>, - workspace: bool, - all_features: bool, - all_targets: bool, - features: Option<&'a [String]>, - passthrough_arguments: Option<&'a [String]>, +pub struct Cargo { + host: Host, + environment: Environment, } -impl<'a> CargoCommand<'a> { - pub fn manifest_path(&mut self, manifest_path: &'a Path) -> Result<()> { - if !manifest_path.is_relative() { - bail!("manifest path must be relative to repository root") +impl Cargo { + pub fn local(environment: Environment) -> Self { + Self { + host: Host::Local, + environment, } - self.manifest_path = Some(manifest_path); - Ok(()) - } - - pub fn profile(&mut self, profile: &'a str) { - self.profile = Some(profile); - } - - pub fn workspace(&mut self) { - self.workspace = true; - } - - pub fn all_features(&mut self) { - self.all_features = true; - } - - pub fn all_targets(&mut self) { - self.all_targets = true; } - pub fn features(&mut self, features: &'a [String]) { - self.features = Some(features); - } - - pub fn passthrough_arguments(&mut self, passthrough_arguments: &'a [String]) { - self.passthrough_arguments = Some(passthrough_arguments); + pub fn remote(environment: Environment) -> Self { + Self { + host: Host::Remote, + environment, + } } - pub fn shell_command(self) -> Result { - let mut cargo_arguments = String::new(); - - if let Some(manifest_path) = self.manifest_path { - cargo_arguments.push_str(&format!( - "--manifest-path {path}", - path = manifest_path - .to_str() - .wrap_err("failed to convert manifest path to string")? - )); - } - if let Some(profile) = self.profile { - cargo_arguments.push_str(&format!(" --profile {profile}")); - } - if self.workspace { - cargo_arguments.push_str(" --workspace"); - } - if self.all_features { - cargo_arguments.push_str(" --all-features"); - } - if self.all_targets { - cargo_arguments.push_str(" --all-targets"); - } - if let Some(features) = self.features { - cargo_arguments.push_str(" --features "); - cargo_arguments.push_str(&features.join(",")); - } - if let Some(passthrough_arguments) = self.passthrough_arguments { - cargo_arguments.push_str(" -- "); - cargo_arguments.push_str(&passthrough_arguments.join(" ")); - } + pub fn command(self, repository_root: impl AsRef) -> Result { + let repository_root = repository_root.as_ref(); - let shell_command = match self.cargo { - Cargo::Native => { - format!( - "cd {repository_root} && cargo {command} {cargo_arguments}", - repository_root = self - .repository_root - .to_str() - .wrap_err("failed to convert repository root to string")?, - command = self.sub_command, - ) - } - Cargo::Sdk { - environment: - Environment { - executor: Executor::Native, - version, - }, - } => { + // TODO: implement remote + let command = match self.environment { + Environment::Native => Command::new("cargo"), + Environment::Sdk(Sdk::Installed { version }) => { let data_home = get_data_home().wrap_err("failed to get data home")?; let environment_file = &data_home.join(format!( "sdk/{version}/environment-setup-corei7-64-aldebaran-linux" @@ -156,63 +57,40 @@ impl<'a> CargoCommand<'a> { let sdk_environment_setup = environment_file .to_str() .wrap_err("failed to convert sdk environment setup path to string")?; - let cargo_command = format!( - "cargo {command} {cargo_arguments}", - command = self.sub_command, - ); - format!( - "cd {repository_root} && . {sdk_environment_setup} && {cargo_command}", - repository_root = self - .repository_root - .to_str() - .wrap_err("failed to convert repository root to string")?, - ) + let mut command = Command::new("bash"); + command + .arg("-c") + .arg(format!(". {sdk_environment_setup} && cargo $@")) + .arg("cargo"); + command } - Cargo::Sdk { - environment: - Environment { - executor: Executor::Docker, - version, - }, - } => { + Environment::Sdk(Sdk::Docker { image }) => { let data_home = get_data_home().wrap_err("failed to get data home")?; let cargo_home = data_home.join("container-cargo-home/"); + // TODO: This has to cd into the current pwd first + let mut command = Command::new("bash"); + command.arg("-c"); + command.arg( format!("\ - mkdir -p {cargo_home} && + mkdir -p {cargo_home} && \ docker run \ --volume={repository_root}:/hulk:z \ - --volume={cargo_home}:/naosdk/sysroots/corei7-64-aldebaran-linux/home/cargo:Z \ + --volume={cargo_home}:/naosdk/sysroots/corei7-64-aldebaran-linux/home/cargo:z \ --rm \ --interactive \ - --tty ghcr.io/hulks/naosdk:{version} \ + --tty {image} \ /bin/bash -c \"\ cd /hulk && \ . /naosdk/environment-setup-corei7-64-aldebaran-linux && \ - cargo {command} {cargo_arguments}\ + cargo $@\ \" ", - repository_root=self.repository_root.to_str().wrap_err("failed to convert repository root to string")?, + repository_root=repository_root.to_str().wrap_err("failed to convert repository root to string")?, cargo_home=cargo_home.to_str().wrap_err("failed to convert cargo home to string")?, - command=self.sub_command, - ) + )).arg("cargo"); + command } }; - Ok(shell_command) - } -} - -pub async fn run_shell(command: &str) -> Result<()> { - info!("Executing command: `{command}`"); - - let status = Command::new("sh") - .arg("-c") - .arg(command) - .status() - .await - .wrap_err("failed to execute cargo command")?; - - if !status.success() { - bail!("cargo command exited with {status}"); + Ok(command) } - Ok(()) } diff --git a/tools/pepsi/src/cargo.rs b/tools/pepsi/src/cargo.rs index 15fdbd20d2..4ae1fa4dd4 100644 --- a/tools/pepsi/src/cargo.rs +++ b/tools/pepsi/src/cargo.rs @@ -1,142 +1,178 @@ -use std::path::Path; +use std::{ + ffi::OsStr, + path::{Path, PathBuf}, + process::Command, +}; use clap::Args; -use color_eyre::{eyre::WrapErr, Result}; +use color_eyre::{eyre::Context, Result}; +use environment::EnvironmentArguments; use repository::{ - cargo::{run_shell, Cargo, Environment, Executor}, + cargo::{Cargo, Environment}, configuration::read_sdk_version, - data_home::get_data_home, - sdk::download_and_install, }; -#[derive(Args, Clone)] -pub struct Arguments { - #[arg(long, default_value = "incremental")] - pub profile: String, - #[arg(long, default_value = None, num_args = 1..)] - pub features: Option>, - #[arg(default_value = "nao")] - pub target: String, - #[arg(long)] - pub workspace: bool, - /// Pass through arguments to cargo - #[arg(last = true, value_parser)] - pub passthrough_arguments: Vec, - /// Use the SDK (automatically set when target is `nao`) - #[arg(long)] - pub sdk: bool, - /// Use docker for execution, only relevant when using the SDK - #[arg(long)] - pub docker: bool, - /// Use a remote machine for execution, see ./scripts/remote for details - #[arg(long)] - pub remote: bool, +pub mod build; +pub mod check; +pub mod clippy; +pub mod common; +pub mod environment; +pub mod run; +mod heading { + pub const PACKAGE_SELECTION: &str = "Package Selection"; + pub const TARGET_SELECTION: &str = "Target Selection"; + pub const FEATURE_SELECTION: &str = "Feature Selection"; + pub const COMPILATION_OPTIONS: &str = "Compilation Options"; + pub const MANIFEST_OPTIONS: &str = "Manifest Options"; } -pub async fn cargo( - command: &str, - arguments: Arguments, - repository_root: impl AsRef, -) -> Result<()> { - if arguments.remote { - let remote_script = "./scripts/remoteWorkspace"; - let mut remote_command = remote_script.to_string(); - if command == "build" { - let profile_name = match arguments.profile.as_str() { - "dev" => "debug", - other => other, - }; - let toolchain_name = match arguments.target.as_str() { - "nao" => "x86_64-aldebaran-linux-gnu/", - _ => "", - }; - remote_command.push_str(&format!( - " --return-file target/{toolchain_name}{profile_name}/hulk_{target}", - profile_name = profile_name, - toolchain_name = toolchain_name, - target = arguments.target - )); - } - remote_command.push_str(&format!( - " ./pepsi {command} --profile {profile}", - profile = arguments.profile, - )); - if let Some(features) = &arguments.features { - remote_command.push_str(&format!( - " --features {features}", - features = features.join(",") - )); - } - if arguments.workspace { - remote_command.push_str(" --workspace"); - } - if arguments.sdk { - remote_command.push_str(" --sdk"); - } - if arguments.docker { - remote_command.push_str(" --docker"); - } - remote_command.push_str(&format!(" {target}", target = arguments.target)); - if !arguments.passthrough_arguments.is_empty() { - remote_command.push_str(" -- "); - remote_command.push_str(&arguments.passthrough_arguments.join(" ")); - } - run_shell(&remote_command) - .await - .wrap_err("failed to run remote script")?; - } else { - let sdk_version = read_sdk_version(&repository_root) - .await - .wrap_err("failed to get HULK OS version")?; - let data_home = get_data_home().wrap_err("failed to get data home")?; - let use_sdk = arguments.sdk || (command == "build" && arguments.target == "nao"); - let cargo = if use_sdk { - if arguments.docker || !cfg!(target_os = "linux") { - Cargo::sdk(Environment { - executor: Executor::Docker, - version: sdk_version, - }) - } else { - download_and_install(&sdk_version, data_home) - .await - .wrap_err("failed to install SDK")?; - Cargo::sdk(Environment { - executor: Executor::Native, - version: sdk_version, - }) - } - } else { - Cargo::native() - }; - - let mut cargo_command = cargo.command(command, repository_root.as_ref())?; - - cargo_command.profile(&arguments.profile); +pub trait CargoCommand { + fn apply<'a>(&self, cmd: &'a mut Command) -> &'a mut Command; +} - if let Some(features) = &arguments.features { - cargo_command.features(features); - } +pub async fn cargo( + environment_arguments: EnvironmentArguments, + cargo_arguments: CargoArguments, + repository_root: impl AsRef, +) -> Result<()> +where + CargoArguments: clap::Args + CargoCommand, +{ + let repository_root = repository_root.as_ref(); - let manifest_path = format!( - "./crates/hulk_{target}/Cargo.toml", - target = arguments.target - ); - cargo_command.manifest_path(Path::new(&manifest_path))?; + let sdk_version = read_sdk_version(repository_root) + .await + .wrap_err("failed to read SDK version")?; - if !arguments.passthrough_arguments.is_empty() { - cargo_command.passthrough_arguments(&arguments.passthrough_arguments); - } + let environment = match environment_arguments.sdk { + Some(executor) => Environment::Sdk { + executor, + version: sdk_version, + }, + None => Environment::Native, + }; + let cargo = if environment_arguments.remote { + Cargo::remote(environment) + } else { + Cargo::local(environment) + }; - if arguments.workspace { - cargo_command.workspace(); - cargo_command.all_targets(); - cargo_command.all_features(); - } + let mut command = cargo + .command(repository_root) + .wrap_err("failed to create cargo command")?; + cargo_arguments.apply(&mut command); - let shell_command = cargo_command.shell_command()?; - run_shell(&shell_command) - .await - .wrap_err("failed to run cargo build")?; - } + tokio::process::Command::from(command) + .status() + .await + .wrap_err("failed to run cargo")?; Ok(()) } + +//pub async fn cargo( +// command: &str, +// arguments: Arguments, +// repository_root: impl AsRef, +//) -> Result<()> { +// if arguments.remote { +// let remote_script = "./scripts/remoteWorkspace"; +// let mut remote_command = remote_script.to_string(); +// if command == "build" { +// let profile_name = match arguments.profile.as_str() { +// "dev" => "debug", +// other => other, +// }; +// let toolchain_name = match arguments.target.as_str() { +// "nao" => "x86_64-aldebaran-linux-gnu/", +// _ => "", +// }; +// remote_command.push_str(&format!( +// " --return-file target/{toolchain_name}{profile_name}/hulk_{target}", +// profile_name = profile_name, +// toolchain_name = toolchain_name, +// target = arguments.target +// )); +// } +// remote_command.push_str(&format!( +// " ./pepsi {command} --profile {profile}", +// profile = arguments.profile, +// )); +// if let Some(features) = &arguments.features { +// remote_command.push_str(&format!( +// " --features {features}", +// features = features.join(",") +// )); +// } +// if arguments.workspace { +// remote_command.push_str(" --workspace"); +// } +// if arguments.sdk { +// remote_command.push_str(" --sdk"); +// } +// if arguments.docker { +// remote_command.push_str(" --docker"); +// } +// remote_command.push_str(&format!(" {target}", target = arguments.target)); +// if !arguments.passthrough_arguments.is_empty() { +// remote_command.push_str(" -- "); +// remote_command.push_str(&arguments.passthrough_arguments.join(" ")); +// } +// run_shell(&remote_command) +// .await +// .wrap_err("failed to run remote script")?; +// } else { +// let sdk_version = read_sdk_version(&repository_root) +// .await +// .wrap_err("failed to get HULK OS version")?; +// let data_home = get_data_home().wrap_err("failed to get data home")?; +// let use_sdk = arguments.sdk || (command == "build" && arguments.target == "nao"); +// let cargo = if use_sdk { +// if arguments.docker || !cfg!(target_os = "linux") { +// Cargo::sdk(Environment { +// executor: Executor::Docker, +// version: sdk_version, +// }) +// } else { +// download_and_install(&sdk_version, data_home) +// .await +// .wrap_err("failed to install SDK")?; +// Cargo::sdk(Environment { +// executor: Executor::Native, +// version: sdk_version, +// }) +// } +// } else { +// Cargo::native() +// }; +// +// let mut cargo_command = cargo.command(command, repository_root.as_ref())?; +// +// cargo_command.profile(&arguments.profile); +// +// if let Some(features) = &arguments.features { +// cargo_command.features(features); +// } +// +// let manifest_path = format!( +// "./crates/hulk_{target}/Cargo.toml", +// target = arguments.target +// ); +// cargo_command.manifest_path(Path::new(&manifest_path))?; +// +// if !arguments.passthrough_arguments.is_empty() { +// cargo_command.passthrough_arguments(&arguments.passthrough_arguments); +// } +// +// if arguments.workspace { +// cargo_command.workspace(); +// cargo_command.all_targets(); +// cargo_command.all_features(); +// } +// +// let shell_command = cargo_command.shell_command()?; +// run_shell(&shell_command) +// .await +// .wrap_err("failed to run cargo build")?; +// } +// Ok(()) +//} diff --git a/tools/pepsi/src/cargo/build.rs b/tools/pepsi/src/cargo/build.rs new file mode 100644 index 0000000000..269fc3650c --- /dev/null +++ b/tools/pepsi/src/cargo/build.rs @@ -0,0 +1,206 @@ +use std::path::PathBuf; +use std::process::Command; + +use clap::{ArgAction, Parser}; + +use super::CargoCommand; +use super::{common::CommonOptions, heading}; + +#[derive(Clone, Debug, Default, Parser)] +#[command(display_order = 1)] +pub struct Arguments { + #[command(flatten)] + common: CommonOptions, + + /// Path to Cargo.toml + #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)] + pub manifest_path: Option, + + /// Build artifacts in release mode, with optimizations + #[arg(short = 'r', long, help_heading = heading::COMPILATION_OPTIONS)] + release: bool, + + /// Ignore `rust-version` specification in packages + #[arg(long)] + ignore_rust_version: bool, + + /// Output build graph in JSON (unstable) + #[arg(long, help_heading = heading::COMPILATION_OPTIONS)] + unit_graph: bool, + + /// Package to build (see `cargo help pkgid`) + #[arg( + short = 'p', + long = "package", + value_name = "SPEC", + action = ArgAction::Append, + num_args=0..=1, + help_heading = heading::PACKAGE_SELECTION, + )] + packages: Vec, + + /// Build all packages in the workspace + #[arg(long, help_heading = heading::PACKAGE_SELECTION)] + workspace: bool, + + /// Exclude packages from the build + #[arg( + long, + value_name = "SPEC", + action = ArgAction::Append, + help_heading = heading::PACKAGE_SELECTION, + )] + exclude: Vec, + + /// Alias for workspace (deprecated) + #[arg(long, help_heading = heading::PACKAGE_SELECTION)] + all: bool, + + /// Build only this package's library + #[arg(long, help_heading = heading::TARGET_SELECTION)] + lib: bool, + + /// Build only the specified binary + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + num_args=0..=1, + help_heading = heading::TARGET_SELECTION, + )] + bin: Vec, + + /// Build all binaries + #[arg(long, help_heading = heading::TARGET_SELECTION)] + bins: bool, + + /// Build only the specified example + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + num_args=0..=1, + help_heading = heading::TARGET_SELECTION, + )] + example: Vec, + + /// Build all examples + #[arg(long, help_heading = heading::TARGET_SELECTION)] + examples: bool, + + /// Build only the specified test target + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + help_heading = heading::TARGET_SELECTION, + )] + test: Vec, + + /// Build all tests + #[arg(long, help_heading = heading::TARGET_SELECTION)] + tests: bool, + + /// Build only the specified bench target + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + help_heading = heading::TARGET_SELECTION, + )] + bench: Vec, + + /// Build all benches + #[arg(long, help_heading = heading::TARGET_SELECTION)] + benches: bool, + + /// Build all targets + #[arg(long, help_heading = heading::TARGET_SELECTION)] + all_targets: bool, + + /// Copy final artifacts to this directory (unstable) + #[arg(long, alias = "out-dir", value_name = "PATH", help_heading = heading::COMPILATION_OPTIONS)] + artifact_dir: Option, + + /// Output the build plan in JSON (unstable) + #[arg(long, help_heading = heading::COMPILATION_OPTIONS)] + build_plan: bool, + + /// Outputs a future incompatibility report at the end of the build (unstable) + #[arg(long)] + future_incompat_report: bool, +} + +impl CargoCommand for Arguments { + fn apply<'a>(&self, cmd: &'a mut Command) -> &'a mut Command { + cmd.arg("build"); + + self.common.apply(cmd); + + if let Some(path) = self.manifest_path.as_ref() { + cmd.arg("--manifest-path").arg(path); + } + if self.release { + cmd.arg("--release"); + } + if self.ignore_rust_version { + cmd.arg("--ignore-rust-version"); + } + if self.unit_graph { + cmd.arg("--unit-graph"); + } + for pkg in &self.packages { + cmd.arg("--package").arg(pkg); + } + if self.workspace { + cmd.arg("--workspace"); + } + for item in &self.exclude { + cmd.arg("--exclude").arg(item); + } + if self.all { + cmd.arg("--all"); + } + if self.lib { + cmd.arg("--lib"); + } + for bin in &self.bin { + cmd.arg("--bin").arg(bin); + } + if self.bins { + cmd.arg("--bins"); + } + for example in &self.example { + cmd.arg("--example").arg(example); + } + if self.examples { + cmd.arg("--examples"); + } + for test in &self.test { + cmd.arg("--test").arg(test); + } + if self.tests { + cmd.arg("--tests"); + } + for bench in &self.bench { + cmd.arg("--bench").arg(bench); + } + if self.benches { + cmd.arg("--benches"); + } + if self.all_targets { + cmd.arg("--all-targets"); + } + if let Some(dir) = self.artifact_dir.as_ref() { + cmd.arg("--artifact-dir").arg(dir); + } + if self.build_plan { + cmd.arg("--build-plan"); + } + if self.future_incompat_report { + cmd.arg("--future-incompat-report"); + } + + cmd + } +} diff --git a/tools/pepsi/src/cargo/check.rs b/tools/pepsi/src/cargo/check.rs new file mode 100644 index 0000000000..10db2e3042 --- /dev/null +++ b/tools/pepsi/src/cargo/check.rs @@ -0,0 +1,205 @@ +use std::{path::PathBuf, process::Command}; + +use clap::{ArgAction, Parser}; + +use super::{common::CommonOptions, heading, CargoCommand}; + +/// `cargo check` options which are also a subset of `cargo clippy` +#[derive(Clone, Debug, Default, Parser)] +pub struct CheckOptions { + /// Package to build (see `cargo help pkgid`) + #[arg( + short = 'p', + long = "package", + value_name = "SPEC", + action = ArgAction::Append, + num_args=0..=1, + help_heading = heading::PACKAGE_SELECTION, + )] + pub packages: Vec, + + /// Check all packages in the workspace + #[arg(long, help_heading = heading::PACKAGE_SELECTION)] + pub workspace: bool, + + /// Exclude packages from the build + #[arg( + long, + value_name = "SPEC", + action = ArgAction::Append, + help_heading = heading::PACKAGE_SELECTION, + )] + pub exclude: Vec, + + /// Alias for workspace (deprecated) + #[arg(long, help_heading = heading::PACKAGE_SELECTION,)] + pub all: bool, + + /// Check only this package's library + #[arg(long, help_heading = heading::TARGET_SELECTION)] + pub lib: bool, + + /// Check only the specified binary + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + num_args=0..=1, + help_heading = heading::TARGET_SELECTION, + )] + pub bin: Vec, + + /// Check all binaries + #[arg(long, help_heading = heading::TARGET_SELECTION)] + pub bins: bool, + + /// Check only the specified example + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + num_args=0..=1, + help_heading = heading::TARGET_SELECTION, + )] + pub example: Vec, + + /// Check all examples + #[arg(long, help_heading = heading::TARGET_SELECTION)] + pub examples: bool, + + /// Check only the specified test target + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + help_heading = heading::TARGET_SELECTION, + )] + pub test: Vec, + + /// Check all tests + #[arg(long, help_heading = heading::TARGET_SELECTION)] + pub tests: bool, + + /// Check only the specified bench target + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + help_heading = heading::TARGET_SELECTION, + )] + pub bench: Vec, + + /// Check all benches + #[arg(long, help_heading = heading::TARGET_SELECTION)] + pub benches: bool, + + /// Check all targets + #[arg(long, help_heading = heading::TARGET_SELECTION)] + pub all_targets: bool, + + /// Outputs a future incompatibility report at the end of the build (unstable) + #[arg(long)] + pub future_incompat_report: bool, +} + +impl CheckOptions { + pub fn apply(&self, cmd: &mut Command) { + for pkg in &self.packages { + cmd.arg("--package").arg(pkg); + } + if self.workspace { + cmd.arg("--workspace"); + } + for item in &self.exclude { + cmd.arg("--exclude").arg(item); + } + if self.all { + cmd.arg("--all"); + } + if self.lib { + cmd.arg("--lib"); + } + for bin in &self.bin { + cmd.arg("--bin").arg(bin); + } + if self.bins { + cmd.arg("--bins"); + } + for example in &self.example { + cmd.arg("--example").arg(example); + } + if self.examples { + cmd.arg("--examples"); + } + for test in &self.test { + cmd.arg("--test").arg(test); + } + if self.tests { + cmd.arg("--tests"); + } + for bench in &self.bench { + cmd.arg("--bench").arg(bench); + } + if self.benches { + cmd.arg("--benches"); + } + if self.all_targets { + cmd.arg("--all-targets"); + } + if self.future_incompat_report { + cmd.arg("--future-incompat-report"); + } + } +} + +/// Check a local package and all of its dependencies for errors +#[derive(Clone, Debug, Default, Parser)] +#[command(display_order = 1)] +#[group(skip)] +pub struct Arguments { + #[command(flatten)] + pub common: CommonOptions, + + #[command(flatten)] + pub check: CheckOptions, + + /// Path to Cargo.toml + #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)] + pub manifest_path: Option, + + /// Build artifacts in release mode, with optimizations + #[arg(short = 'r', long, help_heading = heading::COMPILATION_OPTIONS)] + pub release: bool, + + /// Ignore `rust-version` specification in packages + #[arg(long)] + pub ignore_rust_version: bool, + + /// Output build graph in JSON (unstable) + #[arg(long, help_heading = heading::COMPILATION_OPTIONS)] + pub unit_graph: bool, +} + +impl CargoCommand for Arguments { + fn apply<'a>(&self, cmd: &'a mut Command) -> &'a mut Command { + cmd.arg("check"); + + self.common.apply(cmd); + self.check.apply(cmd); + + if let Some(path) = self.manifest_path.as_ref() { + cmd.arg("--manifest-path").arg(path); + } + if self.release { + cmd.arg("--release"); + } + if self.ignore_rust_version { + cmd.arg("--ignore-rust-version"); + } + if self.unit_graph { + cmd.arg("--unit-graph"); + } + + cmd + } +} diff --git a/tools/pepsi/src/cargo/clippy.rs b/tools/pepsi/src/cargo/clippy.rs new file mode 100644 index 0000000000..3a012f73b4 --- /dev/null +++ b/tools/pepsi/src/cargo/clippy.rs @@ -0,0 +1,79 @@ +use std::{path::PathBuf, process::Command}; + +use clap::Parser; + +use super::{check::CheckOptions, common::CommonOptions, heading, CargoCommand}; + +/// Checks a package to catch common mistakes and improve your Rust code +#[derive(Clone, Debug, Default, Parser)] +#[command(display_order = 1)] +#[group(skip)] +pub struct Arguments { + #[command(flatten)] + pub common: CommonOptions, + + #[command(flatten)] + pub check: CheckOptions, + + /// Path to Cargo.toml + #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)] + pub manifest_path: Option, + + /// Build artifacts in release mode, with optimizations + #[arg(short = 'r', long, help_heading = heading::COMPILATION_OPTIONS)] + pub release: bool, + + /// Ignore `rust-version` specification in packages + #[arg(long)] + pub ignore_rust_version: bool, + + /// Output build graph in JSON (unstable) + #[arg(long, help_heading = heading::COMPILATION_OPTIONS)] + pub unit_graph: bool, + + /// Ignore dependencies, run only on crate + #[arg(long)] + pub no_deps: bool, + + /// Automatically apply lint suggestions (see `cargo help clippy`) + #[arg(long)] + pub fix: bool, + + /// Arguments passed to rustc. + #[arg(value_name = "args", trailing_var_arg = true, num_args = 0..)] + pub args: Vec, +} + +impl CargoCommand for Arguments { + fn apply<'a>(&self, cmd: &'a mut Command) -> &'a mut Command { + cmd.arg("clippy"); + + self.common.apply(cmd); + self.check.apply(cmd); + + if let Some(path) = self.manifest_path.as_ref() { + cmd.arg("--manifest-path").arg(path); + } + if self.release { + cmd.arg("--release"); + } + if self.ignore_rust_version { + cmd.arg("--ignore-rust-version"); + } + if self.unit_graph { + cmd.arg("--unit-graph"); + } + if self.no_deps { + cmd.arg("--no-deps"); + } + if self.fix { + cmd.arg("--fix"); + } + if !self.args.is_empty() { + cmd.arg("--"); + cmd.args(&self.args); + } + + cmd + } +} diff --git a/tools/pepsi/src/cargo/common.rs b/tools/pepsi/src/cargo/common.rs new file mode 100644 index 0000000000..7cf46b6caf --- /dev/null +++ b/tools/pepsi/src/cargo/common.rs @@ -0,0 +1,185 @@ +use std::path::PathBuf; +use std::process::Command; + +use clap::{ArgAction, Parser}; + +use super::heading; + +#[derive(Clone, Debug, Default, Parser)] +pub struct CommonOptions { + /// Do not print cargo log messages + #[arg(short = 'q', long)] + pub quiet: bool, + + /// Number of parallel jobs, defaults to # of CPUs + #[arg( + short = 'j', + long, + value_name = "N", + help_heading = heading::COMPILATION_OPTIONS, + )] + pub jobs: Option, + + /// Do not abort the build as soon as there is an error (unstable) + #[arg(long, help_heading = heading::COMPILATION_OPTIONS)] + pub keep_going: bool, + + /// Build artifacts with the specified Cargo profile + #[arg( + long, + value_name = "PROFILE-NAME", + help_heading = heading::COMPILATION_OPTIONS, + )] + pub profile: Option, + + /// Space or comma separated list of features to activate + #[arg( + short = 'F', + long, + action = ArgAction::Append, + help_heading = heading::FEATURE_SELECTION, + )] + pub features: Vec, + + /// Activate all available features + #[arg(long, help_heading = heading::FEATURE_SELECTION)] + pub all_features: bool, + + /// Do not activate the `default` feature + #[arg(long, help_heading = heading::FEATURE_SELECTION)] + pub no_default_features: bool, + + /// Build for the target triple + #[arg( + long, + value_name = "TRIPLE", + env = "CARGO_BUILD_TARGET", + action = ArgAction::Append, + help_heading = heading::COMPILATION_OPTIONS, + )] + pub target: Vec, + + /// Directory for all generated artifacts + #[arg( + long, + value_name = "DIRECTORY", + help_heading = heading::COMPILATION_OPTIONS, + )] + pub target_dir: Option, + + /// Error format + #[arg(long, value_name = "FMT", action = ArgAction::Append)] + pub message_format: Vec, + + /// Use verbose output (-vv very verbose/build.rs output) + #[arg(short = 'v', long, action = ArgAction::Count)] + pub verbose: u8, + + /// Coloring: auto, always, never + #[arg(long, value_name = "WHEN")] + pub color: Option, + + /// Require Cargo.lock and cache are up to date + #[arg(long, help_heading = heading::MANIFEST_OPTIONS)] + pub frozen: bool, + + /// Require Cargo.lock is up to date + #[arg(long, help_heading = heading::MANIFEST_OPTIONS)] + pub locked: bool, + + /// Run without accessing the network + #[arg(long, help_heading = heading::MANIFEST_OPTIONS)] + pub offline: bool, + + /// Override a configuration value (unstable) + #[arg(long, value_name = "KEY=VALUE", action = ArgAction::Append)] + pub config: Vec, + + /// Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details + #[arg(short = 'Z', value_name = "FLAG", action = ArgAction::Append)] + pub unstable_flags: Vec, + + /// Timing output formats (unstable) (comma separated): html, json + #[arg( + long, + value_name = "FMTS", + num_args = 0.., + value_delimiter = ',', + require_equals = true, + help_heading = heading::COMPILATION_OPTIONS, + )] + pub timings: Option>, +} + +impl CommonOptions { + pub fn apply(&self, cmd: &mut Command) { + if self.quiet { + cmd.arg("--quiet"); + } + if let Some(jobs) = self.jobs { + cmd.arg("--jobs").arg(jobs.to_string()); + } + if self.keep_going { + cmd.arg("--keep-going"); + } + if let Some(profile) = self.profile.as_ref() { + cmd.arg("--profile").arg(profile); + } + for feature in &self.features { + cmd.arg("--features").arg(feature); + } + if self.all_features { + cmd.arg("--all-features"); + } + if self.no_default_features { + cmd.arg("--no-default-features"); + } + + // Support . syntax + // For example: x86_64-unknown-linux-gnu.2.17 + let rust_targets = self + .target + .iter() + .map(|target| target.split_once('.').map(|(t, _)| t).unwrap_or(target)) + .collect::>(); + rust_targets.iter().for_each(|target| { + cmd.arg("--target").arg(target); + }); + + if let Some(dir) = self.target_dir.as_ref() { + cmd.arg("--target-dir").arg(dir); + } + for fmt in &self.message_format { + cmd.arg("--message-format").arg(fmt); + } + if self.verbose > 0 { + cmd.arg(format!("-{}", "v".repeat(self.verbose.into()))); + } + if let Some(color) = self.color.as_ref() { + cmd.arg("--color").arg(color); + } + if self.frozen { + cmd.arg("--frozen"); + } + if self.locked { + cmd.arg("--locked"); + } + if self.offline { + cmd.arg("--offline"); + } + for config in &self.config { + cmd.arg("--config").arg(config); + } + for flag in &self.unstable_flags { + cmd.arg("-Z").arg(flag); + } + if let Some(timings) = &self.timings { + if timings.is_empty() { + cmd.arg("--timings"); + } else { + let timings: Vec<_> = timings.iter().map(|x| x.as_str()).collect(); + cmd.arg(format!("--timings={}", timings.join(","))); + } + } + } +} diff --git a/tools/pepsi/src/cargo/environment.rs b/tools/pepsi/src/cargo/environment.rs new file mode 100644 index 0000000000..9bb2f75bf0 --- /dev/null +++ b/tools/pepsi/src/cargo/environment.rs @@ -0,0 +1,17 @@ +use clap::Args; +use repository::cargo::SdkExecutor; + +#[derive(Args, Debug, Clone)] +pub struct EnvironmentArguments { + /// Use an SDK execution environment (default: installed) + #[arg( + long, + default_missing_value = "installed", + require_equals = true, + num_args = 0..=1 + )] + pub sdk: Option, + /// Use a remote machine for execution, see ./scripts/remote for details + #[arg(long)] + pub remote: bool, +} diff --git a/tools/pepsi/src/cargo/run.rs b/tools/pepsi/src/cargo/run.rs new file mode 100644 index 0000000000..0cb27da32c --- /dev/null +++ b/tools/pepsi/src/cargo/run.rs @@ -0,0 +1,101 @@ +use std::path::PathBuf; +use std::process::Command; + +use clap::{ArgAction, Parser}; + +use super::common::CommonOptions; +use super::{heading, CargoCommand}; + +#[derive(Clone, Debug, Default, Parser)] +#[command(display_order = 1)] +pub struct Arguments { + #[command(flatten)] + pub common: CommonOptions, + + /// Path to Cargo.toml + #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)] + pub manifest_path: Option, + + /// Build artifacts in release mode, with optimizations + #[arg(short = 'r', long, help_heading = heading::COMPILATION_OPTIONS)] + pub release: bool, + + /// Ignore `rust-version` specification in packages + #[arg(long)] + pub ignore_rust_version: bool, + + /// Output build graph in JSON (unstable) + #[arg(long, help_heading = heading::COMPILATION_OPTIONS)] + pub unit_graph: bool, + + /// Package to run (see `cargo help pkgid`) + #[arg( + short = 'p', + long = "package", + value_name = "SPEC", + action = ArgAction::Append, + num_args=0..=1, + help_heading = heading::PACKAGE_SELECTION, + )] + pub packages: Vec, + + /// Run the specified binary + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + num_args=0..=1, + help_heading = heading::TARGET_SELECTION, + )] + pub bin: Vec, + + /// Run the specified example + #[arg( + long, + value_name = "NAME", + action = ArgAction::Append, + num_args=0..=1, + help_heading = heading::TARGET_SELECTION, + )] + pub example: Vec, + + /// Arguments for the binary to run + #[arg(value_name = "args", trailing_var_arg = true, num_args = 0..)] + pub args: Vec, +} + +impl CargoCommand for Arguments { + fn apply<'a>(&self, cmd: &'a mut Command) -> &'a mut Command { + cmd.arg("run"); + + self.common.apply(cmd); + + if let Some(path) = self.manifest_path.as_ref() { + cmd.arg("--manifest-path").arg(path); + } + if self.release { + cmd.arg("--release"); + } + if self.ignore_rust_version { + cmd.arg("--ignore-rust-version"); + } + if self.unit_graph { + cmd.arg("--unit-graph"); + } + for pkg in &self.packages { + cmd.arg("--package").arg(pkg); + } + for bin in &self.bin { + cmd.arg("--bin").arg(bin); + } + for example in &self.example { + cmd.arg("--example").arg(example); + } + if !self.args.is_empty() { + cmd.arg("--"); + cmd.args(&self.args); + } + + cmd + } +} diff --git a/tools/pepsi/src/main.rs b/tools/pepsi/src/main.rs index efc2936039..cc2176696c 100644 --- a/tools/pepsi/src/main.rs +++ b/tools/pepsi/src/main.rs @@ -11,7 +11,11 @@ use repository::{find_root::find_repository_root, inspect_version::check_for_upd use crate::aliveness::{aliveness, Arguments as AlivenessArguments}; use analyze::{analyze, Arguments as AnalyzeArguments}; -use cargo::{cargo, Arguments as CargoArguments}; +use cargo::{ + build::Arguments as BuildArguments, cargo, check::Arguments as CheckArguments, + clippy::Arguments as ClippyArguments, run::Arguments as RunArguments, + Arguments as CargoArguments, +}; use communication::{communication, Arguments as CommunicationArguments}; use completions::{completions, Arguments as CompletionArguments}; use gammaray::{gammaray, Arguments as GammarayArguments}; @@ -70,11 +74,11 @@ enum Command { /// Get aliveness information from NAOs Aliveness(AlivenessArguments), /// Builds the code for a target - Build(CargoArguments), - /// Checks the code with cargo check - Check(CargoArguments), - /// Checks the code with cargo clippy - Clippy(CargoArguments), + Build(CargoArguments), + ///// Checks the code with cargo check + Check(CargoArguments), + ///// Checks the code with cargo clippy + Clippy(CargoArguments), /// Enable/disable communication #[command(subcommand)] Communication(CommunicationArguments), @@ -105,7 +109,7 @@ enum Command { /// Set cycler instances to be recorded Recording(RecordingArguments), /// Runs the code for a target - Run(CargoArguments), + Run(CargoArguments), /// Manage the NAO SDK #[command(subcommand)] Sdk(SdkArguments), @@ -146,13 +150,13 @@ async fn main() -> Result<()> { Command::Aliveness(arguments) => aliveness(arguments, repository_root) .await .wrap_err("failed to execute aliveness command")?, - Command::Build(arguments) => cargo("build", arguments, repository_root?) + Command::Build(arguments) => cargo(arguments, repository_root?) .await .wrap_err("failed to execute build command")?, - Command::Check(arguments) => cargo("check", arguments, repository_root?) + Command::Check(arguments) => cargo(arguments, repository_root?) .await .wrap_err("failed to execute check command")?, - Command::Clippy(arguments) => cargo("clippy", arguments, repository_root?) + Command::Clippy(arguments) => cargo(arguments, repository_root?) .await .wrap_err("failed to execute clippy command")?, Command::Communication(arguments) => communication(arguments, repository_root?) @@ -192,7 +196,7 @@ async fn main() -> Result<()> { Command::Recording(arguments) => recording(arguments, repository_root?) .await .wrap_err("failed to execute recording command")?, - Command::Run(arguments) => cargo("run", arguments, repository_root?) + Command::Run(arguments) => cargo(arguments, repository_root?) .await .wrap_err("failed to execute run command")?, Command::Sdk(arguments) => sdk(arguments, repository_root?) diff --git a/tools/pepsi/src/pre_game.rs b/tools/pepsi/src/pre_game.rs index 1be1cac360..caff0d8cf0 100644 --- a/tools/pepsi/src/pre_game.rs +++ b/tools/pepsi/src/pre_game.rs @@ -22,7 +22,6 @@ use repository::{ use tempfile::tempdir; use crate::{ - cargo::{cargo, Arguments as CargoArguments}, player_number::{player_number, Arguments as PlayerNumberArguments}, progress_indicator::ProgressIndicator, recording::parse_key_value, @@ -30,8 +29,8 @@ use crate::{ #[derive(Args)] pub struct Arguments { - #[command(flatten)] - pub cargo: CargoArguments, + //#[command(flatten)] + //pub cargo: CargoArguments, /// Do not build before uploading #[arg(long)] pub no_build: bool, @@ -73,140 +72,140 @@ pub struct Arguments { } pub async fn pre_game(arguments: Arguments, repository_root: impl AsRef) -> Result<()> { - let repository_root = repository_root.as_ref(); - - let naos: Vec<_> = arguments - .assignments - .iter() - .map(|assignment| assignment.nao_address) - .collect(); - - configure_recording_intervals( - HashMap::from_iter(arguments.recording_intervals.clone()), - repository_root, - ) - .await - .wrap_err("failed to set recording settings")?; - - set_location("nao", &arguments.location, repository_root) - .await - .wrap_err_with(|| format!("failed setting location for nao to {}", arguments.location))?; - - configure_communication(arguments.with_communication, repository_root) - .await - .wrap_err("failed to set communication")?; - - player_number( - PlayerNumberArguments { - assignments: arguments - .assignments - .iter() - .copied() - .map(TryFrom::try_from) - .collect::, _>>() - .wrap_err("failed to convert NAO address assignments into NAO number assignments for player number setting")? - }, - repository_root - ) - .await - .wrap_err("failed to set player numbers")?; - - if !arguments.no_build { - cargo("build", arguments.cargo.clone(), repository_root) - .await - .wrap_err("failed to build the code")?; - } - - if arguments.prepare { - warn!("Preparation complete, skipping the rest"); - return Ok(()); - } - - let upload_directory = tempdir().wrap_err("failed to get temporary directory")?; - populate_upload_directory(&upload_directory, &arguments.cargo.profile, repository_root) - .await - .wrap_err("failed to populate upload directory")?; - - let arguments = &arguments; - let upload_directory = &upload_directory; - - ProgressIndicator::map_tasks( - &naos, - "Executing pregame tasks", - |nao_address, progress_bar| async move { - setup_nao( - nao_address, - upload_directory, - arguments, - progress_bar, - repository_root, - ) - .await - }, - ) - .await; - - Ok(()) -} - -async fn setup_nao( - nao_address: &NaoAddress, - upload_directory: impl AsRef, - arguments: &Arguments, - progress: ProgressBar, - repository_root: &Path, -) -> Result<()> { - progress.set_message("Pinging NAO..."); - let nao = Nao::try_new_with_ping(nao_address.ip).await?; - - if !arguments.skip_os_check { - progress.set_message("Checking OS version..."); - let nao_os_version = nao - .get_os_version() - .await - .wrap_err_with(|| format!("failed to get OS version of {nao_address}"))?; - let expected_os_version = read_os_version(repository_root) - .await - .wrap_err("failed to get configured OS version")?; - if nao_os_version != expected_os_version { - bail!("mismatched OS versions: Expected {expected_os_version}, found {nao_os_version}"); - } - } - - progress.set_message("Stopping HULK..."); - nao.execute_systemctl(SystemctlAction::Stop, "hulk") - .await - .wrap_err_with(|| format!("failed to stop HULK service on {nao_address}"))?; - - progress.set_message("Uploading: ..."); - nao.upload(upload_directory, "hulk", !arguments.no_clean, |status| { - progress.set_message(format!("Uploading: {}", status)) - }) - .await - .wrap_err_with(|| format!("failed to upload binary to {nao_address}"))?; - - if arguments.wifi != Network::None { - progress.set_message("Scanning for WiFi..."); - nao.scan_networks() - .await - .wrap_err_with(|| format!("failed to scan for networks on {nao_address}"))?; - } - - progress.set_message("Setting WiFi..."); - nao.set_wifi(arguments.wifi) - .await - .wrap_err_with(|| format!("failed to set network on {nao_address}"))?; - - if !arguments.no_restart { - progress.set_message("Restarting HULK..."); - if let Err(error) = nao.execute_systemctl(SystemctlAction::Start, "hulk").await { - let logs = nao - .retrieve_logs() - .await - .wrap_err("failed to retrieve logs")?; - bail!("failed to restart hulk: {error:#?}\nLogs:\n{logs}") - }; - } + // let repository_root = repository_root.as_ref(); + // + // let naos: Vec<_> = arguments + // .assignments + // .iter() + // .map(|assignment| assignment.nao_address) + // .collect(); + // + // configure_recording_intervals( + // HashMap::from_iter(arguments.recording_intervals.clone()), + // repository_root, + // ) + // .await + // .wrap_err("failed to set recording settings")?; + // + // set_location("nao", &arguments.location, repository_root) + // .await + // .wrap_err_with(|| format!("failed setting location for nao to {}", arguments.location))?; + // + // configure_communication(arguments.with_communication, repository_root) + // .await + // .wrap_err("failed to set communication")?; + // + // player_number( + // PlayerNumberArguments { + // assignments: arguments + // .assignments + // .iter() + // .copied() + // .map(TryFrom::try_from) + // .collect::, _>>() + // .wrap_err("failed to convert NAO address assignments into NAO number assignments for player number setting")? + // }, + // repository_root + // ) + // .await + // .wrap_err("failed to set player numbers")?; + // + // if !arguments.no_build { + // cargo("build", arguments.cargo.clone(), repository_root) + // .await + // .wrap_err("failed to build the code")?; + // } + // + // if arguments.prepare { + // warn!("Preparation complete, skipping the rest"); + // return Ok(()); + // } + // + // let upload_directory = tempdir().wrap_err("failed to get temporary directory")?; + // populate_upload_directory(&upload_directory, &arguments.cargo.profile, repository_root) + // .await + // .wrap_err("failed to populate upload directory")?; + // + // let arguments = &arguments; + // let upload_directory = &upload_directory; + // + // ProgressIndicator::map_tasks( + // &naos, + // "Executing pregame tasks", + // |nao_address, progress_bar| async move { + // setup_nao( + // nao_address, + // upload_directory, + // arguments, + // progress_bar, + // repository_root, + // ) + // .await + // }, + // ) + // .await; + // + // Ok(()) + //} + // + //async fn setup_nao( + // nao_address: &NaoAddress, + // upload_directory: impl AsRef, + // arguments: &Arguments, + // progress: ProgressBar, + // repository_root: &Path, + //) -> Result<()> { + // progress.set_message("Pinging NAO..."); + // let nao = Nao::try_new_with_ping(nao_address.ip).await?; + // + // if !arguments.skip_os_check { + // progress.set_message("Checking OS version..."); + // let nao_os_version = nao + // .get_os_version() + // .await + // .wrap_err_with(|| format!("failed to get OS version of {nao_address}"))?; + // let expected_os_version = read_os_version(repository_root) + // .await + // .wrap_err("failed to get configured OS version")?; + // if nao_os_version != expected_os_version { + // bail!("mismatched OS versions: Expected {expected_os_version}, found {nao_os_version}"); + // } + // } + // + // progress.set_message("Stopping HULK..."); + // nao.execute_systemctl(SystemctlAction::Stop, "hulk") + // .await + // .wrap_err_with(|| format!("failed to stop HULK service on {nao_address}"))?; + // + // progress.set_message("Uploading: ..."); + // nao.upload(upload_directory, "hulk", !arguments.no_clean, |status| { + // progress.set_message(format!("Uploading: {}", status)) + // }) + // .await + // .wrap_err_with(|| format!("failed to upload binary to {nao_address}"))?; + // + // if arguments.wifi != Network::None { + // progress.set_message("Scanning for WiFi..."); + // nao.scan_networks() + // .await + // .wrap_err_with(|| format!("failed to scan for networks on {nao_address}"))?; + // } + // + // progress.set_message("Setting WiFi..."); + // nao.set_wifi(arguments.wifi) + // .await + // .wrap_err_with(|| format!("failed to set network on {nao_address}"))?; + // + // if !arguments.no_restart { + // progress.set_message("Restarting HULK..."); + // if let Err(error) = nao.execute_systemctl(SystemctlAction::Start, "hulk").await { + // let logs = nao + // .retrieve_logs() + // .await + // .wrap_err("failed to retrieve logs")?; + // bail!("failed to restart hulk: {error:#?}\nLogs:\n{logs}") + // }; + // } Ok(()) } diff --git a/tools/pepsi/src/upload.rs b/tools/pepsi/src/upload.rs index 30f1095dae..a3ebdb7354 100644 --- a/tools/pepsi/src/upload.rs +++ b/tools/pepsi/src/upload.rs @@ -8,18 +8,26 @@ use color_eyre::{ }; use futures_util::{stream::FuturesUnordered, StreamExt}; use nao::{Nao, SystemctlAction}; -use repository::{configuration::read_os_version, upload::populate_upload_directory}; +use repository::{ + cargo::SdkExecutor, configuration::read_os_version, upload::populate_upload_directory, +}; use tempfile::tempdir; use crate::{ - cargo::{cargo, Arguments as CargoArguments}, + cargo::build::Arguments as BuildArguments, progress_indicator::{ProgressIndicator, Task}, }; #[derive(Args)] pub struct Arguments { + /// SDK execution environment to use + #[arg(long, default_value = "installed")] + pub sdk: SdkExecutor, + /// Use a remote machine for execution, see ./scripts/remote for details + #[arg(long)] + pub remote: bool, #[command(flatten)] - pub cargo: CargoArguments, + pub cargo: BuildArguments, /// Do not build before uploading #[arg(long)] pub no_build: bool, @@ -89,11 +97,7 @@ async fn upload_with_progress( pub async fn upload(arguments: Arguments, repository_root: impl AsRef) -> Result<()> { let repository_root = repository_root.as_ref(); - if !arguments.no_build { - cargo("build", arguments.cargo.clone(), repository_root) - .await - .wrap_err("failed to build the code")?; - } + if !arguments.no_build {} let upload_directory = tempdir().wrap_err("failed to get temporary directory")?; populate_upload_directory(&upload_directory, &arguments.cargo.profile, repository_root)