From c3875e8c7066b5879437b3a5b578a6665fe767f2 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 10 May 2013 19:00:51 -0700 Subject: [PATCH 1/2] 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. --- src/librustpkg/path_util.rs | 107 +++++++++++++----------- src/librustpkg/rustpkg.rc | 160 ++++++++++++------------------------ src/librustpkg/tests.rs | 40 ++++++--- src/librustpkg/util.rs | 115 +++++++++++++++++--------- src/librustpkg/workspace.rs | 7 +- src/libuv | 2 +- 6 files changed, 223 insertions(+), 208 deletions(-) diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 477a7af45504b..3cc2a5f3fb6ef 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -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 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 in 's build /// directory is, and if the file exists, return it. pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option { 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 library name for in 's build +/// Figure out what the test name for in 's build +/// directory is, and if the file exists, return it. +pub fn built_test_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { + output_in_workspace(pkgid, workspace, Test) +} + +/// Figure out what the test name for in 's build /// directory is, and if the file exists, return it. -pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option { +pub fn built_bench_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { + output_in_workspace(pkgid, workspace, Bench) +} + +fn output_in_workspace(pkgid: PkgId, workspace: &Path, what: OutputType) -> Option { 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); + 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 in 's build +/// directory is, and if the file exists, return it. +pub fn built_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { + 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 Path { /// Returns the test executable that would be installed for /// in -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 /// in -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 { - if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) { - cond.raise((copy result, - fmt!("I couldn't create the %s dir", subdir))); - } + debug!("target_file_in_workspace: %s %?", result.to_str(), create_dir); + if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) { + 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 's build artifacts in . @@ -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 } diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index 884f0a73589dc..1f72b24345417 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -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)); - } - } - } - - 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!(); + if !(os::mkdir_recursive(&target_lib.dir_path(), u_rwx) && + os::copy_file(lib, &target_lib)) { + cond.raise((*lib, target_lib)); } } } - 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 { @@ -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); } } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index e661e758d41a5..6379dd9b3407b 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -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)); } diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index e9c4b7fde5548..ca9596afbf82b 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -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,13 +570,11 @@ 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 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())))])))]); + mk_string_lit(@pkg_id.version.to_str())))])))]); } driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate_to_use)); @@ -586,17 +605,35 @@ 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 { /* FIXME (#1768): Investigate how to do this on win32 @@ -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}; diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index 8941dbfd20eab..cb9f735bce8d4 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -21,9 +21,10 @@ 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(), - rust_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| { if action(ws) { diff --git a/src/libuv b/src/libuv index 97ac7c087a0ca..218ab86721eef 160000 --- a/src/libuv +++ b/src/libuv @@ -1 +1 @@ -Subproject commit 97ac7c087a0caf6b0f611b80e14f7fe3cb18bb27 +Subproject commit 218ab86721eefd7b7e97fa6d9f95a80a1fa8686c From 80a7e2644c86846e06907a6bed5b0d7773051d20 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 14 May 2013 17:46:52 -0700 Subject: [PATCH 2/2] rustpkg: Tests for well-formed and ill-formed package IDs... ...and cleanup, making how we handle version numbers more rational (specifically, not passing in a versioned name to rustc with the -o flag), and removing unused code. --- src/librustpkg/conditions.rs | 4 + src/librustpkg/path_util.rs | 31 +++--- src/librustpkg/rustpkg.rc | 88 +++------------- src/librustpkg/tests.rs | 72 ++++++++++--- src/librustpkg/util.rs | 197 +++++------------------------------ 5 files changed, 121 insertions(+), 271 deletions(-) diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs index 5b19a3bd66042..680e0924d798c 100644 --- a/src/librustpkg/conditions.rs +++ b/src/librustpkg/conditions.rs @@ -28,3 +28,7 @@ condition! { condition! { missing_pkg_files: (super::PkgId) -> (); } + +condition! { + bad_pkg_id: (super::Path, ~str) -> ::util::PkgId; +} diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 3cc2a5f3fb6ef..bbd8d09235484 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -35,7 +35,7 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) } /// True if there's a directory in with /// pkgid's short name -pub fn workspace_contains_package_id(pkgid: PkgId, workspace: &Path) -> bool { +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) } @@ -67,17 +67,17 @@ pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option< /// Figure out what the test name for in 's build /// directory is, and if the file exists, return it. -pub fn built_test_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { +pub fn built_test_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option { output_in_workspace(pkgid, workspace, Test) } /// Figure out what the test name for in 's build /// directory is, and if the file exists, return it. -pub fn built_bench_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { +pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option { output_in_workspace(pkgid, workspace, Bench) } -fn output_in_workspace(pkgid: PkgId, workspace: &Path, what: OutputType) -> Option { +fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option { let mut result = workspace.push("build"); // should use a target-specific subdirectory result = mk_output_path(what, pkgid, &result); @@ -94,7 +94,7 @@ fn output_in_workspace(pkgid: PkgId, workspace: &Path, what: OutputType) -> Opti /// Figure out what the library name for in 's build /// directory is, and if the file exists, return it. -pub fn built_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { +pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option { let result = mk_output_path(Lib, pkgid, &workspace.push("build")); debug!("built_library_in_workspace: checking whether %s exists", result.to_str()); @@ -177,14 +177,14 @@ pub fn target_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { /// Returns the test executable that would be installed for /// in /// 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 { +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 /// in /// 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 { +pub fn target_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { target_file_in_workspace(pkgid, workspace, Bench) } @@ -192,13 +192,12 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Path { use conditions::bad_path::cond; - let (subdir, create_dir) = match what { + let subdir = match what { Lib => "lib", Main | Test | Bench => "bin" }; let result = workspace.push(subdir); - debug!("target_file_in_workspace: %s %?", result.to_str(), create_dir); if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) { - cond.raise((result, fmt!("I couldn't create the %s dir", subdir))); + cond.raise((copy result, fmt!("I couldn't create the %s dir", subdir))); } mk_output_path(what, pkgid, &result) } @@ -222,17 +221,19 @@ 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, pkg_id: PkgId, workspace: &Path) -> Path { - let short_name = pkg_id.short_name_with_version(); +pub fn mk_output_path(what: OutputType, pkg_id: &PkgId, workspace: &Path) -> Path { + let short_name_with_version = 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()); + if what == Lib { copy short_name_with_version } else { copy pkg_id.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, + Lib => dir.push(os::dll_filename(short_name_with_version)), + // executable names *aren't* versioned + _ => dir.push(fmt!("%s%s%s", copy pkg_id.short_name, match what { Test => "test", Bench => "bench", diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index 1f72b24345417..a69613776efdc 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -157,27 +157,6 @@ impl<'self> PkgScript<'self> { impl Ctx { fn run(&self, cmd: ~str, args: ~[~str]) { - let root = util::root(); - - util::need_dir(&root); - util::need_dir(&root.push(~"work")); - util::need_dir(&root.push(~"lib")); - util::need_dir(&root.push(~"bin")); - util::need_dir(&root.push(~"tmp")); - - fn sep_name_vers(in: ~str) -> (Option<~str>, Option<~str>) { - let mut name = None; - let mut vers = None; - - for str::each_split_char(in, '@') |s| { - if name.is_none() { name = Some(s.to_owned()); } - else if vers.is_none() { vers = Some(s.to_owned()); } - else { break; } - } - - (name, vers) - } - match cmd { ~"build" => { if args.len() < 1 { @@ -227,9 +206,7 @@ impl Ctx { return usage::uninstall(); } - let (name, vers) = sep_name_vers(copy args[0]); - - self.prefer(name.get(), vers); + self.prefer(args[0], None); } ~"test" => { self.test(); @@ -239,20 +216,16 @@ impl Ctx { return usage::uninstall(); } - let (name, vers) = sep_name_vers(copy args[0]); - - self.uninstall(name.get(), vers); + self.uninstall(args[0], None); } ~"unprefer" => { if args.len() < 1 { return usage::uninstall(); } - let (name, vers) = sep_name_vers(copy args[0]); - - self.unprefer(name.get(), vers); + self.unprefer(args[0], None); } - _ => fail!("reached an unhandled command") + _ => fail!(fmt!("I don't know the command `%s`", cmd)) } } @@ -267,7 +240,7 @@ impl Ctx { debug!("Destination dir = %s", build_dir.to_str()); // Create the package source - let mut src = PkgSrc::new(workspace, &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 @@ -305,7 +278,6 @@ impl Ctx { // Build it! src.build(&build_dir, cfgs, self.sysroot_opt); } - } fn clean(&self, workspace: &Path, id: &PkgId) { @@ -317,7 +289,7 @@ impl Ctx { util::note(fmt!("Cleaning package %s (removing directory %s)", id.to_str(), dir.to_str())); if os::path_exists(&dir) { - util::remove_dir_r(&dir); + os::remove_dir_recursive(&dir); util::note(fmt!("Removed directory %s", dir.to_str())); } @@ -353,19 +325,19 @@ impl Ctx { debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str()); if !(os::mkdir_recursive(&target_exec.dir_path(), u_rwx) && os::copy_file(exec, &target_exec)) { - cond.raise((*exec, target_exec)); + cond.raise((copy *exec, copy target_exec)); } } for maybe_library.each |lib| { debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str()); if !(os::mkdir_recursive(&target_lib.dir_path(), u_rwx) && os::copy_file(lib, &target_lib)) { - cond.raise((*lib, target_lib)); + cond.raise((copy *lib, copy target_lib)); } } } - fn prefer(&self, _id: ~str, _vers: Option<~str>) { + fn prefer(&self, _id: &str, _vers: Option<~str>) { fail!(~"prefer not yet implemented"); } @@ -374,15 +346,16 @@ impl Ctx { fail!("test not yet implemented"); } - fn uninstall(&self, _id: ~str, _vers: Option<~str>) { + fn uninstall(&self, _id: &str, _vers: Option<~str>) { fail!("uninstall not yet implemented"); } - fn unprefer(&self, _id: ~str, _vers: Option<~str>) { + fn unprefer(&self, _id: &str, _vers: Option<~str>) { fail!("unprefer not yet implemented"); } } + pub fn main() { io::println("WARNING: The Rust package manager is experimental and may be unstable"); @@ -443,32 +416,6 @@ pub struct Crate { cfgs: ~[~str] } -pub struct Listener { - cmds: ~[~str], - cb: ~fn() -} - -pub fn run(listeners: ~[Listener]) { - let rcmd = copy os::args()[2]; - let mut found = false; - - for listeners.each |listener| { - for listener.cmds.each |&cmd| { - if cmd == rcmd { - (listener.cb)(); - - found = true; - - break; - } - } - } - - if !found { - os::set_exit_status(42); - } -} - pub impl Crate { fn new(p: &Path) -> Crate { @@ -527,10 +474,6 @@ pub fn src_dir() -> Path { os::getcwd() } -condition! { - bad_pkg_id: (super::Path, ~str) -> ::util::PkgId; -} - // An enumeration of the unpacked source of a package workspace. // This contains a list of files found in the source workspace. pub struct PkgSrc { @@ -576,7 +519,7 @@ impl PkgSrc { if !os::path_exists(&dir) { if !self.fetch_git() { - cond.raise((self.id, ~"supplied path for package dir does not \ + cond.raise((copy self.id, ~"supplied path for package dir does not \ exist, and couldn't interpret it as a URL fragment")); } } @@ -598,12 +541,12 @@ impl PkgSrc { 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); + os::remove_dir_recursive(&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 { + if run::program_output(~"git", ~[~"clone", copy url, local.to_str()]).status != 0 { util::note(fmt!("fetching %s failed: can't clone repository", url)); return false; } @@ -733,3 +676,4 @@ impl PkgSrc { self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, Bench); } } + diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 6379dd9b3407b..487e8d0da36e2 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -19,7 +19,6 @@ use path_util::{target_executable_in_workspace, target_library_in_workspace, target_test_in_workspace, target_bench_in_workspace, 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 { Ctx { @@ -33,7 +32,7 @@ fn fake_pkg() -> PkgId { let sn = ~"bogus"; let remote = RemotePath(Path(sn)); PkgId { - local_path: normalize(remote), + local_path: normalize(copy remote), remote_path: remote, short_name: sn, version: default_version() @@ -43,7 +42,7 @@ fn fake_pkg() -> PkgId { fn remote_pkg() -> PkgId { let remote = RemotePath(Path(~"github.com/catamorphism/test-pkg")); PkgId { - local_path: normalize(remote), + local_path: normalize(copy remote), remote_path: remote, short_name: ~"test_pkg", version: default_version() @@ -59,9 +58,9 @@ fn writeFile(file_path: &Path, contents: ~str) { fn mk_temp_workspace(short_name: &LocalPath) -> Path { let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); - // 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)); + // include version number in directory name + let package_dir = workspace.push(~"src").push(fmt!("%s-0.1", short_name.to_str())); + assert!(os::mkdir_recursive(&package_dir, u_rwx)); // Create main, lib, test, and bench files writeFile(&package_dir.push(~"main.rs"), ~"fn main() { let _x = (); }"); @@ -162,25 +161,72 @@ fn test_install_url() { let ctxt = fake_ctxt(Some(@sysroot)); let temp_pkg_id = remote_pkg(); // should have test, bench, lib, and main - ctxt.install(&workspace, temp_pkg_id); + ctxt.install(&workspace, &temp_pkg_id); // Check that all files exist - let exec = target_executable_in_workspace(temp_pkg_id, &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, &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"); + 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"); + 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 - let test = target_test_in_workspace(temp_pkg_id, &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); + let bench = target_bench_in_workspace(&temp_pkg_id, &workspace); debug!("bench = %s", bench.to_str()); assert!(!os::path_exists(&bench)); } + +#[test] +fn test_package_ids_must_be_relative_path_like() { + use conditions::bad_pkg_id::cond; + + /* + Okay: + - One identifier, with no slashes + - Several slash-delimited things, with no / at the root + + Not okay: + - Empty string + - Absolute path (as per os::is_absolute) + + */ + + let default_version_str = "0.1"; + let addversion = |s| { + fmt!("%s-%s", s, default_version_str) + }; + + let whatever = PkgId::new("foo"); + + assert!(addversion("foo") == whatever.to_str()); + assert!(addversion("github.com/mozilla/rust") == + PkgId::new("github.com/mozilla/rust").to_str()); + + do cond.trap(|(p, e)| { + assert!("" == p.to_str()); + assert!("0-length pkgid" == e); + copy whatever + }).in { + let x = PkgId::new(""); + assert!(addversion("foo") == x.to_str()); + } + + do cond.trap(|(p, e)| { + assert!(p.to_str() == os::make_absolute(&Path("foo/bar/quux")).to_str()); + assert!("absolute pkgid" == e); + copy whatever + }).in { + let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str()); + assert!(addversion("foo") == z.to_str()); + } + +} diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index ca9596afbf82b..4a9c276948aa0 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -16,13 +16,12 @@ use rustc::driver::{driver, session}; use rustc::metadata::filesearch; use std::getopts::groups::getopts; use std::semver; -use std::{json, term, getopts}; +use std::{term, getopts}; use syntax::ast_util::*; use syntax::codemap::{dummy_sp, spanned, dummy_spanned}; use syntax::ext::base::{mk_ctxt, ext_ctxt}; -use syntax::ext::build; use syntax::{ast, attr, codemap, diagnostic, fold}; -use syntax::ast::{meta_name_value, meta_list, attribute}; +use syntax::ast::{meta_name_value, meta_list}; use syntax::attr::{mk_attr}; use rustc::back::link::output_type_exe; use rustc::driver::session::{lib_crate, bin_crate}; @@ -109,7 +108,7 @@ pub struct PkgId { pub impl PkgId { fn new(s: &str) -> PkgId { - use bad_pkg_id::cond; + use conditions::bad_pkg_id::cond; let p = Path(s); if p.is_absolute { @@ -119,11 +118,12 @@ pub impl PkgId { return cond.raise((p, ~"0-length pkgid")); } let remote_path = RemotePath(p); - let local_path = normalize(remote_path); + let local_path = normalize(copy remote_path); + let short_name = (copy local_path).filestem().expect(fmt!("Strange path! %s", s)); PkgId { local_path: local_path, remote_path: remote_path, - short_name: local_path.filestem().expect(fmt!("Strange path! %s", s)), + short_name: short_name, version: default_version() } } @@ -142,14 +142,7 @@ pub impl PkgId { impl ToStr for PkgId { fn to_str(&self) -> ~str { // should probably use the filestem and not the whole path - 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 - // (Temporary hack until I figure out how to - // get rustc to not name the object file - // foo-0.o if I pass in foo-0.1 to build_output_filenames) - str::replace(self.version.to_str(), ".", "-")) + fmt!("%s-%s", self.local_path.to_str(), self.version.to_str()) } } @@ -176,26 +169,6 @@ pub fn is_cmd(cmd: &str) -> bool { Commands.any(|&c| c == cmd) } -pub fn parse_name(id: ~str) -> result::Result<~str, ~str> { - let mut last_part = None; - - for str::each_split_char(id, '.') |part| { - for str::each_char(part) |char| { - if char::is_whitespace(char) { - return result::Err( - ~"could not parse id: contains whitespace"); - } else if char::is_uppercase(char) { - return result::Err( - ~"could not parse id: should be all lowercase"); - } - } - last_part = Some(part.to_owned()); - } - if last_part.is_none() { return result::Err(~"could not parse id: is empty"); } - - result::Ok(last_part.unwrap()) -} - struct ListenerFn { cmds: ~[~str], span: codemap::span, @@ -268,52 +241,6 @@ fn fold_item(ctx: @mut ReadyCtx, res } -fn add_pkg_module(ctx: @mut ReadyCtx, m: ast::_mod) -> ast::_mod { - let listeners = mk_listener_vec(ctx); - let ext_cx = ctx.ext_cx; - let item = quote_item! ( - mod __pkg { - extern mod rustpkg (vers="0.7-pre"); - static listeners : &[rustpkg::Listener] = $listeners; - #[main] - fn main() { - rustpkg::run(listeners); - } - } - ); - ast::_mod { - items: vec::append_one(/*bad*/copy m.items, item.get()), - .. m - } -} - -fn mk_listener_vec(ctx: @mut ReadyCtx) -> @ast::expr { - let descs = do ctx.fns.map |listener| { - mk_listener_rec(ctx, listener) - }; - let ext_cx = ctx.ext_cx; - build::mk_slice_vec_e(ext_cx, dummy_sp(), descs) -} - -fn mk_listener_rec(ctx: @mut ReadyCtx, listener: &ListenerFn) -> @ast::expr { - let span = listener.span; - let cmds = do listener.cmds.map |&cmd| { - let ext_cx = ctx.ext_cx; - build::mk_base_str(ext_cx, span, cmd) - }; - - let ext_cx = ctx.ext_cx; - let cmds_expr = build::mk_slice_vec_e(ext_cx, span, cmds); - let cb_expr = build::mk_path(ext_cx, span, copy listener.path); - - quote_expr!( - Listener { - cmds: $cmds_expr, - cb: $cb_expr - } - ) -} - /// Generate/filter main function, add the list of commands, etc. pub fn ready_crate(sess: session::Session, crate: @ast::crate) -> @ast::crate { @@ -395,67 +322,6 @@ pub fn hash(data: ~str) -> ~str { hasher.result_str() } -pub fn temp_change_dir(dir: &Path, cb: &fn() -> T) { - let cwd = os::getcwd(); - - os::change_dir(dir); - cb(); - os::change_dir(&cwd); -} - -pub fn touch(path: &Path) { - match io::mk_file_writer(path, ~[io::Create]) { - result::Ok(writer) => writer.write_line(~""), - _ => {} - } -} - -pub fn remove_dir_r(path: &Path) { - for os::walk_dir(path) |&file| { - let mut cdir = file; - - loop { - if os::path_is_dir(&cdir) { - os::remove_dir(&cdir); - } else { - os::remove_file(&cdir); - } - - cdir = cdir.dir_path(); - - if cdir == *path { break; } - } - } - - os::remove_dir(path); -} - -pub fn wait_for_lock(path: &Path) { - if os::path_exists(path) { - warn(fmt!("the database appears locked, please wait (or rm %s)", - path.to_str())); - - loop { - if !os::path_exists(path) { break; } - } - } -} - -pub fn load_pkgs() -> result::Result<~[json::Json], ~str> { - fail!("load_pkg not implemented"); -} - -pub fn get_pkg(_id: ~str, - _vers: Option<~str>) -> result::Result { - fail!("get_pkg not implemented"); -} - -pub fn add_pkg(pkg: &Pkg) -> bool { - note(fmt!("Would be adding package, but add_pkg is not yet implemented %s", - pkg.to_str())); - false -} - // FIXME (#4432): Use workcache to only compile when needed pub fn compile_input(sysroot: Option<@Path>, pkg_id: &PkgId, @@ -466,22 +332,20 @@ pub fn compile_input(sysroot: Option<@Path>, opt: bool, what: OutputType) -> bool { - 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(), what); // tjc: by default, use the package ID name as the link name // not sure if we should support anything else - let binary = os::args()[0]; + let binary = @(copy os::args()[0]); let building_library = what == Lib; let out_file = if building_library { - out_dir.push(os::dll_filename(short_name)) + out_dir.push(os::dll_filename(pkg_id.short_name)) } else { - out_dir.push(short_name + match what { + out_dir.push(pkg_id.short_name + match what { Test => ~"test", Bench => ~"bench", Main | Lib => ~"" } + os::EXE_SUFFIX) }; @@ -561,24 +425,27 @@ pub fn compile_crate_from_input(input: &driver::input, debug!("Calling compile_upto, outputs = %?", outputs); let (crate, _) = driver::compile_upto(sess, copy cfg, input, driver::cu_parse, Some(outputs)); + let mut crate = crate; debug!("About to inject link_meta info..."); // Inject the inferred link_meta info if it's not already there // (assumes that name and vers are the only linkage metas) - let mut crate_to_use = crate; 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(*crate, ~[mk_attr(@dummy_spanned(meta_list(@~"link", - ~[@dummy_spanned(meta_name_value(@~"name", - mk_string_lit(@pkg_id.short_name))), - @dummy_spanned(meta_name_value(@~"vers", - mk_string_lit(@pkg_id.version.to_str())))])))]); + crate = @codemap::respan(crate.span, ast::crate_ { + attrs: ~[mk_attr(@dummy_spanned( + meta_list(@~"link", + ~[@dummy_spanned(meta_name_value(@~"name", + mk_string_lit(@(copy pkg_id.short_name)))), + @dummy_spanned(meta_name_value(@~"vers", + mk_string_lit(@(copy pkg_id.version.to_str()))))])))], + ..copy crate.node}); } - driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate_to_use)); - crate_to_use + driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate)); + crate } } } @@ -592,14 +459,6 @@ pub fn exe_suffix() -> ~str { ~".exe" } #[cfg(target_os = "macos")] pub fn exe_suffix() -> ~str { ~"" } - -/// Returns a copy of crate `c` with attributes `attrs` added to its -/// attributes -fn add_attrs(mut c: ast::crate, new_attrs: ~[attribute]) -> @ast::crate { - c.node.attrs += new_attrs; - @c -} - // Called by build_crates // FIXME (#4432): Use workcache to only compile when needed pub fn compile_crate(sysroot: Option<@Path>, pkg_id: &PkgId, @@ -619,16 +478,17 @@ pub fn compile_crate(sysroot: Option<@Path>, pkg_id: &PkgId, /// 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 { +pub fn normalize(p_: RemotePath) -> LocalPath { + let RemotePath(p) = p_; match p.filestem() { - None => LocalPath(*p), + None => LocalPath(p), Some(st) => { let replaced = str::replace(st, "-", "_"); if replaced != st { LocalPath(p.with_filestem(replaced)) } else { - LocalPath(*p) + LocalPath(p) } } } @@ -671,7 +531,7 @@ pub struct LocalPath (Path); #[cfg(test)] mod test { - use super::{is_cmd, parse_name}; + use super::is_cmd; #[test] fn test_is_cmd() { @@ -686,9 +546,4 @@ mod test { assert!(is_cmd(~"unprefer")); } - #[test] - fn test_parse_name() { - assert!(parse_name(~"org.mozilla.servo").get() == ~"servo"); - assert!(parse_name(~"org. mozilla.servo 2131").is_err()); - } }