use std::env;
use std::path::{Path, PathBuf};
use cargo_metadata::{self, Metadata};
use command;
#[derive(Debug, StructOpt)]
pub enum Entry {
#[structopt(name = "build")]
Build {
#[structopt(
long = "no-detect-workspace",
help = "Disable detection of whether the current crate is a workspace crate.",
parse(from_occurrences = "parse_detect_workspace")
)]
detect_workspace: bool,
#[structopt(
help = "Arguments to pass through to `cargo build`.\nSee `cargo help build` for the full list.",
raw(allow_hyphen_values = "true")
)]
args: Vec<String>,
},
#[structopt(name = "each")]
Each {
#[structopt(help = "Command to execute", parse(from_os_str))]
command: PathBuf,
#[structopt(
help = "For workspaces, the command to run inside each crate directory.",
raw(allow_hyphen_values = "true")
)]
args: Vec<String>,
},
}
fn parse_detect_workspace(occurrences: u64) -> bool {
occurrences == 0
}
impl Entry {
pub fn command<'c>(self, manifest_path: &'c PathBuf) -> Box<command::Command + 'c> {
let metadata = cargo_metadata::metadata(Some(manifest_path).as_ref().map(|p| p.as_path()))
.expect("Failed to read workspace metadata.");
match self {
command::Entry::Build {
detect_workspace,
args: pass_through_args,
} => {
let workspace = is_workspace(&metadata);
let processing_member_crate = is_processing_member_crate(manifest_path, &metadata);
if detect_workspace && workspace && !processing_member_crate {
let mut args = vec!["build", "--no-detect-workspace", "--"]
.into_iter()
.map(|s| s.to_string())
.collect::<Vec<String>>();
args.extend(pass_through_args);
Box::new(command::Each {
manifest_path,
command: env::current_exe().expect("Failed to get current exe."),
args,
})
} else {
Box::new(command::Build {
manifest_path,
args: pass_through_args,
})
}
}
command::Entry::Each { command, args } => Box::new(command::Each {
manifest_path,
command,
args,
}),
}
}
}
fn is_workspace(metadata: &Metadata) -> bool {
metadata.packages.len() > 1
}
fn is_processing_member_crate(manifest_path: &PathBuf, metadata: &Metadata) -> bool {
let crate_dir = manifest_path
.parent()
.expect("Failed to get manifest parent dir.");
let workspace_root = Path::new(&metadata.workspace_root);
crate_dir != workspace_root
}