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));