diff --git a/src/cargo.rs b/src/cargo.rs index 9c976afcb..654ed580a 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -1,6 +1,6 @@ +use serde::Deserialize; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus}; -use std::{env, fs}; use crate::errors::*; use crate::extensions::CommandExt; @@ -54,7 +54,7 @@ impl<'a> From<&'a str> for Subcommand { #[derive(Debug)] pub struct Root { - path: PathBuf, + pub path: PathBuf, } impl Root { @@ -64,26 +64,28 @@ impl Root { } /// Cargo project root -pub fn root() -> Result> { - let cd = env::current_dir().wrap_err("couldn't get current directory")?; - - let mut dir = &*cd; - loop { - let toml = dir.join("Cargo.toml"); - - if fs::metadata(&toml).is_ok() { - return Ok(Some(Root { - path: dir.to_owned(), - })); - } - - match dir.parent() { - Some(p) => dir = p, - None => break, - } +pub fn root(cd: Option<&Path>) -> Result> { + #[derive(Deserialize)] + struct Manifest { + workspace_root: PathBuf, } - - Ok(None) + let mut command = std::process::Command::new( + std::env::var("CARGO") + .ok() + .unwrap_or_else(|| "cargo".to_string()), + ); + command + .arg("metadata") + .arg("--format-version=1") + .arg("--no-deps"); + if let Some(cd) = cd { + command.current_dir(cd); + } + let output = command.output()?; + let manifest: Option = serde_json::from_slice(&output.stdout)?; + Ok(manifest.map(|m| Root { + path: m.workspace_root, + })) } /// Pass-through mode diff --git a/src/docker.rs b/src/docker.rs index 6f9085696..bccb1edf1 100644 --- a/src/docker.rs +++ b/src/docker.rs @@ -111,7 +111,17 @@ pub fn run( } #[cfg(not(target_os = "windows"))] { - mount_root = host_root.clone(); + mount_root = mount_finder.find_mount_path(host_root.clone()); + } + let mount_cwd: PathBuf; + #[cfg(target_os = "windows")] + { + // On Windows, we can not mount the directory name directly. Instead, we use wslpath to convert the path to a linux compatible path. + mount_cwd = wslpath(&std::env::current_dir()?, verbose)?; + } + #[cfg(not(target_os = "windows"))] + { + mount_cwd = mount_finder.find_mount_path(std::env::current_dir()?); } let sysroot = mount_finder.find_mount_path(sysroot); @@ -236,9 +246,20 @@ pub fn run( .args(&["-v", &format!("{}:/target:Z", target_dir.display())]); if env_volumes { - docker.args(&["-w", &mount_root.display().to_string()]); - } else { + docker.args(&["-w".as_ref(), mount_cwd.as_os_str()]); + } else if mount_cwd == root { docker.args(&["-w", "/project"]); + } else { + // We do this to avoid clashes with path separators. Windows uses `\` as a path separator on Path::join + let cwd = &std::env::current_dir()?; + let working_dir = Path::new("project").join(cwd.strip_prefix(root)?); + // No [T].join for OsStr + let mut mount_wd = std::ffi::OsString::new(); + for part in working_dir.iter() { + mount_wd.push("/"); + mount_wd.push(part); + } + docker.args(&["-w".as_ref(), mount_wd.as_os_str()]); } // When running inside NixOS or using Nix packaging we need to add the Nix diff --git a/src/main.rs b/src/main.rs index 04e24e26d..0012ffa6c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -282,7 +282,7 @@ fn run() -> Result { let host_version_meta = rustc_version::version_meta().wrap_err("couldn't fetch the `rustc` version")?; - if let Some(root) = cargo::root()? { + if let Some(root) = cargo::root(None)? { let host = host_version_meta.host(); let toml = toml(&root)?; let config = Config::new(toml); diff --git a/src/tests.rs b/src/tests.rs index 90c4278ba..6970ff077 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -15,23 +15,10 @@ static WORKSPACE: OnceCell = OnceCell::new(); pub fn get_cargo_workspace() -> &'static Path { let manifest_dir = env!("CARGO_MANIFEST_DIR"); WORKSPACE.get_or_init(|| { - #[derive(Deserialize)] - struct Manifest { - workspace_root: PathBuf, - } - let output = std::process::Command::new( - std::env::var("CARGO") - .ok() - .unwrap_or_else(|| "cargo".to_string()), - ) - .arg("metadata") - .arg("--format-version=1") - .arg("--no-deps") - .current_dir(manifest_dir) - .output() - .unwrap(); - let manifest: Manifest = serde_json::from_slice(&output.stdout).unwrap(); - manifest.workspace_root + crate::cargo::root(Some(manifest_dir.as_ref())) + .unwrap() + .unwrap() + .path }) }