use crate::prelude::*;
use std::path::PathBuf;
use std::process::Command;
#[derive(Debug, Clone, Component)]
pub struct CargoBuildCmd {
pub cmd: String,
pub package: Option<String>,
pub bin: Option<String>,
pub example: Option<String>,
pub test: Option<String>,
pub release: bool,
pub lib: bool,
pub doc: bool,
pub target: Option<String>,
pub message_format: Option<String>,
pub verbose: u8,
pub quiet: bool,
pub color: Option<String>,
pub config: Option<String>,
pub z: Option<String>,
pub features: Option<String>,
pub all_features: bool,
pub no_default_features: bool,
pub jobs: Option<String>,
pub keep_going: bool,
pub profile: Option<String>,
pub target_dir: Option<String>,
pub unit_graph: bool,
pub timings: Option<String>,
pub manifest_path: Option<String>,
pub lockfile_path: Option<String>,
pub ignore_rust_version: bool,
pub locked: bool,
pub offline: bool,
pub frozen: bool,
pub trailing_args: Vec<String>,
}
impl Default for CargoBuildCmd {
fn default() -> Self {
Self {
cmd: "build".to_string(),
package: None,
bin: None,
example: None,
test: None,
release: false,
lib: false,
doc: false,
target: None,
message_format: None,
verbose: 0,
quiet: false,
color: None,
config: None,
z: None,
features: None,
all_features: false,
no_default_features: false,
jobs: None,
keep_going: false,
profile: None,
target_dir: None,
unit_graph: false,
timings: None,
manifest_path: None,
lockfile_path: None,
ignore_rust_version: false,
locked: false,
offline: false,
frozen: false,
trailing_args: Vec::new(),
}
}
}
impl CargoBuildCmd {
pub fn new(cmd: impl Into<String>) -> Self {
Self {
cmd: cmd.into(),
..default()
}
}
pub fn cmd(mut self, cmd: impl Into<String>) -> Self {
self.cmd = cmd.into();
self
}
pub fn release(mut self) -> Self {
self.release = true;
self
}
pub fn package(mut self, package: impl Into<String>) -> Self {
self.package = Some(package.into());
self
}
pub fn no_default_features(mut self) -> Self {
self.no_default_features = true;
self
}
pub fn target(mut self, target: impl Into<String>) -> Self {
self.target = Some(target.into());
self
}
pub fn trailing_arg(mut self, arg: impl Into<String>) -> Self {
self.trailing_args.push(arg.into());
self
}
pub fn feature(mut self, feature: impl Into<String>) -> Self {
self.push_feature(feature);
self
}
pub fn push_feature(&mut self, feature: impl Into<String>) -> &mut Self {
let feature = feature.into();
if let Some(features) = &mut self.features {
features.push_str(&format!(",{}", feature));
} else {
self.features = Some(feature);
}
self
}
pub fn binary_name(&self, pkg_name: Option<&str>) -> String {
if let Some(bin) = &self.bin {
bin.clone()
} else if let Some(example) = &self.example {
example.clone()
} else if let Some(pkg) = &self.package {
pkg.clone()
} else if let Some(pkg_name) = pkg_name {
pkg_name.to_string()
} else {
panic!("No binary or package name provided.");
}
}
pub fn exe_path(&self, pkg_name: Option<&str>) -> PathBuf {
let target_dir = env_ext::var("CARGO_TARGET_DIR")
.unwrap_or_else(|_| "target".to_string());
let mut path = PathBuf::from(target_dir);
if let Some(target) = &self.target {
path.push(target);
}
if self.release {
path.push("release");
} else {
path.push("debug");
}
if let Some(example) = &self.example {
path.push("examples");
path.push(example);
} else if let Some(pkg) = &self.package {
path.push(pkg);
} else if let Some(bin) = &self.bin {
path.push(bin);
} else if let Some(pkg_name) = pkg_name {
path.push(pkg_name);
} else {
panic!(
"No crate name provided and no package, bin or example is set."
);
}
if let Some("wasm32-unknown-unknown") = self.target.as_deref() {
path.set_extension("wasm");
}
path
}
pub fn get_args(&self) -> Vec<&str> {
let CargoBuildCmd {
cmd,
package,
bin,
example,
test,
lib,
doc,
release,
target,
trailing_args,
message_format,
verbose,
quiet,
color,
config,
z,
features,
all_features,
no_default_features,
jobs,
keep_going,
profile,
target_dir,
unit_graph,
timings,
manifest_path,
lockfile_path,
ignore_rust_version,
locked,
offline,
frozen,
} = self;
let mut args = Vec::new();
args.push(cmd.as_str());
if let Some(pkg) = package {
args.push("--package");
args.push(pkg.as_str());
}
if let Some(bin) = bin {
args.push("--bin");
args.push(bin.as_str());
}
if let Some(ex) = example {
args.push("--example");
args.push(ex.as_str());
}
if let Some(test) = test {
args.push("--test");
args.push(test.as_str());
}
if *lib {
args.push("--lib");
}
if *doc {
args.push("--doc");
}
if *release {
args.push("--release");
}
if let Some(target) = target {
args.push("--target");
args.push(target.as_str());
}
if let Some(format) = message_format {
args.push("--message-format");
args.push(format.as_str());
}
match verbose {
1 => {
args.push("-v");
}
2 => {
args.push("-vv");
}
n if *n > 2 => {
args.push("-vvv");
}
_ => {}
}
if *quiet {
args.push("--quiet");
}
if let Some(color_opt) = color {
args.push("--color");
args.push(color_opt.as_str());
}
if let Some(config_value) = config {
args.push("--config");
args.push(config_value.as_str());
}
if let Some(z_flag) = z {
args.push("-Z");
args.push(z_flag.as_str());
}
if *no_default_features {
args.push("--no-default-features");
}
if *all_features {
args.push("--all-features");
}
if let Some(features_list) = features {
args.push("--features");
args.push(features_list.as_str());
}
if let Some(jobs_count) = jobs {
args.push("--jobs");
args.push(jobs_count.as_str());
}
if *keep_going {
args.push("--keep-going");
}
if let Some(profile_name) = profile {
args.push("--profile");
args.push(profile_name.as_str());
}
if let Some(dir) = target_dir {
args.push("--target-dir");
args.push(dir.as_str());
}
if *unit_graph {
args.push("--unit-graph");
}
if let Some(timings_format) = timings {
args.push("--timings");
args.push(timings_format.as_str());
}
if let Some(manifest) = manifest_path {
args.push("--manifest-path");
args.push(manifest.as_str());
}
if let Some(lockfile) = lockfile_path {
args.push("--lockfile-path");
args.push(lockfile.as_str());
}
if *ignore_rust_version {
args.push("--ignore-rust-version");
}
if *locked {
args.push("--locked");
}
if *offline {
args.push("--offline");
}
if *frozen {
args.push("--frozen");
}
if !trailing_args.is_empty() {
args.push("--");
for arg in trailing_args {
args.push(arg);
}
}
args
}
pub fn spawn(&self) -> Result<&Self> {
let args = self.get_args();
debug!("Running: cargo {}", args.join(" "));
let mut command = Command::new("cargo");
command.args(&args);
command.status()?.exit_ok()?;
Ok(self)
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
#[test]
fn works() { CargoBuildCmd::default().cmd.xpect_eq("build"); }
}