Skip to content

Commit e9fdc75

Browse files
authored
Try #684: --target x86_64-apple-darwin
2 parents 6b42263 + 3e59d85 commit e9fdc75

File tree

9 files changed

+233
-71
lines changed

9 files changed

+233
-71
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1616
- #543 - Added environment variables to control the UID and GID in the container
1717
- #524 - docker: Add Nix Store volume support
1818
- Added support for mounting volumes.
19+
- #684 - Enable cargo workspaces to work from any path in the workspace, and make path dependencies mount seamlessly.
1920

2021
### Changed
2122

@@ -45,6 +46,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4546
- Re-enabled `sparc64-unknown-linux-gnu` image
4647
- #582 - Added `libprocstat.so` to FreeBSD images
4748
- #665 - when not using [env.volumes](https://github.com/cross-rs/cross#mounting-volumes-into-the-build-environment), mount project in /project
49+
- #494 - Parse Cargo's --manifest-path option to determine mounted docker root
4850

4951

5052
### Removed

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,6 @@ $ QEMU_STRACE=1 cross run --target aarch64-unknown-linux-gnu
362362
9 exit_group(0)
363363
```
364364

365-
## Caveats
366-
367-
- path dependencies (in Cargo.toml) that point outside the Cargo project won't
368-
work because `cross` use docker containers only mounts the Cargo project so
369-
the container doesn't have access to the rest of the filesystem.
370-
371365
## Minimum Supported Rust Version (MSRV)
372366

373367
This crate is guaranteed to compile on stable Rust 1.58.1 and up. It *might*

ci/test.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ function retry {
2525
return ${exit_code}
2626
}
2727

28+
workspace_test() {
29+
# "${@}" is an unbound variable for bash 3.2, which is the installed version on macOS
30+
cross build --target "${TARGET}" --workspace "$@"
31+
cross run --target "${TARGET}" -p binary "$@"
32+
cross run --target "${TARGET}" --bin dependencies \
33+
--features=dependencies "$@"
34+
}
35+
2836
main() {
2937
local td=
3038

@@ -135,6 +143,21 @@ EOF
135143
popd
136144

137145
rm -rf "${td}"
146+
td=$(mktemp -d)
147+
git clone \
148+
--depth 1 \
149+
--recursive \
150+
https://github.com/cross-rs/test-workspace "${td}"
151+
152+
pushd "${td}"
153+
TARGET="${TARGET}" workspace_test --manifest-path="./workspace/Cargo.toml"
154+
pushd "workspace"
155+
TARGET="${TARGET}" workspace_test
156+
pushd "binary"
157+
cross run --target "${TARGET}"
158+
popd
159+
popd
160+
popd
138161
;;
139162
esac
140163

src/cargo.rs

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
use serde::Deserialize;
12
use std::path::{Path, PathBuf};
23
use std::process::{Command, ExitStatus};
3-
use std::{env, fs};
44

5+
use crate::cli::Args;
56
use crate::errors::*;
67
use crate::extensions::CommandExt;
78

@@ -52,38 +53,90 @@ impl<'a> From<&'a str> for Subcommand {
5253
}
5354
}
5455

55-
#[derive(Debug)]
56-
pub struct Root {
57-
path: PathBuf,
56+
#[derive(Debug, Deserialize)]
57+
pub struct CargoMetadata {
58+
pub workspace_root: PathBuf,
59+
pub target_directory: PathBuf,
60+
pub packages: Vec<Package>,
61+
pub workspace_members: Vec<String>,
5862
}
5963

60-
impl Root {
61-
pub fn path(&self) -> &Path {
62-
&self.path
64+
impl CargoMetadata {
65+
fn non_workspace_members(&self) -> impl Iterator<Item = &Package> {
66+
self.packages
67+
.iter()
68+
.filter(|p| !self.workspace_members.iter().any(|m| m == &p.id))
6369
}
64-
}
6570

66-
/// Cargo project root
67-
pub fn root() -> Result<Option<Root>> {
68-
let cd = env::current_dir().wrap_err("couldn't get current directory")?;
71+
pub fn path_dependencies(&self) -> impl Iterator<Item = &Path> {
72+
// TODO: Also filter out things that are in workspace, but not a workspace member
73+
self.non_workspace_members().filter_map(|p| p.crate_path())
74+
}
75+
}
6976

70-
let mut dir = &*cd;
71-
loop {
72-
let toml = dir.join("Cargo.toml");
77+
#[derive(Debug, Deserialize)]
78+
pub struct Package {
79+
id: String,
80+
manifest_path: PathBuf,
81+
source: Option<String>,
82+
}
7383

74-
if fs::metadata(&toml).is_ok() {
75-
return Ok(Some(Root {
76-
path: dir.to_owned(),
77-
}));
84+
impl Package {
85+
/// Returns the absolute path to the packages manifest "folder"
86+
fn crate_path(&self) -> Option<&Path> {
87+
// when source is none, this package is a path dependency or a workspace member
88+
if self.source.is_none() {
89+
self.manifest_path.parent()
90+
} else {
91+
None
7892
}
93+
}
94+
}
7995

80-
match dir.parent() {
81-
Some(p) => dir = p,
82-
None => break,
96+
/// Cargo metadata with specific invocation
97+
pub fn cargo_metadata_with_args(
98+
cd: Option<&Path>,
99+
args: Option<&Args>,
100+
verbose: bool,
101+
) -> Result<Option<CargoMetadata>> {
102+
let mut command = std::process::Command::new(
103+
std::env::var("CARGO")
104+
.ok()
105+
.unwrap_or_else(|| "cargo".to_string()),
106+
);
107+
command.arg("metadata").arg("--format-version=1");
108+
if let Some(cd) = cd {
109+
command.current_dir(cd);
110+
}
111+
if let Some(config) = args {
112+
if let Some(ref manifest_path) = config.manifest_path {
113+
command.args(["--manifest-path".as_ref(), manifest_path.as_os_str()]);
83114
}
115+
} else {
116+
command.arg("--no-deps");
84117
}
85-
86-
Ok(None)
118+
if let Some(target) = args.and_then(|a| a.target.as_ref()) {
119+
command.args(["--filter-platform", target.triple()]);
120+
}
121+
if let Some(features) = args.map(|a| &a.features).filter(|v| !v.is_empty()) {
122+
command.args([String::from("--features"), features.join(",")]);
123+
}
124+
let output = command.run_and_get_output(verbose)?;
125+
if !output.status.success() {
126+
// TODO: logging
127+
return Ok(None);
128+
}
129+
let manifest: Option<CargoMetadata> = serde_json::from_slice(&output.stdout)?;
130+
manifest
131+
.map(|m| -> Result<_> {
132+
Ok(CargoMetadata {
133+
target_directory: args
134+
.and_then(|a| a.target_dir.clone())
135+
.unwrap_or(m.target_directory),
136+
..m
137+
})
138+
})
139+
.transpose()
87140
}
88141

89142
/// Pass-through mode

src/cli.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ pub struct Args {
1212
pub subcommand: Option<Subcommand>,
1313
pub channel: Option<String>,
1414
pub target: Option<Target>,
15+
pub features: Vec<String>,
1516
pub target_dir: Option<PathBuf>,
1617
pub docker_in_docker: bool,
1718
pub enable_doctests: bool,
19+
pub manifest_path: Option<PathBuf>,
1820
}
1921

2022
// Fix for issue #581. target_dir must be absolute.
@@ -72,6 +74,8 @@ pub fn fmt_subcommands(stdout: &str) {
7274
pub fn parse(target_list: &TargetList) -> Result<Args> {
7375
let mut channel = None;
7476
let mut target = None;
77+
let mut features = Vec::new();
78+
let mut manifest_path: Option<PathBuf> = None;
7579
let mut target_dir = None;
7680
let mut sc = None;
7781
let mut all: Vec<String> = Vec::new();
@@ -82,7 +86,21 @@ pub fn parse(target_list: &TargetList) -> Result<Args> {
8286
if arg.is_empty() {
8387
continue;
8488
}
85-
if let ("+", ch) = arg.split_at(1) {
89+
if arg == "--manifest-path" {
90+
all.push(arg);
91+
if let Some(m) = args.next() {
92+
let p = PathBuf::from(&m);
93+
all.push(m);
94+
manifest_path = env::current_dir().ok().map(|cwd| cwd.join(p));
95+
}
96+
} else if arg.starts_with("--manifest-path=") {
97+
manifest_path = arg
98+
.split_once('=')
99+
.map(|x| x.1)
100+
.map(PathBuf::from)
101+
.and_then(|p| env::current_dir().ok().map(|cwd| cwd.join(p)));
102+
all.push(arg);
103+
} else if let ("+", ch) = arg.split_at(1) {
86104
channel = Some(ch.to_string());
87105
} else if arg == "--target" {
88106
all.push(arg);
@@ -95,6 +113,15 @@ pub fn parse(target_list: &TargetList) -> Result<Args> {
95113
.split_once('=')
96114
.map(|(_, t)| Target::from(t, target_list));
97115
all.push(arg);
116+
} else if arg == "--features" {
117+
all.push(arg);
118+
if let Some(t) = args.next() {
119+
features.push(t.clone());
120+
all.push(t);
121+
}
122+
} else if arg.starts_with("--features=") {
123+
features.extend(arg.split_once('=').map(|(_, t)| t.to_owned()));
124+
all.push(arg);
98125
} else if arg == "--target-dir" {
99126
all.push(arg);
100127
if let Some(td) = args.next() {
@@ -128,8 +155,10 @@ pub fn parse(target_list: &TargetList) -> Result<Args> {
128155
subcommand: sc,
129156
channel,
130157
target,
158+
features,
131159
target_dir,
132160
docker_in_docker,
133161
enable_doctests,
162+
manifest_path,
134163
})
135164
}

0 commit comments

Comments
 (0)