Skip to content

Commit

Permalink
auto merge of #7681 : catamorphism/rust/rustpkg-local-repos, r=catamo…
Browse files Browse the repository at this point in the history
…rphism

r? @graydon 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.
  • Loading branch information
bors committed Jul 15, 2013
2 parents 9d7e01b + 0fa9ad8 commit 04f9ce0
Show file tree
Hide file tree
Showing 10 changed files with 378 additions and 103 deletions.
12 changes: 6 additions & 6 deletions src/librustpkg/api.rs
Expand Up @@ -28,8 +28,8 @@ pub fn build_lib(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Ve

let pkg_src = PkgSrc {
root: root,
dst_dir: dest,
id: PkgId{ version: version, ..PkgId::new(name)},
dst_dir: dest.clone(),
id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())},
libs: ~[mk_crate(lib)],
mains: ~[],
tests: ~[],
Expand All @@ -42,8 +42,8 @@ pub fn build_exe(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Ve
main: Path) {
let pkg_src = PkgSrc {
root: root,
dst_dir: dest,
id: PkgId{ version: version, ..PkgId::new(name)},
dst_dir: dest.clone(),
id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())},
libs: ~[],
mains: ~[mk_crate(main)],
tests: ~[],
Expand All @@ -62,7 +62,7 @@ pub fn install_lib(sysroot: @Path,
debug!("sysroot = %s", sysroot.to_str());
debug!("workspace = %s", workspace.to_str());
// make a PkgSrc
let pkg_id = PkgId{ version: version, ..PkgId::new(name)};
let pkg_id = PkgId{ version: version, ..PkgId::new(name, &workspace)};
let build_dir = workspace.push("build");
let dst_dir = build_dir.push_rel(&*pkg_id.local_path);
let pkg_src = PkgSrc {
Expand All @@ -81,7 +81,7 @@ pub fn install_lib(sysroot: @Path,

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

}

Expand Down
4 changes: 2 additions & 2 deletions src/librustpkg/installed_packages.rs
Expand Up @@ -18,11 +18,11 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool {
for workspaces.iter().advance |p| {
let binfiles = os::list_dir(&p.push("bin"));
for binfiles.iter().advance() |exec| {
f(&PkgId::new(*exec));
f(&PkgId::new(*exec, p));
}
let libfiles = os::list_dir(&p.push("lib"));
for libfiles.iter().advance() |lib| {
f(&PkgId::new(*lib));
f(&PkgId::new(*lib, p));
}
}
true
Expand Down
15 changes: 11 additions & 4 deletions src/librustpkg/package_id.rs
Expand Up @@ -9,7 +9,8 @@
// except according to those terms.

pub use package_path::{RemotePath, LocalPath, normalize, hash};
use version::{try_getting_version, Version, NoVersion, split_version};
use version::{try_getting_version, try_getting_local_version,
Version, NoVersion, split_version};

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

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

let mut given_version = None;
Expand Down Expand Up @@ -71,9 +75,12 @@ impl PkgId {

let version = match given_version {
Some(v) => v,
None => match try_getting_version(&remote_path) {
None => match try_getting_local_version(&work_dir.push_rel(&*local_path)) {
Some(v) => v,
None => NoVersion
None => match try_getting_version(&remote_path) {
Some(v) => v,
None => NoVersion
}
}
};

Expand Down
18 changes: 16 additions & 2 deletions src/librustpkg/package_source.rs
Expand Up @@ -15,6 +15,7 @@ use std::{os, run, str};
use context::*;
use crate::Crate;
use messages::*;
use source_control::git_clone;
use path_util::pkgid_src_in_workspace;
use util::compile_crate;
use version::{ExactRevision, SemanticVersion, NoVersion};
Expand Down Expand Up @@ -76,9 +77,10 @@ impl PkgSrc {
dir
}

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

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

debug!("Checking whether %s exists locally. Cwd = %s, does it? %?",
self.id.local_path.to_str(),
os::getcwd().to_str(),
os::path_exists(&*self.id.local_path));

if os::path_exists(&*self.id.local_path) {
debug!("%s exists locally! Cloning it into %s",
self.id.local_path.to_str(), local.to_str());
git_clone(&*self.id.local_path, &local, &self.id.version);
return Some(local);
}

let url = fmt!("https://%s", self.id.remote_path.to_str());
let branch_args = match self.id.version {
NoVersion => ~[],
Expand Down
17 changes: 17 additions & 0 deletions src/librustpkg/path_util.rs
Expand Up @@ -54,13 +54,30 @@ pub fn rust_path() -> ~[Path] {
};
let cwd = os::getcwd();
// now add in default entries
env_rust_path.push(cwd.push(".rust"));
env_rust_path.push(copy cwd);
do cwd.each_parent() |p| { push_if_exists(&mut env_rust_path, p) };
let h = os::homedir();
for h.iter().advance |h| { push_if_exists(&mut env_rust_path, h); }
env_rust_path
}

pub fn default_workspace() -> Path {
let p = rust_path();
if p.is_empty() {
fail!("Empty RUST_PATH");
}
let result = p[0];
if !os::path_is_dir(&result) {
os::mkdir_recursive(&result, U_RWX);
}
result
}

pub fn in_rust_path(p: &Path) -> bool {
rust_path().contains(p)
}

pub static U_RWX: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;

/// Creates a directory that is readable, writeable,
Expand Down
39 changes: 32 additions & 7 deletions src/librustpkg/rustpkg.rs
Expand Up @@ -38,9 +38,10 @@ use syntax::{ast, diagnostic};
use util::*;
use messages::*;
use path_util::{build_pkg_id_in_workspace, first_pkgid_src_in_workspace};
use path_util::{U_RWX, rust_path};
use path_util::{built_executable_in_workspace, built_library_in_workspace};
use path_util::{U_RWX, rust_path, in_rust_path};
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
use path_util::{target_executable_in_workspace, target_library_in_workspace};
use source_control::is_git_dir;
use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces};
use context::Ctx;
use package_id::PkgId;
Expand All @@ -57,6 +58,7 @@ mod package_path;
mod package_source;
mod path_util;
mod search;
mod source_control;
mod target;
#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -201,8 +203,10 @@ impl CtxMethods for Ctx {
}
// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(copy args[0]);
let pkgid = PkgId::new(copy args[0], &os::getcwd());
for each_pkg_parent_workspace(&pkgid) |workspace| {
debug!("found pkg %s in workspace %s, trying to build",
pkgid.to_str(), workspace.to_str());
self.build(workspace, &pkgid);
}
}
Expand All @@ -212,7 +216,7 @@ impl CtxMethods for Ctx {
}
// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(copy args[0]);
let pkgid = PkgId::new(copy args[0], &os::getcwd());
let cwd = os::getcwd();
self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd
}
Expand All @@ -233,9 +237,10 @@ impl CtxMethods for Ctx {

// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(args[0]);
let pkgid = PkgId::new(args[0], &os::getcwd());
let workspaces = pkg_parent_workspaces(&pkgid);
if workspaces.is_empty() {
debug!("install! workspaces was empty");
let rp = rust_path();
assert!(!rp.is_empty());
let src = PkgSrc::new(&rp[0], &build_pkg_id_in_workspace(&pkgid, &rp[0]),
Expand All @@ -245,6 +250,9 @@ impl CtxMethods for Ctx {
}
else {
for each_pkg_parent_workspace(&pkgid) |workspace| {
debug!("install: found pkg %s in workspace %s, trying to build",
pkgid.to_str(), workspace.to_str());

self.install(workspace, &pkgid);
}
}
Expand Down Expand Up @@ -272,7 +280,7 @@ impl CtxMethods for Ctx {
return usage::uninstall();
}

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

fn build(&self, workspace: &Path, pkgid: &PkgId) {
debug!("build: workspace = %s pkgid = %s", workspace.to_str(),
debug!("build: workspace = %s (in Rust path? %? is git dir? %? \
pkgid = %s", workspace.to_str(),
in_rust_path(workspace), is_git_dir(&workspace.push_rel(&*pkgid.local_path)),
pkgid.to_str());
let src_dir = first_pkgid_src_in_workspace(pkgid, workspace);
let build_dir = build_pkg_id_in_workspace(pkgid, workspace);
debug!("Destination dir = %s", build_dir.to_str());

// If workspace isn't in the RUST_PATH, and it's a git repo,
// then clone it into the first entry in RUST_PATH, and repeat
debug!("%? %? %s", in_rust_path(workspace),
is_git_dir(&workspace.push_rel(&*pkgid.local_path)),
workspace.to_str());
if !in_rust_path(workspace) && is_git_dir(&workspace.push_rel(&*pkgid.local_path)) {
let out_dir = default_workspace().push("src").push_rel(&*pkgid.local_path);
source_control::git_clone(&workspace.push_rel(&*pkgid.local_path),
&out_dir, &pkgid.version);
let default_ws = default_workspace();
debug!("Calling build recursively with %? and %?", default_ws.to_str(),
pkgid.to_str());
return self.build(&default_ws, pkgid);
}

// Create the package source
let mut src = PkgSrc::new(workspace, &build_dir, pkgid);
debug!("Package src = %?", src);
Expand Down
48 changes: 48 additions & 0 deletions src/librustpkg/source_control.rs
@@ -0,0 +1,48 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Utils for working with version control repositories. Just git right now.

use std::{io, os, run, str};
use version::*;

/// For a local git repo
pub fn git_clone(source: &Path, target: &Path, v: &Version) {
assert!(os::path_is_dir(source));
assert!(is_git_dir(source));
if !os::path_exists(target) {
let version_args = match v {
&ExactRevision(ref s) => ~[~"--branch", s.to_owned()],
_ => ~[]
};
debug!("Running: git clone %s %s %s", version_args.to_str(), source.to_str(),
target.to_str());
let outp = run::process_output("git", ~[~"clone"] + version_args +
~[source.to_str(), target.to_str()]);
if outp.status != 0 {
io::println(str::from_bytes_owned(outp.output.clone()));
io::println(str::from_bytes_owned(outp.error));
fail!("Couldn't `git clone` %s", source.to_str());
}
}
else {
// Pull changes
debug!("Running: git --work-tree=%s --git-dir=%s pull --no-edit %s",
target.to_str(), target.push(".git").to_str(), source.to_str());
let outp = run::process_output("git", [fmt!("--work-tree=%s", target.to_str()),
fmt!("--git-dir=%s", target.push(".git").to_str()),
~"pull", ~"--no-edit", source.to_str()]);
assert!(outp.status == 0);
}
}

pub fn is_git_dir(p: &Path) -> bool {
os::path_is_dir(&p.push(".git"))
}

0 comments on commit 04f9ce0

Please sign in to comment.