Skip to content

Commit 8002a09

Browse files
committed
auto merge of #8831 : catamorphism/rust/extend_rust_path, r=catamorphism
r? @brson @metajack requested the ability to violate the "only workspaces can be in the RUST_PATH" rule for the purpose of bootstrapping Servo without having to restructure all the directories. This patch gives rustpkg the ability to find sources if a directory in the RUST_PATH directly contains one of rustpkg's "special" files (lib.rs, main.rs, bench.rs, or test.rs), even if it's not a workspace. In this case, it puts the build artifacts in the first workspace in the RUST_PATH. I'm not sure whether or not it's a good idea to keep this feature in rustpkg permanently. Thus, I added a flag, ```--use-rust-path-hack```, and only enabled it when the flag is set.
2 parents 6a22595 + 98e470a commit 8002a09

File tree

12 files changed

+506
-104
lines changed

12 files changed

+506
-104
lines changed

Diff for: src/librustc/middle/kind.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ fn check_impl_of_trait(cx: Context, it: @item, trait_ref: &trait_ref, self_type:
129129

130130
// If this trait has builtin-kind supertraits, meet them.
131131
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
132-
error!("checking impl with self type %?", ty::get(self_ty).sty);
132+
debug!("checking impl with self type %?", ty::get(self_ty).sty);
133133
do check_builtin_bounds(cx, self_ty, trait_def.bounds) |missing| {
134134
cx.tcx.sess.span_err(self_type.span,
135135
fmt!("the type `%s', which does not fulfill `%s`, cannot implement this \

Diff for: src/librustpkg/api.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ use std::hashmap::*;
2020
/// Convenience functions intended for calling from pkg.rs
2121
2222
fn default_ctxt(p: @Path) -> Ctx {
23-
Ctx { sysroot_opt: Some(p), json: false, dep_cache: @mut HashMap::new() }
23+
Ctx {
24+
use_rust_path_hack: false,
25+
sysroot_opt: Some(p),
26+
json: false,
27+
dep_cache: @mut HashMap::new()
28+
}
2429
}
2530

2631
pub fn build_lib(sysroot: @Path, root: Path, name: ~str, version: Version,

Diff for: src/librustpkg/conditions.rs

+8
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,11 @@ condition! {
3636
condition! {
3737
no_rust_path: (~str) -> super::Path;
3838
}
39+
40+
condition! {
41+
not_a_workspace: (~str) -> super::Path;
42+
}
43+
44+
condition! {
45+
failed_to_create_temp_dir: (~str) -> super::Path;
46+
}

Diff for: src/librustpkg/context.rs

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ use std::hashmap::HashMap;
1515
use std::os;
1616

1717
pub struct Ctx {
18+
// If use_rust_path_hack is true, rustpkg searches for sources
19+
// in *package* directories that are in the RUST_PATH (for example,
20+
// FOO/src/bar-0.1 instead of FOO). The flag doesn't affect where
21+
// rustpkg stores build artifacts.
22+
use_rust_path_hack: bool,
1823
// Sysroot -- if this is None, uses rustc filesearch's
1924
// idea of the default
2025
sysroot_opt: Option<@Path>,

Diff for: src/librustpkg/package_source.rs

+80-22
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
extern mod extra;
12+
1113
use target::*;
1214
use package_id::PkgId;
1315
use std::path::Path;
@@ -16,8 +18,9 @@ use context::*;
1618
use crate::Crate;
1719
use messages::*;
1820
use source_control::{git_clone, git_clone_general};
19-
use path_util::pkgid_src_in_workspace;
21+
use path_util::{pkgid_src_in_workspace, find_dir_using_rust_path_hack, default_workspace};
2022
use util::compile_crate;
23+
use workspace::is_workspace;
2124

2225
// An enumeration of the unpacked source of a package workspace.
2326
// This contains a list of files found in the source workspace.
@@ -48,7 +51,7 @@ impl PkgSrc {
4851
}
4952

5053

51-
fn check_dir(&self) -> Path {
54+
fn check_dir(&self, cx: &Ctx) -> Path {
5255
use conditions::nonexistent_package::cond;
5356

5457
debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str());
@@ -59,12 +62,21 @@ impl PkgSrc {
5962

6063
let dir = match path {
6164
Some(d) => (*d).clone(),
62-
None => match self.fetch_git() {
63-
Some(d) => d,
64-
None => cond.raise((self.id.clone(), ~"supplied path for package dir does not \
65-
exist, and couldn't interpret it as a URL fragment"))
65+
None => {
66+
match self.fetch_git() {
67+
Some(d) => d,
68+
None => {
69+
match find_dir_using_rust_path_hack(cx, &self.id) {
70+
Some(d) => d,
71+
None => cond.raise((self.id.clone(),
72+
~"supplied path for package dir does not \
73+
exist, and couldn't interpret it as a URL fragment"))
74+
}
75+
}
76+
}
6677
}
6778
};
79+
debug!("For package id %s, returning %s", self.id.to_str(), dir.to_str());
6880
if !os::path_is_dir(&dir) {
6981
cond.raise((self.id.clone(), ~"supplied path for package dir is a \
7082
non-directory"));
@@ -79,11 +91,19 @@ impl PkgSrc {
7991
/// refers to a git repo on the local version, also check it out.
8092
/// (right now we only support git)
8193
pub fn fetch_git(&self) -> Option<Path> {
94+
use conditions::failed_to_create_temp_dir::cond;
95+
96+
// We use a temporary directory because if the git clone fails,
97+
// it creates the target directory anyway and doesn't delete it
98+
99+
let scratch_dir = extra::tempfile::mkdtemp(&os::tmpdir(), "rustpkg");
100+
let clone_target = match scratch_dir {
101+
Some(d) => d.push("rustpkg_temp"),
102+
None => cond.raise(~"Failed to create temporary directory for fetching git sources")
103+
};
82104

83105
let mut local = self.root.push("src");
84106
local = local.push(self.id.to_str());
85-
// Git can't clone into a non-empty directory
86-
os::remove_dir_recursive(&local);
87107

88108
debug!("Checking whether %s exists locally. Cwd = %s, does it? %?",
89109
self.id.path.to_str(),
@@ -93,15 +113,28 @@ impl PkgSrc {
93113
if os::path_exists(&self.id.path) {
94114
debug!("%s exists locally! Cloning it into %s",
95115
self.id.path.to_str(), local.to_str());
116+
// Ok to use local here; we know it will succeed
96117
git_clone(&self.id.path, &local, &self.id.version);
97118
return Some(local);
98119
}
99120

121+
if (self.id.path.clone()).components().len() < 2 {
122+
// If a non-URL, don't bother trying to fetch
123+
return None;
124+
}
125+
100126
let url = fmt!("https://%s", self.id.path.to_str());
101127
note(fmt!("Fetching package: git clone %s %s [version=%s]",
102-
url, local.to_str(), self.id.version.to_str()));
103-
if git_clone_general(url, &local, &self.id.version) {
104-
Some(local)
128+
url, clone_target.to_str(), self.id.version.to_str()));
129+
130+
if git_clone_general(url, &clone_target, &self.id.version) {
131+
// since the operation succeeded, move clone_target to local
132+
if !os::rename_file(&clone_target, &local) {
133+
None
134+
}
135+
else {
136+
Some(local)
137+
}
105138
}
106139
else {
107140
None
@@ -138,10 +171,10 @@ impl PkgSrc {
138171

139172
/// Infers crates to build. Called only in the case where there
140173
/// is no custom build logic
141-
pub fn find_crates(&mut self) {
174+
pub fn find_crates(&mut self, cx: &Ctx) {
142175
use conditions::missing_pkg_files::cond;
143176

144-
let dir = self.check_dir();
177+
let dir = self.check_dir(cx);
145178
debug!("Called check_dir, I'm in %s", dir.to_str());
146179
let prefix = dir.components.len();
147180
debug!("Matching against %?", self.id.short_name);
@@ -183,6 +216,7 @@ impl PkgSrc {
183216
fn build_crates(&self,
184217
ctx: &Ctx,
185218
src_dir: &Path,
219+
destination_dir: &Path,
186220
crates: &[Crate],
187221
cfgs: &[~str],
188222
what: OutputType) {
@@ -194,8 +228,8 @@ impl PkgSrc {
194228
let result = compile_crate(ctx,
195229
&self.id,
196230
path,
197-
// compile_crate wants the workspace
198-
&self.root,
231+
// compile_crate wants the destination workspace
232+
destination_dir,
199233
crate.flags,
200234
crate.cfgs + cfgs,
201235
false,
@@ -209,15 +243,39 @@ impl PkgSrc {
209243
}
210244
}
211245

212-
pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) {
213-
let dir = self.check_dir();
214-
debug!("Building libs in %s", dir.to_str());
215-
self.build_crates(ctx, &dir, self.libs, cfgs, Lib);
246+
pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) -> Path {
247+
use conditions::not_a_workspace::cond;
248+
249+
// Determine the destination workspace (which depends on whether
250+
// we're using the rust_path_hack)
251+
let destination_workspace = if is_workspace(&self.root) {
252+
debug!("%s is indeed a workspace", self.root.to_str());
253+
self.root.clone()
254+
}
255+
else {
256+
// It would be nice to have only one place in the code that checks
257+
// for the use_rust_path_hack flag...
258+
if ctx.use_rust_path_hack {
259+
let rs = default_workspace();
260+
debug!("Using hack: %s", rs.to_str());
261+
rs
262+
}
263+
else {
264+
cond.raise(fmt!("Package root %s is not a workspace; pass in --rust_path_hack \
265+
if you want to treat it as a package source", self.root.to_str()))
266+
}
267+
};
268+
269+
let dir = self.check_dir(ctx);
270+
debug!("Building libs in %s, destination = %s", dir.to_str(),
271+
destination_workspace.to_str());
272+
self.build_crates(ctx, &dir, &destination_workspace, self.libs, cfgs, Lib);
216273
debug!("Building mains");
217-
self.build_crates(ctx, &dir, self.mains, cfgs, Main);
274+
self.build_crates(ctx, &dir, &destination_workspace, self.mains, cfgs, Main);
218275
debug!("Building tests");
219-
self.build_crates(ctx, &dir, self.tests, cfgs, Test);
276+
self.build_crates(ctx, &dir, &destination_workspace, self.tests, cfgs, Test);
220277
debug!("Building benches");
221-
self.build_crates(ctx, &dir, self.benchs, cfgs, Bench);
278+
self.build_crates(ctx, &dir, &destination_workspace, self.benchs, cfgs, Bench);
279+
destination_workspace
222280
}
223281
}

Diff for: src/librustpkg/path_util.rs

+40-14
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub use package_id::PkgId;
1414
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
1515
pub use version::{Version, NoVersion, split_version_general, try_parsing_version};
1616
pub use rustc::metadata::filesearch::rust_path;
17+
use context::Ctx;
1718

1819
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
1920
use std::os::mkdir_recursive;
@@ -51,18 +52,23 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) }
5152
pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
5253
debug!("Checking in src dir of %s for %s",
5354
workspace.to_str(), pkgid.to_str());
55+
workspace_contains_package_id_(pkgid, workspace, |p| { p.push("src") }).is_some()
56+
}
5457

55-
let src_dir = workspace.push("src");
58+
pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
59+
// Returns the directory it was actually found in
60+
workspace_to_src_dir: &fn(&Path) -> Path) -> Option<Path> {
61+
let src_dir = workspace_to_src_dir(workspace);
5662

57-
let mut found = false;
63+
let mut found = None;
5864
do os::walk_dir(&src_dir) |p| {
5965
debug!("=> p = %s", p.to_str());
6066

61-
let was_found = os::path_is_dir(p) && {
67+
if os::path_is_dir(p) {
6268
debug!("p = %s, path = %s [%s]", p.to_str(), pkgid.path.to_str(),
6369
src_dir.push_rel(&pkgid.path).to_str());
6470

65-
*p == src_dir.push_rel(&pkgid.path) || {
71+
if *p == src_dir.push_rel(&pkgid.path) || {
6672
let pf = p.filename();
6773
do pf.iter().any |pf| {
6874
let g = pf.to_str();
@@ -76,16 +82,15 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
7682
}
7783
}
7884
}
85+
} {
86+
found = Some(p.clone());
7987
}
80-
};
8188

82-
if was_found {
83-
found = true
84-
}
89+
};
8590
true
8691
};
8792

88-
debug!(if found { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
93+
debug!(if found.is_some() { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
8994
else { fmt!("Didn't find %s in %s", pkgid.to_str(), workspace.to_str()) });
9095
found
9196
}
@@ -123,8 +128,7 @@ pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<
123128
Some(result)
124129
}
125130
else {
126-
// This is not an error, but it's worth logging it
127-
error!(fmt!("built_executable_in_workspace: %s does not exist", result.to_str()));
131+
debug!("built_executable_in_workspace: %s does not exist", result.to_str());
128132
None
129133
}
130134
}
@@ -164,7 +168,7 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat
164168

165169
/// Does the actual searching stuff
166170
pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option<Path> {
167-
// NOTE: this could break once we're handling multiple versions better... want a test for it
171+
// This could break once we're handling multiple versions better -- I should add a test for it
168172
library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib", &NoVersion)
169173
}
170174

@@ -246,8 +250,8 @@ pub fn library_in_workspace(path: &Path, short_name: &str, where: Target,
246250
} // for
247251

248252
if result_filename.is_none() {
249-
warn(fmt!("library_in_workspace didn't find a library in %s for %s",
250-
dir_to_search.to_str(), short_name));
253+
debug!("warning: library_in_workspace didn't find a library in %s for %s",
254+
dir_to_search.to_str(), short_name);
251255
}
252256

253257
// Return the filename that matches, which we now know exists
@@ -392,3 +396,25 @@ pub fn uninstall_package_from(workspace: &Path, pkgid: &PkgId) {
392396
}
393397

394398
}
399+
400+
fn dir_has_file(dir: &Path, file: &str) -> bool {
401+
assert!(dir.is_absolute());
402+
os::path_exists(&dir.push(file))
403+
}
404+
405+
pub fn find_dir_using_rust_path_hack(cx: &Ctx, p: &PkgId) -> Option<Path> {
406+
if !cx.use_rust_path_hack {
407+
return None;
408+
}
409+
let rp = rust_path();
410+
for dir in rp.iter() {
411+
debug!("In find_dir_using_rust_path_hack: checking dir %s", dir.to_str());
412+
if dir_has_file(dir, "lib.rs") || dir_has_file(dir, "main.rs")
413+
|| dir_has_file(dir, "test.rs") || dir_has_file(dir, "bench.rs") {
414+
debug!("Did find id %s in dir %s", p.to_str(), dir.to_str());
415+
return Some(dir.clone());
416+
}
417+
debug!("Didn't find id %s in dir %s", p.to_str(), dir.to_str())
418+
}
419+
None
420+
}

0 commit comments

Comments
 (0)