rustpkg: Make checked-out source files read-only, and overhaul where temporary files are stored

rustpkg now makes source files that it checks out automatically read-only, and stores
them under build/.

Also, refactored the `PkgSrc` type to keep track of separate source and destination
workspaces, as well as to have a `build_workspace` method that returns the workspace
to put temporary files in (usually the source, sometimes the destination -- see
comments for more details).

Closes #6480
This commit is contained in:
Tim Chevalier 2013-10-05 16:40:01 -04:00
parent 8b8a41a287
commit 8854b78b55
11 changed files with 542 additions and 296 deletions

View File

@ -137,6 +137,9 @@ and builds it in any workspace(s) where it finds one.
Supposing such packages are found in workspaces X, Y, and Z,
the command leaves behind files in `X`'s, `Y`'s, and `Z`'s `build` directories,
but not in their `lib` or `bin` directories.
(The exception is when rustpkg fetches a package `foo`'s sources from a remote repository.
In that case, it stores both the sources *and* the build artifacts for `foo`
in the workspace that `foo` will install to (see ##install below)).
## clean
@ -148,7 +151,11 @@ but not in their `lib` or `bin` directories.
If `RUST_PATH` is declared as an environment variable, then rustpkg installs the
libraries and executables into the `lib` and `bin` subdirectories
of the first entry in `RUST_PATH`.
Otherwise, it installs them into `foo`'s `lib` and `bin` directories.
Otherwise, if the current working directory CWD is a workspace,
it installs them into CWD's `lib` and `bin` subdirectories.
Otherwise, if the current working directory is CWD,
it installs them into the .rust/lib and .rust/bin subdirectories of CWD
(creating them if necessary).
## test

View File

@ -16,6 +16,8 @@ use target::*;
use version::Version;
use workcache_support::*;
pub use source_control::{safe_git_clone, git_clone_url};
use std::os;
use extra::arc::{Arc,RWArc};
use extra::workcache;
@ -68,15 +70,17 @@ pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
lib: Path) {
let cx = default_context(sysroot);
let pkg_src = PkgSrc {
workspace: root.clone(),
start_dir: root.push("src").push(name),
id: PkgId{ version: version, ..PkgId::new(name)},
// n.b. This assumes the package only has one crate
libs: ~[mk_crate(lib)],
mains: ~[],
tests: ~[],
benchs: ~[]
};
source_workspace: root.clone(),
build_in_destination: false,
destination_workspace: root.clone(),
start_dir: root.push("src").push(name),
id: PkgId{ version: version, ..PkgId::new(name)},
// n.b. This assumes the package only has one crate
libs: ~[mk_crate(lib)],
mains: ~[],
tests: ~[],
benchs: ~[]
};
pkg_src.build(&cx, ~[]);
}
@ -84,7 +88,9 @@ pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
main: Path) {
let cx = default_context(sysroot);
let pkg_src = PkgSrc {
workspace: root.clone(),
source_workspace: root.clone(),
build_in_destination: false,
destination_workspace: root.clone(),
start_dir: root.push("src").push(name),
id: PkgId{ version: version, ..PkgId::new(name)},
libs: ~[],
@ -100,7 +106,7 @@ pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
let cx = default_context(sysroot);
let pkgid = PkgId{ version: version, ..PkgId::new(name)};
cx.install(PkgSrc::new(workspace, false, pkgid), &Everything);
cx.install(PkgSrc::new(workspace.clone(), workspace, false, pkgid), &Everything);
}
fn mk_crate(p: Path) -> Crate {

View File

@ -50,3 +50,7 @@ condition! {
condition! {
pub failed_to_create_temp_dir: (~str) -> Path;
}
condition! {
pub git_checkout_failed: (~str, Path) -> ();
}

View File

@ -102,10 +102,7 @@ impl PkgId {
}
pub fn prefixes_iter(&self) -> Prefixes {
Prefixes {
components: self.path.components().to_owned(),
remaining: ~[]
}
prefixes_iter(&self.path)
}
// This is the workcache function name for the *installed*
@ -116,6 +113,13 @@ impl PkgId {
}
}
pub fn prefixes_iter(p: &Path) -> Prefixes {
Prefixes {
components: p.components().to_owned(),
remaining: ~[]
}
}
struct Prefixes {
priv components: ~[~str],
priv remaining: ~[~str]

View File

@ -17,10 +17,11 @@ use std::os;
use context::*;
use crate::Crate;
use messages::*;
use source_control::{git_clone, git_clone_general};
use path_util::{find_dir_using_rust_path_hack, default_workspace, make_dir_rwx_recursive};
use source_control::{safe_git_clone, git_clone_url, DirToUse, CheckedOutSources};
use source_control::make_read_only;
use path_util::{find_dir_using_rust_path_hack, make_dir_rwx_recursive};
use path_util::{target_build_dir, versionize};
use util::compile_crate;
use workspace::is_workspace;
use workcache_support;
use workcache_support::crate_tag;
use extra::workcache;
@ -30,7 +31,17 @@ use extra::workcache;
#[deriving(Clone)]
pub struct PkgSrc {
/// Root of where the package source code lives
workspace: Path,
source_workspace: Path,
/// If build_in_destination is true, temporary results should
/// go in the build/ subdirectory of the destination workspace.
/// (Otherwise, they go in the build/ subdirectory of the
/// source workspace.) This happens if the "RUST_PATH hack" is
/// in effect, or if sources were fetched from a remote
/// repository.
build_in_destination: bool,
/// Where to install the results. May or may not be the same
/// as source_workspace
destination_workspace: Path,
// Directory to start looking in for packages -- normally
// this is workspace/src/id but it may be just workspace
start_dir: Path,
@ -41,11 +52,15 @@ pub struct PkgSrc {
benchs: ~[Crate],
}
pub enum BuildSort { InPlace, Discovered }
impl ToStr for PkgSrc {
fn to_str(&self) -> ~str {
format!("Package ID {} in start dir {} [workspace = {}]",
format!("Package ID {} in start dir {} [workspaces = {} -> {}]",
self.id.to_str(),
self.start_dir.to_str(), self.workspace.to_str())
self.start_dir.to_str(),
self.source_workspace.to_str(),
self.destination_workspace.to_str())
}
}
condition! {
@ -55,27 +70,53 @@ condition! {
impl PkgSrc {
pub fn new(workspace: Path, use_rust_path_hack: bool, id: PkgId) -> PkgSrc {
pub fn new(mut source_workspace: Path,
destination_workspace: Path,
use_rust_path_hack: bool,
id: PkgId) -> PkgSrc {
use conditions::nonexistent_package::cond;
debug2!("Checking package source for package ID {}, \
workspace = {} use_rust_path_hack = {:?}",
id.to_str(), workspace.to_str(), use_rust_path_hack);
workspace = {} -> {}, use_rust_path_hack = {:?}",
id.to_str(),
source_workspace.to_str(),
destination_workspace.to_str(),
use_rust_path_hack);
let mut destination_workspace = destination_workspace.clone();
let mut to_try = ~[];
let mut output_names = ~[];
let build_dir = target_build_dir(&source_workspace);
if use_rust_path_hack {
to_try.push(workspace.clone());
to_try.push(source_workspace.clone());
} else {
let result = workspace.push("src").push_rel(&id.path.pop()).push(format!("{}-{}",
// We search for sources under both src/ and build/ , because build/ is where
// automatically-checked-out sources go.
let result = source_workspace.push("src").push_rel(&id.path.pop()).push(format!("{}-{}",
id.short_name, id.version.to_str()));
to_try.push(result);
to_try.push(workspace.push("src").push_rel(&id.path));
to_try.push(source_workspace.push("src").push_rel(&id.path));
let result = build_dir.push("src").push_rel(&id.path.pop()).push(format!("{}-{}",
id.short_name, id.version.to_str()));
to_try.push(result.clone());
output_names.push(result);
let other_result = build_dir.push("src").push_rel(&id.path);
to_try.push(other_result.clone());
output_names.push(other_result);
}
debug2!("Checking dirs: {:?}", to_try.map(|s| s.to_str()).connect(":"));
let path = to_try.iter().find(|&d| os::path_exists(d));
// See the comments on the definition of PkgSrc
let mut build_in_destination = use_rust_path_hack;
debug2!("1. build_in_destination = {:?}", build_in_destination);
let dir: Path = match path {
Some(d) => (*d).clone(),
None => {
@ -83,23 +124,33 @@ impl PkgSrc {
// That is, is this a package ID that points into the middle of a workspace?
for (prefix, suffix) in id.prefixes_iter() {
let package_id = PkgId::new(prefix.to_str());
let path = workspace.push("src").push_rel(&package_id.path);
let path = build_dir.push_rel(&package_id.path);
debug2!("in loop: checking if {} is a directory", path.to_str());
if os::path_is_dir(&path) {
let ps = PkgSrc::new(workspace.clone(),
let ps = PkgSrc::new(source_workspace,
destination_workspace,
use_rust_path_hack,
PkgId::new(prefix.to_str()));
debug2!("pkgsrc: Returning [{}|{}|{}]", workspace.to_str(),
ps.start_dir.push_rel(&suffix).to_str(), ps.id.to_str());
return PkgSrc {
workspace: workspace,
start_dir: ps.start_dir.push_rel(&suffix),
id: ps.id,
libs: ~[],
mains: ~[],
tests: ~[],
benchs: ~[]
match ps {
PkgSrc {
source_workspace: source,
destination_workspace: destination,
start_dir: start,
id: id, _ } => {
let result = PkgSrc {
source_workspace: source.clone(),
build_in_destination: build_in_destination,
destination_workspace: destination,
start_dir: start.push_rel(&suffix),
id: id,
libs: ~[],
mains: ~[],
tests: ~[],
benchs: ~[]
};
debug2!("pkgsrc: Returning {}", result.to_str());
return result;
}
}
};
@ -107,14 +158,33 @@ impl PkgSrc {
// Ok, no prefixes work, so try fetching from git
let mut ok_d = None;
for w in to_try.iter() {
for w in output_names.iter() {
debug2!("Calling fetch_git on {}", w.to_str());
let gf = PkgSrc::fetch_git(w, &id);
for p in gf.iter() {
let target_dir_opt = PkgSrc::fetch_git(w, &id);
for p in target_dir_opt.iter() {
ok_d = Some(p.clone());
build_in_destination = true;
debug2!("2. build_in_destination = {:?}", build_in_destination);
break;
}
if ok_d.is_some() { break; }
match ok_d {
Some(ref d) => {
if d.is_parent_of(&id.path)
|| d.is_parent_of(&versionize(&id.path, &id.version)) {
// Strip off the package ID
source_workspace = d.clone();
for _ in id.path.components().iter() {
source_workspace = source_workspace.pop();
}
// Strip off the src/ part
source_workspace = source_workspace.pop();
// Strip off the build/<target-triple> part to get the workspace
destination_workspace = source_workspace.pop().pop();
}
break;
}
None => ()
}
}
match ok_d {
Some(d) => d,
@ -138,6 +208,9 @@ impl PkgSrc {
}
}
};
debug2!("3. build_in_destination = {:?}", build_in_destination);
debug2!("source: {} dest: {}", source_workspace.to_str(), destination_workspace.to_str());
debug2!("For package id {}, returning {}", id.to_str(), dir.to_str());
if !os::path_is_dir(&dir) {
@ -145,11 +218,10 @@ impl PkgSrc {
non-directory"));
}
debug2!("pkgsrc: Returning \\{{}|{}|{}\\}", workspace.to_str(),
dir.to_str(), id.to_str());
PkgSrc {
workspace: workspace,
source_workspace: source_workspace.clone(),
build_in_destination: build_in_destination,
destination_workspace: destination_workspace,
start_dir: dir,
id: id,
libs: ~[],
@ -165,56 +237,53 @@ impl PkgSrc {
/// refers to a git repo on the local version, also check it out.
/// (right now we only support git)
pub fn fetch_git(local: &Path, pkgid: &PkgId) -> Option<Path> {
use conditions::failed_to_create_temp_dir::cond;
use conditions::git_checkout_failed::cond;
// We use a temporary directory because if the git clone fails,
// it creates the target directory anyway and doesn't delete it
let scratch_dir = extra::tempfile::mkdtemp(&os::tmpdir(), "rustpkg");
let clone_target = match scratch_dir {
Some(d) => d.push("rustpkg_temp"),
None => cond.raise(~"Failed to create temporary directory for fetching git sources")
};
debug2!("Checking whether {} (path = {}) exists locally. Cwd = {}, does it? {:?}",
pkgid.to_str(), pkgid.path.to_str(),
os::getcwd().to_str(),
os::path_exists(&pkgid.path));
pkgid.to_str(), pkgid.path.to_str(),
os::getcwd().to_str(),
os::path_exists(&pkgid.path));
if os::path_exists(&pkgid.path) {
debug2!("{} exists locally! Cloning it into {}",
pkgid.path.to_str(), local.to_str());
// Ok to use local here; we know it will succeed
git_clone(&pkgid.path, local, &pkgid.version);
return Some(local.clone());
}
if pkgid.path.components().len() < 2 {
// If a non-URL, don't bother trying to fetch
return None;
}
let url = format!("https://{}", pkgid.path.to_str());
debug2!("Fetching package: git clone {} {} [version={}]",
url, clone_target.to_str(), pkgid.version.to_str());
if git_clone_general(url, &clone_target, &pkgid.version) {
// Since the operation succeeded, move clone_target to local.
// First, create all ancestor directories.
if make_dir_rwx_recursive(&local.pop())
&& os::rename_file(&clone_target, local) {
Some(local.clone())
match safe_git_clone(&pkgid.path, &pkgid.version, local) {
CheckedOutSources => {
make_read_only(local);
Some(local.clone())
}
else {
None
DirToUse(clone_target) => {
if pkgid.path.components().len() < 2 {
// If a non-URL, don't bother trying to fetch
return None;
}
let url = format!("https://{}", pkgid.path.to_str());
debug2!("Fetching package: git clone {} {} [version={}]",
url, clone_target.to_str(), pkgid.version.to_str());
let mut failed = false;
do cond.trap(|_| {
failed = true;
}).inside {
git_clone_url(url, &clone_target, &pkgid.version);
};
if failed {
return None;
}
// Move clone_target to local.
// First, create all ancestor directories.
let moved = make_dir_rwx_recursive(&local.pop())
&& os::rename_file(&clone_target, local);
if moved { Some(local.clone()) }
else { None }
}
}
else {
None
}
}
// If a file named "pkg.rs" in the start directory exists,
// return the path for it. Otherwise, None
pub fn package_script_option(&self) -> Option<Path> {
@ -292,7 +361,6 @@ impl PkgSrc {
fn build_crates(&self,
ctx: &BuildContext,
destination_dir: &Path,
crates: &[Crate],
cfgs: &[~str],
what: OutputType) {
@ -311,7 +379,7 @@ impl PkgSrc {
let subpath_str = path_str.clone();
let subcx = ctx.clone();
let id = self.id.clone();
let sub_dir = destination_dir.clone();
let sub_dir = self.build_workspace().clone();
let sub_flags = crate.flags.clone();
do prep.exec |exec| {
let result = compile_crate(&subcx,
@ -351,42 +419,30 @@ impl PkgSrc {
// Encodable.
pub fn build(&self,
build_context: &BuildContext,
cfgs: ~[~str]) -> ~str {
use conditions::not_a_workspace::cond;
// Determine the destination workspace (which depends on whether
// we're using the rust_path_hack)
let destination_workspace = if is_workspace(&self.workspace) {
debug2!("{} is indeed a workspace", self.workspace.to_str());
self.workspace.clone()
} else {
// It would be nice to have only one place in the code that checks
// for the use_rust_path_hack flag...
if build_context.context.use_rust_path_hack {
let rs = default_workspace();
debug2!("Using hack: {}", rs.to_str());
rs
} else {
cond.raise(format!("Package root {} is not a workspace; pass in --rust_path_hack \
if you want to treat it as a package source",
self.workspace.to_str()))
}
};
cfgs: ~[~str]) {
let libs = self.libs.clone();
let mains = self.mains.clone();
let tests = self.tests.clone();
let benchs = self.benchs.clone();
debug2!("Building libs in {}, destination = {}",
destination_workspace.to_str(), destination_workspace.to_str());
self.build_crates(build_context, &destination_workspace, libs, cfgs, Lib);
self.source_workspace.to_str(), self.build_workspace().to_str());
self.build_crates(build_context, libs, cfgs, Lib);
debug2!("Building mains");
self.build_crates(build_context, &destination_workspace, mains, cfgs, Main);
self.build_crates(build_context, mains, cfgs, Main);
debug2!("Building tests");
self.build_crates(build_context, &destination_workspace, tests, cfgs, Test);
self.build_crates(build_context, tests, cfgs, Test);
debug2!("Building benches");
self.build_crates(build_context, &destination_workspace, benchs, cfgs, Bench);
destination_workspace.to_str()
self.build_crates(build_context, benchs, cfgs, Bench);
}
/// Return the workspace to put temporary files in. See the comment on `PkgSrc`
pub fn build_workspace<'a>(&'a self) -> &'a Path {
if self.build_in_destination {
&self.destination_workspace
}
else {
&self.source_workspace
}
}
/// Debugging

View File

@ -16,6 +16,7 @@ pub use version::{Version, NoVersion, split_version_general, try_parsing_version
pub use rustc::metadata::filesearch::rust_path;
use rustc::driver::driver::host_triple;
use std::libc;
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use std::os::mkdir_recursive;
use std::os;
@ -447,9 +448,30 @@ pub fn user_set_rust_path() -> bool {
}
/// Append the version string onto the end of the path's filename
fn versionize(p: &Path, v: &Version) -> Path {
pub fn versionize(p: &Path, v: &Version) -> Path {
let q = p.file_path().to_str();
p.with_filename(format!("{}-{}", q, v.to_str()))
}
#[cfg(target_os = "win32")]
pub fn chmod_read_only(p: &Path) -> bool {
#[fixed_stack_segment];
unsafe {
do p.to_str().with_c_str |src_buf| {
libc::chmod(src_buf, S_IRUSR as libc::c_int) == 0 as libc::c_int
}
}
}
#[cfg(not(target_os = "win32"))]
pub fn chmod_read_only(p: &Path) -> bool {
#[fixed_stack_segment];
unsafe {
do p.to_str().with_c_str |src_buf| {
libc::chmod(src_buf, S_IRUSR as libc::mode_t) == 0
as libc::c_int
}
}
}

View File

@ -39,8 +39,9 @@ use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
use path_util::{U_RWX, 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 source_control::{CheckedOutSources, is_git_dir, make_read_only};
use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, cwd_to_workspace};
use workspace::determine_destination;
use context::{Context, BuildContext,
RustcFlags, Trans, Link, Nothing, Pretty, Analysis, Assemble,
LLVMAssemble, LLVMCompileBitcode};
@ -183,7 +184,7 @@ pub trait CtxMethods {
/// Returns a pair of the selected package ID, and the destination workspace
fn build_args(&self, args: ~[~str], what: &WhatToBuild) -> Option<(PkgId, Path)>;
/// Returns the destination workspace
fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild) -> Path;
fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild);
fn clean(&self, workspace: &Path, id: &PkgId);
fn info(&self);
/// Returns a pair. First component is a list of installed paths,
@ -208,34 +209,47 @@ impl CtxMethods for BuildContext {
None if self.context.use_rust_path_hack => {
let cwd = os::getcwd();
let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
let dest_ws = self.build(&mut pkg_src, what);
Some((pkg_src.id, dest_ws))
let mut pkg_src = PkgSrc::new(cwd, default_workspace(), true, pkgid);
self.build(&mut pkg_src, what);
match pkg_src {
PkgSrc { destination_workspace: ws,
id: id, _ } => {
Some((id, ws))
}
}
}
None => { usage::build(); None }
Some((ws, pkgid)) => {
let mut pkg_src = PkgSrc::new(ws, false, pkgid);
let dest_ws = self.build(&mut pkg_src, what);
Some((pkg_src.id, dest_ws))
let mut pkg_src = PkgSrc::new(ws.clone(), ws, false, pkgid);
self.build(&mut pkg_src, what);
match pkg_src {
PkgSrc { destination_workspace: ws,
id: id, _ } => {
Some((id, ws))
}
}
}
}
} else {
// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(args[0].clone());
let mut dest_ws = None;
let mut dest_ws = default_workspace();
do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
debug2!("found pkg {} in workspace {}, trying to build",
pkgid.to_str(), workspace.to_str());
let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
dest_ws = Some(self.build(&mut pkg_src, what));
dest_ws = determine_destination(os::getcwd(),
self.context.use_rust_path_hack,
workspace);
let mut pkg_src = PkgSrc::new(workspace.clone(), dest_ws.clone(),
false, pkgid.clone());
self.build(&mut pkg_src, what);
true
};
assert!(dest_ws.is_some());
// n.b. If this builds multiple packages, it only returns the workspace for
// the last one. The whole building-multiple-packages-with-the-same-ID is weird
// anyway and there are no tests for it, so maybe take it out
Some((pkgid, dest_ws.unwrap()))
Some((pkgid, dest_ws))
}
}
fn run(&self, cmd: &str, args: ~[~str]) {
@ -278,11 +292,12 @@ impl CtxMethods for BuildContext {
let cwd = os::getcwd();
let inferred_pkgid =
PkgId::new(cwd.components[cwd.components.len() - 1]);
self.install(PkgSrc::new(cwd, true, inferred_pkgid), &Everything);
self.install(PkgSrc::new(cwd, default_workspace(),
true, inferred_pkgid), &Everything);
}
None => { usage::install(); return; }
Some((ws, pkgid)) => {
let pkg_src = PkgSrc::new(ws, false, pkgid);
let pkg_src = PkgSrc::new(ws.clone(), ws.clone(), false, pkgid);
self.install(pkg_src, &Everything);
}
}
@ -295,14 +310,17 @@ impl CtxMethods for BuildContext {
debug2!("package ID = {}, found it in {:?} workspaces",
pkgid.to_str(), workspaces.len());
if workspaces.is_empty() {
let rp = rust_path();
assert!(!rp.is_empty());
let src = PkgSrc::new(rp[0].clone(), false, pkgid.clone());
let d = default_workspace();
let src = PkgSrc::new(d.clone(), d, false, pkgid.clone());
self.install(src, &Everything);
}
else {
for workspace in workspaces.iter() {
let dest = determine_destination(os::getcwd(),
self.context.use_rust_path_hack,
workspace);
let src = PkgSrc::new(workspace.clone(),
dest,
self.context.use_rust_path_hack,
pkgid.clone());
self.install(src, &Everything);
@ -382,12 +400,10 @@ impl CtxMethods for BuildContext {
fail2!("`do` not yet implemented");
}
/// Returns the destination workspace
/// In the case of a custom build, we don't know, so we just return the source workspace
/// what_to_build says: "Just build the lib.rs file in one subdirectory,
/// don't walk anything recursively." Or else, everything.
fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) -> Path {
let workspace = pkg_src.workspace.clone();
fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) {
use conditions::git_checkout_failed::cond;
let workspace = pkg_src.source_workspace.clone();
let pkgid = pkg_src.id.clone();
debug2!("build: workspace = {} (in Rust path? {:?} is git dir? {:?} \
@ -399,12 +415,20 @@ impl CtxMethods for BuildContext {
// then clone it into the first entry in RUST_PATH, and repeat
if !in_rust_path(&workspace) && is_git_dir(&workspace.push_rel(&pkgid.path)) {
let out_dir = default_workspace().push("src").push_rel(&pkgid.path);
source_control::git_clone(&workspace.push_rel(&pkgid.path),
&out_dir, &pkgid.version);
let git_result = source_control::safe_git_clone(&workspace.push_rel(&pkgid.path),
&pkgid.version,
&out_dir);
match git_result {
CheckedOutSources => make_read_only(&out_dir),
_ => cond.raise((pkgid.path.to_str(), out_dir.clone()))
};
let default_ws = default_workspace();
debug2!("Calling build recursively with {:?} and {:?}", default_ws.to_str(),
pkgid.to_str());
return self.build(&mut PkgSrc::new(default_ws, false, pkgid.clone()), what_to_build);
return self.build(&mut PkgSrc::new(default_ws.clone(),
default_ws,
false,
pkgid.clone()), what_to_build);
}
// Is there custom build logic? If so, use it
@ -469,17 +493,12 @@ impl CtxMethods for BuildContext {
PkgSrc::push_crate(&mut pkg_src.benchs, 0, p);
} else {
warn(format!("Not building any crates for dependency {}", p.to_str()));
return workspace.clone();
return;
}
}
}
// Build it!
let rs_path = pkg_src.build(self, cfgs);
Path(rs_path)
}
else {
// Just return the source workspace
workspace.clone()
pkg_src.build(self, cfgs);
}
}
@ -509,11 +528,13 @@ impl CtxMethods for BuildContext {
let id = pkg_src.id.clone();
let mut installed_files = ~[];
let inputs = ~[];
let mut inputs = ~[];
debug2!("Installing package source: {}", pkg_src.to_str());
// workcache only knows about *crates*. Building a package
// just means inferring all the crates in it, then building each one.
let destination_workspace = self.build(&mut pkg_src, what).to_str();
self.build(&mut pkg_src, what);
let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
pkg_src.tests.clone(), pkg_src.benchs.clone()];
@ -522,41 +543,35 @@ impl CtxMethods for BuildContext {
for c in cs.iter() {
let path = pkg_src.start_dir.push_rel(&c.file).normalize();
debug2!("Recording input: {}", path.to_str());
installed_files.push(path);
inputs.push((~"file", path.to_str()));
}
}
// See #7402: This still isn't quite right yet; we want to
// install to the first workspace in the RUST_PATH if there's
// a non-default RUST_PATH. This code installs to the same
// workspace the package was built in.
let actual_workspace = if path_util::user_set_rust_path() {
default_workspace()
}
else {
Path(destination_workspace)
};
debug2!("install: destination workspace = {}, id = {}, installing to {}",
destination_workspace, id.to_str(), actual_workspace.to_str());
let result = self.install_no_build(&Path(destination_workspace),
&actual_workspace,
let result = self.install_no_build(pkg_src.build_workspace(),
&pkg_src.destination_workspace,
&id).map(|s| Path(*s));
debug2!("install: id = {}, about to call discover_outputs, {:?}",
id.to_str(), result.to_str());
installed_files = installed_files + result;
note(format!("Installed package {} to {}", id.to_str(), actual_workspace.to_str()));
note(format!("Installed package {} to {}",
id.to_str(),
pkg_src.destination_workspace.to_str()));
(installed_files, inputs)
}
// again, working around lack of Encodable for Path
fn install_no_build(&self,
source_workspace: &Path,
build_workspace: &Path,
target_workspace: &Path,
id: &PkgId) -> ~[~str] {
use conditions::copy_failed::cond;
debug2!("install_no_build: assuming {} comes from {} with target {}",
id.to_str(), build_workspace.to_str(), target_workspace.to_str());
// Now copy stuff into the install dirs
let maybe_executable = built_executable_in_workspace(id, source_workspace);
let maybe_library = built_library_in_workspace(id, source_workspace);
let maybe_executable = built_executable_in_workspace(id, build_workspace);
let maybe_library = built_library_in_workspace(id, build_workspace);
let target_exec = target_executable_in_workspace(id, target_workspace);
let target_lib = maybe_library.as_ref()
.map(|_| target_library_in_workspace(id, target_workspace));
@ -602,11 +617,11 @@ impl CtxMethods for BuildContext {
didn't install it!", lib.to_str()));
let target_lib = target_lib
.pop().push(lib.filename().expect("weird target lib"));
debug2!("Copying: {} -> {}", lib.to_str(), sub_target_lib.to_str());
if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
os::copy_file(lib, &target_lib)) {
cond.raise(((*lib).clone(), target_lib.clone()));
}
debug2!("3. discovering output {}", target_lib.to_str());
exe_thing.discover_output("binary",
target_lib.to_str(),
workcache_support::digest_only_date(&target_lib));
@ -841,25 +856,6 @@ pub fn main_args(args: &[~str]) -> int {
return 0;
}
/**
* Get the working directory of the package script.
* Assumes that the package script has been compiled
* in is the working directory.
*/
pub fn work_dir() -> Path {
os::self_exe_path().unwrap()
}
/**
* Get the source directory of the package (i.e.
* where the crates are located). Assumes
* that the cwd is changed to it before
* running this executable.
*/
pub fn src_dir() -> Path {
os::getcwd()
}
fn declare_package_script_dependency(prep: &mut workcache::Prep, pkg_src: &PkgSrc) {
match pkg_src.package_script_option() {
Some(ref p) => prep.declare_input("file", p.to_str(),

View File

@ -12,62 +12,99 @@
use std::{io, os, run, str};
use std::run::{ProcessOutput, ProcessOptions, Process};
use extra::tempfile;
use version::*;
use path_util::chmod_read_only;
/// 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) {
debug2!("Running: git clone {} {}", source.to_str(), target.to_str());
let outp = run::process_output("git", [~"clone", source.to_str(), target.to_str()]);
if outp.status != 0 {
io::println(str::from_utf8_owned(outp.output.clone()));
io::println(str::from_utf8_owned(outp.error));
fail2!("Couldn't `git clone` {}", source.to_str());
}
else {
match v {
&ExactRevision(ref s) => {
debug2!("`Running: git --work-tree={} --git-dir={} checkout {}",
*s, target.to_str(), target.push(".git").to_str());
let outp = run::process_output("git",
[format!("--work-tree={}", target.to_str()),
format!("--git-dir={}", target.push(".git").to_str()),
~"checkout", format!("{}", *s)]);
if outp.status != 0 {
io::println(str::from_utf8_owned(outp.output.clone()));
io::println(str::from_utf8_owned(outp.error));
fail2!("Couldn't `git checkout {}` in {}",
*s, target.to_str());
}
}
_ => ()
/// Attempts to clone `source`, a local git repository, into `target`, a local
/// directory that doesn't exist.
/// Returns `DirToUse(p)` if the clone fails, where `p` is a newly created temporary
/// directory (that the callee may use, for example, to check out remote sources into).
/// Returns `CheckedOutSources` if the clone succeeded.
pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult {
use conditions::failed_to_create_temp_dir::cond;
let scratch_dir = tempfile::mkdtemp(&os::tmpdir(), "rustpkg");
let clone_target = match scratch_dir {
Some(d) => d.push("rustpkg_temp"),
None => cond.raise(~"Failed to create temporary directory for fetching git sources")
};
if os::path_exists(source) {
debug2!("{} exists locally! Cloning it into {}",
source.to_str(), target.to_str());
// Ok to use target here; we know it will succeed
assert!(os::path_is_dir(source));
assert!(is_git_dir(source));
if !os::path_exists(target) {
debug2!("Running: git clone {} {}", source.to_str(), target.to_str());
let outp = run::process_output("git", [~"clone", source.to_str(), target.to_str()]);
if outp.status != 0 {
io::println(str::from_utf8_owned(outp.output.clone()));
io::println(str::from_utf8_owned(outp.error));
return DirToUse(target.clone());
}
else {
match v {
&ExactRevision(ref s) => {
debug2!("`Running: git --work-tree={} --git-dir={} checkout {}",
*s, target.to_str(), target.push(".git").to_str());
let outp = run::process_output("git",
[format!("--work-tree={}", target.to_str()),
format!("--git-dir={}", target.push(".git").to_str()),
~"checkout", format!("{}", *s)]);
if outp.status != 0 {
io::println(str::from_utf8_owned(outp.output.clone()));
io::println(str::from_utf8_owned(outp.error));
return DirToUse(target.clone());
}
}
_ => ()
}
}
} else {
// Check that no version was specified. There's no reason to not handle the
// case where a version was requested, but I haven't implemented it.
assert!(*v == NoVersion);
debug2!("Running: git --work-tree={} --git-dir={} pull --no-edit {}",
target.to_str(), target.push(".git").to_str(), source.to_str());
let args = [format!("--work-tree={}", target.to_str()),
format!("--git-dir={}", target.push(".git").to_str()),
~"pull", ~"--no-edit", source.to_str()];
let outp = run::process_output("git", args);
assert!(outp.status == 0);
}
}
else {
// Check that no version was specified. There's no reason to not handle the
// case where a version was requested, but I haven't implemented it.
assert!(*v == NoVersion);
debug2!("Running: git --work-tree={} --git-dir={} pull --no-edit {}",
target.to_str(), target.push(".git").to_str(), source.to_str());
let args = [format!("--work-tree={}", target.to_str()),
format!("--git-dir={}", target.push(".git").to_str()),
~"pull", ~"--no-edit", source.to_str()];
let outp = run::process_output("git", args);
assert!(outp.status == 0);
CheckedOutSources
} else {
DirToUse(clone_target)
}
}
pub enum CloneResult {
DirToUse(Path), // Created this empty directory to use as the temp dir for git
CheckedOutSources // Successfully checked sources out into the given target dir
}
pub fn make_read_only(target: &Path) {
// Now, make all the files in the target dir read-only
do os::walk_dir(target) |p| {
if !os::path_is_dir(p) {
assert!(chmod_read_only(p));
};
true
};
}
/// Source can be either a URL or a local file path.
/// true if successful
pub fn git_clone_general(source: &str, target: &Path, v: &Version) -> bool {
pub fn git_clone_url(source: &str, target: &Path, v: &Version) {
use conditions::git_checkout_failed::cond;
let outp = run::process_output("git", [~"clone", source.to_str(), target.to_str()]);
if outp.status != 0 {
debug2!("{}", str::from_utf8_owned(outp.output.clone()));
debug2!("{}", str::from_utf8_owned(outp.error));
false
cond.raise((source.to_owned(), target.clone()))
}
else {
match v {
@ -77,15 +114,12 @@ pub fn git_clone_general(source: &str, target: &Path, v: &Version) -> bool {
if outp.status != 0 {
debug2!("{}", str::from_utf8_owned(outp.output.clone()));
debug2!("{}", str::from_utf8_owned(outp.error));
false
cond.raise((source.to_owned(), target.clone()))
}
else {
true
}
}
_ => true
}
_ => ()
}
}
}
fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> ProcessOutput {

View File

@ -11,7 +11,7 @@
// rustpkg unit tests
use context::{BuildContext, Context, RustcFlags};
use std::{io, libc, os, run, str, task};
use std::{io, os, run, str, task};
use extra::arc::Arc;
use extra::arc::RWArc;
use extra::tempfile::mkdtemp;
@ -27,13 +27,15 @@ use path_util::{target_executable_in_workspace, target_test_in_workspace,
target_bench_in_workspace, make_dir_rwx, U_RWX,
library_in_workspace, installed_library_in_workspace,
built_bench_in_workspace, built_test_in_workspace,
built_library_in_workspace, built_executable_in_workspace, target_build_dir};
built_library_in_workspace, built_executable_in_workspace, target_build_dir,
chmod_read_only};
use rustc::back::link::get_cc_prog;
use rustc::metadata::filesearch::rust_path;
use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups};
use syntax::diagnostic;
use target::*;
use package_source::PkgSrc;
use source_control::{CheckedOutSources, DirToUse, safe_git_clone};
use util::datestamp;
fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
@ -83,6 +85,13 @@ fn writeFile(file_path: &Path, contents: &str) {
out.write_line(contents);
}
fn mk_emptier_workspace(tag: &str) -> Path {
let workspace = mkdtemp(&os::tmpdir(), tag).expect("couldn't create temp dir");
let package_dir = workspace.push("src");
assert!(os::mkdir_recursive(&package_dir, U_RWX));
workspace
}
fn mk_empty_workspace(short_name: &Path, version: &Version, tag: &str) -> Path {
let workspace_dir = mkdtemp(&os::tmpdir(), tag).expect("couldn't create temp dir");
mk_workspace(&workspace_dir, short_name, version);
@ -192,6 +201,18 @@ fn is_rwx(p: &Path) -> bool {
}
}
fn is_read_only(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
match p.get_mode() {
None => return false,
Some(m) =>
((m & S_IRUSR as uint) == S_IRUSR as uint
&& (m & S_IWUSR as uint) == 0 as uint
&& (m & S_IXUSR as uint) == 0 as uint)
}
}
fn test_sysroot() -> Path {
// Totally gross hack but it's just for test cases.
// Infer the sysroot from the exe name and pray that it's right.
@ -499,8 +520,8 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) {
Ok(w) => w.write_line("/* hi */")
}
}
None => fail2!(format!("frob_source_file failed to find a source file in {}",
pkg_src_dir.to_str()))
None => fail2!("frob_source_file failed to find a source file in {}",
pkg_src_dir.to_str())
}
}
@ -528,7 +549,10 @@ fn test_install_valid() {
let ctxt = fake_ctxt(sysroot, &temp_workspace);
debug2!("temp_workspace = {}", temp_workspace.to_str());
// should have test, bench, lib, and main
let src = PkgSrc::new(temp_workspace.clone(), false, temp_pkg_id.clone());
let src = PkgSrc::new(temp_workspace.clone(),
temp_workspace.clone(),
false,
temp_pkg_id.clone());
ctxt.install(src, &Everything);
// Check that all files exist
let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
@ -557,7 +581,10 @@ fn test_install_invalid() {
// Uses task::try because of #9001
let result = do task::try {
let pkg_src = PkgSrc::new(temp_workspace.clone(), false, pkgid.clone());
let pkg_src = PkgSrc::new(temp_workspace.clone(),
temp_workspace.clone(),
false,
pkgid.clone());
ctxt.install(pkg_src, &Everything);
};
// Not the best test -- doesn't test that we failed in the right way.
@ -568,8 +595,6 @@ fn test_install_invalid() {
// Tests above should (maybe) be converted to shell out to rustpkg, too
#[test]
fn test_install_git() {
let sysroot = test_sysroot();
debug2!("sysroot = {}", sysroot.to_str());
let temp_pkg_id = git_repo_pkg();
let repo = init_git_repo(&temp_pkg_id.path);
debug2!("repo = {}", repo.to_str());
@ -724,12 +749,10 @@ fn test_package_request_version() {
assert!(target_executable_in_workspace(&temp_pkg_id, &repo.push(".rust"))
== repo.push_many([~".rust", ~"bin", ~"test_pkg_version"]));
let dir = &repo.push_many([~".rust",
~"src",
~"mockgithub.com",
~"catamorphism",
~"test_pkg_version-0.3"]);
let dir = target_build_dir(&repo.push(".rust"))
.push_rel(&Path("src/mockgithub.com/catamorphism/test_pkg_version-0.3"));
debug2!("dir = {}", dir.to_str());
assert!(os::path_is_dir(&dir));
assert!(os::path_exists(&dir.push("version-0.3-file.txt")));
assert!(!os::path_exists(&dir.push("version-0.4-file.txt")));
}
@ -988,8 +1011,7 @@ fn no_rebuilding_dep() {
Fail(_) => fail2!("no_rebuilding_dep failed for some other reason")
}
let bar_date_2 = datestamp(&lib_output_file_name(&workspace,
"bar"));
let bar_date_2 = datestamp(&bar_lib);
assert_eq!(bar_date_1, bar_date_2);
}
@ -1713,13 +1735,11 @@ fn test_target_specific_install_dir() {
}
#[test]
#[ignore(reason = "See #7240")]
fn test_dependencies_terminate() {
// let a_id = PkgId::new("a");
let b_id = PkgId::new("b");
// let workspace = create_local_package_with_dep(&b_id, &a_id);
let workspace = create_local_package(&b_id);
let b_dir = workspace.push_many([~"src", ~"b-0.1"]);
// writeFile(&b_dir.push("lib.rs"), "extern mod a; pub fn f() {}");
let b_subdir = b_dir.push("test");
assert!(os::mkdir_recursive(&b_subdir, U_RWX));
writeFile(&b_subdir.push("test.rs"),
@ -1860,6 +1880,107 @@ fn test_no_rebuilding() {
}
}
#[test]
fn test_installed_read_only() {
// Install sources from a "remote" (actually a local github repo)
// Check that afterward, sources are read-only and installed under build/
let temp_pkg_id = git_repo_pkg();
let repo = init_git_repo(&temp_pkg_id.path);
debug2!("repo = {}", repo.to_str());
let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test-pkg"]);
debug2!("repo_subdir = {}", repo_subdir.to_str());
writeFile(&repo_subdir.push("main.rs"),
"fn main() { let _x = (); }");
writeFile(&repo_subdir.push("lib.rs"),
"pub fn f() { let _x = (); }");
add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files
command_line_test([~"install", temp_pkg_id.path.to_str()], &repo);
let ws = repo.push(".rust");
// Check that all files exist
debug2!("Checking for files in {}", ws.to_str());
let exec = target_executable_in_workspace(&temp_pkg_id, &ws);
debug2!("exec = {}", exec.to_str());
assert!(os::path_exists(&exec));
assert!(is_rwx(&exec));
let built_lib =
built_library_in_workspace(&temp_pkg_id,
&ws).expect("test_install_git: built lib should exist");
assert!(os::path_exists(&built_lib));
assert!(is_rwx(&built_lib));
// Make sure sources are (a) under "build" and (b) read-only
let src1 = target_build_dir(&ws).push_many([~"src", temp_pkg_id.to_str(), ~"main.rs"]);
let src2 = target_build_dir(&ws).push_many([~"src", temp_pkg_id.to_str(), ~"lib.rs"]);
assert!(os::path_exists(&src1));
assert!(os::path_exists(&src2));
assert!(is_read_only(&src1));
assert!(is_read_only(&src2));
}
#[test]
fn test_installed_local_changes() {
let temp_pkg_id = git_repo_pkg();
let repo = init_git_repo(&temp_pkg_id.path);
debug2!("repo = {}", repo.to_str());
let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test-pkg"]);
debug2!("repo_subdir = {}", repo_subdir.to_str());
assert!(os::mkdir_recursive(&repo.push_many([".rust", "src"]), U_RWX));
writeFile(&repo_subdir.push("main.rs"),
"fn main() { let _x = (); }");
writeFile(&repo_subdir.push("lib.rs"),
"pub fn f() { let _x = (); }");
add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files
command_line_test([~"install", temp_pkg_id.path.to_str()], &repo);
// We installed the dependency.
// Now start a new workspace and clone it into it
let hacking_workspace = mk_emptier_workspace("hacking_workspace");
let target_dir = hacking_workspace.push_many([~"src",
~"mockgithub.com",
~"catamorphism",
~"test-pkg-0.1"]);
debug2!("---- git clone {} {}", repo_subdir.to_str(), target_dir.to_str());
let c_res = safe_git_clone(&repo_subdir, &NoVersion, &target_dir);
match c_res {
DirToUse(_) => fail2!("test_installed_local_changes failed"),
CheckedOutSources => ()
};
// Make a local change to it
writeFile(&target_dir.push("lib.rs"),
"pub fn g() { let _x = (); }");
// Finally, make *another* package that uses it
let importer_pkg_id = fake_pkg();
let main_subdir = create_local_package_in(&importer_pkg_id, &hacking_workspace);
writeFile(&main_subdir.push("main.rs"),
"extern mod test = \"mockgithub.com/catamorphism/test-pkg\"; \
use test::g;
fn main() { g(); }");
// And make sure we can build it
command_line_test([~"build", importer_pkg_id.path.to_str()], &hacking_workspace);
}
#[test]
fn test_7402() {
let dir = create_local_package(&PkgId::new("foo"));
let dest_workspace = mkdtemp(&os::tmpdir(), "more_rust").expect("test_7402");
let rust_path = Some(~[(~"RUST_PATH",
format!("{}:{}", dest_workspace.to_str(), dir.to_str()))]);
let cwd = os::getcwd();
command_line_test_with_env([~"install", ~"foo"], &cwd, rust_path);
assert_executable_exists(&dest_workspace, "foo");
}
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IXUSR};
@ -1869,25 +1990,3 @@ fn is_executable(p: &Path) -> bool {
Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint
}
}
#[cfg(target_os = "win32")]
fn chmod_read_only(p: &Path) -> bool {
#[fixed_stack_segment];
unsafe {
do p.to_str().with_c_str |src_buf| {
libc::chmod(src_buf, libc::consts::os::posix88::S_IRUSR as c_int) == 0 as libc::c_int
}
}
}
#[cfg(not(target_os = "win32"))]
fn chmod_read_only(p: &Path) -> bool {
#[fixed_stack_segment];
unsafe {
do p.to_str().with_c_str |src_buf| {
libc::chmod(src_buf,
libc::consts::os::posix88::S_IRUSR as libc::mode_t) == 0
as libc::c_int
}
}
}

View File

@ -27,8 +27,8 @@ use context::{in_target, StopBefore, Link, Assemble, BuildContext};
use package_id::PkgId;
use package_source::PkgSrc;
use workspace::pkg_parent_workspaces;
use path_util::{installed_library_in_workspace, U_RWX, system_library, target_build_dir};
use path_util::default_workspace;
use path_util::{U_RWX, system_library, target_build_dir};
use path_util::{default_workspace, built_library_in_workspace};
pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
use workcache_support::{digest_file_with_date, digest_only_date};
@ -298,7 +298,7 @@ pub fn compile_input(context: &BuildContext,
crate);
// Discover the output
let discovered_output = if what == Lib {
installed_library_in_workspace(&pkg_id.path, workspace)
built_library_in_workspace(pkg_id, workspace) // Huh???
}
else {
result
@ -306,6 +306,7 @@ pub fn compile_input(context: &BuildContext,
debug2!("About to discover output {}", discovered_output.to_str());
for p in discovered_output.iter() {
if os::path_exists(p) {
debug2!("4. discovering output {}", p.to_str());
exec.discover_output("binary", p.to_str(), digest_only_date(p));
}
// Nothing to do if it doesn't exist -- that could happen if we had the
@ -443,7 +444,13 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
let dest_workspace = if workspaces.is_empty() {
default_workspace()
} else { workspaces[0] };
let pkg_src = PkgSrc::new(dest_workspace,
// In this case, the source and destination workspaces are the same:
// Either it's a remote package, so the local sources don't exist
// and the `PkgSrc` constructor will detect that;
// or else it's already in a workspace and we'll build into that
// workspace
let pkg_src = PkgSrc::new(dest_workspace.clone(),
dest_workspace,
// Use the rust_path_hack to search for dependencies iff
// we were already using it
self.context.context.use_rust_path_hack,
@ -453,14 +460,18 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
debug2!("Installed {}, returned {:?} dependencies and \
{:?} transitive dependencies",
lib_name, outputs_disc.len(), inputs_disc.len());
debug2!("discovered outputs = {:?} discovered_inputs = {:?}",
outputs_disc, inputs_disc);
// It must have installed *something*...
assert!(!outputs_disc.is_empty());
let target_workspace = outputs_disc[0].pop();
for dep in outputs_disc.iter() {
debug2!("Discovering a binary input: {}", dep.to_str());
self.exec.discover_input("binary",
dep.to_str(),
digest_only_date(dep));
// Also, add an additional search path
debug2!("Installed {} into {}", dep.to_str(), dep.pop().to_str());
(self.save)(dep.pop());
}
for &(ref what, ref dep) in inputs_disc.iter() {
if *what == ~"file" {
@ -477,9 +488,6 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
fail2!("Bad kind: {}", *what);
}
}
// Also, add an additional search path
debug2!("Installed {} into {}", lib_name, target_workspace.to_str());
(self.save)(target_workspace);
}
}
}

View File

@ -13,12 +13,11 @@
use std::{os,util};
use std::path::Path;
use context::Context;
use path_util::{workspace_contains_package_id, find_dir_using_rust_path_hack};
use path_util::{workspace_contains_package_id, find_dir_using_rust_path_hack, default_workspace};
use path_util::rust_path;
use util::option_to_vec;
use package_id::PkgId;
use path_util::rust_path;
pub fn each_pkg_parent_workspace(cx: &Context, pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
// Using the RUST_PATH, find workspaces that contain
// this package ID
@ -75,3 +74,14 @@ pub fn cwd_to_workspace() -> Option<(Path, PkgId)> {
}
None
}
/// If `workspace` is the same as `cwd`, and use_rust_path_hack is false,
/// return `workspace`; otherwise, return the first workspace in the RUST_PATH.
pub fn determine_destination(cwd: Path, use_rust_path_hack: bool, workspace: &Path) -> Path {
if workspace == &cwd && !use_rust_path_hack {
workspace.clone()
}
else {
default_workspace()
}
}