Skip to content

Commit

Permalink
make manifest path work with metadata
Browse files Browse the repository at this point in the history
contains a minor workaround for when logic is hard
  • Loading branch information
Emilgardis committed May 26, 2022
1 parent 72ffc4e commit cd9a395
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 59 deletions.
80 changes: 42 additions & 38 deletions src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use serde::Deserialize;
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};

use crate::cli::Args;
use crate::config::Config;
use crate::errors::*;
use crate::extensions::CommandExt;

Expand Down Expand Up @@ -50,52 +52,54 @@ impl<'a> From<&'a str> for Subcommand {
}
}

#[derive(Debug)]
pub struct Root {
pub path: PathBuf,
#[derive(Debug, Deserialize)]
pub struct CargoMetadata {
pub workspace_root: PathBuf,
}

impl Root {
pub fn path(&self) -> &Path {
&self.path
impl CargoMetadata {
pub fn workspace_root(&self) -> &Path {
&self.workspace_root
}
}

/// Cargo project root
pub fn root(cd: Option<&Path>, manifest_path: Option<PathBuf>) -> Result<Option<Root>> {
if let Some(manifest_path) = manifest_path {
if !manifest_path.is_file() {
eyre::bail!("No manifest found at \"{}\"", manifest_path.display());
/// Cargo metadata with specific invocation
pub fn cargo_metadata_with_args(
cd: Option<&Path>,
args: Option<&Args>,
) -> Result<Option<CargoMetadata>> {
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");
if let Some(cd) = cd {
command.current_dir(cd);
}
if let Some(config) = args {
if let Some(ref manifest_path) = config.manifest_path {
command.args(["--manifest-path".as_ref(), manifest_path.as_os_str()]);
}
return Ok(Some(Root {
path: manifest_path
.parent()
.expect("File must have a parent")
.to_owned(),
}));
} else {
#[derive(Deserialize)]
struct Manifest {
workspace_root: PathBuf,
}
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<Manifest> = serde_json::from_slice(&output.stdout)?;
Ok(manifest.map(|m| Root {
path: m.workspace_root,
}))
command.arg("--no-deps");
}
let output = command.output()?;
let manifest: Option<CargoMetadata> =
serde_json::from_slice(&output.stdout).wrap_err_with(|| {
format!(
"{command:?} returned nothing. {:?}",
String::from_utf8(output.stderr)
)
})?;
Ok(manifest.map(|m| CargoMetadata {
workspace_root: m.workspace_root,
}))
}

/// Cargo metadata
pub fn cargo_metadata(cd: Option<&Path>) -> Result<Option<CargoMetadata>> {
cargo_metadata_with_args(cd, None)
}

/// Pass-through mode
Expand Down
34 changes: 23 additions & 11 deletions src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};
use std::{env, fs};

use crate::cargo::Root;
use crate::cargo::CargoMetadata;
use crate::errors::*;
use crate::extensions::{CommandExt, SafeCommand};
use crate::id;
Expand Down Expand Up @@ -57,28 +57,29 @@ pub fn run(
target: &Target,
args: &[String],
target_dir: &Option<PathBuf>,
root: &Root,
docker_root: &Path,
metadata: &CargoMetadata,
config: &Config,
uses_xargo: bool,
sysroot: &Path,
verbose: bool,
docker_in_docker: bool,
cwd: &Path,
) -> Result<ExitStatus> {
let mount_finder = if docker_in_docker {
MountFinder::new(docker_read_mount_paths()?)
} else {
MountFinder::default()
};

let root = root.path();
let home_dir = home::home_dir().ok_or_else(|| eyre::eyre!("could not find home directory"))?;
let cargo_dir = home::cargo_home()?;
let xargo_dir = env::var_os("XARGO_HOME")
.map(PathBuf::from)
.unwrap_or_else(|| home_dir.join(".xargo"));
let nix_store_dir = env::var_os("NIX_STORE").map(PathBuf::from);
let target_dir = target_dir.clone().unwrap_or_else(|| root.join("target"));
let target_dir = target_dir
.clone()
.unwrap_or_else(|| metadata.workspace_root().join("target"));

// create the directories we are going to mount before we mount them,
// otherwise `docker` will create them but they will be owned by `root`
Expand All @@ -90,7 +91,12 @@ pub fn run(
let cargo_dir = mount_finder.find_mount_path(cargo_dir);
let xargo_dir = mount_finder.find_mount_path(xargo_dir);
let target_dir = mount_finder.find_mount_path(target_dir);
let host_root = mount_finder.find_mount_path(docker_root);
// root is either workspace_root, or, if we're outside the workspace root, the current directory
let host_root = mount_finder.find_mount_path(if metadata.workspace_root().starts_with(cwd) {
cwd
} else {
metadata.workspace_root()
});
let mount_root: PathBuf;
#[cfg(target_os = "windows")]
{
Expand All @@ -105,11 +111,11 @@ pub fn run(
#[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)?;
mount_cwd = wslpath(&cwd, verbose)?;
}
#[cfg(not(target_os = "windows"))]
{
mount_cwd = mount_finder.find_mount_path(std::env::current_dir()?);
mount_cwd = mount_finder.find_mount_path(cwd);
}
let sysroot = mount_finder.find_mount_path(sysroot);

Expand Down Expand Up @@ -145,6 +151,12 @@ pub fn run(
docker.args(&["-e", var]);
}
let mut env_volumes = false;
// FIXME(emilgardis 2022-04-07): This is a fallback so that if it's hard for use to do mounting logic, make it simple(r)
// Preferably we would not have to do this.
if cwd.strip_prefix(metadata.workspace_root()).is_err() {
env_volumes = true;
}

for ref var in config.env_volumes(target)? {
validate_env_var(var)?;

Expand Down Expand Up @@ -243,12 +255,12 @@ pub fn run(

if env_volumes {
docker.args(&["-w".as_ref(), mount_cwd.as_os_str()]);
} else if mount_cwd == root {
} else if mount_cwd == metadata.workspace_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(docker_root)?);
let cwd = &cwd;
let working_dir = Path::new("project").join(cwd.strip_prefix(metadata.workspace_root())?);
// No [T].join for OsStr
let mut mount_wd = std::ffi::OsString::new();
for part in working_dir.iter() {
Expand Down
17 changes: 9 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::process::ExitStatus;
use config::Config;
use serde::Deserialize;

use self::cargo::{Root, Subcommand};
use self::cargo::{CargoMetadata, Subcommand};
use self::cross_toml::CrossToml;
use self::errors::*;
use self::rustc::{TargetList, VersionMetaExt};
Expand Down Expand Up @@ -279,9 +279,10 @@ fn run() -> Result<ExitStatus> {

let host_version_meta =
rustc_version::version_meta().wrap_err("couldn't fetch the `rustc` version")?;
if let Some(root) = cargo::root(None, args.manifest_path)? {
let cwd = std::env::current_dir()?;
if let Some(metadata) = cargo::cargo_metadata_with_args(Some(&cwd), Some(&args))? {
let host = host_version_meta.host();
let toml = toml(&root)?;
let toml = toml(&metadata)?;
let config = Config::new(toml);
let target = args
.target
Expand Down Expand Up @@ -399,13 +400,13 @@ fn run() -> Result<ExitStatus> {
&target,
&filtered_args,
&args.target_dir,
&root,
&docker_root,
&metadata,
&config,
uses_xargo,
&sysroot,
verbose,
args.docker_in_docker,
&cwd,
);
}
}
Expand Down Expand Up @@ -464,10 +465,10 @@ pub(crate) fn warn_host_version_mismatch(

/// Parses the `Cross.toml` at the root of the Cargo project or from the
/// `CROSS_CONFIG` environment variable (if any exist in either location).
fn toml(root: &Root) -> Result<Option<CrossToml>> {
fn toml(root: &CargoMetadata) -> Result<Option<CrossToml>> {
let path = match env::var("CROSS_CONFIG") {
Ok(var) => PathBuf::from(var),
Err(_) => root.path().join("Cross.toml"),
Err(_) => root.workspace_root().join("Cross.toml"),
};

if path.exists() {
Expand All @@ -480,7 +481,7 @@ fn toml(root: &Root) -> Result<Option<CrossToml>> {
Ok(Some(config))
} else {
// Checks if there is a lowercase version of this file
if root.path().join("cross.toml").exists() {
if root.workspace_root().join("cross.toml").exists() {
eprintln!("There's a file named cross.toml, instead of Cross.toml. You may want to rename it, or it won't be considered.");
}
Ok(None)
Expand Down
4 changes: 2 additions & 2 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ static WORKSPACE: OnceCell<PathBuf> = OnceCell::new();
pub fn get_cargo_workspace() -> &'static Path {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
WORKSPACE.get_or_init(|| {
crate::cargo::root(Some(manifest_dir.as_ref()))
crate::cargo::cargo_metadata(Some(manifest_dir.as_ref()))
.unwrap()
.unwrap()
.path
.workspace_root
})
}

Expand Down

0 comments on commit cd9a395

Please sign in to comment.