From c1af3bd7ee792644fb073f7452f044e2a542c2e2 Mon Sep 17 00:00:00 2001 From: Alex Huszagh Date: Mon, 11 Jul 2022 17:23:58 -0500 Subject: [PATCH] Allow users to ignore config files in the package. Adds the `CROSS_BUILD_ENV_IGNORE_CARGO_CONFIG` environment variable, which if set will mount an anoymous data volume for each `.cargo` subdirectory for the current directory and any parent directories up to the workspace root. If the build is called outside the workspace root or at the workspace root, only mount at the `$PWD/.cargo`. --- .changes/936.json | 5 ++++ docs/cross_toml.md | 1 + src/config.rs | 12 +++++++++ src/cross_toml.rs | 18 +++++++++++++ src/docker/local.rs | 2 +- src/docker/remote.rs | 2 +- src/docker/shared.rs | 64 +++++++++++++++++++++++++++++++++++++------- src/lib.rs | 10 +++++-- 8 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 .changes/936.json diff --git a/.changes/936.json b/.changes/936.json new file mode 100644 index 000000000..27fc3d223 --- /dev/null +++ b/.changes/936.json @@ -0,0 +1,5 @@ +{ + "type": "added", + "description": "allow users to ignore config files in the package.", + "issues": [621] +} diff --git a/docs/cross_toml.md b/docs/cross_toml.md index 91e3f36f3..5813f9435 100644 --- a/docs/cross_toml.md +++ b/docs/cross_toml.md @@ -21,6 +21,7 @@ For example: ```toml [build.env] +ignore-cargo-config = false volumes = ["VOL1_ARG", "VOL2_ARG"] passthrough = ["IMPORTANT_ENV_VARIABLES"] ``` diff --git a/src/config.rs b/src/config.rs index a5d583016..1574af818 100644 --- a/src/config.rs +++ b/src/config.rs @@ -96,6 +96,10 @@ impl Environment { self.get_target_var(target, "RUNNER") } + fn ignore_cargo_config(&self, target: &Target) -> (Option, Option) { + self.get_values_for("ENV_IGNORE_CARGO_CONFIG", target, bool_from_envvar) + } + fn passthrough(&self, target: &Target) -> (Option>, Option>) { self.get_values_for("ENV_PASSTHROUGH", target, split_to_cloned_by_ws) } @@ -275,6 +279,14 @@ impl Config { self.bool_from_config(target, Environment::build_std, CrossToml::build_std) } + pub fn ignore_cargo_config(&self, target: &Target) -> Option { + self.bool_from_config( + target, + Environment::ignore_cargo_config, + CrossToml::ignore_cargo_config, + ) + } + pub fn image(&self, target: &Target) -> Result> { self.string_from_config(target, Environment::image, CrossToml::image) } diff --git a/src/cross_toml.rs b/src/cross_toml.rs index 819143f05..bdaa9d743 100644 --- a/src/cross_toml.rs +++ b/src/cross_toml.rs @@ -11,7 +11,9 @@ use std::str::FromStr; /// Environment configuration #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default)] +#[serde(rename_all = "kebab-case")] pub struct CrossEnvConfig { + ignore_cargo_config: Option, volumes: Option>, passthrough: Option>, } @@ -273,6 +275,15 @@ impl CrossToml { self.get_value(target, |b| b.build_std, |t| t.build_std) } + /// Returns the whether to ignore cargo config files. + pub fn ignore_cargo_config(&self, target: &Target) -> (Option, Option) { + self.get_value( + target, + |b| b.env.ignore_cargo_config, + |t| t.env.ignore_cargo_config, + ) + } + /// Returns the list of environment variables to pass through for `build` and `target` pub fn env_passthrough(&self, target: &Target) -> (Option<&[String]>, Option<&[String]>) { self.get_ref( @@ -489,6 +500,7 @@ mod tests { targets: HashMap::new(), build: CrossBuildConfig { env: CrossEnvConfig { + ignore_cargo_config: Some(false), volumes: Some(vec![s!("VOL1_ARG"), s!("VOL2_ARG")]), passthrough: Some(vec![s!("VAR1"), s!("VAR2")]), }, @@ -506,6 +518,7 @@ mod tests { pre-build = ["echo 'Hello World!'"] [build.env] + ignore-cargo-config = false volumes = ["VOL1_ARG", "VOL2_ARG"] passthrough = ["VAR1", "VAR2"] "#; @@ -526,6 +539,7 @@ mod tests { }, CrossTargetConfig { env: CrossEnvConfig { + ignore_cargo_config: None, passthrough: Some(vec![s!("VAR1"), s!("VAR2")]), volumes: Some(vec![s!("VOL1_ARG"), s!("VOL2_ARG")]), }, @@ -580,6 +594,7 @@ mod tests { pre_build: Some(PreBuild::Lines(vec![s!("echo 'Hello'")])), runner: None, env: CrossEnvConfig { + ignore_cargo_config: None, passthrough: None, volumes: Some(vec![s!("VOL")]), }, @@ -590,6 +605,7 @@ mod tests { targets: target_map, build: CrossBuildConfig { env: CrossEnvConfig { + ignore_cargo_config: Some(true), volumes: None, passthrough: Some(vec![]), }, @@ -607,6 +623,7 @@ mod tests { pre-build = [] [build.env] + ignore-cargo-config = true passthrough = [] [target.aarch64-unknown-linux-gnu] @@ -648,6 +665,7 @@ mod tests { targets: HashMap::new(), build: CrossBuildConfig { env: CrossEnvConfig { + ignore_cargo_config: None, passthrough: None, volumes: None, }, diff --git a/src/docker/local.rs b/src/docker/local.rs index 72ecd9c49..75e6c4cd3 100644 --- a/src/docker/local.rs +++ b/src/docker/local.rs @@ -50,7 +50,7 @@ pub(crate) fn run( docker .args(&["-v", &format!("{}:/rust:Z,ro", dirs.sysroot.to_utf8()?)]) .args(&["-v", &format!("{}:/target:Z", dirs.target.to_utf8()?)]); - docker_cwd(&mut docker, &paths)?; + docker_cwd(&mut docker, &paths, options.ignore_cargo_config)?; // When running inside NixOS or using Nix packaging we need to add the Nix // Store to the running container so it can load the needed binaries. diff --git a/src/docker/remote.rs b/src/docker/remote.rs index 88f5c8a3a..d8a36e8df 100644 --- a/src/docker/remote.rs +++ b/src/docker/remote.rs @@ -1170,7 +1170,7 @@ symlink_recurse \"${{prefix}}\" let mut docker = subcommand(engine, "exec"); docker_user_id(&mut docker, engine.kind); docker_envvars(&mut docker, &options.config, target, msg_info)?; - docker_cwd(&mut docker, &paths)?; + docker_cwd(&mut docker, &paths, options.ignore_cargo_config)?; docker.arg(&container); docker.args(&["sh", "-c", &format!("PATH=$PATH:/rust/bin {:?}", cmd)]); bail_container_exited!(); diff --git a/src/docker/shared.rs b/src/docker/shared.rs index 573ba2458..48b3eb165 100644 --- a/src/docker/shared.rs +++ b/src/docker/shared.rs @@ -9,15 +9,12 @@ use crate::cargo::{cargo_metadata_with_args, CargoMetadata}; use crate::config::{bool_from_envvar, Config}; use crate::errors::*; use crate::extensions::{CommandExt, SafeCommand}; -use crate::file::{self, write_file, ToUtf8}; +use crate::file::{self, write_file, PathExt, ToUtf8}; use crate::id; use crate::rustc::{self, VersionMetaExt}; use crate::shell::{MessageInfo, Verbosity}; use crate::Target; -#[cfg(target_os = "windows")] -use crate::file::PathExt; - pub use super::custom::CROSS_CUSTOM_DOCKERFILE_IMAGE_PREFIX; pub const CROSS_IMAGE: &str = "ghcr.io/cross-rs"; @@ -37,15 +34,23 @@ pub struct DockerOptions { pub target: Target, pub config: Config, pub uses_xargo: bool, + pub ignore_cargo_config: bool, } impl DockerOptions { - pub fn new(engine: Engine, target: Target, config: Config, uses_xargo: bool) -> DockerOptions { + pub fn new( + engine: Engine, + target: Target, + config: Config, + uses_xargo: bool, + ignore_cargo_config: bool, + ) -> DockerOptions { DockerOptions { engine, target, config, uses_xargo, + ignore_cargo_config, } } @@ -220,10 +225,18 @@ impl DockerPaths { self.workspace_from_cwd().is_ok() } + pub fn cargo_home(&self) -> &Path { + &self.directories.cargo + } + pub fn mount_cwd(&self) -> &str { &self.directories.mount_cwd } + pub fn mount_root(&self) -> &str { + &self.directories.mount_root + } + pub fn host_root(&self) -> &Path { &self.directories.host_root } @@ -499,8 +512,44 @@ pub(crate) fn docker_envvars( Ok(()) } -pub(crate) fn docker_cwd(docker: &mut Command, paths: &DockerPaths) -> Result<()> { +fn mount_to_ignore_cargo_config( + docker: &mut Command, + paths: &DockerPaths, + ignore_cargo_config: bool, +) -> Result<()> { + let check_mount = + |cmd: &mut Command, host: &Path, mount: &Path, relpath: &Path| -> Result<()> { + let cargo_dir = relpath.join(".cargo"); + if host.join(&cargo_dir).exists() { + // this is fine, since it has to be a POSIX path on the mount. + cmd.args(&["-v", &mount.join(&cargo_dir).as_posix()?]); + } + + Ok(()) + }; + if ignore_cargo_config { + let mount_root = Path::new(paths.mount_root()); + let mount_cwd = Path::new(paths.mount_cwd()); + check_mount(docker, &paths.cwd, mount_cwd, Path::new(""))?; + // CWD isn't guaranteed to be a subdirectory of the mount root. + if let Ok(mut relpath) = mount_cwd.strip_prefix(mount_root) { + while let Some(parent) = relpath.parent() { + check_mount(docker, paths.host_root(), mount_root, parent)?; + relpath = parent; + } + } + } + + Ok(()) +} + +pub(crate) fn docker_cwd( + docker: &mut Command, + paths: &DockerPaths, + ignore_cargo_config: bool, +) -> Result<()> { docker.args(&["-w", paths.mount_cwd()]); + mount_to_ignore_cargo_config(docker, paths, ignore_cargo_config)?; Ok(()) } @@ -788,9 +837,6 @@ mod tests { use super::*; use crate::id; - #[cfg(not(target_os = "windows"))] - use crate::file::PathExt; - #[test] fn test_docker_user_id() { let var = "CROSS_ROOTLESS_CONTAINER_ENGINE"; diff --git a/src/lib.rs b/src/lib.rs index 31f6d8f1f..faf9556ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -532,8 +532,14 @@ pub fn run() -> Result { } let paths = docker::DockerPaths::create(&engine, metadata, cwd, sysroot)?; - let options = - docker::DockerOptions::new(engine, target.clone(), config, uses_xargo); + let ignore_cargo_config = config.ignore_cargo_config(&target).unwrap_or_default(); + let options = docker::DockerOptions::new( + engine, + target.clone(), + config, + uses_xargo, + ignore_cargo_config, + ); let status = docker::run(options, paths, &filtered_args, &mut msg_info) .wrap_err("could not run container")?; let needs_host = args.subcommand.map_or(false, |sc| sc.needs_host(is_remote));