condition! {
bad_pkg_id: (super::Path, ~str) -> super::PkgId;
}
+
+condition! {
+ no_rust_path: (~str) -> super::Path;
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Listing installed packages
+
+use path_util::*;
+use std::os;
+
+pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool {
+ let workspaces = rust_path();
+ for workspaces.iter().advance() |p| {
+ let binfiles = os::list_dir(&p.push("bin"));
+ for binfiles.iter().advance() |exec| {
+ f(&PkgId::new(*exec));
+ }
+ let libfiles = os::list_dir(&p.push("lib"));
+ for libfiles.iter().advance() |lib| {
+ f(&PkgId::new(*lib));
+ }
+ }
+ true
+}
+
+pub fn package_is_installed(p: &PkgId) -> bool {
+ let mut is_installed = false;
+ let _ = do list_installed_packages() |installed| {
+ if installed == p {
+ is_installed = true;
+ }
+ false
+ };
+ is_installed
+}
\ No newline at end of file
version: Version
}
+impl Eq for PkgId {
+ fn eq(&self, p: &PkgId) -> bool {
+ *p.local_path == *self.local_path && p.version == self.version
+ }
+ fn ne(&self, p: &PkgId) -> bool {
+ !(self.eq(p))
+ }
+}
+
impl PkgId {
pub fn new(s: &str) -> PkgId {
use conditions::bad_pkg_id::cond;
#[cfg(not(windows))]
static PATH_ENTRY_SEPARATOR: &'static str = ":";
+/// Returns RUST_PATH as a string, without default paths added
+pub fn get_rust_path() -> Option<~str> {
+ os::getenv("RUST_PATH")
+}
+
/// Returns the value of RUST_PATH, as a list
/// of Paths. Includes default entries for, if they exist:
/// $HOME/.rust
/// DIR/.rust for any DIR that's the current working directory
/// or an ancestor of it
pub fn rust_path() -> ~[Path] {
- let mut env_rust_path: ~[Path] = match os::getenv("RUST_PATH") {
+ let mut env_rust_path: ~[Path] = match get_rust_path() {
Some(env_path) => {
let env_path_components: ~[&str] =
env_path.split_str_iter(PATH_ENTRY_SEPARATOR).collect();
debug!("mk_output_path: returning %s", output_path.to_str());
output_path
}
+
+/// Removes files for the package `pkgid`, assuming it's installed in workspace `workspace`
+pub fn uninstall_package_from(workspace: &Path, pkgid: &PkgId) {
+ let mut did_something = false;
+ let installed_bin = target_executable_in_workspace(pkgid, workspace);
+ if os::path_exists(&installed_bin) {
+ os::remove_file(&installed_bin);
+ did_something = true;
+ }
+ let installed_lib = target_library_in_workspace(pkgid, workspace);
+ if os::path_exists(&installed_lib) {
+ os::remove_file(&installed_lib);
+ did_something = true;
+ }
+ if !did_something {
+ warn(fmt!("Warning: there don't seem to be any files for %s installed in %s",
+ pkgid.to_str(), workspace.to_str()));
+ }
+
+}
mod conditions;
mod context;
mod crate;
+mod installed_packages;
mod messages;
mod package_id;
mod package_path;
}
}
}
+ "list" => {
+ io::println("Installed packages:");
+ for installed_packages::list_installed_packages |pkg_id| {
+ io::println(fmt!("%s-%s",
+ pkg_id.local_path.to_str(),
+ pkg_id.version.to_str()));
+ }
+ }
"prefer" => {
if args.len() < 1 {
return usage::uninstall();
return usage::uninstall();
}
- self.uninstall(args[0], None);
+ let pkgid = PkgId::new(args[0]);
+ if !installed_packages::package_is_installed(&pkgid) {
+ warn(fmt!("Package %s doesn't seem to be installed! Doing nothing.", args[0]));
+ return;
+ }
+ else {
+ let rp = rust_path();
+ assert!(!rp.is_empty());
+ for each_pkg_parent_workspace(&pkgid) |workspace| {
+ path_util::uninstall_package_from(workspace, &pkgid);
+ note(fmt!("Uninstalled package %s (was installed in %s)",
+ pkgid.to_str(), workspace.to_str()));
+ }
+ }
}
"unprefer" => {
if args.len() < 1 {
- return usage::uninstall();
+ return usage::unprefer();
}
self.unprefer(args[0], None);
~"do" => usage::do_cmd(),
~"info" => usage::info(),
~"install" => usage::install(),
+ ~"list" => usage::list(),
~"prefer" => usage::prefer(),
~"test" => usage::test(),
~"uninstall" => usage::uninstall(),
use context::Ctx;
use std::hashmap::HashMap;
-use std::{io, libc, os, result, run, str, vec};
+use std::{io, libc, os, result, run, str};
use extra::tempfile::mkdtemp;
use std::run::ProcessOutput;
+use installed_packages::list_installed_packages;
use package_path::*;
use package_id::{PkgId};
use package_source::*;
self_path.pop()
}
+fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
+ command_line_test_with_env(args, cwd, None)
+}
+
/// Runs `rustpkg` (based on the directory that this executable was
/// invoked from) with the given arguments, in the given working directory.
/// Returns the process's output.
-fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
+fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
+ -> ProcessOutput {
let cmd = test_sysroot().push("bin").push("rustpkg").to_str();
let cwd = normalize(RemotePath(copy *cwd));
debug!("About to run command: %? %? in %s", cmd, args, cwd.to_str());
assert!(os::path_is_dir(&*cwd));
- let mut prog = run::Process::new(cmd, args, run::ProcessOptions { env: None,
- dir: Some(&*cwd),
- in_fd: None,
- out_fd: None,
- err_fd: None
- });
+ let cwd = cwd.clone();
+ let mut prog = run::Process::new(cmd, args, run::ProcessOptions {
+ env: env.map(|v| v.slice(0, v.len())),
+ dir: Some(&cwd),
+ in_fd: None,
+ out_fd: None,
+ err_fd: None
+ });
let output = prog.finish_with_output();
debug!("Output from command %s with args %? was %s {%s}[%?]",
cmd, args, str::from_bytes(output.output),
result
}
+fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
+ let mut result = ~[];
+ let p_output = command_line_test_with_env(args, &os::getcwd(), Some(env));
+ let test_output = str::from_bytes(p_output.output);
+ for test_output.split_iter('\n').advance |s| {
+ result.push(s.to_owned());
+ }
+ result
+}
+
// assumes short_name and local_path are one and the same -- I should fix
fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Path {
debug!("lib_output_file_name: given %s and parent %s and short name %s",
push("test_pkg_version")));
}
-// FIXME #7006: Fails on linux/mac for some reason
-#[test] #[ignore]
+// FIXME #7006: Fails on linux for some reason
+#[test]
+#[ignore]
fn test_package_request_version() {
let temp_pkg_id = PkgId::new("github.com/catamorphism/test_pkg_version#0.3");
let temp = mk_empty_workspace(&LocalPath(Path("test_pkg_version")), &ExactRevision(~"0.3"));
}
#[test]
-#[ignore(reason = "Package database not yet implemented")]
+fn test_list() {
+ let foo = PkgId::new("foo");
+ let dir = mkdtemp(&os::tmpdir(), "test_list").expect("test_list failed");
+ create_local_package_in(&foo, &dir);
+ let bar = PkgId::new("bar");
+ create_local_package_in(&bar, &dir);
+ let quux = PkgId::new("quux");
+ create_local_package_in(&quux, &dir);
+
+ command_line_test([~"install", ~"foo"], &dir);
+ let env_arg = ~[(~"RUST_PATH", dir.to_str())];
+ let list_output = command_line_test_output_with_env([~"list"], env_arg.clone());
+ assert!(list_output.iter().any(|x| x.starts_with("foo-")));
+
+ command_line_test([~"install", ~"bar"], &dir);
+ let list_output = command_line_test_output_with_env([~"list"], env_arg.clone());
+ assert!(list_output.iter().any(|x| x.starts_with("foo-")));
+ assert!(list_output.iter().any(|x| x.starts_with("bar-")));
+
+ command_line_test([~"install", ~"quux"], &dir);
+ let list_output = command_line_test_output_with_env([~"list"], env_arg);
+ assert!(list_output.iter().any(|x| x.starts_with("foo-")));
+ assert!(list_output.iter().any(|x| x.starts_with("bar-")));
+ assert!(list_output.iter().any(|x| x.starts_with("quux-")));
+}
+
+#[test]
fn install_remove() {
let foo = PkgId::new("foo");
let bar = PkgId::new("bar");
create_local_package_in(&foo, &dir);
create_local_package_in(&bar, &dir);
create_local_package_in(&quux, &dir);
+ let rust_path_to_use = ~[(~"RUST_PATH", dir.to_str())];
command_line_test([~"install", ~"foo"], &dir);
command_line_test([~"install", ~"bar"], &dir);
command_line_test([~"install", ~"quux"], &dir);
- let list_output = command_line_test_output([~"list"]);
- assert!(list_output.iter().any(|x| x == &~"foo"));
- assert!(list_output.iter().any(|x| x == &~"bar"));
- assert!(list_output.iter().any(|x| x == &~"quux"));
- command_line_test([~"remove", ~"foo"], &dir);
- let list_output = command_line_test_output([~"list"]);
- assert!(!list_output.iter().any(|x| x == &~"foo"));
- assert!(list_output.iter().any(|x| x == &~"bar"));
- assert!(list_output.iter().any(|x| x == &~"quux"));
+ let list_output = command_line_test_output_with_env([~"list"], rust_path_to_use.clone());
+ assert!(list_output.iter().any(|x| x.starts_with("foo")));
+ assert!(list_output.iter().any(|x| x.starts_with("bar")));
+ assert!(list_output.iter().any(|x| x.starts_with("quux")));
+ command_line_test([~"uninstall", ~"foo"], &dir);
+ let list_output = command_line_test_output_with_env([~"list"], rust_path_to_use.clone());
+ assert!(!list_output.iter().any(|x| x.starts_with("foo")));
+ assert!(list_output.iter().any(|x| x.starts_with("bar")));
+ assert!(list_output.iter().any(|x| x.starts_with("quux")));
+}
+
+#[test]
+fn install_check_duplicates() {
+ // should check that we don't install two packages with the same full name *and* version
+ // ("Is already installed -- doing nothing")
+ // check invariant that there are no dups in the pkg database
+ let dir = mkdtemp(&os::tmpdir(), "install_remove").expect("install_remove");
+ let foo = PkgId::new("foo");
+ create_local_package_in(&foo, &dir);
+
+ command_line_test([~"install", ~"foo"], &dir);
+ command_line_test([~"install", ~"foo"], &dir);
+ let mut contents = ~[];
+ let check_dups = |p: &PkgId| {
+ if contents.contains(p) {
+ fail!("package database contains duplicate ID");
+ }
+ else {
+ contents.push(copy *p);
+ }
+ false
+ };
+ list_installed_packages(check_dups);
}
#[test]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f() -> int { 42 }
+pub fn f() -> int { 42 }
* install-paths/build/install_pathsbench exists and is an executable
*/
-fn main() {}
+use lib::f;
+
+mod lib;
+
+fn main() {
+ let _ = f();
+}
io::println("Usage: rustpkg [options] <cmd> [args..]
Where <cmd> is one of:
- build, clean, do, info, install, prefer, test, uninstall, unprefer
+ build, clean, do, info, install, list, prefer, test, uninstall, unprefer
Options:
-j, --json Output the result as JSON");
}
+pub fn list() {
+ io::println("rustpkg list
+
+List all installed packages.");
+}
+
pub fn install() {
io::println("rustpkg [options..] install [url] [target]
use path_util::target_library_in_workspace;
pub use target::{OutputType, Main, Lib, Bench, Test};
+// It would be nice to have the list of commands in just one place -- for example,
+// you could update the match in rustpkg.rc but forget to update this list. I think
+// that should be fixed.
static COMMANDS: &'static [&'static str] =
- &["build", "clean", "do", "info", "install", "prefer", "test", "uninstall",
+ &["build", "clean", "do", "info", "install", "list", "prefer", "test", "uninstall",
"unprefer"];
@fold.fold_crate(crate)
}
-pub fn need_dir(s: &Path) {
- if !os::path_is_dir(s) && !os::make_dir(s, 493_i32) {
- fail!("can't create dir: %s", s.to_str());
- }
-}
-
// FIXME (#4432): Use workcache to only compile when needed
pub fn compile_input(ctxt: &Ctx,
pkg_id: &PkgId,
use package_path::RemotePath;
use extra::tempfile::mkdtemp;
-#[deriving(Eq)]
pub enum Version {
ExactRevision(~str), // Should look like a m.n.(...).x
SemanticVersion(semver::Version),
NoVersion // user didn't specify a version -- prints as 0.1
}
+impl Eq for Version {
+ fn eq(&self, other: &Version) -> bool {
+ match (self, other) {
+ (&ExactRevision(ref s1), &ExactRevision(ref s2)) => *s1 == *s2,
+ (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => *v1 == *v2,
+ (&NoVersion, _) => true,
+ _ => false
+ }
+ }
+ fn ne(&self, other: &Version) -> bool {
+ !self.eq(other)
+ }
+}
impl Ord for Version {
fn lt(&self, other: &Version) -> bool {