diff options
| author | Zack Corr <zack@z0w0.me> | 2013-01-19 19:59:19 +1000 |
|---|---|---|
| committer | Graydon Hoare <graydon@mozilla.com> | 2013-02-15 18:04:10 -0800 |
| commit | bd28fa4af5b5200b274b8e965a422174fb7ad354 (patch) | |
| tree | 1fcd297c24ad7a3e19fafaccec3225ca7a0063b4 /src/librustpkg | |
| parent | 321e3c490906fed6ed1d46a7cbd2d2f9a42c9a53 (diff) | |
| download | rust-bd28fa4af5b5200b274b8e965a422174fb7ad354.tar.gz rust-bd28fa4af5b5200b274b8e965a422174fb7ad354.zip | |
rustpkg: Finish all commands and declarative logic
Diffstat (limited to 'src/librustpkg')
| -rw-r--r-- | src/librustpkg/rustpkg.rc | 331 | ||||
| -rw-r--r-- | src/librustpkg/usage.rs | 29 | ||||
| -rw-r--r-- | src/librustpkg/util.rs | 373 |
3 files changed, 640 insertions, 93 deletions
diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index f95eabd584b..aec3f21eb6f 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -29,6 +29,7 @@ use core::*; use io::{ReaderUtil, WriterUtil}; use std::getopts; use std::net::url; +use send_map::linear::LinearMap; use rustc::driver::{driver, session}; use rustc::metadata::{filesearch}; use syntax::{ast, attr, codemap, diagnostic, parse, visit}; @@ -38,6 +39,8 @@ mod api; mod usage; mod util; +use util::Package; + struct PackageScript { id: ~str, name: ~str, @@ -167,23 +170,26 @@ impl PackageScript { } let id = id.get(); - let vers = vers.get(); + let name = match util::parse_name(id) { + result::Ok(name) => name, + result::Err(err) => return result::Err(err) + }; + let vers = match util::parse_vers(vers.get()) { + result::Ok(vers) => vers, + result::Err(err) => return result::Err(err) + }; result::Ok(PackageScript { id: id, - name: util::parse_id(id), - vers: util::parse_vers(vers), + name: name, + vers: vers, crates: crates, deps: deps }) } fn hash() -> ~str { - let hasher = hash::default_state(); - - hasher.write_str(self.id + self.vers.to_str()); - - fmt!("%s-%s-%s", self.name, hasher.result_str(), self.vers.to_str()) + fmt!("%s-%s-%s", self.name, util::hash(self.id + self.vers.to_str()), self.vers.to_str()) } fn work_dir() -> Path { @@ -192,8 +198,8 @@ impl PackageScript { } struct Ctx { - cfgs: ~[~str], - prefer: bool + cfg: ast::crate_cfg, + mut dep_cache: LinearMap<~str, bool> } impl Ctx { @@ -213,8 +219,10 @@ impl Ctx { if parts.len() >= 1 { name = Some(parts[0]); - } else if parts.len() >= 2 { - vers = Some(parts[1]); + + if parts.len() >= 2 { + vers = Some(parts[1]); + } } (name, vers) @@ -301,7 +309,8 @@ impl Ctx { } for script.crates.each |&crate| { - success = self.compile(&work_dir, &dir.push_rel(&Path(crate)), ~[]); + success = self.compile(&work_dir, &dir.push_rel(&Path(crate)), ~[], + false, false); if !success { break; } } @@ -318,15 +327,20 @@ impl Ctx { true } - fn compile(dir: &Path, crate: &Path, flags: ~[~str]) -> bool { + fn compile(dir: &Path, crate: &Path, flags: ~[~str], + opt: bool, test: bool) -> bool { util::note(~"compiling " + crate.to_str()); let lib_dir = dir.push(~"lib"); let bin_dir = dir.push(~"bin"); + let test_dir = dir.push(~"test"); let binary = os::args()[0]; let options: @session::options = @{ binary: binary, + addl_lib_search_paths: ~[util::root().push(~"lib")], crate_type: session::unknown_crate, + optimize: if opt { session::Aggressive } else { session::No }, + test: test, .. *session::basic_options() }; let input = driver::file_input(*crate); @@ -421,19 +435,33 @@ impl Ctx { } }; - if is_bin { - let hasher = hash::default_state(); + if test { + util::need_dir(&test_dir); + outputs = driver::build_output_filenames(input, &Some(test_dir), + &None, sess) + } + else if is_bin { util::need_dir(&bin_dir); - hasher.write_str(name + uuid + vers); - let path = bin_dir.push(fmt!("%s-%s-%s", name, hasher.result_str(), vers)); + #[cfg(windows)] + fn suffix() -> ~str { ~".exe" } + + #[cfg(target_os = "linux")] + #[cfg(target_os = "android")] + #[cfg(target_os = "freebsd")] + #[cfg(target_os = "macos")] + fn suffix() -> ~str { ~"" } + + let path = bin_dir.push(fmt!("%s-%s-%s%s", name, + util::hash(name + uuid + vers), + vers, suffix())); outputs = driver::build_output_filenames(input, &None, &Some(path), sess); } else { util::need_dir(&lib_dir); - outputs = driver::build_output_filenames(input, &Some(lib_dir), &None, - sess) + outputs = driver::build_output_filenames(input, &Some(lib_dir), + &None, sess) } driver::compile_upto(sess, cfg, input, driver::cu_everything, @@ -456,19 +484,14 @@ impl Ctx { util::note(fmt!("cleaning %s v%s (%s)", script.name, script.vers.to_str(), script.id)); - if os::path_is_dir(&dir) { - if os::remove_dir(&dir) { - util::note(fmt!("cleaned %s v%s", script.name, - script.vers.to_str())); - } else { - util::error(fmt!("cleaning %s v%s failed", - script.name, script.vers.to_str())); - } - } else { - util::note(fmt!("cleaned %s v%s", script.name, - script.vers.to_str())); + if os::path_exists(&dir) { + util::remove_dir_r(&dir); + util::note(fmt!("removed %s", dir.to_str())); } + util::note(fmt!("cleaned %s v%s", script.name, + script.vers.to_str())); + true } @@ -482,15 +505,17 @@ impl Ctx { dir = os::getcwd(); } else { let url = url.get(); - let hasher = hash::default_state(); + let hash = util::hash(if !target.is_none() { url + target.get() } else { url }); - hasher.write_str(url); + if self.dep_cache.contains_key(&hash) { + util::warn(~"already installed dep this run"); - if !target.is_none() { - hasher.write_str(target.get()); + return true; } - dir = util::root().push(~"tmp").push(hasher.result_str()); + self.dep_cache.insert(hash, true); + + dir = util::root().push(~"tmp").push(hash); if cache && os::path_exists(&dir) { return true; @@ -538,7 +563,8 @@ impl Ctx { } for script.crates.each |&crate| { - success = self.compile(&work_dir, &dir.push_rel(&Path(crate)), ~[]); + success = self.compile(&work_dir, &dir.push_rel(&Path(crate)), ~[], + true, false); if !success { break; } } @@ -549,24 +575,37 @@ impl Ctx { return false; } - let from_bin_dir = dir.push(~"bin"); - let from_lib_dir = dir.push(~"lib"); + let from_bin_dir = work_dir.push(~"bin"); + let from_lib_dir = work_dir.push(~"lib"); let to_bin_dir = util::root().push(~"bin"); let to_lib_dir = util::root().push(~"lib"); + let mut bins = ~[]; + let mut libs = ~[]; for os::walk_dir(&from_bin_dir) |bin| { let to = to_bin_dir.push_rel(&bin.file_path()); os::copy_file(bin, &to); + bins.push(to.to_str()); } + for os::walk_dir(&from_lib_dir) |lib| { let to = to_lib_dir.push_rel(&lib.file_path()); os::copy_file(lib, &to); + libs.push(to.to_str()); } + let package = Package { + id: script.id, + vers: script.vers, + bins: bins, + libs: libs + }; + util::note(fmt!("installed %s v%s", script.name, script.vers.to_str())); + util::add_pkg(&package); true } @@ -626,21 +665,7 @@ impl Ctx { util::note(fmt!("fetching from %s using git", url)); // Git can't clone into a non-empty directory - for os::walk_dir(dir) |&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 == *dir { break; } - } - } + 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"); @@ -665,19 +690,190 @@ impl Ctx { true } - fn prefer(name: ~str, vers: Option<~str>) -> bool { + fn prefer(id: ~str, vers: Option<~str>) -> bool { + let package = match util::get_pkg(id, vers) { + result::Ok(package) => package, + result::Err(err) => { + util::error(err); + + return false; + } + }; + let name = match util::parse_name(package.id) { + result::Ok(name) => name, + result::Err(err) => { + util::error(err); + + return false; + } + }; + + util::note(fmt!("preferring %s v%s (%s)", name, package.vers.to_str(), + package.id)); + + let bin_dir = util::root().push(~"bin"); + + for package.bins.each |&bin| { + let path = Path(bin); + let name = str::split_char(path.file_path().to_str(), '-')[0]; + let out = bin_dir.push(name); + + util::link_exe(&path, &out); + util::note(fmt!("linked %s", out.to_str())); + } + + util::note(fmt!("preferred %s v%s", name, package.vers.to_str())); + true } fn test() -> bool { + let dir = os::getcwd(); + let script = match PackageScript::parse(dir) { + result::Ok(script) => script, + result::Err(err) => { + util::error(err); + + return false; + } + }; + let work_dir = script.work_dir(); + let test_dir = work_dir.push(~"test"); + let mut success = true; + + util::need_dir(&work_dir); + util::note(fmt!("testing %s v%s (%s)", script.name, script.vers.to_str(), + script.id)); + + if script.deps.len() >= 1 { + util::note(~"installing dependencies"); + + for script.deps.each |&dep| { + let (url, target) = dep; + + success = self.install(Some(url), target, true); + + if !success { break; } + } + + + if !success { + util::error(fmt!("testing %s v%s failed: a dep wasn't installed", + script.name, script.vers.to_str())); + + return false; + } + + util::note(~"installed dependencies"); + } + + for script.crates.each |&crate| { + success = self.compile(&work_dir, &dir.push_rel(&Path(crate)), ~[], + false, true); + + if !success { break; } + } + + if !success { + util::error(fmt!("testing %s v%s failed: a crate failed to compile", + script.name, script.vers.to_str())); + + return false; + } + + for os::walk_dir(&test_dir) |test| { + util::note(fmt!("running %s", test.to_str())); + + let status = run::run_program(test.to_str(), ~[]); + + if status != 0 { + os::set_exit_status(status); + } + } + + util::note(fmt!("tested %s v%s", script.name, script.vers.to_str())); + true } - fn uninstall(name: ~str, vers: Option<~str>) -> bool { + fn uninstall(id: ~str, vers: Option<~str>) -> bool { + let package = match util::get_pkg(id, vers) { + result::Ok(package) => package, + result::Err(err) => { + util::error(err); + + return false; + } + }; + let name = match util::parse_name(package.id) { + result::Ok(name) => name, + result::Err(err) => { + util::error(err); + + return false; + } + }; + + util::note(fmt!("uninstalling %s v%s (%s)", name, package.vers.to_str(), + package.id)); + + for vec::append(package.bins, package.libs).each |&file| { + let path = Path(file); + + if os::path_exists(&path) { + if os::remove_file(&path) { + util::note(fmt!("removed %s", path.to_str())); + } else { + util::error(fmt!("could not remove %s", path.to_str())); + } + } + } + + util::note(fmt!("uninstalled %s v%s", name, package.vers.to_str())); + util::remove_pkg(&package); + true } - fn unprefer(name: ~str, vers: Option<~str>) -> bool { + fn unprefer(id: ~str, vers: Option<~str>) -> bool { + let package = match util::get_pkg(id, vers) { + result::Ok(package) => package, + result::Err(err) => { + util::error(err); + + return false; + } + }; + let name = match util::parse_name(package.id) { + result::Ok(name) => name, + result::Err(err) => { + util::error(err); + + return false; + } + }; + + util::note(fmt!("unpreferring %s v%s (%s)", name, package.vers.to_str(), + package.id)); + + let bin_dir = util::root().push(~"bin"); + + for package.bins.each |&bin| { + let path = Path(bin); + let name = str::split_char(path.file_path().to_str(), '-')[0]; + let out = bin_dir.push(name); + + if os::path_exists(&out) { + if os::remove_file(&out) { + util::note(fmt!("unlinked %s", out.to_str())); + } else { + util::error(fmt!("could not unlink %s", out.to_str())); + } + } + } + + util::note(fmt!("unpreferred %s v%s", name, package.vers.to_str())); + true } } @@ -685,20 +881,19 @@ impl Ctx { pub fn main() { let args = os::args(); let opts = ~[getopts::optflag(~"h"), getopts::optflag(~"help"), - getopts::optmulti(~"c"), getopts::optmulti(~"cfg"), - getopts::optmulti(~"p"), getopts::optmulti(~"prefer")]; + getopts::optmulti(~"c"), getopts::optmulti(~"cfg")]; let matches = &match getopts::getopts(args, opts) { result::Ok(m) => m, result::Err(f) => { - fail fmt!("%s", getopts::fail_str(f)); + util::error(fmt!("%s", getopts::fail_str(f))); + + return; } }; let help = getopts::opt_present(matches, ~"h") || getopts::opt_present(matches, ~"help"); - let cfgs = vec::append(getopts::opt_strs(matches, ~"cfg"), + let cfg = vec::append(getopts::opt_strs(matches, ~"cfg"), getopts::opt_strs(matches, ~"c")); - let prefer = getopts::opt_present(matches, ~"p") || - getopts::opt_present(matches, ~"prefer"); let mut args = copy matches.free; args.shift(); @@ -724,9 +919,15 @@ pub fn main() { }; } + let mut cfg_specs = ~[]; + + for cfg.each |s| { + cfg_specs.push(attr::mk_word_item(/*bad*/copy *s)); + } + Ctx { - cfgs: cfgs, - prefer: prefer + cfg: cfg_specs, + mut dep_cache: LinearMap() }.run(cmd, args); } diff --git a/src/librustpkg/usage.rs b/src/librustpkg/usage.rs index a46e918e3b7..28694948511 100644 --- a/src/librustpkg/usage.rs +++ b/src/librustpkg/usage.rs @@ -1,5 +1,5 @@ use core::io; - + pub fn general() { io::println(~"Usage: rustpkg [options] <cmd> [args..] @@ -46,29 +46,22 @@ Examples: rustpkg install http://rust-lang.org/servo-0.1.2.tar.gz Options: - -c, --cfg Pass a cfg flag to the package script - -p, --prefer Prefer the package after installing - (see `rustpkg prefer -h`)"); + -c, --cfg Pass a cfg flag to the package script"); } pub fn uninstall() { - io::println(~"rustpkg uninstall <name>[@version] - -Remove a package by name and/or version. If version is omitted then all -versions of the package will be removed. If the package[s] is/are depended -on by another package then they cannot be removed. If the package is preferred -(see `rustpkg prefer -h`), it will attempt to prefer the next latest -version of the package if another version is installed, otherwise it'll remove -the symlink."); + io::println(~"rustpkg uninstall <id|name>[@version] + +Remove a package by id or name and optionally version. If the package(s) is/are depended +on by another package then they cannot be removed."); } pub fn prefer() { - io::println(~"rustpkg [options..] prefer <name>[@version] + io::println(~"rustpkg [options..] prefer <id|name>[@version] By default all binaries are given a unique name so that multiple versions can coexist. The prefer command will symlink the uniquely named binary to -the binary directory under its bare name. The user will need to confirm -if the symlink will overwrite another. If version is not supplied, the latest +the binary directory under its bare name. If version is not supplied, the latest version of the package will be preferred. Example: @@ -82,10 +75,12 @@ Example: } pub fn unprefer() { - io::println(~"rustpkg [options..] unprefer <name> + io::println(~"rustpkg [options..] unprefer <id|name>[@version] Remove all symlinks from the store to the binary directory for a package -name. See `rustpkg prefer -h` for more information."); +name and optionally version. If version is not supplied, the latest version +of the package will be unpreferred. See `rustpkg prefer -h` for more +information."); } pub fn test() { diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 67587ae9360..16ded3c640b 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -1,7 +1,15 @@ use core::*; +use send_map::linear::LinearMap; use rustc::metadata::filesearch; use semver::Version; -use std::term; +use std::{json, term, sort}; + +pub struct Package { + id: ~str, + vers: Version, + bins: ~[~str], + libs: ~[~str], +} pub fn root() -> Path { match filesearch::get_rustpkg_root() { @@ -17,26 +25,26 @@ pub fn is_cmd(cmd: ~str) -> bool { vec::contains(cmds, &cmd) } -pub fn parse_id(id: ~str) -> ~str { +pub fn parse_name(id: ~str) -> result::Result<~str, ~str> { let parts = str::split_char(id, '.'); for parts.each |&part| { for str::chars(part).each |&char| { if char::is_whitespace(char) { - fail ~"could not parse id: contains whitespace"; + return result::Err(~"could not parse id: contains whitespace"); } else if char::is_uppercase(char) { - fail ~"could not parse id: should be all lowercase"; + return result::Err(~"could not parse id: should be all lowercase"); } } } - parts.last() + result::Ok(parts.last()) } -pub fn parse_vers(vers: ~str) -> Version { +pub fn parse_vers(vers: ~str) -> result::Result<Version, ~str> { match semver::parse(vers) { - Some(vers) => vers, - None => fail ~"could not parse version: invalid" + Some(vers) => result::Ok(vers), + None => result::Err(~"could not parse version: invalid") } } @@ -80,6 +88,13 @@ pub fn error(msg: ~str) { else { out.write_line(~"error: " + msg); } } +pub fn hash(data: ~str) -> ~str { + let hasher = hash::default_state(); + + hasher.write_str(data); + hasher.result_str() +} + pub fn temp_change_dir<T>(dir: &Path, cb: fn() -> T) { let cwd = os::getcwd(); @@ -88,6 +103,342 @@ pub fn temp_change_dir<T>(dir: &Path, cb: fn() -> T) { 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; } + } + } +} + +fn _add_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { + for packages.each |&package| { + match package { + json::Object(map) => { + let mut has_id = false; + + match map.get(&~"id") { + json::String(str) => { + if pkg.id == str { + has_id = true; + } + } + _ => {} + } + + match map.get(&~"vers") { + json::String(str) => { + if pkg.vers.to_str() == str { + return packages; + } + } + _ => {} + } + } + _ => {} + } + } + + let mut map = ~LinearMap(); + + map.insert(~"id", json::String(pkg.id)); + map.insert(~"vers", json::String(pkg.vers.to_str())); + map.insert(~"bins", json::List(do pkg.bins.map |&bin| { + json::String(bin) + })); + map.insert(~"libs", json::List(do pkg.libs.map |&lib| { + json::String(lib) + })); + + vec::append(packages, ~[json::Object(map)]) +} + +fn _rm_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { + do packages.filter_map |&package| { + match package { + json::Object(map) => { + let mut has_id = false; + + match map.get(&~"id") { + json::String(str) => { + if pkg.id == str { + has_id = true; + } + } + _ => {} + } + + match map.get(&~"vers") { + json::String(str) => { + if pkg.vers.to_str() == str { None } + else { Some(package) } + } + _ => { Some(package) } + } + } + _ => { Some(package) } + } + } +} + +pub fn load_pkgs() -> result::Result<~[json::Json], ~str> { + let root = root(); + let db = root.push(~"db.json"); + let db_lock = root.push(~"db.json.lck"); + + wait_for_lock(&db_lock); + touch(&db_lock); + + let packages = if os::path_exists(&db) { + match io::read_whole_file_str(&db) { + result::Ok(str) => { + match json::from_str(str) { + result::Ok(json) => { + match json { + json::List(list) => list, + _ => { + os::remove_file(&db_lock); + + return result::Err(~"package db's json is not a list"); + } + } + } + result::Err(err) => { + os::remove_file(&db_lock); + + return result::Err(fmt!("failed to parse package db: %s", err.to_str())); + } + } + } + result::Err(err) => { + os::remove_file(&db_lock); + + return result::Err(fmt!("failed to read package db: %s", err)); + } + } + } else { ~[] }; + + os::remove_file(&db_lock); + + result::Ok(packages) +} + +pub fn get_pkg(id: ~str, vers: Option<~str>) -> result::Result<Package, ~str> { + let name = match parse_name(id) { + result::Ok(name) => name, + result::Err(err) => return result::Err(err) + }; + let packages = match load_pkgs() { + result::Ok(packages) => packages, + result::Err(err) => return result::Err(err) + }; + let mut sel = None; + let mut possibs = ~[]; + let mut err = None; + + for packages.each |&package| { + match package { + json::Object(map) => { + let pid = match map.get(&~"id") { + json::String(str) => str, + _ => loop + }; + let pname = match parse_name(pid) { + result::Ok(pname) => pname, + result::Err(perr) => { + err = Some(perr); + + break; + } + }; + let pvers = match map.get(&~"vers") { + json::String(str) => str, + _ => loop + }; + if pid == id || pname == name { + let bins = match map.get(&~"bins") { + json::List(list) => { + do list.map |&bin| { + match bin { + json::String(str) => str, + _ => ~"" + } + } + } + _ => ~[] + }; + let libs = match map.get(&~"libs") { + json::List(list) => { + do list.map |&lib| { + match lib { + json::String(str) => str, + _ => ~"" + } + } + } + _ => ~[] + }; + let package = Package { + id: pid, + vers: match parse_vers(pvers) { + result::Ok(vers) => vers, + result::Err(verr) => { + err = Some(verr); + + break; + } + }, + bins: bins, + libs: libs + }; + + if !vers.is_none() && vers.get() == pvers { + sel = Some(package); + } + else { + possibs.push(package); + } + } + } + _ => {} + } + } + + if !err.is_none() { + return result::Err(err.get()); + } + if !sel.is_none() { + return result::Ok(sel.get()); + } + if !vers.is_none() || possibs.len() < 1 { + return result::Err(~"package not found"); + } + + result::Ok(sort::merge_sort(possibs, |v1, v2| { + v1.vers <= v2.vers + }).last()) +} + +pub fn add_pkg(pkg: &Package) -> bool { + let root = root(); + let db = root.push(~"db.json"); + let db_lock = root.push(~"db.json.lck"); + let packages = match load_pkgs() { + result::Ok(packages) => packages, + result::Err(err) => { + error(err); + + return false; + } + }; + + wait_for_lock(&db_lock); + touch(&db_lock); + os::remove_file(&db); + + match io::mk_file_writer(&db, ~[io::Create]) { + result::Ok(writer) => { + writer.write_line(json::to_pretty_str(&json::List(_add_pkg(packages, pkg)))); + } + result::Err(err) => { + error(fmt!("failed to dump package db: %s", err)); + os::remove_file(&db_lock); + + return false; + } + } + + os::remove_file(&db_lock); + + true +} + +pub fn remove_pkg(pkg: &Package) -> bool { + let root = root(); + let db = root.push(~"db.json"); + let db_lock = root.push(~"db.json.lck"); + let packages = match load_pkgs() { + result::Ok(packages) => packages, + result::Err(err) => { + error(err); + + return false; + } + }; + + wait_for_lock(&db_lock); + touch(&db_lock); + os::remove_file(&db); + + match io::mk_file_writer(&db, ~[io::Create]) { + result::Ok(writer) => { + writer.write_line(json::to_pretty_str(&json::List(_rm_pkg(packages, pkg)))); + } + result::Err(err) => { + error(fmt!("failed to dump package db: %s", err)); + os::remove_file(&db_lock); + + return false; + } + } + + os::remove_file(&db_lock); + + true +} + +#[cfg(windows)] +pub fn link_exe(_src: &Path, _dest: &Path) -> bool{ + /* FIXME: Investigate how to do this on win32 + Node wraps symlinks by having a .bat, + but that won't work with minGW. */ + + false +} + +#[cfg(target_os = "linux")] +#[cfg(target_os = "android")] +#[cfg(target_os = "freebsd")] +#[cfg(target_os = "macos")] +pub fn link_exe(src: &Path, dest: &Path) -> bool unsafe { + do str::as_c_str(src.to_str()) |src_buf| { + do str::as_c_str(dest.to_str()) |dest_buf| { + libc::link(src_buf, dest_buf) == 0 as libc::c_int && + libc::chmod(dest_buf, 755) == 0 as libc::c_int + } + } +} + #[test] fn test_is_cmd() { assert is_cmd(~"build"); @@ -100,7 +451,7 @@ fn test_is_cmd() { } #[test] -fn test_parse_id() { - assert parse_id(~"org.mozilla.servo").get() == ~"servo"; - assert parse_id(~"org. mozilla.servo 2131").is_err(); +fn test_parse_name() { + assert parse_name(~"org.mozilla.servo").get() == ~"servo"; + assert parse_name(~"org. mozilla.servo 2131").is_err(); } |
