/// Convenience functions intended for calling from pkg.rs
fn default_ctxt(p: @Path) -> Ctx {
- Ctx { sysroot_opt: Some(p), json: false, dep_cache: @mut HashMap::new() }
+ Ctx {
+ use_rust_path_hack: false,
+ sysroot_opt: Some(p),
+ json: false,
+ dep_cache: @mut HashMap::new()
+ }
}
pub fn build_lib(sysroot: @Path, root: Path, name: ~str, version: Version,
use std::os;
pub struct Ctx {
+ // If use_rust_path_hack is true, rustpkg searches for sources
+ // in *package* directories that are in the RUST_PATH (for example,
+ // FOO/src/bar-0.1 instead of FOO). The flag doesn't affect where
+ // rustpkg stores build artifacts.
+ use_rust_path_hack: bool,
// Sysroot -- if this is None, uses rustc filesearch's
// idea of the default
sysroot_opt: Option<@Path>,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+extern mod extra;
+
use target::*;
use package_id::PkgId;
use std::path::Path;
use crate::Crate;
use messages::*;
use source_control::{git_clone, git_clone_general};
-use path_util::pkgid_src_in_workspace;
+use path_util::{pkgid_src_in_workspace, find_dir_using_rust_path_hack, default_workspace};
use util::compile_crate;
+use workspace::is_workspace;
// An enumeration of the unpacked source of a package workspace.
// This contains a list of files found in the source workspace.
}
- fn check_dir(&self) -> Path {
+ fn check_dir(&self, cx: &Ctx) -> Path {
use conditions::nonexistent_package::cond;
debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str());
let dir = match path {
Some(d) => (*d).clone(),
- None => match self.fetch_git() {
- Some(d) => d,
- None => cond.raise((self.id.clone(), ~"supplied path for package dir does not \
- exist, and couldn't interpret it as a URL fragment"))
+ None => {
+ match self.fetch_git() {
+ Some(d) => d,
+ None => {
+ match find_dir_using_rust_path_hack(cx, &self.id) {
+ Some(d) => d,
+ None => cond.raise((self.id.clone(),
+ ~"supplied path for package dir does not \
+ exist, and couldn't interpret it as a URL fragment"))
+ }
+ }
+ }
}
};
+ debug!("For package id %s, returning %s", self.id.to_str(), dir.to_str());
if !os::path_is_dir(&dir) {
cond.raise((self.id.clone(), ~"supplied path for package dir is a \
non-directory"));
/// refers to a git repo on the local version, also check it out.
/// (right now we only support git)
pub fn fetch_git(&self) -> Option<Path> {
+ use conditions::failed_to_create_temp_dir::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")
+ };
let mut local = self.root.push("src");
local = local.push(self.id.to_str());
- // Git can't clone into a non-empty directory
- os::remove_dir_recursive(&local);
debug!("Checking whether %s exists locally. Cwd = %s, does it? %?",
self.id.path.to_str(),
if os::path_exists(&self.id.path) {
debug!("%s exists locally! Cloning it into %s",
self.id.path.to_str(), local.to_str());
+ // Ok to use local here; we know it will succeed
git_clone(&self.id.path, &local, &self.id.version);
return Some(local);
}
+ if (self.id.path.clone()).components().len() < 2 {
+ // If a non-URL, don't bother trying to fetch
+ return None;
+ }
+
let url = fmt!("https://%s", self.id.path.to_str());
note(fmt!("Fetching package: git clone %s %s [version=%s]",
- url, local.to_str(), self.id.version.to_str()));
- if git_clone_general(url, &local, &self.id.version) {
- Some(local)
+ url, clone_target.to_str(), self.id.version.to_str()));
+
+ if git_clone_general(url, &clone_target, &self.id.version) {
+ // since the operation succeeded, move clone_target to local
+ if !os::rename_file(&clone_target, &local) {
+ None
+ }
+ else {
+ Some(local)
+ }
}
else {
None
/// Infers crates to build. Called only in the case where there
/// is no custom build logic
- pub fn find_crates(&mut self) {
+ pub fn find_crates(&mut self, cx: &Ctx) {
use conditions::missing_pkg_files::cond;
- let dir = self.check_dir();
+ let dir = self.check_dir(cx);
debug!("Called check_dir, I'm in %s", dir.to_str());
let prefix = dir.components.len();
debug!("Matching against %?", self.id.short_name);
fn build_crates(&self,
ctx: &Ctx,
src_dir: &Path,
+ destination_dir: &Path,
crates: &[Crate],
cfgs: &[~str],
what: OutputType) {
let result = compile_crate(ctx,
&self.id,
path,
- // compile_crate wants the workspace
- &self.root,
+ // compile_crate wants the destination workspace
+ destination_dir,
crate.flags,
crate.cfgs + cfgs,
false,
}
}
- pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) {
- let dir = self.check_dir();
- debug!("Building libs in %s", dir.to_str());
- self.build_crates(ctx, &dir, self.libs, cfgs, Lib);
+ pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) -> Path {
+ 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.root) {
+ debug!("%s is indeed a workspace", self.root.to_str());
+ self.root.clone()
+ }
+ else {
+ // It would be nice to have only one place in the code that checks
+ // for the use_rust_path_hack flag...
+ if ctx.use_rust_path_hack {
+ let rs = default_workspace();
+ debug!("Using hack: %s", rs.to_str());
+ rs
+ }
+ else {
+ cond.raise(fmt!("Package root %s is not a workspace; pass in --rust_path_hack \
+ if you want to treat it as a package source", self.root.to_str()))
+ }
+ };
+
+ let dir = self.check_dir(ctx);
+ debug!("Building libs in %s, destination = %s", dir.to_str(),
+ destination_workspace.to_str());
+ self.build_crates(ctx, &dir, &destination_workspace, self.libs, cfgs, Lib);
debug!("Building mains");
- self.build_crates(ctx, &dir, self.mains, cfgs, Main);
+ self.build_crates(ctx, &dir, &destination_workspace, self.mains, cfgs, Main);
debug!("Building tests");
- self.build_crates(ctx, &dir, self.tests, cfgs, Test);
+ self.build_crates(ctx, &dir, &destination_workspace, self.tests, cfgs, Test);
debug!("Building benches");
- self.build_crates(ctx, &dir, self.benchs, cfgs, Bench);
+ self.build_crates(ctx, &dir, &destination_workspace, self.benchs, cfgs, Bench);
+ destination_workspace
}
}
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
pub use version::{Version, NoVersion, split_version_general, try_parsing_version};
pub use rustc::metadata::filesearch::rust_path;
+use context::Ctx;
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use std::os::mkdir_recursive;
pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
debug!("Checking in src dir of %s for %s",
workspace.to_str(), pkgid.to_str());
+ workspace_contains_package_id_(pkgid, workspace, |p| { p.push("src") }).is_some()
+}
- let src_dir = workspace.push("src");
+pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
+// Returns the directory it was actually found in
+ workspace_to_src_dir: &fn(&Path) -> Path) -> Option<Path> {
+ let src_dir = workspace_to_src_dir(workspace);
- let mut found = false;
+ let mut found = None;
do os::walk_dir(&src_dir) |p| {
debug!("=> p = %s", p.to_str());
- let was_found = os::path_is_dir(p) && {
+ if os::path_is_dir(p) {
debug!("p = %s, path = %s [%s]", p.to_str(), pkgid.path.to_str(),
src_dir.push_rel(&pkgid.path).to_str());
- *p == src_dir.push_rel(&pkgid.path) || {
+ if *p == src_dir.push_rel(&pkgid.path) || {
let pf = p.filename();
do pf.iter().any |pf| {
let g = pf.to_str();
}
}
}
+ } {
+ found = Some(p.clone());
}
- };
- if was_found {
- found = true
- }
+ };
true
};
- debug!(if found { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
+ debug!(if found.is_some() { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
else { fmt!("Didn't find %s in %s", pkgid.to_str(), workspace.to_str()) });
found
}
Some(result)
}
else {
- // This is not an error, but it's worth logging it
- error!(fmt!("built_executable_in_workspace: %s does not exist", result.to_str()));
+ debug!("built_executable_in_workspace: %s does not exist", result.to_str());
None
}
}
/// Does the actual searching stuff
pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option<Path> {
- // NOTE: this could break once we're handling multiple versions better... want a test for it
+ // This could break once we're handling multiple versions better -- I should add a test for it
library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib", &NoVersion)
}
} // for
if result_filename.is_none() {
- warn(fmt!("library_in_workspace didn't find a library in %s for %s",
- dir_to_search.to_str(), short_name));
+ debug!("warning: library_in_workspace didn't find a library in %s for %s",
+ dir_to_search.to_str(), short_name);
}
// Return the filename that matches, which we now know exists
}
}
+
+fn dir_has_file(dir: &Path, file: &str) -> bool {
+ assert!(dir.is_absolute());
+ os::path_exists(&dir.push(file))
+}
+
+pub fn find_dir_using_rust_path_hack(cx: &Ctx, p: &PkgId) -> Option<Path> {
+ if !cx.use_rust_path_hack {
+ return None;
+ }
+ let rp = rust_path();
+ for dir in rp.iter() {
+ debug!("In find_dir_using_rust_path_hack: checking dir %s", dir.to_str());
+ if dir_has_file(dir, "lib.rs") || dir_has_file(dir, "main.rs")
+ || dir_has_file(dir, "test.rs") || dir_has_file(dir, "bench.rs") {
+ debug!("Did find id %s in dir %s", p.to_str(), dir.to_str());
+ return Some(dir.clone());
+ }
+ debug!("Didn't find id %s in dir %s", p.to_str(), dir.to_str())
+ }
+ None
+}
extern mod rustc;
extern mod syntax;
-use std::result;
-use std::io;
-use std::os;
-use std::run;
-use std::str;
-
+use std::{io, os, result, run, str};
pub use std::path::Path;
use std::hashmap::HashMap;
pub trait CtxMethods {
fn run(&self, cmd: &str, args: ~[~str]);
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
- fn build(&self, workspace: &Path, pkgid: &PkgId);
+ /// Returns the destination workspace
+ fn build(&self, workspace: &Path, pkgid: &PkgId) -> Path;
fn clean(&self, workspace: &Path, id: &PkgId);
fn info(&self);
fn install(&self, workspace: &Path, id: &PkgId);
"build" => {
if args.len() < 1 {
match cwd_to_workspace() {
- None => { usage::build(); return }
- Some((ws, pkgid)) => self.build(&ws, &pkgid)
+ None if self.use_rust_path_hack => {
+ let cwd = os::getcwd();
+ self.build(&cwd, &PkgId::new(cwd.components[cwd.components.len() - 1]));
+ }
+ None => { usage::build(); return; }
+ Some((ws, pkgid)) => { self.build(&ws, &pkgid); }
}
}
else {
// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(args[0].clone());
- do each_pkg_parent_workspace(&pkgid) |workspace| {
+ do each_pkg_parent_workspace(self, &pkgid) |workspace| {
debug!("found pkg %s in workspace %s, trying to build",
pkgid.to_str(), workspace.to_str());
self.build(workspace, &pkgid);
"install" => {
if args.len() < 1 {
match cwd_to_workspace() {
- None => { usage::install(); return }
- Some((ws, pkgid)) => self.install(&ws, &pkgid)
- }
+ None if self.use_rust_path_hack => {
+ let cwd = os::getcwd();
+ self.install(&cwd,
+ &PkgId::new(cwd.components[cwd.components.len() - 1]));
+ }
+ None => { usage::install(); return; }
+ Some((ws, pkgid)) => self.install(&ws, &pkgid),
+ }
}
else {
// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(args[0]);
- let workspaces = pkg_parent_workspaces(&pkgid);
+ let workspaces = pkg_parent_workspaces(self, &pkgid);
debug!("package ID = %s, found it in %? workspaces",
pkgid.to_str(), workspaces.len());
if workspaces.is_empty() {
self.install(&rp[0], &pkgid);
}
else {
- do each_pkg_parent_workspace(&pkgid) |workspace| {
+ do each_pkg_parent_workspace(self, &pkgid) |workspace| {
self.install(workspace, &pkgid);
true
};
else {
let rp = rust_path();
assert!(!rp.is_empty());
- do each_pkg_parent_workspace(&pkgid) |workspace| {
+ do each_pkg_parent_workspace(self, &pkgid) |workspace| {
path_util::uninstall_package_from(workspace, &pkgid);
note(fmt!("Uninstalled package %s (was installed in %s)",
pkgid.to_str(), workspace.to_str()));
fail!("`do` not yet implemented");
}
- fn build(&self, workspace: &Path, pkgid: &PkgId) {
+ /// Returns the destination workspace
+ /// In the case of a custom build, we don't know, so we just return the source workspace
+ fn build(&self, workspace: &Path, pkgid: &PkgId) -> Path {
debug!("build: workspace = %s (in Rust path? %? is git dir? %? \
pkgid = %s", workspace.to_str(),
in_rust_path(workspace), is_git_dir(&workspace.push_rel(&pkgid.path)),
// the build already. Otherwise...
if !custom {
// Find crates inside the workspace
- src.find_crates();
+ src.find_crates(self);
// Build it!
- src.build(self, cfgs);
+ src.build(self, cfgs)
+ }
+ else {
+ // Just return the source workspace
+ workspace.clone()
}
}
}
fn install(&self, workspace: &Path, id: &PkgId) {
- // FIXME #7402: Use RUST_PATH to determine target dir
// Also should use workcache to not build if not necessary.
- self.build(workspace, id);
- debug!("install: workspace = %s, id = %s", workspace.to_str(),
- id.to_str());
- self.install_no_build(workspace, id);
+ let destination_workspace = self.build(workspace, id);
+ // 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.
+ debug!("install: destination workspace = %s, id = %s",
+ destination_workspace.to_str(), id.to_str());
+ self.install_no_build(&destination_workspace, id);
}
let opts = ~[getopts::optflag("h"), getopts::optflag("help"),
getopts::optflag("j"), getopts::optflag("json"),
getopts::optmulti("c"), getopts::optmulti("cfg"),
- getopts::optflag("v"), getopts::optflag("version")];
+ getopts::optflag("v"), getopts::optflag("version"),
+ getopts::optflag("r"), getopts::optflag("rust-path-hack")];
let matches = &match getopts::getopts(args, opts) {
result::Ok(m) => m,
result::Err(f) => {
return;
}
+ let use_rust_path_hack = getopts::opt_present(matches, "r") ||
+ getopts::opt_present(matches, "rust-path-hack");
+
let mut args = matches.free.clone();
args.shift();
return usage::general();
}
- let cmd = args.shift();
-
- if !util::is_cmd(cmd) {
- return usage::general();
- } else if help {
- return match cmd {
- ~"build" => usage::build(),
- ~"clean" => usage::clean(),
- ~"do" => usage::do_cmd(),
- ~"info" => usage::info(),
- ~"install" => usage::install(),
- ~"list" => usage::list(),
- ~"prefer" => usage::prefer(),
- ~"test" => usage::test(),
- ~"uninstall" => usage::uninstall(),
- ~"unprefer" => usage::unprefer(),
- _ => usage::general()
- };
+ let mut cmd_opt = None;
+ for a in args.iter() {
+ if util::is_cmd(*a) {
+ cmd_opt = Some(a);
+ break;
+ }
}
+ let cmd = match cmd_opt {
+ None => return usage::general(),
+ Some(cmd) => if help {
+ return match *cmd {
+ ~"build" => usage::build(),
+ ~"clean" => usage::clean(),
+ ~"do" => usage::do_cmd(),
+ ~"info" => usage::info(),
+ ~"install" => usage::install(),
+ ~"list" => usage::list(),
+ ~"prefer" => usage::prefer(),
+ ~"test" => usage::test(),
+ ~"uninstall" => usage::uninstall(),
+ ~"unprefer" => usage::unprefer(),
+ _ => usage::general()
+ };
+ }
+ else {
+ cmd
+ }
+ };
+ // Pop off all flags, plus the command
+ let remaining_args = args.iter().skip_while(|s| !util::is_cmd(**s));
+ // I had to add this type annotation to get the code to typecheck
+ let mut remaining_args: ~[~str] = remaining_args.map(|s| (*s).clone()).collect();
+ remaining_args.shift();
let sroot = Some(@filesearch::get_or_default_sysroot());
debug!("Using sysroot: %?", sroot);
Ctx {
+ use_rust_path_hack: use_rust_path_hack,
sysroot_opt: sroot, // Currently, only tests override this
json: json,
dep_cache: @mut HashMap::new()
- }.run(cmd, args);
+ }.run(*cmd, remaining_args)
}
/**
fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
Ctx {
+ use_rust_path_hack: false,
sysroot_opt: sysroot_opt,
json: false,
dep_cache: @mut HashMap::new()
out.write_line(contents);
}
-fn mk_empty_workspace(short_name: &Path, version: &Version) -> Path {
- let workspace_dir = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
+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);
workspace_dir
}
fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path {
let package_dir = mk_empty_workspace(short_name,
- version).push("src").push(fmt!("%s-%s",
+ version, "temp_workspace").push("src").push(fmt!("%s-%s",
short_name.to_str(),
version.to_str()));
}
-fn assert_lib_exists(repo: &Path, short_name: &str, _v: Version) { // ??? version?
+fn assert_lib_exists(repo: &Path, short_name: &str, v: Version) {
+ assert!(lib_exists(repo, short_name, v));
+}
+
+fn lib_exists(repo: &Path, short_name: &str, _v: Version) -> bool { // ??? version?
debug!("assert_lib_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
let lib = installed_library_in_workspace(short_name, repo);
debug!("assert_lib_exists: checking whether %? exists", lib);
- assert!(lib.is_some());
- let libname = lib.get_ref();
- assert!(os::path_exists(libname));
- assert!(is_rwx(libname));
+ lib.is_some() && {
+ let libname = lib.get_ref();
+ os::path_exists(libname) && is_rwx(libname)
+ }
}
fn assert_executable_exists(repo: &Path, short_name: &str) {
+ assert!(executable_exists(repo, short_name));
+}
+
+fn executable_exists(repo: &Path, short_name: &str) -> bool {
debug!("assert_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
let exec = target_executable_in_workspace(&PkgId::new(short_name), repo);
- assert!(os::path_exists(&exec));
- assert!(is_rwx(&exec));
+ os::path_exists(&exec) && is_rwx(&exec)
}
fn assert_built_executable_exists(repo: &Path, short_name: &str) {
+ assert!(built_executable_exists(repo, short_name));
+}
+
+fn built_executable_exists(repo: &Path, short_name: &str) -> bool {
debug!("assert_built_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
- let exec = built_executable_in_workspace(&PkgId::new(short_name),
- repo).expect("assert_built_executable_exists failed");
- assert!(os::path_exists(&exec));
- assert!(is_rwx(&exec));
+ let exec = built_executable_in_workspace(&PkgId::new(short_name), repo);
+ exec.is_some() && {
+ let execname = exec.get_ref();
+ os::path_exists(execname) && is_rwx(execname)
+ }
+}
+
+fn assert_built_library_exists(repo: &Path, short_name: &str) {
+ assert!(built_library_exists(repo, short_name));
+}
+
+fn built_library_exists(repo: &Path, short_name: &str) -> bool {
+ debug!("assert_built_library_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
+ let lib = built_library_in_workspace(&PkgId::new(short_name), repo);
+ lib.is_some() && {
+ let libname = lib.get_ref();
+ os::path_exists(libname) && is_rwx(libname)
+ }
}
fn command_line_test_output(args: &[~str]) -> ~[~str] {
fn test_install_invalid() {
use conditions::nonexistent_package::cond;
use cond1 = conditions::missing_pkg_files::cond;
+ use cond2 = conditions::not_a_workspace::cond;
let ctxt = fake_ctxt(None);
let pkgid = fake_pkg();
let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
let mut error_occurred = false;
let mut error1_occurred = false;
+ let mut error2_occurred = false;
do cond1.trap(|_| {
error1_occurred = true;
}).inside {
error_occurred = true;
temp_workspace.clone()
}).inside {
- ctxt.install(&temp_workspace, &pkgid);
+ do cond2.trap(|_| {
+ error2_occurred = true;
+ temp_workspace.clone()
+ }).inside {
+ ctxt.install(&temp_workspace, &pkgid);
+ }
}
}
- assert!(error_occurred && error1_occurred);
+ assert!(error_occurred && error1_occurred && error2_occurred);
}
// Tests above should (maybe) be converted to shell out to rustpkg, too
command_line_test_with_env([~"install", ~"bar"], &c_loc, env);
}
+fn rust_path_hack_test(hack_flag: bool) {
+/*
+ Make a workspace containing a pkg foo [A]
+ Make a second, empty workspace [B]
+ Set RUST_PATH to B:A
+ rustpkg install foo
+ make sure built files for foo are in B
+ make sure nothing gets built into A or A/../build[lib,bin]
+*/
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH",
+ fmt!("%s:%s", dest_workspace.to_str(), workspace.push_many(["src", "foo-0.1"]).to_str()))]);
+ debug!("declare -x RUST_PATH=%s:%s",
+ dest_workspace.to_str(), workspace.push_many(["src", "foo-0.1"]).to_str());
+ command_line_test_with_env(~[~"install"] + if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } +
+ ~[~"foo"], &dest_workspace, rust_path);
+ assert_lib_exists(&dest_workspace, "foo", NoVersion);
+ assert_executable_exists(&dest_workspace, "foo");
+ assert_built_library_exists(&dest_workspace, "foo");
+ assert_built_executable_exists(&dest_workspace, "foo");
+ assert!(!lib_exists(&workspace, "foo", NoVersion));
+ assert!(!executable_exists(&workspace, "foo"));
+ assert!(!built_library_exists(&workspace, "foo"));
+ assert!(!built_executable_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_rust_path_can_contain_package_dirs_with_flag() {
+/*
+ Test that the temporary hack added for bootstrapping Servo builds
+ works. That is: if you add $FOO/src/some_pkg to the RUST_PATH,
+ it will find the sources in some_pkg, build them, and install them
+ into the first entry in the RUST_PATH.
+
+ When the hack is removed, we should change this to a should_fail test.
+*/
+ rust_path_hack_test(true);
+}
+
+#[test]
+#[should_fail]
+fn test_rust_path_can_contain_package_dirs_without_flag() {
+ rust_path_hack_test(false);
+}
+
+#[test]
+fn rust_path_hack_cwd() {
+ // Same as rust_path_hack_test, but the CWD is the dir to build out of
+ let cwd = mkdtemp(&os::tmpdir(), "pkg_files").expect("rust_path_hack_cwd");
+ writeFile(&cwd.push("lib.rs"), "pub fn f() { }");
+
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
+ debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
+ command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path);
+ debug!("Checking that foo exists in %s", dest_workspace.to_str());
+ assert_lib_exists(&dest_workspace, "foo", NoVersion);
+ assert_built_library_exists(&dest_workspace, "foo");
+ assert!(!lib_exists(&cwd, "foo", NoVersion));
+ assert!(!built_library_exists(&cwd, "foo"));
+}
+
+#[test]
+fn rust_path_hack_multi_path() {
+ // Same as rust_path_hack_test, but with a more complex package ID
+ let cwd = mkdtemp(&os::tmpdir(), "pkg_files").expect("rust_path_hack_cwd");
+ let subdir = cwd.push_many([~"foo", ~"bar", ~"quux"]);
+ assert!(os::mkdir_recursive(&subdir, U_RWX));
+ writeFile(&subdir.push("lib.rs"), "pub fn f() { }");
+ let name = ~"foo/bar/quux";
+
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
+ debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
+ command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path);
+ debug!("Checking that %s exists in %s", name, dest_workspace.to_str());
+ assert_lib_exists(&dest_workspace, "quux", NoVersion);
+ assert_built_library_exists(&dest_workspace, name);
+ assert!(!lib_exists(&subdir, "quux", NoVersion));
+ assert!(!built_library_exists(&subdir, name));
+}
+
+#[test]
+fn rust_path_hack_install_no_arg() {
+ // Same as rust_path_hack_cwd, but making rustpkg infer the pkg id
+ let cwd = mkdtemp(&os::tmpdir(), "pkg_files").expect("rust_path_hack_install_no_arg");
+ let source_dir = cwd.push("foo");
+ assert!(make_dir_rwx(&source_dir));
+ writeFile(&source_dir.push("lib.rs"), "pub fn f() { }");
+
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
+ debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
+ command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path);
+ debug!("Checking that foo exists in %s", dest_workspace.to_str());
+ assert_lib_exists(&dest_workspace, "foo", NoVersion);
+ assert_built_library_exists(&dest_workspace, "foo");
+ assert!(!lib_exists(&source_dir, "foo", NoVersion));
+ assert!(!built_library_exists(&cwd, "foo"));
+}
+
+#[test]
+fn rust_path_hack_build_no_arg() {
+ // Same as rust_path_hack_install_no_arg, but building instead of installing
+ let cwd = mkdtemp(&os::tmpdir(), "pkg_files").expect("rust_path_hack_build_no_arg");
+ let source_dir = cwd.push("foo");
+ assert!(make_dir_rwx(&source_dir));
+ writeFile(&source_dir.push("lib.rs"), "pub fn f() { }");
+
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
+ debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
+ command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path);
+ debug!("Checking that foo exists in %s", dest_workspace.to_str());
+ assert_built_library_exists(&dest_workspace, "foo");
+ assert!(!built_library_exists(&source_dir, "foo"));
+}
+
+#[test]
+#[ignore (reason = "#7402 not yet implemented")]
+fn rust_path_install_target() {
+ let dir_for_path = mkdtemp(&os::tmpdir(),
+ "source_workspace").expect("rust_path_install_target failed");
+ let dir = mk_workspace(&dir_for_path, &Path("foo"), &NoVersion);
+ debug!("dir = %s", dir.to_str());
+ writeFile(&dir.push("main.rs"), "fn main() { let _x = (); }");
+ let dir_to_install_to = mkdtemp(&os::tmpdir(),
+ "dest_workspace").expect("rust_path_install_target failed");
+ let dir = dir.pop().pop();
+
+ let rust_path = Some(~[(~"RUST_PATH", fmt!("%s:%s", dir_to_install_to.to_str(),
+ dir.to_str()))]);
+ let cwd = os::getcwd();
+
+ debug!("RUST_PATH=%s:%s", dir_to_install_to.to_str(), dir.to_str());
+ command_line_test_with_env([~"install", ~"foo"],
+ &cwd,
+ rust_path);
+
+ assert_executable_exists(&dir_to_install_to, "foo");
+
+}
+
+
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IXUSR};
}
+pub fn option_to_vec<T>(x: Option<T>) -> ~[T] {
+ match x {
+ Some(y) => ~[y],
+ None => ~[]
+ }
+}
+
// tjc: cheesy
fn debug_flags() -> ~[~str] { ~[] }
// static DEBUG_FLAGS: ~[~str] = ~[~"-Z", ~"time-passes"];
use std::{os,util};
use std::path::Path;
-use path_util::workspace_contains_package_id;
+use context::Ctx;
+use path_util::{workspace_contains_package_id, find_dir_using_rust_path_hack};
+use util::option_to_vec;
use package_id::PkgId;
use path_util::rust_path;
-pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
+pub fn each_pkg_parent_workspace(cx: &Ctx, pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
// Using the RUST_PATH, find workspaces that contain
// this package ID
- let workspaces = pkg_parent_workspaces(pkgid);
+ let workspaces = pkg_parent_workspaces(cx, pkgid);
if workspaces.is_empty() {
// tjc: make this a condition
fail!("Package %s not found in any of \
return true;
}
-pub fn pkg_parent_workspaces(pkgid: &PkgId) -> ~[Path] {
- rust_path().move_iter()
+pub fn pkg_parent_workspaces(cx: &Ctx, pkgid: &PkgId) -> ~[Path] {
+ let rs: ~[Path] = rust_path().move_iter()
.filter(|ws| workspace_contains_package_id(pkgid, ws))
- .collect()
+ .collect();
+ if cx.use_rust_path_hack {
+ rs + option_to_vec(find_dir_using_rust_path_hack(cx, pkgid))
+ }
+ else {
+ rs
+ }
+}
+
+pub fn is_workspace(p: &Path) -> bool {
+ os::path_is_dir(&p.push("src"))
}
/// Construct a workspace and package-ID name based on the current directory.