Skip to content

Commit 0fa9ad8

Browse files
committed
rustpkg: Handle local git repositories
rustpkg can now build code from a local git repository. In the case where the local repo is in a directory not in the RUST_PATH, it checks out the repository into a directory in the first workspace in the RUST_PATH. The tests no longer try to connect to github.com, which should solve some of the sporadic failures we've been seeing.
1 parent 9c22f65 commit 0fa9ad8

10 files changed

+378
-103
lines changed

src/librustpkg/api.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ pub fn build_lib(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Ve
2828

2929
let pkg_src = PkgSrc {
3030
root: root,
31-
dst_dir: dest,
32-
id: PkgId{ version: version, ..PkgId::new(name)},
31+
dst_dir: dest.clone(),
32+
id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())},
3333
libs: ~[mk_crate(lib)],
3434
mains: ~[],
3535
tests: ~[],
@@ -42,8 +42,8 @@ pub fn build_exe(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Ve
4242
main: Path) {
4343
let pkg_src = PkgSrc {
4444
root: root,
45-
dst_dir: dest,
46-
id: PkgId{ version: version, ..PkgId::new(name)},
45+
dst_dir: dest.clone(),
46+
id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())},
4747
libs: ~[],
4848
mains: ~[mk_crate(main)],
4949
tests: ~[],
@@ -62,7 +62,7 @@ pub fn install_lib(sysroot: @Path,
6262
debug!("sysroot = %s", sysroot.to_str());
6363
debug!("workspace = %s", workspace.to_str());
6464
// make a PkgSrc
65-
let pkg_id = PkgId{ version: version, ..PkgId::new(name)};
65+
let pkg_id = PkgId{ version: version, ..PkgId::new(name, &workspace)};
6666
let build_dir = workspace.push("build");
6767
let dst_dir = build_dir.push_rel(&*pkg_id.local_path);
6868
let pkg_src = PkgSrc {
@@ -81,7 +81,7 @@ pub fn install_lib(sysroot: @Path,
8181

8282
pub fn install_exe(sysroot: @Path, workspace: Path, name: ~str, version: Version) {
8383
default_ctxt(sysroot).install(&workspace, &PkgId{ version: version,
84-
..PkgId::new(name)});
84+
..PkgId::new(name, &workspace)});
8585

8686
}
8787

src/librustpkg/installed_packages.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool {
1818
for workspaces.iter().advance |p| {
1919
let binfiles = os::list_dir(&p.push("bin"));
2020
for binfiles.iter().advance() |exec| {
21-
f(&PkgId::new(*exec));
21+
f(&PkgId::new(*exec, p));
2222
}
2323
let libfiles = os::list_dir(&p.push("lib"));
2424
for libfiles.iter().advance() |lib| {
25-
f(&PkgId::new(*lib));
25+
f(&PkgId::new(*lib, p));
2626
}
2727
}
2828
true

src/librustpkg/package_id.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
// except according to those terms.
1010

1111
pub use package_path::{RemotePath, LocalPath, normalize, hash};
12-
use version::{try_getting_version, Version, NoVersion, split_version};
12+
use version::{try_getting_version, try_getting_local_version,
13+
Version, NoVersion, split_version};
1314

1415
/// Path-fragment identifier of a package such as
1516
/// 'github.com/graydon/test'; path must be a relative
@@ -40,7 +41,10 @@ impl Eq for PkgId {
4041
}
4142

4243
impl PkgId {
43-
pub fn new(s: &str) -> PkgId {
44+
// The PkgId constructor takes a Path argument so as
45+
// to be able to infer the version if the path refers
46+
// to a local git repository
47+
pub fn new(s: &str, work_dir: &Path) -> PkgId {
4448
use conditions::bad_pkg_id::cond;
4549

4650
let mut given_version = None;
@@ -71,9 +75,12 @@ impl PkgId {
7175

7276
let version = match given_version {
7377
Some(v) => v,
74-
None => match try_getting_version(&remote_path) {
78+
None => match try_getting_local_version(&work_dir.push_rel(&*local_path)) {
7579
Some(v) => v,
76-
None => NoVersion
80+
None => match try_getting_version(&remote_path) {
81+
Some(v) => v,
82+
None => NoVersion
83+
}
7784
}
7885
};
7986

src/librustpkg/package_source.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use std::{os, run, str};
1515
use context::*;
1616
use crate::Crate;
1717
use messages::*;
18+
use source_control::git_clone;
1819
use path_util::pkgid_src_in_workspace;
1920
use util::compile_crate;
2021
use version::{ExactRevision, SemanticVersion, NoVersion};
@@ -76,9 +77,10 @@ impl PkgSrc {
7677
dir
7778
}
7879

79-
/// Try interpreting self's package id as a remote package, and try
80+
/// Try interpreting self's package id as a git repository, and try
8081
/// fetching it and caching it in a local directory. Return the cached directory
81-
/// if this was successful, None otherwise
82+
/// if this was successful, None otherwise. Similarly, if the package id
83+
/// refers to a git repo on the local version, also check it out.
8284
/// (right now we only support git)
8385
pub fn fetch_git(&self) -> Option<Path> {
8486

@@ -87,6 +89,18 @@ impl PkgSrc {
8789
// Git can't clone into a non-empty directory
8890
os::remove_dir_recursive(&local);
8991

92+
debug!("Checking whether %s exists locally. Cwd = %s, does it? %?",
93+
self.id.local_path.to_str(),
94+
os::getcwd().to_str(),
95+
os::path_exists(&*self.id.local_path));
96+
97+
if os::path_exists(&*self.id.local_path) {
98+
debug!("%s exists locally! Cloning it into %s",
99+
self.id.local_path.to_str(), local.to_str());
100+
git_clone(&*self.id.local_path, &local, &self.id.version);
101+
return Some(local);
102+
}
103+
90104
let url = fmt!("https://%s", self.id.remote_path.to_str());
91105
let branch_args = match self.id.version {
92106
NoVersion => ~[],

src/librustpkg/path_util.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,30 @@ pub fn rust_path() -> ~[Path] {
5454
};
5555
let cwd = os::getcwd();
5656
// now add in default entries
57+
env_rust_path.push(cwd.push(".rust"));
5758
env_rust_path.push(copy cwd);
5859
do cwd.each_parent() |p| { push_if_exists(&mut env_rust_path, p) };
5960
let h = os::homedir();
6061
for h.iter().advance |h| { push_if_exists(&mut env_rust_path, h); }
6162
env_rust_path
6263
}
6364

65+
pub fn default_workspace() -> Path {
66+
let p = rust_path();
67+
if p.is_empty() {
68+
fail!("Empty RUST_PATH");
69+
}
70+
let result = p[0];
71+
if !os::path_is_dir(&result) {
72+
os::mkdir_recursive(&result, U_RWX);
73+
}
74+
result
75+
}
76+
77+
pub fn in_rust_path(p: &Path) -> bool {
78+
rust_path().contains(p)
79+
}
80+
6481
pub static U_RWX: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
6582

6683
/// Creates a directory that is readable, writeable,

src/librustpkg/rustpkg.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ use syntax::{ast, diagnostic};
3838
use util::*;
3939
use messages::*;
4040
use path_util::{build_pkg_id_in_workspace, first_pkgid_src_in_workspace};
41-
use path_util::{U_RWX, rust_path};
42-
use path_util::{built_executable_in_workspace, built_library_in_workspace};
41+
use path_util::{U_RWX, rust_path, in_rust_path};
42+
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
4343
use path_util::{target_executable_in_workspace, target_library_in_workspace};
44+
use source_control::is_git_dir;
4445
use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces};
4546
use context::Ctx;
4647
use package_id::PkgId;
@@ -57,6 +58,7 @@ mod package_path;
5758
mod package_source;
5859
mod path_util;
5960
mod search;
61+
mod source_control;
6062
mod target;
6163
#[cfg(test)]
6264
mod tests;
@@ -201,8 +203,10 @@ impl CtxMethods for Ctx {
201203
}
202204
// The package id is presumed to be the first command-line
203205
// argument
204-
let pkgid = PkgId::new(copy args[0]);
206+
let pkgid = PkgId::new(copy args[0], &os::getcwd());
205207
for each_pkg_parent_workspace(&pkgid) |workspace| {
208+
debug!("found pkg %s in workspace %s, trying to build",
209+
pkgid.to_str(), workspace.to_str());
206210
self.build(workspace, &pkgid);
207211
}
208212
}
@@ -212,7 +216,7 @@ impl CtxMethods for Ctx {
212216
}
213217
// The package id is presumed to be the first command-line
214218
// argument
215-
let pkgid = PkgId::new(copy args[0]);
219+
let pkgid = PkgId::new(copy args[0], &os::getcwd());
216220
let cwd = os::getcwd();
217221
self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd
218222
}
@@ -233,9 +237,10 @@ impl CtxMethods for Ctx {
233237

234238
// The package id is presumed to be the first command-line
235239
// argument
236-
let pkgid = PkgId::new(args[0]);
240+
let pkgid = PkgId::new(args[0], &os::getcwd());
237241
let workspaces = pkg_parent_workspaces(&pkgid);
238242
if workspaces.is_empty() {
243+
debug!("install! workspaces was empty");
239244
let rp = rust_path();
240245
assert!(!rp.is_empty());
241246
let src = PkgSrc::new(&rp[0], &build_pkg_id_in_workspace(&pkgid, &rp[0]),
@@ -245,6 +250,9 @@ impl CtxMethods for Ctx {
245250
}
246251
else {
247252
for each_pkg_parent_workspace(&pkgid) |workspace| {
253+
debug!("install: found pkg %s in workspace %s, trying to build",
254+
pkgid.to_str(), workspace.to_str());
255+
248256
self.install(workspace, &pkgid);
249257
}
250258
}
@@ -272,7 +280,7 @@ impl CtxMethods for Ctx {
272280
return usage::uninstall();
273281
}
274282

275-
let pkgid = PkgId::new(args[0]);
283+
let pkgid = PkgId::new(args[0], &os::getcwd()); // ??
276284
if !installed_packages::package_is_installed(&pkgid) {
277285
warn(fmt!("Package %s doesn't seem to be installed! Doing nothing.", args[0]));
278286
return;
@@ -304,12 +312,29 @@ impl CtxMethods for Ctx {
304312
}
305313

306314
fn build(&self, workspace: &Path, pkgid: &PkgId) {
307-
debug!("build: workspace = %s pkgid = %s", workspace.to_str(),
315+
debug!("build: workspace = %s (in Rust path? %? is git dir? %? \
316+
pkgid = %s", workspace.to_str(),
317+
in_rust_path(workspace), is_git_dir(&workspace.push_rel(&*pkgid.local_path)),
308318
pkgid.to_str());
309319
let src_dir = first_pkgid_src_in_workspace(pkgid, workspace);
310320
let build_dir = build_pkg_id_in_workspace(pkgid, workspace);
311321
debug!("Destination dir = %s", build_dir.to_str());
312322

323+
// If workspace isn't in the RUST_PATH, and it's a git repo,
324+
// then clone it into the first entry in RUST_PATH, and repeat
325+
debug!("%? %? %s", in_rust_path(workspace),
326+
is_git_dir(&workspace.push_rel(&*pkgid.local_path)),
327+
workspace.to_str());
328+
if !in_rust_path(workspace) && is_git_dir(&workspace.push_rel(&*pkgid.local_path)) {
329+
let out_dir = default_workspace().push("src").push_rel(&*pkgid.local_path);
330+
source_control::git_clone(&workspace.push_rel(&*pkgid.local_path),
331+
&out_dir, &pkgid.version);
332+
let default_ws = default_workspace();
333+
debug!("Calling build recursively with %? and %?", default_ws.to_str(),
334+
pkgid.to_str());
335+
return self.build(&default_ws, pkgid);
336+
}
337+
313338
// Create the package source
314339
let mut src = PkgSrc::new(workspace, &build_dir, pkgid);
315340
debug!("Package src = %?", src);

src/librustpkg/source_control.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Utils for working with version control repositories. Just git right now.
12+
13+
use std::{io, os, run, str};
14+
use version::*;
15+
16+
/// For a local git repo
17+
pub fn git_clone(source: &Path, target: &Path, v: &Version) {
18+
assert!(os::path_is_dir(source));
19+
assert!(is_git_dir(source));
20+
if !os::path_exists(target) {
21+
let version_args = match v {
22+
&ExactRevision(ref s) => ~[~"--branch", s.to_owned()],
23+
_ => ~[]
24+
};
25+
debug!("Running: git clone %s %s %s", version_args.to_str(), source.to_str(),
26+
target.to_str());
27+
let outp = run::process_output("git", ~[~"clone"] + version_args +
28+
~[source.to_str(), target.to_str()]);
29+
if outp.status != 0 {
30+
io::println(str::from_bytes_owned(outp.output.clone()));
31+
io::println(str::from_bytes_owned(outp.error));
32+
fail!("Couldn't `git clone` %s", source.to_str());
33+
}
34+
}
35+
else {
36+
// Pull changes
37+
debug!("Running: git --work-tree=%s --git-dir=%s pull --no-edit %s",
38+
target.to_str(), target.push(".git").to_str(), source.to_str());
39+
let outp = run::process_output("git", [fmt!("--work-tree=%s", target.to_str()),
40+
fmt!("--git-dir=%s", target.push(".git").to_str()),
41+
~"pull", ~"--no-edit", source.to_str()]);
42+
assert!(outp.status == 0);
43+
}
44+
}
45+
46+
pub fn is_git_dir(p: &Path) -> bool {
47+
os::path_is_dir(&p.push(".git"))
48+
}

0 commit comments

Comments
 (0)