Skip to content

Commit 767c630

Browse files
aidanhsluser
authored andcommitted
Perform path remapping when compiling from Windows
1 parent 4545379 commit 767c630

File tree

3 files changed

+85
-31
lines changed

3 files changed

+85
-31
lines changed

src/compiler/compiler.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ fn dist_or_local_compile<T>(dist_client: Arc<dist::Client>,
341341
-> SFuture<(Cacheable, process::Output)>
342342
where T: CommandCreatorSync {
343343
use futures::future;
344+
use std::error::Error as StdError;
344345
use std::io;
345346

346347
debug!("[{}]: Attempting distributed compilation", out_pretty);
@@ -415,7 +416,8 @@ fn dist_or_local_compile<T>(dist_client: Arc<dist::Client>,
415416
})
416417
// Something failed, do a local compilation
417418
.or_else(move |e| {
418-
info!("[{}]: Could not perform distributed compile, falling back to local: {}", compile_out_pretty3, e);
419+
let cause = e.cause().map(|c| format!(": {}", c)).unwrap_or_else(String::new);
420+
info!("[{}]: Could not perform distributed compile, falling back to local: {}{}", compile_out_pretty3, e, cause);
419421
compile_cmd.execute(&creator)
420422
})
421423
.map(move |o| (cacheable, o))

src/compiler/rust.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,22 @@ impl Compilation for RustCompilation {
11041104
// We can't rely on the packaged toolchain necessarily having the same default target triple
11051105
// as us (typically host triple), so make sure to always explicitly specify a target.
11061106
if !saw_target {
1107-
dist_arguments.push(format!("--target={}", host));
1107+
dist_arguments.push(format!("--target={}", host))
1108+
}
1109+
1110+
// Add any necessary path transforms - although we haven't packaged up inputs yet, we've
1111+
// probably seen all drives (e.g. on Windows), so let's just transform those rather than
1112+
// trying to do every single path.
1113+
// TODO: we do end up with slashes facing the wrong way, but Windows is agnostic so it's
1114+
// mostly ok. We currently don't do it for every single path because it means we need to
1115+
// figure out all prefixes and send them over the wire.
1116+
for (local_path, dist_path) in path_transformer.disk_mappings() {
1117+
// "The from=to parameter is scanned from right to left, so from may contain '=', but to may not."
1118+
let local_path = local_path.to_str()?;
1119+
if local_path.contains('=') {
1120+
return None
1121+
}
1122+
dist_arguments.push(format!("--remap-path-prefix={}={}", dist_path, local_path))
11081123
}
11091124

11101125
let sysroot_executable = sysroot.join(BINS_DIR).join("rustc").with_extension(EXE_EXTENSION);

src/dist/mod.rs

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,39 @@ mod pkg {
5151
#[cfg(target_os = "windows")]
5252
mod path_transform {
5353
use std::collections::HashMap;
54-
use std::path::{Component, Path, PathBuf, Prefix};
54+
use std::path::{Component, Components, Path, PathBuf, Prefix, PrefixComponent};
5555
use std::str;
5656

57+
fn take_prefix<'a>(components: &'a mut Components) -> PrefixComponent<'a> {
58+
let prefix = components.next().unwrap();
59+
let pc = match prefix {
60+
Component::Prefix(pc) => pc,
61+
_ => panic!("unrecognised start to path: {:?}", prefix),
62+
};
63+
let root = components.next().unwrap();
64+
if root != Component::RootDir {
65+
panic!("unexpected non-root component in path starting {:?}", prefix)
66+
}
67+
pc
68+
}
69+
70+
fn transform_prefix_component(pc: PrefixComponent) -> Option<String> {
71+
match pc.kind() {
72+
// Transforming these to the same place means these may flip-flop
73+
// in the tracking map, but they're equivalent so not really an
74+
// issue
75+
Prefix::Disk(diskchar) |
76+
Prefix::VerbatimDisk(diskchar) => {
77+
assert!(diskchar.is_ascii_alphabetic());
78+
Some(format!("/prefix/disk-{}", str::from_utf8(&[diskchar]).unwrap()))
79+
},
80+
Prefix::Verbatim(_) |
81+
Prefix::VerbatimUNC(_, _) |
82+
Prefix::DeviceNS(_) |
83+
Prefix::UNC(_, _) => None,
84+
}
85+
}
86+
5787
pub struct PathTransformer {
5888
dist_to_local_path: HashMap<String, PathBuf>,
5989
}
@@ -72,31 +102,8 @@ mod path_transform {
72102
let mut components = p.components();
73103

74104
let maybe_dist_prefix = if p.is_absolute() {
75-
let prefix = components.next().unwrap();
76-
let dist_prefix = match prefix {
77-
Component::Prefix(pc) => {
78-
match pc.kind() {
79-
// Transforming these to the same place means these may flip-flop
80-
// in the tracking map, but they're equivalent so not really an
81-
// issue
82-
Prefix::Disk(diskchar) |
83-
Prefix::VerbatimDisk(diskchar) => {
84-
assert!(diskchar.is_ascii_alphabetic());
85-
format!("disk-{}", str::from_utf8(&[diskchar]).unwrap())
86-
},
87-
Prefix::Verbatim(_) |
88-
Prefix::VerbatimUNC(_, _) |
89-
Prefix::DeviceNS(_) |
90-
Prefix::UNC(_, _) => return None,
91-
}
92-
},
93-
_ => panic!("unrecognised start to path {:?}", p),
94-
};
95-
96-
let root = components.next().unwrap();
97-
if root != Component::RootDir { panic!("unexpected non-root component in {:?}", p) }
98-
99-
Some(dist_prefix)
105+
let pc = take_prefix(&mut components);
106+
Some(transform_prefix_component(pc)?)
100107
} else {
101108
None
102109
};
@@ -105,7 +112,13 @@ mod path_transform {
105112
for component in components {
106113
let part = match component {
107114
Component::Prefix(_) |
108-
Component::RootDir => panic!("unexpected part in path {:?}", p),
115+
Component::RootDir => {
116+
// On Windows there is such a thing as a path like C:file.txt
117+
// It's not clear to me what the semantics of such a path are,
118+
// so give up.
119+
error!("unexpected part in path {:?}", p);
120+
return None
121+
},
109122
Component::Normal(osstr) => osstr.to_str()?,
110123
// TODO: should be forbidden
111124
Component::CurDir => ".",
@@ -117,14 +130,34 @@ mod path_transform {
117130
dist_suffix.push_str(part)
118131
}
119132

120-
let dist_path = if let Some(dist_prefix) = maybe_dist_prefix {
121-
format!("/prefix/{}/{}", dist_prefix, dist_suffix)
133+
let dist_path = if let Some(mut dist_prefix) = maybe_dist_prefix {
134+
dist_prefix.push('/');
135+
dist_prefix.push_str(&dist_suffix);
136+
dist_prefix
122137
} else {
123138
dist_suffix
124139
};
125140
self.dist_to_local_path.insert(dist_path.clone(), p.to_owned());
126141
Some(dist_path)
127142
}
143+
pub fn disk_mappings(&self) -> impl Iterator<Item=(PathBuf, String)> {
144+
let mut mappings = HashMap::new();
145+
for (_dist_path, local_path) in self.dist_to_local_path.iter() {
146+
if !local_path.is_absolute() {
147+
continue
148+
}
149+
let mut components = local_path.components();
150+
let local_prefix = take_prefix(&mut components);
151+
let local_prefix_component = Component::Prefix(local_prefix);
152+
let local_prefix_path: &Path = local_prefix_component.as_ref();
153+
if mappings.contains_key(local_prefix_path) {
154+
continue
155+
}
156+
let dist_prefix = transform_prefix_component(local_prefix).unwrap();
157+
mappings.insert(local_prefix_path.to_owned(), dist_prefix);
158+
}
159+
mappings.into_iter()
160+
}
128161
pub fn to_local(&self, p: &str) -> PathBuf {
129162
self.dist_to_local_path.get(p).unwrap().clone()
130163
}
@@ -133,6 +166,7 @@ mod path_transform {
133166

134167
#[cfg(unix)]
135168
mod path_transform {
169+
use std::iter;
136170
use std::path::{Path, PathBuf};
137171

138172
pub struct PathTransformer;
@@ -146,6 +180,9 @@ mod path_transform {
146180
pub fn to_dist(&mut self, p: &Path) -> Option<String> {
147181
p.as_os_str().to_str().map(Into::into)
148182
}
183+
pub fn disk_mappings(&self) -> impl Iterator<Item=(PathBuf, String)> {
184+
iter::empty()
185+
}
149186
pub fn to_local(&self, p: &str) -> PathBuf {
150187
PathBuf::from(p)
151188
}

0 commit comments

Comments
 (0)