Skip to content

Commit 4050e27

Browse files
pietroalbiniMark-Simulacrum
authored andcommitted
bootstrap: fix x.py install not working with relative prefix
1 parent 13cd768 commit 4050e27

File tree

1 file changed

+44
-55
lines changed

1 file changed

+44
-55
lines changed

src/bootstrap/install.rs

+44-55
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
use std::env;
77
use std::fs;
8-
use std::path::{Component, Path, PathBuf};
8+
use std::path::{Component, PathBuf};
99
use std::process::Command;
1010

1111
use build_helper::t;
@@ -26,74 +26,63 @@ fn install_sh(
2626
) {
2727
builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));
2828

29-
let prefix_default = PathBuf::from("/usr/local");
30-
let sysconfdir_default = PathBuf::from("/etc");
31-
let datadir_default = PathBuf::from("share");
32-
let docdir_default = datadir_default.join("doc/rust");
33-
let libdir_default = PathBuf::from("lib");
34-
let mandir_default = datadir_default.join("man");
35-
let prefix = builder.config.prefix.as_ref().unwrap_or(&prefix_default);
36-
let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
37-
let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
38-
let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
39-
let bindir = &builder.config.bindir;
40-
let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
41-
let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);
42-
43-
let sysconfdir = prefix.join(sysconfdir);
44-
let datadir = prefix.join(datadir);
45-
let docdir = prefix.join(docdir);
46-
let bindir = prefix.join(bindir);
47-
let libdir = prefix.join(libdir);
48-
let mandir = prefix.join(mandir);
49-
50-
let destdir = env::var_os("DESTDIR").map(PathBuf::from);
51-
52-
let prefix = add_destdir(&prefix, &destdir);
53-
let sysconfdir = add_destdir(&sysconfdir, &destdir);
54-
let datadir = add_destdir(&datadir, &destdir);
55-
let docdir = add_destdir(&docdir, &destdir);
56-
let bindir = add_destdir(&bindir, &destdir);
57-
let libdir = add_destdir(&libdir, &destdir);
58-
let mandir = add_destdir(&mandir, &destdir);
59-
60-
let prefix = {
61-
fs::create_dir_all(&prefix)
62-
.unwrap_or_else(|err| panic!("could not create {}: {}", prefix.display(), err));
63-
fs::canonicalize(&prefix)
64-
.unwrap_or_else(|err| panic!("could not canonicalize {}: {}", prefix.display(), err))
65-
};
29+
let prefix = default_path(&builder.config.prefix, "/usr/local");
30+
let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc"));
31+
let datadir = prefix.join(default_path(&builder.config.datadir, "share"));
32+
let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc"));
33+
let mandir = prefix.join(default_path(&builder.config.mandir, "share/man"));
34+
let libdir = prefix.join(default_path(&builder.config.libdir, "lib"));
35+
let bindir = prefix.join(&builder.config.bindir); // Default in config.rs
6636

6737
let empty_dir = builder.out.join("tmp/empty_dir");
68-
6938
t!(fs::create_dir_all(&empty_dir));
7039

7140
let mut cmd = Command::new("sh");
7241
cmd.current_dir(&empty_dir)
7342
.arg(sanitize_sh(&tarball.decompressed_output().join("install.sh")))
74-
.arg(format!("--prefix={}", sanitize_sh(&prefix)))
75-
.arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
76-
.arg(format!("--datadir={}", sanitize_sh(&datadir)))
77-
.arg(format!("--docdir={}", sanitize_sh(&docdir)))
78-
.arg(format!("--bindir={}", sanitize_sh(&bindir)))
79-
.arg(format!("--libdir={}", sanitize_sh(&libdir)))
80-
.arg(format!("--mandir={}", sanitize_sh(&mandir)))
43+
.arg(format!("--prefix={}", prepare_dir(prefix)))
44+
.arg(format!("--sysconfdir={}", prepare_dir(sysconfdir)))
45+
.arg(format!("--datadir={}", prepare_dir(datadir)))
46+
.arg(format!("--docdir={}", prepare_dir(docdir)))
47+
.arg(format!("--bindir={}", prepare_dir(bindir)))
48+
.arg(format!("--libdir={}", prepare_dir(libdir)))
49+
.arg(format!("--mandir={}", prepare_dir(mandir)))
8150
.arg("--disable-ldconfig");
8251
builder.run(&mut cmd);
8352
t!(fs::remove_dir_all(&empty_dir));
8453
}
8554

86-
fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
87-
let mut ret = match *destdir {
88-
Some(ref dest) => dest.clone(),
89-
None => return path.to_path_buf(),
90-
};
91-
for part in path.components() {
92-
if let Component::Normal(s) = part {
93-
ret.push(s)
55+
fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf {
56+
PathBuf::from(config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default)))
57+
}
58+
59+
fn prepare_dir(mut path: PathBuf) -> String {
60+
// The DESTDIR environment variable is a standard way to install software in a subdirectory
61+
// while keeping the original directory structure, even if the prefix or other directories
62+
// contain absolute paths.
63+
//
64+
// More information on the environment variable is available here:
65+
// https://www.gnu.org/prep/standards/html_node/DESTDIR.html
66+
if let Some(destdir) = env::var_os("DESTDIR").map(PathBuf::from) {
67+
let without_destdir = path.clone();
68+
path = destdir;
69+
// Custom .join() which ignores disk roots.
70+
for part in without_destdir.components() {
71+
if let Component::Normal(s) = part {
72+
path.push(s)
73+
}
9474
}
9575
}
96-
ret
76+
77+
// The installation command is not executed from the current directory, but from a temporary
78+
// directory. To prevent relative paths from breaking this converts relative paths to absolute
79+
// paths. std::fs::canonicalize is not used as that requires the path to actually be present.
80+
if path.is_relative() {
81+
path = std::env::current_dir().expect("failed to get the current directory").join(path);
82+
assert!(path.is_absolute(), "could not make the path relative");
83+
}
84+
85+
sanitize_sh(&path)
9786
}
9887

9988
macro_rules! install {

0 commit comments

Comments
 (0)