Add target directory parameter --target-dir
authorSimon Smith <smithsps@gmail.com>
Mon, 16 Apr 2018 23:50:30 +0000 (19:50 -0400)
committerSimon Smith <smithsps@gmail.com>
Mon, 23 Apr 2018 22:23:48 +0000 (18:23 -0400)
16 files changed:
src/bin/cli.rs
src/bin/command_prelude.rs
src/bin/commands/bench.rs
src/bin/commands/build.rs
src/bin/commands/check.rs
src/bin/commands/clean.rs
src/bin/commands/doc.rs
src/bin/commands/package.rs
src/bin/commands/publish.rs
src/bin/commands/run.rs
src/bin/commands/rustc.rs
src/bin/commands/rustdoc.rs
src/bin/commands/test.rs
src/cargo/util/config.rs
tests/testsuite/build.rs
tests/testsuite/resolve.rs

index 0161a0f6bf9ca1454fe64b4c3a89fb8c0df31dc3..dd33ce5387e61f07f2a37007be2be0e11f0d8b6b 100644 (file)
@@ -72,6 +72,16 @@ Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
 }
 
 fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult {
+    let (cmd, subcommand_args) = match args.subcommand() {
+        (cmd, Some(args)) => (cmd, args),
+        _ => {
+            cli().print_help()?;
+            return Ok(());
+        }
+    };
+    
+    let arg_target_dir = &subcommand_args.value_of_path("target-dir", config);
+
     config.configure(
         args.occurrences_of("verbose") as u32,
         if args.is_present("quiet") {
@@ -82,35 +92,28 @@ fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult {
         &args.value_of("color").map(|s| s.to_string()),
         args.is_present("frozen"),
         args.is_present("locked"),
+        arg_target_dir,
         &args.values_of_lossy("unstable-features")
             .unwrap_or_default(),
     )?;
 
-    let (cmd, args) = match args.subcommand() {
-        (cmd, Some(args)) => (cmd, args),
-        _ => {
-            cli().print_help()?;
-            return Ok(());
-        }
-    };
-
     if let Some(exec) = commands::builtin_exec(cmd) {
-        return exec(config, args);
+        return exec(config, subcommand_args);
     }
 
     if let Some(mut alias) = super::aliased_command(config, cmd)? {
         alias.extend(
-            args.values_of("")
-                .unwrap_or_default()
-                .map(|s| s.to_string()),
+            subcommand_args.values_of("")
+                           .unwrap_or_default()
+                           .map(|s| s.to_string()),
         );
-        let args = cli()
+        let subcommand_args = cli()
             .setting(AppSettings::NoBinaryName)
             .get_matches_from_safe(alias)?;
-        return execute_subcommand(config, args);
+        return execute_subcommand(config, subcommand_args);
     }
     let mut ext_args: Vec<&str> = vec![cmd];
-    ext_args.extend(args.values_of("").unwrap_or_default());
+    ext_args.extend(subcommand_args.values_of("").unwrap_or_default());
     super::execute_external_subcommand(config, cmd, &ext_args)
 }
 
index 79572d8d34b366586743be1a432ff5ab87c7c16d..9875b6b7c22f1c1982962d9ae9f1593b86e4d4d8 100644 (file)
@@ -109,6 +109,10 @@ pub trait AppExt: Sized {
         self._arg(opt("target", target).value_name("TRIPLE"))
     }
 
+    fn arg_target_dir(self) -> Self {
+        self._arg(opt("target-dir", "Directory for all generated artifacts").value_name("DIRECTORY"))
+    }
+
     fn arg_manifest_path(self) -> Self {
         self._arg(opt("manifest-path", "Path to Cargo.toml").value_name("PATH"))
     }
index af70656980db9d61538dd83a0c83ff6554cc2d30..83e3ab5af5383cc02a38fb6cfe61c1bbba1d987f 100644 (file)
@@ -37,6 +37,7 @@ pub fn cli() -> App {
         .arg_jobs()
         .arg_features()
         .arg_target_triple("Build for the target triple")
+        .arg_target_dir()
         .arg_manifest_path()
         .arg_message_format()
         .arg(opt(
index 70e9d3225280992759852c28852bed1b285a586e..0ab86aa3a3a8721ffd0ed1765294954db721da60 100644 (file)
@@ -27,6 +27,7 @@ pub fn cli() -> App {
         .arg_release("Build artifacts in release mode, with optimizations")
         .arg_features()
         .arg_target_triple("Build for the target triple")
+        .arg_target_dir()
         .arg(opt("out-dir", "Copy final artifacts to this directory").value_name("PATH"))
         .arg_manifest_path()
         .arg_message_format()
index 45361740d6182e46c92a9d593682f0f2d6a9c41d..e4295c5c32be3337caf7284729b2a93db9c058f1 100644 (file)
@@ -27,6 +27,7 @@ pub fn cli() -> App {
         .arg(opt("profile", "Profile to build the selected target for").value_name("PROFILE"))
         .arg_features()
         .arg_target_triple("Check for the target triple")
+        .arg_target_dir()
         .arg_manifest_path()
         .arg_message_format()
         .after_help(
index 8d0928cc2b2091e2009c7e892741e6a750b82f7b..1661091d8c7729615e6533490d1d8ad82c3b713c 100644 (file)
@@ -8,6 +8,7 @@ pub fn cli() -> App {
         .arg_package_spec_simple("Package to clean artifacts for")
         .arg_manifest_path()
         .arg_target_triple("Target triple to clean output for (default all)")
+        .arg_target_dir()
         .arg_release("Whether or not to clean release artifacts")
         .after_help(
             "\
index a6a2546750ff9afc1f2422123077823607b7d60c..54ba9679794b3dd93117340997fbc24f41e933cf 100644 (file)
@@ -24,6 +24,7 @@ pub fn cli() -> App {
         .arg_release("Build artifacts in release mode, with optimizations")
         .arg_features()
         .arg_target_triple("Build for the target triple")
+        .arg_target_dir()
         .arg_manifest_path()
         .arg_message_format()
         .after_help(
index bc02332bc548d747315cc7975ca257f5e2f401c4..f5e9d9184622b770fb9a48a9cb0b9e5acbaa74ca 100644 (file)
@@ -24,6 +24,7 @@ pub fn cli() -> App {
             "Allow dirty working directories to be packaged",
         ))
         .arg_target_triple("Build for the target triple")
+        .arg_target_dir()
         .arg_manifest_path()
         .arg_jobs()
 }
index fe7ea2a551d05d60380c2ab9d96620df3c4a6d0d..b50d3619cf4e2a488cb65e5201283aad95937b33 100644 (file)
@@ -16,6 +16,7 @@ pub fn cli() -> App {
             "Allow dirty working directories to be packaged",
         ))
         .arg_target_triple("Build for the target triple")
+        .arg_target_dir()
         .arg_manifest_path()
         .arg_jobs()
         .arg(opt("dry-run", "Perform all checks without uploading"))
index 0858e96a591df4e777391b0b977d549e53d8de6b..763263d5a4b63167d0cfff7311c417a0649a608b 100644 (file)
@@ -18,6 +18,7 @@ pub fn cli() -> App {
         .arg_release("Build artifacts in release mode, with optimizations")
         .arg_features()
         .arg_target_triple("Build for the target triple")
+        .arg_target_dir()
         .arg_manifest_path()
         .arg_message_format()
         .after_help(
index fb998c911a51387688b0ebee329e0ae2b1cb35d3..35fb59e8e12e4017531f1ef409367ee4144b0f7a 100644 (file)
@@ -25,6 +25,7 @@ pub fn cli() -> App {
         .arg(opt("profile", "Profile to build the selected target for").value_name("PROFILE"))
         .arg_features()
         .arg_target_triple("Target triple which compiles will be for")
+        .arg_target_dir()
         .arg_manifest_path()
         .arg_message_format()
         .after_help(
index abd2c7405a3a88d63b65f3fb1d93820a25338b8d..301e65449b85c6d12bb6be785b5b7f60770f7e8c 100644 (file)
@@ -27,6 +27,7 @@ pub fn cli() -> App {
         )
         .arg_release("Build artifacts in release mode, with optimizations")
         .arg_features()
+        .arg_target_dir()
         .arg_manifest_path()
         .arg_message_format()
         .after_help(
index 35cab8762d2158a08ed21fa926c405d6e49a26ba..a25f62f8ec30f6eb99604d2d296968efb3901c90 100644 (file)
@@ -41,6 +41,7 @@ pub fn cli() -> App {
         .arg_release("Build artifacts in release mode, with optimizations")
         .arg_features()
         .arg_target_triple("Build for the target triple")
+        .arg_target_dir()
         .arg_manifest_path()
         .arg_message_format()
         .after_help(
index ac8bf21f6a405a19d5d4d5957322b74b0cdbcee0..30c63e279339f5c7b749b3a3afa4720eaa454fe2 100644 (file)
@@ -70,6 +70,8 @@ pub struct Config {
     cache_rustc_info: bool,
     /// Creation time of this config, used to output the total build time
     creation_time: Instant,
+    /// Target Directory via resolved Cli parameter 
+    cli_target_dir: Option<Filesystem>,
 }
 
 impl Config {
@@ -113,6 +115,7 @@ impl Config {
             crates_io_source_id: LazyCell::new(),
             cache_rustc_info,
             creation_time: Instant::now(),
+            cli_target_dir: None,
         }
     }
 
@@ -240,7 +243,9 @@ impl Config {
     }
 
     pub fn target_dir(&self) -> CargoResult<Option<Filesystem>> {
-        if let Some(dir) = env::var_os("CARGO_TARGET_DIR") {
+        if let Some(ref dir) = self.cli_target_dir {
+            Ok(Some(dir.clone()))
+        } else if let Some(dir) = env::var_os("CARGO_TARGET_DIR") {
             Ok(Some(Filesystem::new(self.cwd.join(dir))))
         } else if let Some(val) = self.get_path("build.target-dir")? {
             let val = self.cwd.join(val.val);
@@ -461,6 +466,7 @@ impl Config {
         color: &Option<String>,
         frozen: bool,
         locked: bool,
+        target_dir: &Option<PathBuf>,
         unstable_flags: &[String],
     ) -> CargoResult<()> {
         let extra_verbose = verbose >= 2;
@@ -494,11 +500,17 @@ impl Config {
             | (None, None, None) => Verbosity::Normal,
         };
 
+        let cli_target_dir = match target_dir.as_ref() {
+            Some(dir) => Some(Filesystem::new(dir.clone())),
+            None => None,
+        };
+
         self.shell().set_verbosity(verbosity);
         self.shell().set_color_choice(color.map(|s| &s[..]))?;
         self.extra_verbose = extra_verbose;
         self.frozen = frozen;
         self.locked = locked;
+        self.cli_target_dir = cli_target_dir;
         self.cli_flags.parse(unstable_flags)?;
 
         Ok(())
index 403ef8a3a2d9ca3fe4425c324e46f6ba20f81b69..acc315ceaa6d5c343fe35452e38f7446bb811aa2 100644 (file)
@@ -3603,7 +3603,7 @@ fn dotdir_root() {
 }
 
 #[test]
-fn custom_target_dir() {
+fn custom_target_dir_env() {
     let p = project("foo")
         .file(
             "Cargo.toml",
@@ -3670,6 +3670,123 @@ fn custom_target_dir() {
     );
 }
 
+#[test]
+fn custom_target_dir_line_parameter() {
+    let p = project("foo")
+        .file(
+            "Cargo.toml",
+            r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+        "#,
+        )
+        .file("src/main.rs", "fn main() {}")
+        .build();
+
+    let exe_name = format!("foo{}", env::consts::EXE_SUFFIX);
+
+    assert_that(
+        p.cargo("build").arg("--target-dir").arg("foo/target"),
+        execs().with_status(0),
+    );
+    assert_that(
+        &p.root().join("foo/target/debug").join(&exe_name),
+        existing_file(),
+    );
+    assert_that(
+        &p.root().join("target/debug").join(&exe_name),
+        is_not(existing_file()),
+    );
+
+    assert_that(p.cargo("build"), execs().with_status(0));
+    assert_that(
+        &p.root().join("foo/target/debug").join(&exe_name),
+        existing_file(),
+    );
+    assert_that(
+        &p.root().join("target/debug").join(&exe_name),
+        existing_file(),
+    );
+
+    fs::create_dir(p.root().join(".cargo")).unwrap();
+    File::create(p.root().join(".cargo/config"))
+        .unwrap()
+        .write_all(
+            br#"
+        [build]
+        target-dir = "foo/target"
+    "#,
+        )
+        .unwrap();
+    assert_that(
+        p.cargo("build").arg("--target-dir").arg("bar/target"),
+        execs().with_status(0),
+    );
+    assert_that(
+        &p.root().join("bar/target/debug").join(&exe_name),
+        existing_file(),
+    );
+    assert_that(
+        &p.root().join("foo/target/debug").join(&exe_name),
+        existing_file(),
+    );
+    assert_that(
+        &p.root().join("target/debug").join(&exe_name),
+        existing_file(),
+    );
+
+    assert_that(
+        p.cargo("build")
+            .arg("--target-dir")
+            .arg("foobar/target")
+            .env("CARGO_TARGET_DIR", "bar/target"),
+        execs().with_status(0),
+    );
+    assert_that(
+        &p.root().join("foobar/target/debug").join(&exe_name),
+        existing_file(),
+    );
+    assert_that(
+        &p.root().join("bar/target/debug").join(&exe_name),
+        existing_file(),
+    );
+    assert_that(
+        &p.root().join("foo/target/debug").join(&exe_name),
+        existing_file(),
+    );
+    assert_that(
+        &p.root().join("target/debug").join(&exe_name),
+        existing_file(),
+    );
+}
+
+#[test]
+fn rustc_no_trans() {
+    if !is_nightly() {
+        return;
+    }
+
+    let p = project("foo")
+        .file(
+            "Cargo.toml",
+            r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+        "#,
+        )
+        .file("src/main.rs", "fn main() {}")
+        .build();
+
+    assert_that(
+        p.cargo("rustc").arg("-v").arg("--").arg("-Zno-trans"),
+        execs().with_status(0),
+    );
+}
+
 #[test]
 fn build_multiple_packages() {
     let p = project("foo")
index 427f06938eae942aa5d2f79500795ef60399b3db..a8bf3545b25343ab23c4f6259fc1e79b1502189a 100644 (file)
@@ -362,6 +362,7 @@ fn test_resolving_minimum_version_with_transitive_deps() {
             &None,
             false,
             false,
+            &None,
             &["minimal-versions".to_string()],
         )
         .unwrap();