1
Fork 0

rustpkg: Implement URL-like package IDs

This patch implements package IDs like
github.com/catamorphism/test-pkg.

To support such package IDs, I changed the PkgId struct to contain
a LocalPath and a RemotePath field, where the RemotePath reflects
the actual URL and the LocalPath reflects the file name of the cached
copy. Right now, the only difference is that the local path doesn't
contain dashes, but this will change when we implement #6407.

Also, PkgIds now have a short_name field -- though the short name
can be derived from the LocalPath, I thought it was cleaner not to
call option::get() wantonly.
This commit is contained in:
Tim Chevalier 2013-05-10 19:00:51 -07:00
parent c30414f980
commit c3875e8c70
6 changed files with 223 additions and 208 deletions

View file

@ -10,12 +10,10 @@
// rustpkg utilities having to do with paths and directories
use util::PkgId;
pub use util::{PkgId, RemotePath, LocalPath};
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use core::os::mkdir_recursive;
#[deriving(Eq)]
pub enum OutputType { Main, Lib, Bench, Test }
pub use util::{normalize, OutputType, Main, Lib, Bench, Test};
/// Returns the value of RUST_PATH, as a list
/// of Paths. In general this should be read from the
@ -31,32 +29,14 @@ pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
/// succeeded.
pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) }
/// Replace all occurrences of '-' in the stem part of path with '_'
/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux
/// as the same name
pub fn normalize(p: ~Path) -> ~Path {
match p.filestem() {
None => p,
Some(st) => {
let replaced = str::replace(st, "-", "_");
if replaced != st {
~p.with_filestem(replaced)
}
else {
p
}
}
}
}
// n.b. So far this only handles local workspaces
// n.b. The next three functions ignore the package version right
// now. Should fix that.
/// True if there's a directory in <workspace> with
/// pkgid's short name
pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
let pkgpath = workspace.push("src").push(pkgid.path.to_str());
pub fn workspace_contains_package_id(pkgid: PkgId, workspace: &Path) -> bool {
let pkgpath = workspace.push("src").push(pkgid.local_path.to_str());
os::path_is_dir(&pkgpath)
}
@ -64,34 +44,58 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
/// Doesn't check that it exists.
pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
let result = workspace.push("src");
result.push(pkgid.path.to_str())
result.push(pkgid.local_path.to_str())
}
/// Figure out what the executable name for <pkgid> in <workspace>'s build
/// directory is, and if the file exists, return it.
pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
let mut result = workspace.push("build");
result = result.push_rel(&pkgid.path);
// should use a target-specific subdirectory
result = mk_output_path(Main, fmt!("%s-%s", pkgid.path.to_str(), pkgid.version.to_str()),
result);
result = mk_output_path(Main, pkgid, &result);
debug!("built_executable_in_workspace: checking whether %s exists",
result.to_str());
if os::path_exists(&result) {
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()));
None
}
}
/// Figure out what the test name for <pkgid> in <workspace>'s build
/// directory is, and if the file exists, return it.
pub fn built_test_in_workspace(pkgid: PkgId, workspace: &Path) -> Option<Path> {
output_in_workspace(pkgid, workspace, Test)
}
/// Figure out what the test name for <pkgid> in <workspace>'s build
/// directory is, and if the file exists, return it.
pub fn built_bench_in_workspace(pkgid: PkgId, workspace: &Path) -> Option<Path> {
output_in_workspace(pkgid, workspace, Bench)
}
fn output_in_workspace(pkgid: PkgId, workspace: &Path, what: OutputType) -> Option<Path> {
let mut result = workspace.push("build");
// should use a target-specific subdirectory
result = mk_output_path(what, pkgid, &result);
debug!("output_in_workspace: checking whether %s exists",
result.to_str());
if os::path_exists(&result) {
Some(result)
}
else {
error!(fmt!("output_in_workspace: %s does not exist", result.to_str()));
None
}
}
/// Figure out what the library name for <pkgid> in <workspace>'s build
/// directory is, and if the file exists, return it.
pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
let mut result = workspace.push("build");
result = result.push_rel(&pkgid.path);
// should use a target-specific subdirectory
result = mk_output_path(Lib, pkgid.path.to_str(), result);
pub fn built_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Option<Path> {
let result = mk_output_path(Lib, pkgid, &workspace.push("build"));
debug!("built_library_in_workspace: checking whether %s exists",
result.to_str());
@ -100,8 +104,7 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat
let dir_contents = os::list_dir(&result.pop());
debug!("dir has %? entries", dir_contents.len());
// n.b. This code assumes the pkgid's path only has one element
let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.path.to_str());
let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.short_name);
let lib_filetype = fmt!("%s%s", pkgid.version.to_str(), os::consts::DLL_SUFFIX);
debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype);
@ -173,13 +176,15 @@ pub fn target_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
/// Returns the test executable that would be installed for <pkgid>
/// in <workspace>
pub fn target_test_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
/// note that we *don't* install test executables, so this is just for unit testing
pub fn target_test_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
target_file_in_workspace(pkgid, workspace, Test)
}
/// Returns the bench executable that would be installed for <pkgid>
/// in <workspace>
pub fn target_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
/// note that we *don't* install bench executables, so this is just for unit testing
pub fn target_bench_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
target_file_in_workspace(pkgid, workspace, Bench)
}
@ -188,17 +193,14 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path,
use conditions::bad_path::cond;
let (subdir, create_dir) = match what {
Main => ("bin", true), Lib => ("lib", true), Test | Bench => ("build", false)
Lib => "lib", Main | Test | Bench => "bin"
};
let result = workspace.push(subdir);
if create_dir {
debug!("target_file_in_workspace: %s %?", result.to_str(), create_dir);
if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) {
cond.raise((copy result,
fmt!("I couldn't create the %s dir", subdir)));
cond.raise((result, fmt!("I couldn't create the %s dir", subdir)));
}
}
mk_output_path(what, pkgid.path.to_str(), result)
mk_output_path(what, pkgid, &result)
}
/// Return the directory for <pkgid>'s build artifacts in <workspace>.
@ -209,7 +211,7 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
let mut result = workspace.push("build");
// n.b. Should actually use a target-specific
// subdirectory of build/
result = result.push(normalize(~copy pkgid.path).to_str());
result = result.push_rel(&*pkgid.local_path);
if os::path_exists(&result) || os::mkdir_recursive(&result, u_rwx) {
result
}
@ -220,8 +222,15 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
/// Return the output file for a given directory name,
/// given whether we're building a library and whether we're building tests
pub fn mk_output_path(what: OutputType, short_name: ~str, dir: Path) -> Path {
match what {
pub fn mk_output_path(what: OutputType, pkg_id: PkgId, workspace: &Path) -> Path {
let short_name = pkg_id.short_name_with_version();
// Not local_path.dir_path()! For package foo/bar/blat/, we want
// the executable blat-0.5 to live under blat/
let dir = workspace.push_rel(&*pkg_id.local_path);
debug!("mk_output_path: short_name = %s, path = %s",
short_name, dir.to_str());
let output_path = match what {
// this code is duplicated from elsewhere; fix this
Lib => dir.push(os::dll_filename(short_name)),
_ => dir.push(fmt!("%s%s%s", short_name,
match what {
@ -230,5 +239,7 @@ pub fn mk_output_path(what: OutputType, short_name: ~str, dir: Path) -> Path {
_ => ""
}
os::EXE_SUFFIX))
}
};
debug!("mk_output_path: returning %s", output_path.to_str());
output_path
}

View file

@ -30,12 +30,10 @@ use rustc::metadata::filesearch;
use std::{getopts};
use syntax::{ast, diagnostic};
use util::*;
use path_util::normalize;
use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace};
use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace, u_rwx};
use path_util::{built_executable_in_workspace, built_library_in_workspace};
use path_util::{target_executable_in_workspace, target_library_in_workspace};
use workspace::pkg_parent_workspaces;
use rustc::driver::session::{lib_crate, bin_crate, crate_type};
use context::Ctx;
mod conditions;
@ -269,7 +267,7 @@ impl Ctx {
debug!("Destination dir = %s", build_dir.to_str());
// Create the package source
let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, pkgid);
let mut src = PkgSrc::new(workspace, &build_dir, &pkgid);
debug!("Package src = %?", src);
// Is there custom build logic? If so, use it
@ -337,6 +335,8 @@ impl Ctx {
// Should use RUST_PATH in the future.
// 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());
// Now copy stuff into the install dirs
let maybe_executable = built_executable_in_workspace(id, workspace);
@ -344,104 +344,29 @@ impl Ctx {
let target_exec = target_executable_in_workspace(id, workspace);
let target_lib = target_library_in_workspace(id, workspace);
debug!("target_exec = %s target_lib = %s \
maybe_executable = %? maybe_library = %?",
target_exec.to_str(), target_lib.to_str(),
maybe_executable, maybe_library);
for maybe_executable.each |exec| {
debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
if !os::copy_file(exec, &target_exec) {
cond.raise((copy *exec, copy target_exec));
if !(os::mkdir_recursive(&target_exec.dir_path(), u_rwx) &&
os::copy_file(exec, &target_exec)) {
cond.raise((*exec, target_exec));
}
}
for maybe_library.each |lib| {
debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str());
if !os::copy_file(lib, &target_lib) {
cond.raise((copy *lib, copy target_lib));
if !(os::mkdir_recursive(&target_lib.dir_path(), u_rwx) &&
os::copy_file(lib, &target_lib)) {
cond.raise((*lib, target_lib));
}
}
}
fn fetch(&self, _dir: &Path, _url: ~str, _target: Option<~str>) {
// stub
fail!("fetch not yet implemented");
}
fn fetch_curl(&self, dir: &Path, url: ~str) {
util::note(fmt!("fetching from %s using curl", url));
let tar = dir.dir_path().push(&dir.file_path().to_str() + ~".tar");
if run::program_output(~"curl", ~[~"-f", ~"-s",
~"-o", tar.to_str(),
url]).status != 0 {
util::error(~"fetching failed: downloading using curl failed");
fail!();
}
if run::program_output(~"tar", ~[~"-x", ~"--strip-components=1",
~"-C", dir.to_str(), ~"-f",
tar.to_str()]).status != 0 {
util::error(~"fetching failed: extracting using tar failed" +
~"(is it a valid tar archive?)");
fail!();
}
}
fn fetch_git(&self, dir: &Path, url: ~str, mut target: Option<~str>) {
util::note(fmt!("fetching from %s using git", url));
// Git can't clone into a non-empty directory
util::remove_dir_r(dir);
if run::program_output(~"git", ~[~"clone", url,
dir.to_str()]).status != 0 {
util::error(~"fetching failed: can't clone repository");
fail!();
}
if !target.is_none() {
let mut success = true;
do util::temp_change_dir(dir) {
success = run::program_output(~"git",
~[~"checkout",
target.swap_unwrap()]).status != 0
}
if !success {
util::error(~"fetching failed: can't checkout target");
fail!();
}
}
}
fn prefer(&self, id: ~str, vers: Option<~str>) {
let package = match util::get_pkg(id, vers) {
result::Ok(package) => package,
result::Err(err) => {
util::error(err);
fail!(); // Condition?
}
};
let name = package.id.path.to_str(); // ???
util::note(fmt!("preferring %s v%s", name, package.id.version.to_str()));
let bin_dir = util::root().push(~"bin");
for package.bins.each |&bin| {
let path = Path(bin);
let mut name = None;
for str::each_split_char(path.file_path().to_str(), '-') |s| {
name = Some(s.to_owned());
break;
}
let out = bin_dir.push(name.unwrap());
util::link_exe(&path, &out);
util::note(fmt!("linked %s", out.to_str()));
}
util::note(fmt!("preferred %s v%s", name, package.id.version.to_str()));
fn prefer(&self, _id: ~str, _vers: Option<~str>) {
fail!(~"prefer not yet implemented");
}
fn test(&self) {
@ -641,17 +566,19 @@ impl PkgSrc {
fn check_dir(&self) -> Path {
use conditions::nonexistent_package::cond;
debug!("Pushing onto root: %s | %s", self.id.path.to_str(),
debug!("Pushing onto root: %s | %s", self.id.to_str(),
self.root.to_str());
let dir = self.root.push_rel(&self.id.path).normalize();
let mut dir = self.root.push("src");
dir = dir.push(self.id.to_str()); // ?? Should this use the version number?
debug!("Checking dir: %s", dir.to_str());
// tjc: Rather than erroring out, need to try downloading the
// contents of the path to a local directory (#5679)
if !os::path_exists(&dir) {
cond.raise((copy self.id, ~"missing package dir"));
if !self.fetch_git() {
cond.raise((self.id, ~"supplied path for package dir does not \
exist, and couldn't interpret it as a URL fragment"));
}
}
if !os::path_is_dir(&dir) {
@ -662,6 +589,28 @@ impl PkgSrc {
dir
}
/// Try interpreting self's package id as a remote package, and try
/// fetching it and caching it in a local directory. If that didn't
/// work, return false.
/// (right now we only support git)
fn fetch_git(&self) -> bool {
let mut local = self.root.push("src");
local = local.push(self.id.to_str());
// Git can't clone into a non-empty directory
util::remove_dir_r(&local);
let url = fmt!("https://%s", self.id.remote_path.to_str());
util::note(fmt!("git clone %s %s", url, local.to_str()));
if run::program_output(~"git", ~[~"clone", url, local.to_str()]).status != 0 {
util::note(fmt!("fetching %s failed: can't clone repository", url));
return false;
}
true
}
// If a file named "pkg.rs" in the current directory exists,
// return the path for it. Otherwise, None
fn package_script_option(&self, cwd: &Path) -> Option<Path> {
@ -680,7 +629,7 @@ impl PkgSrc {
/// Requires that dashes in p have already been normalized to
/// underscores
fn stem_matches(&self, p: &Path) -> bool {
let self_id = normalize(~copy self.id.path).filestem();
let self_id = self.id.local_path.filestem();
if self_id == p.filestem() {
return true;
}
@ -715,7 +664,7 @@ impl PkgSrc {
let dir = self.check_dir();
let prefix = dir.components.len();
debug!("Matching against %?", self.id.path.filestem());
debug!("Matching against %?", self.id.local_path.filestem());
for os::walk_dir(&dir) |pth| {
match pth.filename() {
Some(~"lib.rs") => push_crate(&mut self.libs,
@ -752,8 +701,7 @@ impl PkgSrc {
src_dir: &Path,
crates: &[Crate],
cfgs: &[~str],
test: bool, crate_type: crate_type) {
what: OutputType) {
for crates.each |&crate| {
let path = &src_dir.push_rel(&crate.file).normalize();
util::note(fmt!("build_crates: compiling %s", path.to_str()));
@ -763,7 +711,7 @@ impl PkgSrc {
dst_dir,
crate.flags,
crate.cfgs + cfgs,
false, test, crate_type);
false, what);
if !result {
build_err::cond.raise(fmt!("build failure on %s",
path.to_str()));
@ -776,12 +724,12 @@ impl PkgSrc {
fn build(&self, dst_dir: &Path, cfgs: ~[~str], maybe_sysroot: Option<@Path>) {
let dir = self.check_dir();
debug!("Building libs");
self.build_crates(maybe_sysroot, dst_dir, &dir, self.libs, cfgs, false, lib_crate);
self.build_crates(maybe_sysroot, dst_dir, &dir, self.libs, cfgs, Lib);
debug!("Building mains");
self.build_crates(maybe_sysroot, dst_dir, &dir, self.mains, cfgs, false, bin_crate);
self.build_crates(maybe_sysroot, dst_dir, &dir, self.mains, cfgs, Main);
debug!("Building tests");
self.build_crates(maybe_sysroot, dst_dir, &dir, self.tests, cfgs, true, bin_crate);
self.build_crates(maybe_sysroot, dst_dir, &dir, self.tests, cfgs, Test);
debug!("Building benches");
self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, true, bin_crate);
self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, Bench);
}
}

View file

@ -17,7 +17,8 @@ use std::tempfile::mkdtemp;
use util::{PkgId, default_version};
use path_util::{target_executable_in_workspace, target_library_in_workspace,
target_test_in_workspace, target_bench_in_workspace,
make_dir_rwx, u_rwx};
make_dir_rwx, u_rwx, RemotePath, LocalPath, normalize,
built_bench_in_workspace, built_test_in_workspace};
use core::os::mkdir_recursive;
fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
@ -29,15 +30,22 @@ fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
}
fn fake_pkg() -> PkgId {
let sn = ~"bogus";
let remote = RemotePath(Path(sn));
PkgId {
path: Path(~"bogus"),
local_path: normalize(remote),
remote_path: remote,
short_name: sn,
version: default_version()
}
}
fn remote_pkg() -> PkgId {
let remote = RemotePath(Path(~"github.com/catamorphism/test-pkg"));
PkgId {
path: Path(~"github.com/catamorphism/test-pkg"),
local_path: normalize(remote),
remote_path: remote,
short_name: ~"test_pkg",
version: default_version()
}
}
@ -49,9 +57,10 @@ fn writeFile(file_path: &Path, contents: ~str) {
out.write_line(contents);
}
fn mk_temp_workspace(short_name: &Path) -> Path {
fn mk_temp_workspace(short_name: &LocalPath) -> Path {
let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
let package_dir = workspace.push(~"src").push_rel(short_name);
// Ugh, including version number
let package_dir = workspace.push(~"src").push(fmt!("%s-0-1", short_name.to_str()));
assert!(mkdir_recursive(&package_dir, u_rwx));
// Create main, lib, test, and bench files
writeFile(&package_dir.push(~"main.rs"),
@ -104,7 +113,7 @@ fn test_install_valid() {
debug!("sysroot = %s", sysroot.to_str());
let ctxt = fake_ctxt(Some(@sysroot));
let temp_pkg_id = fake_pkg();
let temp_workspace = mk_temp_workspace(&temp_pkg_id.path);
let temp_workspace = mk_temp_workspace(&temp_pkg_id.local_path);
// should have test, bench, lib, and main
ctxt.install(&temp_workspace, &temp_pkg_id);
// Check that all files exist
@ -146,27 +155,32 @@ fn test_install_invalid() {
}
#[test]
#[ignore(reason = "install from URL-fragment not yet implemented")]
fn test_install_url() {
let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
let sysroot = test_sysroot();
debug!("sysroot = %s", sysroot.to_str());
let ctxt = fake_ctxt(Some(@sysroot));
let temp_pkg_id = remote_pkg();
let temp_workspace = mk_temp_workspace(&temp_pkg_id.path);
// should have test, bench, lib, and main
ctxt.install(&temp_workspace, &temp_pkg_id);
ctxt.install(&workspace, temp_pkg_id);
// Check that all files exist
let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
let exec = target_executable_in_workspace(temp_pkg_id, &workspace);
debug!("exec = %s", exec.to_str());
assert!(os::path_exists(&exec));
assert!(is_rwx(&exec));
let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace);
let lib = target_library_in_workspace(temp_pkg_id, &workspace);
debug!("lib = %s", lib.to_str());
assert!(os::path_exists(&lib));
assert!(is_rwx(&lib));
let built_test = built_test_in_workspace(temp_pkg_id, &workspace).expect(~"test_install_url");
assert!(os::path_exists(&built_test));
let built_bench = built_bench_in_workspace(temp_pkg_id, &workspace).expect(~"test_install_url");
assert!(os::path_exists(&built_bench));
// And that the test and bench executables aren't installed
assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
let test = target_test_in_workspace(temp_pkg_id, &workspace);
assert!(!os::path_exists(&test));
debug!("test = %s", test.to_str());
let bench = target_bench_in_workspace(temp_pkg_id, &workspace);
debug!("bench = %s", bench.to_str());
assert!(!os::path_exists(&bench));
}

View file

@ -13,7 +13,6 @@ use core::cmp::Ord;
use core::hash::Streaming;
use core::rt::io::Writer;
use rustc::driver::{driver, session};
use rustc::driver::session::{lib_crate, unknown_crate};
use rustc::metadata::filesearch;
use std::getopts::groups::getopts;
use std::semver;
@ -26,7 +25,7 @@ use syntax::{ast, attr, codemap, diagnostic, fold};
use syntax::ast::{meta_name_value, meta_list, attribute};
use syntax::attr::{mk_attr};
use rustc::back::link::output_type_exe;
use rustc::driver::session::{lib_crate, unknown_crate, crate_type};
use rustc::driver::session::{lib_crate, bin_crate};
static Commands: &'static [&'static str] =
&["build", "clean", "do", "info", "install", "prefer", "test", "uninstall",
@ -83,14 +82,28 @@ impl ToStr for Version {
}
}
#[deriving(Eq)]
pub enum OutputType { Main, Lib, Bench, Test }
/// Placeholder
pub fn default_version() -> Version { ExactRevision(0.1) }
// Path-fragment identifier of a package such as
// 'github.com/graydon/test'; path must be a relative
// path with >=1 component.
/// Path-fragment identifier of a package such as
/// 'github.com/graydon/test'; path must be a relative
/// path with >=1 component.
pub struct PkgId {
path: Path,
/// Remote path: for example, github.com/mozilla/quux-whatever
remote_path: RemotePath,
/// Local path: for example, /home/quux/github.com/mozilla/quux_whatever
/// Note that '-' normalizes to '_' when mapping a remote path
/// onto a local path
/// Also, this will change when we implement #6407, though we'll still
/// need to keep track of separate local and remote paths
local_path: LocalPath,
/// Short name. This is the local path's filestem, but we store it
/// redundantly so as to not call get() everywhere (filestem() returns an
/// option)
short_name: ~str,
version: Version
}
@ -105,24 +118,31 @@ pub impl PkgId {
if p.components.len() < 1 {
return cond.raise((p, ~"0-length pkgid"));
}
let remote_path = RemotePath(p);
let local_path = normalize(remote_path);
PkgId {
path: p,
local_path: local_path,
remote_path: remote_path,
short_name: local_path.filestem().expect(fmt!("Strange path! %s", s)),
version: default_version()
}
}
fn hash(&self) -> ~str {
fmt!("%s-%s-%s", self.path.to_str(),
hash(self.path.to_str() + self.version.to_str()),
fmt!("%s-%s-%s", self.remote_path.to_str(),
hash(self.remote_path.to_str() + self.version.to_str()),
self.version.to_str())
}
fn short_name_with_version(&self) -> ~str {
fmt!("%s-%s", self.short_name, self.version.to_str())
}
}
impl ToStr for PkgId {
fn to_str(&self) -> ~str {
// should probably use the filestem and not the whole path
fmt!("%s-%s", self.path.to_str(),
fmt!("%s-%s", self.local_path.to_str(),
// Replace dots with -s in the version
// this is because otherwise rustc will think
// that foo-0.1 has .1 as its extension
@ -444,31 +464,26 @@ pub fn compile_input(sysroot: Option<@Path>,
flags: &[~str],
cfgs: &[~str],
opt: bool,
test: bool,
crate_type: session::crate_type) -> bool {
what: OutputType) -> bool {
// Want just the directory component here
let pkg_filename = pkg_id.path.filename().expect(~"Weird pkg id");
let short_name = fmt!("%s-%s", pkg_filename, pkg_id.version.to_str());
let short_name = pkg_id.short_name_with_version();
assert!(in_file.components.len() > 1);
let input = driver::file_input(copy *in_file);
debug!("compile_input: %s / %?", in_file.to_str(), crate_type);
debug!("compile_input: %s / %?", in_file.to_str(), what);
// tjc: by default, use the package ID name as the link name
// not sure if we should support anything else
let binary = @copy os::args()[0];
let building_library = match crate_type {
lib_crate | unknown_crate => true,
_ => false
};
let binary = os::args()[0];
let building_library = what == Lib;
let out_file = if building_library {
out_dir.push(os::dll_filename(short_name))
}
else {
out_dir.push(short_name + if test { ~"test" } else { ~"" }
+ os::EXE_SUFFIX)
out_dir.push(short_name + match what {
Test => ~"test", Bench => ~"bench", Main | Lib => ~""
} + os::EXE_SUFFIX)
};
debug!("compiling %s into %s",
@ -478,18 +493,24 @@ pub fn compile_input(sysroot: Option<@Path>,
debug!("cfgs: %s", str::connect(cfgs, ~" "));
debug!("compile_input's sysroot = %?", sysroot);
let crate_type = match what {
Lib => lib_crate,
Test | Bench | Main => bin_crate
};
let matches = getopts(~[~"-Z", ~"time-passes"]
+ if building_library { ~[~"--lib"] }
else if test { ~[~"--test"] }
// bench?
else { ~[] }
+ match what {
Lib => ~[~"--lib"],
// --test compiles both #[test] and #[bench] fns
Test | Bench => ~[~"--test"],
Main => ~[]
}
+ flags
+ cfgs.flat_map(|&c| { ~[~"--cfg", c] }),
driver::optgroups()).get();
let mut options = session::options {
crate_type: crate_type,
optimize: if opt { session::Aggressive } else { session::No },
test: test,
test: what == Test || what == Bench,
maybe_sysroot: sysroot,
addl_lib_search_paths: ~[copy *out_dir],
// output_type should be conditional
@ -549,11 +570,9 @@ pub fn compile_crate_from_input(input: &driver::input,
debug!("How many attrs? %?", attr::find_linkage_metas(crate.node.attrs).len());
if attr::find_linkage_metas(crate.node.attrs).is_empty() {
crate_to_use = add_attrs(copy *crate,
~[mk_attr(@dummy_spanned(meta_list(@~"link",
// change PkgId to have a <shortname> field?
crate_to_use = add_attrs(*crate, ~[mk_attr(@dummy_spanned(meta_list(@~"link",
~[@dummy_spanned(meta_name_value(@~"name",
mk_string_lit(@pkg_id.path.filestem().get()))),
mk_string_lit(@pkg_id.short_name))),
@dummy_spanned(meta_name_value(@~"vers",
mk_string_lit(@pkg_id.version.to_str())))])))]);
}
@ -586,16 +605,34 @@ fn add_attrs(mut c: ast::crate, new_attrs: ~[attribute]) -> @ast::crate {
pub fn compile_crate(sysroot: Option<@Path>, pkg_id: &PkgId,
crate: &Path, dir: &Path,
flags: &[~str], cfgs: &[~str], opt: bool,
test: bool, crate_type: crate_type) -> bool {
what: OutputType) -> bool {
debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str());
debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str());
for flags.each |&fl| {
debug!("+++ %s", fl);
}
compile_input(sysroot, pkg_id,
crate, dir, flags, cfgs, opt, test, crate_type)
compile_input(sysroot, pkg_id, crate, dir, flags, cfgs, opt, what)
}
// normalize should be the only way to construct a LocalPath
// (though this isn't enforced)
/// Replace all occurrences of '-' in the stem part of path with '_'
/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux
/// as the same name
pub fn normalize(p: RemotePath) -> LocalPath {
match p.filestem() {
None => LocalPath(*p),
Some(st) => {
let replaced = str::replace(st, "-", "_");
if replaced != st {
LocalPath(p.with_filestem(replaced))
}
else {
LocalPath(*p)
}
}
}
}
#[cfg(windows)]
pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
@ -628,6 +665,10 @@ pub fn mk_string_lit(s: @~str) -> ast::lit {
}
}
/// Wrappers to prevent local and remote paths from getting confused
pub struct RemotePath (Path);
pub struct LocalPath (Path);
#[cfg(test)]
mod test {
use super::{is_cmd, parse_name};

View file

@ -21,8 +21,9 @@ pub fn pkg_parent_workspaces(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool
workspace_contains_package_id(pkgid, ws));
if workspaces.is_empty() {
// tjc: make this a condition
fail!("Package %s not found in any of the following workspaces: %s",
pkgid.path.to_str(),
fail!("Package %s not found in any of \
the following workspaces: %s",
pkgid.remote_path.to_str(),
rust_path().to_str());
}
for workspaces.each |ws| {

@ -1 +1 @@
Subproject commit 97ac7c087a0caf6b0f611b80e14f7fe3cb18bb27
Subproject commit 218ab86721eefd7b7e97fa6d9f95a80a1fa8686c