blob: 29478d2a3af2849833cc7bc299d0e26f3f71190c [file] [log] [blame]
use crate::command_prelude::*;
use cargo::core::Verbosity;
use cargo::ops::{self, CompileFilter};
pub fn cli() -> App {
subcommand("run")
// subcommand aliases are handled in aliased_command()
// .alias("r")
.setting(AppSettings::TrailingVarArg)
.about("Run a binary or example of the local package")
.arg(opt("quiet", "No output printed to stdout").short("q"))
.arg(Arg::with_name("args").multiple(true))
.arg_targets_bin_example(
"Name of the bin target to run",
"Name of the example target to run",
)
.arg_package("Package with the target to run")
.arg_jobs()
.arg_release("Build artifacts in release mode, with optimizations")
.arg_profile("Build artifacts with the specified profile")
.arg_features()
.arg_target_triple("Build for the target triple")
.arg_target_dir()
.arg_manifest_path()
.arg_message_format()
.after_help(
"\
If neither `--bin` nor `--example` are given, then if the package only has one
bin target it will be run. Otherwise `--bin` specifies the bin target to run,
and `--example` specifies the example target to run. At most one of `--bin` or
`--example` can be provided.
All the arguments following the two dashes (`--`) are passed to the binary to
run. If you're passing arguments to both Cargo and the binary, the ones after
`--` go to the binary, the ones before go to Cargo.
",
)
}
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let ws = args.workspace(config)?;
let mut compile_opts = args.compile_options(
config,
CompileMode::Build,
Some(&ws),
ProfileChecking::Checked,
)?;
if !args.is_present("example") && !args.is_present("bin") {
let default_runs: Vec<_> = compile_opts
.spec
.get_packages(&ws)?
.iter()
.filter_map(|pkg| pkg.manifest().default_run())
.collect();
if default_runs.len() == 1 {
compile_opts.filter = CompileFilter::from_raw_arguments(
false,
vec![default_runs[0].to_owned()],
false,
vec![],
false,
vec![],
false,
vec![],
false,
false,
);
} else {
// ops::run will take care of errors if len pkgs != 1.
compile_opts.filter = CompileFilter::Default {
// Force this to false because the code in ops::run is not
// able to pre-check features before compilation starts to
// enforce that only 1 binary is built.
required_features_filterable: false,
};
}
};
match ops::run(&ws, &compile_opts, &values_os(args, "args"))? {
None => Ok(()),
Some(err) => {
// If we never actually spawned the process then that sounds pretty
// bad and we always want to forward that up.
let exit = match err.exit {
Some(exit) => exit,
None => return Err(CliError::new(err.into(), 101)),
};
// If `-q` was passed then we suppress extra error information about
// a failed process, we assume the process itself printed out enough
// information about why it failed so we don't do so as well
let exit_code = exit.code().unwrap_or(101);
let is_quiet = config.shell().verbosity() == Verbosity::Quiet;
Err(if is_quiet {
CliError::code(exit_code)
} else {
CliError::new(err.into(), exit_code)
})
}
}
}