use std::fs::{self, DirEntry};
use std::collections::HashSet;
-use core::{compiler, Target};
+use core::{compiler, Edition, Target};
use util::errors::CargoResult;
use super::{LibKind, PathValue, StringOrBool, TomlBenchTarget, TomlBinTarget, TomlExampleTarget,
TomlLibTarget, TomlManifest, TomlTarget, TomlTestTarget};
manifest: &TomlManifest,
package_name: &str,
package_root: &Path,
+ edition: Edition,
custom_build: &Option<StringOrBool>,
warnings: &mut Vec<String>,
errors: &mut Vec<String>,
has_lib = false;
}
+ let package = manifest
+ .package
+ .as_ref()
+ .or_else(|| manifest.project.as_ref())
+ .ok_or_else(|| format_err!("manifest has no `package` (or `project`)"))?;
+
targets.extend(clean_bins(
manifest.bin.as_ref(),
package_root,
package_name,
+ edition,
+ package.autobins,
warnings,
errors,
has_lib,
targets.extend(clean_examples(
manifest.example.as_ref(),
package_root,
+ edition,
+ package.autoexamples,
+ warnings,
errors,
)?);
- targets.extend(clean_tests(manifest.test.as_ref(), package_root, errors)?);
+ targets.extend(clean_tests(
+ manifest.test.as_ref(),
+ package_root,
+ edition,
+ package.autotests,
+ warnings,
+ errors,
+ )?);
targets.extend(clean_benches(
manifest.bench.as_ref(),
package_root,
+ edition,
+ package.autobenches,
warnings,
errors,
)?);
toml_bins: Option<&Vec<TomlBinTarget>>,
package_root: &Path,
package_name: &str,
+ edition: Edition,
+ autodiscover: Option<bool>,
warnings: &mut Vec<String>,
errors: &mut Vec<String>,
has_lib: bool,
let bins = toml_targets_and_inferred(
toml_bins,
&inferred,
+ package_root,
+ autodiscover,
+ edition,
+ warnings,
+ "binary",
+ "bin",
+ "autobins",
);
for bin in &bins {
fn clean_examples(
toml_examples: Option<&Vec<TomlExampleTarget>>,
package_root: &Path,
+ edition: Edition,
+ autodiscover: Option<bool>,
+ warnings: &mut Vec<String>,
errors: &mut Vec<String>,
) -> CargoResult<Vec<Target>> {
let inferred = infer_from_directory(&package_root.join("examples"));
toml_examples,
&inferred,
package_root,
+ edition,
+ autodiscover,
+ warnings,
errors,
+ "autoexamples",
)?;
let mut result = Vec::new();
fn clean_tests(
toml_tests: Option<&Vec<TomlTestTarget>>,
package_root: &Path,
+ edition: Edition,
+ autodiscover: Option<bool>,
+ warnings: &mut Vec<String>,
errors: &mut Vec<String>,
) -> CargoResult<Vec<Target>> {
let inferred = infer_from_directory(&package_root.join("tests"));
- let targets = clean_targets("test", "test", toml_tests, &inferred, package_root, errors)?;
+ let targets = clean_targets(
+ "test",
+ "test",
+ toml_tests,
+ &inferred,
+ package_root,
+ edition,
+ autodiscover,
+ warnings,
+ errors,
+ "autotests",
+ )?;
let mut result = Vec::new();
for (path, toml) in targets {
fn clean_benches(
toml_benches: Option<&Vec<TomlBenchTarget>>,
package_root: &Path,
+ edition: Edition,
+ autodiscover: Option<bool>,
warnings: &mut Vec<String>,
errors: &mut Vec<String>,
) -> CargoResult<Vec<Target>> {
toml_benches,
&inferred,
package_root,
+ edition,
+ autodiscover,
+ warnings,
errors,
&mut legacy_bench_path,
+ "autobenches",
)?
};
toml_targets: Option<&Vec<TomlTarget>>,
inferred: &[(String, PathBuf)],
package_root: &Path,
+ edition: Edition,
+ autodiscover: Option<bool>,
+ warnings: &mut Vec<String>,
errors: &mut Vec<String>,
+ autodiscover_flag_name: &str,
) -> CargoResult<Vec<(PathBuf, TomlTarget)>> {
clean_targets_with_legacy_path(
target_kind_human,
toml_targets,
inferred,
package_root,
+ edition,
+ autodiscover,
+ warnings,
errors,
&mut |_| None,
+ autodiscover_flag_name,
)
}
toml_targets: Option<&Vec<TomlTarget>>,
inferred: &[(String, PathBuf)],
package_root: &Path,
+ edition: Edition,
+ autodiscover: Option<bool>,
+ warnings: &mut Vec<String>,
errors: &mut Vec<String>,
legacy_path: &mut FnMut(&TomlTarget) -> Option<PathBuf>,
+ autodiscover_flag_name: &str,
) -> CargoResult<Vec<(PathBuf, TomlTarget)>> {
let toml_targets = toml_targets_and_inferred(
toml_targets,
inferred,
+ package_root,
+ autodiscover,
+ edition,
+ warnings,
+ target_kind_human,
+ target_kind,
+ autodiscover_flag_name,
);
for target in &toml_targets {
fn toml_targets_and_inferred(
toml_targets: Option<&Vec<TomlTarget>>,
inferred: &[(String, PathBuf)],
+ package_root: &Path,
+ autodiscover: Option<bool>,
+ edition: Edition,
+ warnings: &mut Vec<String>,
+ target_kind_human: &str,
+ target_kind: &str,
+ autodiscover_flag_name: &str,
) -> Vec<TomlTarget> {
+ let inferred_targets = inferred_to_toml_targets(inferred);
match toml_targets {
- None => inferred_to_toml_targets(inferred),
- Some(targets) => targets.clone(),
+ None => inferred_targets,
+ Some(targets) => {
+ let mut targets = targets.clone();
+
+ let target_path =
+ |target: &TomlTarget| target.path.clone().map(|p| package_root.join(p.0));
+
+ let mut seen_names = HashSet::new();
+ let mut seen_paths = HashSet::new();
+ for target in targets.iter() {
+ seen_names.insert(target.name.clone());
+ seen_paths.insert(target_path(target));
+ }
+
+ let mut rem_targets = vec![];
+ for target in inferred_targets {
+ if !seen_names.contains(&target.name) && !seen_paths.contains(&target_path(&target))
+ {
+ rem_targets.push(target);
+ }
+ }
+
+ let autodiscover = match autodiscover {
+ Some(autodiscover) => autodiscover,
+ None => match edition {
+ Edition::Edition2018 => true,
+ Edition::Edition2015 => {
+ if !rem_targets.is_empty() {
+ let mut rem_targets_str = String::new();
+ for t in rem_targets.iter() {
+ if let Some(p) = t.path.clone() {
+ rem_targets_str.push_str(&format!("* {:?}\n", p.0))
+ }
+ }
+ warnings.push(format!(
+ "\
+An explicit [[{section}]] section is specified in Cargo.toml which currently disables Cargo from \
+automatically inferring other {target_kind_human} targets. This inference behavior will change in \
+the Rust 2018 edition and the following files will be included as a {target_kind_human} target:
+
+{rem_targets_str}
+This is likely to break cargo build or cargo test as these files may not be ready to be compiled \
+as a {target_kind_human} target today. You can future-proof yourself and disable this warning by \
+adding {autodiscover_flag_name} = false to your [package] section. You may also move the files to \
+a location where Cargo would not automatically infer them to be a target, such as in subfolders.
+
+For more information on this warning you can consult https://github.com/rust-lang/cargo/issues/5330\
+ ",
+ section = target_kind,
+ target_kind_human = target_kind_human,
+ rem_targets_str = rem_targets_str,
+ autodiscover_flag_name = autodiscover_flag_name,
+ ));
+ };
+ false
+ }
+ },
+ };
+
+ if autodiscover {
+ targets.append(&mut rem_targets);
+ }
+
+ targets
+ }
}
}
use std::str;
use cargo::util::process;
-use cargotest::is_nightly;
+use cargotest::{is_nightly, ChannelChanger};
use cargotest::support::paths::CargoPathExt;
use cargotest::support::{basic_bin_manifest, basic_lib_manifest, execs, project};
use hamcrest::{assert_that, existing_file};
);
}
+#[test]
+fn bench_autodiscover_2015() {
+ if !is_nightly() {
+ return;
+ }
+
+ let p = project("foo")
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["edition"]
+
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+ rust = "2015"
+
+ [[bench]]
+ name = "bench_magic"
+ required-features = ["magic"]
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file(
+ "benches/bench_basic.rs",
+ r#"
+ #![feature(test)]
+ #[allow(unused_extern_crates)]
+ extern crate foo;
+ extern crate test;
+
+ #[bench]
+ fn bench_basic(_b: &mut test::Bencher) {}
+ "#,
+ )
+ .file(
+ "benches/bench_magic.rs",
+ r#"
+ #![feature(test)]
+ #[allow(unused_extern_crates)]
+ extern crate foo;
+ extern crate test;
+
+ #[bench]
+ fn bench_magic(_b: &mut test::Bencher) {}
+ "#,
+ )
+ .build();
+
+ assert_that(
+ p.cargo("bench")
+ .arg("bench_basic")
+ .masquerade_as_nightly_cargo(),
+ execs().with_stderr(&format!(
+ "warning: \
+An explicit [[bench]] section is specified in Cargo.toml which currently disables Cargo from \
+automatically inferring other benchmark targets. This inference behavior will change in \
+the Rust 2018 edition and the following files will be included as a benchmark target:
+
+* \"[..]foo[/]benches[/]bench_basic.rs\"
+
+This is likely to break cargo build or cargo test as these files may not be ready to be compiled \
+as a benchmark target today. You can future-proof yourself and disable this warning by \
+adding autobenches = false to your [package] section. You may also move the files to \
+a location where Cargo would not automatically infer them to be a target, such as in subfolders.
+
+For more information on this warning you can consult https://github.com/rust-lang/cargo/issues/5330
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] release [optimized] target(s) in [..]
+[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]
+",
+ p.url()
+ )),
+ );
+}
+
#[test]
fn dont_run_examples() {
if !is_nightly() {
use cargo::util::paths::dylib_path_envvar;
-use cargotest::support::{execs, project, path2url};
+use cargotest::{self, ChannelChanger};
+use cargotest::support::{execs, project, Project, path2url};
use hamcrest::{assert_that, existing_file};
#[test]
);
}
+fn autodiscover_examples_project(rust_edition: &str, autoexamples: Option<bool>) -> Project {
+ let autoexamples = match autoexamples {
+ None => "".to_string(),
+ Some(bool) => format!("autoexamples = {}", bool),
+ };
+ project("foo")
+ .file(
+ "Cargo.toml",
+ &format!(
+ r#"
+ cargo-features = ["edition"]
+
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+ rust = "{rust_edition}"
+ {autoexamples}
+
+ [features]
+ magic = []
+
+ [[example]]
+ name = "do_magic"
+ required-features = ["magic"]
+ "#,
+ rust_edition = rust_edition,
+ autoexamples = autoexamples
+ ),
+ )
+ .file(
+ "examples/a.rs",
+ r#"
+ fn main() { println!("example"); }
+ "#,
+ )
+ .file(
+ "examples/do_magic.rs",
+ r#"
+ fn main() { println!("magic example"); }
+ "#,
+ )
+ .build()
+}
+
+#[test]
+fn run_example_autodiscover_2015() {
+ if !cargotest::is_nightly() {
+ return;
+ }
+
+ let p = autodiscover_examples_project("2015", None);
+ assert_that(
+ p.cargo("run")
+ .arg("--example")
+ .arg("a")
+ .masquerade_as_nightly_cargo(),
+ execs().with_status(101).with_stderr(
+ "warning: \
+An explicit [[example]] section is specified in Cargo.toml which currently disables Cargo from \
+automatically inferring other example targets. This inference behavior will change in \
+the Rust 2018 edition and the following files will be included as a example target:
+
+* \"[..]foo[/]examples[/]a.rs\"
+
+This is likely to break cargo build or cargo test as these files may not be ready to be compiled \
+as a example target today. You can future-proof yourself and disable this warning by \
+adding autoexamples = false to your [package] section. You may also move the files to \
+a location where Cargo would not automatically infer them to be a target, such as in subfolders.
+
+For more information on this warning you can consult https://github.com/rust-lang/cargo/issues/5330
+error: no example target named `a`
+",
+ ),
+ );
+}
+
+#[test]
+fn run_example_autodiscover_2015_with_autoexamples_enabled() {
+ if !cargotest::is_nightly() {
+ return;
+ }
+
+ let p = autodiscover_examples_project("2015", Some(true));
+ assert_that(
+ p.cargo("run")
+ .arg("--example")
+ .arg("a")
+ .masquerade_as_nightly_cargo(),
+ execs()
+ .with_status(0)
+ .with_stderr(&format!(
+ "\
+[COMPILING] foo v0.0.1 ({dir})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] `target[/]debug[/]examples[/]a[EXE]`",
+ dir = path2url(p.root())
+ ))
+ .with_stdout("example"),
+ );
+}
+
+#[test]
+fn run_example_autodiscover_2015_with_autoexamples_disabled() {
+ if !cargotest::is_nightly() {
+ return;
+ }
+
+ let p = autodiscover_examples_project("2015", Some(false));
+ assert_that(
+ p.cargo("run")
+ .arg("--example")
+ .arg("a")
+ .masquerade_as_nightly_cargo(),
+ execs()
+ .with_status(101)
+ .with_stderr("error: no example target named `a`\n"),
+ );
+}
+
+#[test]
+fn run_example_autodiscover_2018() {
+ if !cargotest::is_nightly() {
+ return;
+ }
+
+ let p = autodiscover_examples_project("2018", None);
+ assert_that(
+ p.cargo("run")
+ .arg("--example")
+ .arg("a")
+ .masquerade_as_nightly_cargo(),
+ execs()
+ .with_status(0)
+ .with_stderr(&format!(
+ "\
+[COMPILING] foo v0.0.1 ({dir})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] `target[/]debug[/]examples[/]a[EXE]`",
+ dir = path2url(p.root())
+ ))
+ .with_stdout("example"),
+ );
+}
+
#[test]
fn run_bins() {
let p = project("foo")