mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Auto merge of #5710 - RalfJung:default-run, r=alexcrichton
implement default-run option to set default binary for cargo run The implementation is not pretty but as good as I could make it. The fact that all this logic in `cargo_run` is for diagnosis only and essentially just re-implements the filtering done elsewhere really threw me off. Fixes #2200
This commit is contained in:
commit
e325bff3c4
@ -40,9 +40,26 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
|
|||||||
|
|
||||||
let mut compile_opts = args.compile_options_for_single_package(config, CompileMode::Build)?;
|
let mut compile_opts = args.compile_options_for_single_package(config, CompileMode::Build)?;
|
||||||
if !args.is_present("example") && !args.is_present("bin") {
|
if !args.is_present("example") && !args.is_present("bin") {
|
||||||
compile_opts.filter = CompileFilter::Default {
|
if let Some(default_run) = compile_opts.get_package(&ws)?
|
||||||
required_features_filterable: false,
|
.and_then(|pkg| pkg.manifest().default_run())
|
||||||
};
|
{
|
||||||
|
compile_opts.filter = CompileFilter::new(
|
||||||
|
false,
|
||||||
|
vec![default_run.to_owned()],
|
||||||
|
false,
|
||||||
|
vec![],
|
||||||
|
false,
|
||||||
|
vec![],
|
||||||
|
false,
|
||||||
|
vec![],
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
compile_opts.filter = CompileFilter::Default {
|
||||||
|
required_features_filterable: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
match ops::run(&ws, &compile_opts, &values(args, "args"))? {
|
match ops::run(&ws, &compile_opts, &values(args, "args"))? {
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
|
@ -186,6 +186,9 @@ features! {
|
|||||||
|
|
||||||
// Separating the namespaces for features and dependencies
|
// Separating the namespaces for features and dependencies
|
||||||
[unstable] namespaced_features: bool,
|
[unstable] namespaced_features: bool,
|
||||||
|
|
||||||
|
// "default-run" manifest option,
|
||||||
|
[unstable] default_run: bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ pub struct Manifest {
|
|||||||
features: Features,
|
features: Features,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
im_a_teapot: Option<bool>,
|
im_a_teapot: Option<bool>,
|
||||||
|
default_run: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When parsing `Cargo.toml`, some warnings should silenced
|
/// When parsing `Cargo.toml`, some warnings should silenced
|
||||||
@ -297,6 +298,7 @@ impl Manifest {
|
|||||||
features: Features,
|
features: Features,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
im_a_teapot: Option<bool>,
|
im_a_teapot: Option<bool>,
|
||||||
|
default_run: Option<String>,
|
||||||
original: Rc<TomlManifest>,
|
original: Rc<TomlManifest>,
|
||||||
) -> Manifest {
|
) -> Manifest {
|
||||||
Manifest {
|
Manifest {
|
||||||
@ -317,6 +319,7 @@ impl Manifest {
|
|||||||
edition,
|
edition,
|
||||||
original,
|
original,
|
||||||
im_a_teapot,
|
im_a_teapot,
|
||||||
|
default_run,
|
||||||
publish_lockfile,
|
publish_lockfile,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,6 +410,16 @@ impl Manifest {
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.default_run.is_some() {
|
||||||
|
self.features
|
||||||
|
.require(Feature::default_run())
|
||||||
|
.chain_err(|| {
|
||||||
|
format_err!(
|
||||||
|
"the `default-run` manifest key is unstable"
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,6 +439,10 @@ impl Manifest {
|
|||||||
pub fn custom_metadata(&self) -> Option<&toml::Value> {
|
pub fn custom_metadata(&self) -> Option<&toml::Value> {
|
||||||
self.custom_metadata.as_ref()
|
self.custom_metadata.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_run(&self) -> Option<&str> {
|
||||||
|
self.default_run.as_ref().map(|s| &s[..])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualManifest {
|
impl VirtualManifest {
|
||||||
|
@ -83,6 +83,24 @@ impl<'a> CompileOptions<'a> {
|
|||||||
export_dir: None,
|
export_dir: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the unique specified package, or None
|
||||||
|
pub fn get_package<'b>(&self, ws: &'b Workspace) -> CargoResult<Option<&'b Package>> {
|
||||||
|
Ok(match self.spec {
|
||||||
|
Packages::All | Packages::Default | Packages::OptOut(_) => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Packages::Packages(ref xs) => match xs.len() {
|
||||||
|
0 => Some(ws.current()?),
|
||||||
|
1 => Some(ws.members()
|
||||||
|
.find(|pkg| *pkg.name() == xs[0])
|
||||||
|
.ok_or_else(|| {
|
||||||
|
format_err!("package `{}` is not a member of the workspace", xs[0])
|
||||||
|
})?),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use ops::{self, Packages};
|
use ops;
|
||||||
use util::{self, CargoResult, ProcessError};
|
use util::{self, CargoResult, ProcessError};
|
||||||
use core::{TargetKind, Workspace};
|
use core::{TargetKind, Workspace};
|
||||||
|
|
||||||
@ -11,21 +11,11 @@ pub fn run(
|
|||||||
) -> CargoResult<Option<ProcessError>> {
|
) -> CargoResult<Option<ProcessError>> {
|
||||||
let config = ws.config();
|
let config = ws.config();
|
||||||
|
|
||||||
let pkg = match options.spec {
|
let pkg = options.get_package(ws)?
|
||||||
Packages::All | Packages::Default | Packages::OptOut(_) => {
|
.unwrap_or_else(|| unreachable!("cargo run supports single package only"));
|
||||||
unreachable!("cargo run supports single package only")
|
|
||||||
}
|
|
||||||
Packages::Packages(ref xs) => match xs.len() {
|
|
||||||
0 => ws.current()?,
|
|
||||||
1 => ws.members()
|
|
||||||
.find(|pkg| *pkg.name() == xs[0])
|
|
||||||
.ok_or_else(|| {
|
|
||||||
format_err!("package `{}` is not a member of the workspace", xs[0])
|
|
||||||
})?,
|
|
||||||
_ => unreachable!("cargo run supports single package only"),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// We compute the `bins` here *just for diagnosis*. The actual set of packages to be run
|
||||||
|
// is determined by the `ops::compile` call below.
|
||||||
let bins: Vec<_> = pkg.manifest()
|
let bins: Vec<_> = pkg.manifest()
|
||||||
.targets()
|
.targets()
|
||||||
.iter()
|
.iter()
|
||||||
@ -66,9 +56,8 @@ pub fn run(
|
|||||||
bail!(
|
bail!(
|
||||||
"`cargo run` requires that a project only have one \
|
"`cargo run` requires that a project only have one \
|
||||||
executable; use the `--bin` option to specify which one \
|
executable; use the `--bin` option to specify which one \
|
||||||
to run\navailable binaries: {}",
|
to run\navailable binaries: {}",
|
||||||
names.join(", ")
|
names.join(", ")
|
||||||
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
bail!(
|
bail!(
|
||||||
@ -102,4 +91,4 @@ pub fn run(
|
|||||||
Ok(Some(err))
|
Ok(Some(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -586,6 +586,8 @@ pub struct TomlProject {
|
|||||||
autobenches: Option<bool>,
|
autobenches: Option<bool>,
|
||||||
#[serde(rename = "namespaced-features")]
|
#[serde(rename = "namespaced-features")]
|
||||||
namespaced_features: Option<bool>,
|
namespaced_features: Option<bool>,
|
||||||
|
#[serde(rename = "default-run")]
|
||||||
|
default_run: Option<String>,
|
||||||
|
|
||||||
// package metadata
|
// package metadata
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
@ -970,6 +972,7 @@ impl TomlManifest {
|
|||||||
features,
|
features,
|
||||||
edition,
|
edition,
|
||||||
project.im_a_teapot,
|
project.im_a_teapot,
|
||||||
|
project.default_run.clone(),
|
||||||
Rc::clone(me),
|
Rc::clone(me),
|
||||||
);
|
);
|
||||||
if project.license_file.is_some() && project.license.is_some() {
|
if project.license_file.is_some() && project.license.is_some() {
|
||||||
|
@ -308,3 +308,15 @@ $ cargo +nightly build -Z compile-progress
|
|||||||
Compiling utf8-ranges v1.0.0
|
Compiling utf8-ranges v1.0.0
|
||||||
Building [=======> ] 2/14: libc, regex, uc...
|
Building [=======> ] 2/14: libc, regex, uc...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### default-run
|
||||||
|
* Original issue: [#2200](https://github.com/rust-lang/cargo/issues/2200)
|
||||||
|
|
||||||
|
The `default-run` option in the `[project]` section of the manifest can be used
|
||||||
|
to specify a default binary picked by `cargo run`. For example, when there is
|
||||||
|
both `src/bin/a.rs` and `src/bin/b.rs`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project]
|
||||||
|
default-run = "a"
|
||||||
|
```
|
||||||
|
@ -275,6 +275,7 @@ fn too_many_bins() {
|
|||||||
|
|
||||||
assert_that(
|
assert_that(
|
||||||
p.cargo("run"),
|
p.cargo("run"),
|
||||||
|
// Using [..] here because the order is not stable
|
||||||
execs().with_status(101).with_stderr(
|
execs().with_status(101).with_stderr(
|
||||||
"[ERROR] `cargo run` requires that a project only \
|
"[ERROR] `cargo run` requires that a project only \
|
||||||
have one executable; use the `--bin` option \
|
have one executable; use the `--bin` option \
|
||||||
@ -345,6 +346,124 @@ fn specify_name() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn specify_default_run() {
|
||||||
|
let p = project("foo")
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
cargo-features = ["default-run"]
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
default-run = "a"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.file("src/bin/a.rs", r#"fn main() { println!("hello A"); }"#)
|
||||||
|
.file("src/bin/b.rs", r#"fn main() { println!("hello B"); }"#)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assert_that(
|
||||||
|
p.cargo("run").masquerade_as_nightly_cargo(),
|
||||||
|
execs()
|
||||||
|
.with_status(0)
|
||||||
|
.with_stdout("hello A"),
|
||||||
|
);
|
||||||
|
assert_that(
|
||||||
|
p.cargo("run").masquerade_as_nightly_cargo().arg("--bin").arg("a"),
|
||||||
|
execs()
|
||||||
|
.with_status(0)
|
||||||
|
.with_stdout("hello A"),
|
||||||
|
);
|
||||||
|
assert_that(
|
||||||
|
p.cargo("run").masquerade_as_nightly_cargo().arg("--bin").arg("b"),
|
||||||
|
execs()
|
||||||
|
.with_status(0)
|
||||||
|
.with_stdout("hello B"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bogus_default_run() {
|
||||||
|
let p = project("foo")
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
cargo-features = ["default-run"]
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
default-run = "b"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.file("src/bin/a.rs", r#"fn main() { println!("hello A"); }"#)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assert_that(
|
||||||
|
p.cargo("run").masquerade_as_nightly_cargo(),
|
||||||
|
execs().with_status(101).with_stderr(
|
||||||
|
"error: no bin target named `b`\n\nDid you mean [..]?",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_run_unstable() {
|
||||||
|
let p = project("foo")
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
default-run = "a"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/bin/a.rs", r#"fn main() { println!("hello A"); }"#)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assert_that(
|
||||||
|
p.cargo("run"),
|
||||||
|
execs().with_status(101).with_stderr(
|
||||||
|
r#"error: failed to parse manifest at [..]
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
the `default-run` manifest key is unstable
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
feature `default-run` is required
|
||||||
|
|
||||||
|
this Cargo does not support nightly features, but if you
|
||||||
|
switch to nightly channel you can add
|
||||||
|
`cargo-features = ["default-run"]` to enable this feature
|
||||||
|
"#,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_that(
|
||||||
|
p.cargo("run").masquerade_as_nightly_cargo(),
|
||||||
|
execs().with_status(101).with_stderr(
|
||||||
|
r#"error: failed to parse manifest at [..]
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
the `default-run` manifest key is unstable
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
feature `default-run` is required
|
||||||
|
|
||||||
|
consider adding `cargo-features = ["default-run"]` to the manifest
|
||||||
|
"#,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn run_example() {
|
fn run_example() {
|
||||||
let p = project("foo")
|
let p = project("foo")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user