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:
parent
8b8a41a287
commit
8854b78b55
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -50,3 +50,7 @@ condition! {
|
||||
condition! {
|
||||
pub failed_to_create_temp_dir: (~str) -> Path;
|
||||
}
|
||||
|
||||
condition! {
|
||||
pub git_checkout_failed: (~str, Path) -> ();
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user