From f10a500844ea9778d81e478b977fdc43d3a33bed Mon Sep 17 00:00:00 2001 From: Tycho Sci Date: Sun, 5 Feb 2012 18:30:03 +0900 Subject: [PATCH 1/2] cargo: Add local mode and use it by default --- src/cargo/cargo.rs | 93 ++++++++++++++++++++++++------------- src/comp/util/filesearch.rs | 37 +++++++++++++++ 2 files changed, 99 insertions(+), 31 deletions(-) diff --git a/src/cargo/cargo.rs b/src/cargo/cargo.rs index 0acd3e4f1c8e5..0056059b1c8fb 100644 --- a/src/cargo/cargo.rs +++ b/src/cargo/cargo.rs @@ -5,7 +5,7 @@ use std; import rustc::syntax::{ast, codemap}; import rustc::syntax::parse::parser; -import rustc::util::filesearch::get_cargo_root; +import rustc::util::filesearch::{get_cargo_root, get_cargo_root_nearest}; import rustc::driver::diagnostic; import std::fs; @@ -19,6 +19,8 @@ import std::run; import str; import std::tempfile; import vec; +import std::getopts; +import getopts::{optflag, opt_present}; enum _src { /* Break cycles in package <-> source */ @@ -53,7 +55,7 @@ type cargo = { workdir: str, sourcedir: str, sources: map::hashmap, - mutable test: bool + opts: options }; type pkg = { @@ -65,6 +67,16 @@ type pkg = { crate_type: option }; +type options = { + test: bool, + cwd: bool, + free: [str], +}; + +fn opts() -> [getopts::opt] { + [optflag("g"), optflag("global"), optflag("test")] +} + fn info(msg: str) { io::stdout().write_line("info: " + msg); } @@ -322,8 +334,28 @@ fn load_source_packages(&c: cargo, &src: source) { }; } -fn configure() -> cargo { - let p = alt get_cargo_root() { +fn build_cargo_options(argv: [str]) -> options { + let match = alt getopts::getopts(argv, opts()) { + result::ok(m) { m } + result::err(f) { + fail #fmt["%s", getopts::fail_str(f)]; + } + }; + + let test = opt_present(match, "test"); + let cwd = !(opt_present(match, "g") || opt_present(match, "global")); + + {test: test, cwd: cwd, free: match.free} +} + +fn configure(opts: options) -> cargo { + let get_cargo_dir = if opts.cwd { + get_cargo_root_nearest + } else { + get_cargo_root + }; + + let p = alt get_cargo_dir() { result::ok(p) { p } result::err(e) { fail e } }; @@ -339,7 +371,7 @@ fn configure() -> cargo { workdir: fs::connect(p, "work"), sourcedir: fs::connect(p, "sources"), sources: sources, - mutable test: false + opts: opts }; need_dir(c.root); @@ -430,7 +462,7 @@ fn install_source(c: cargo, path: str) { alt p { none { cont; } some(_p) { - if c.test { + if c.opts.test { test_one_crate(c, path, cf, _p); } install_one_crate(c, path, cf, _p); @@ -573,19 +605,14 @@ fn install_named_specific(c: cargo, wd: str, src: str, name: str) { error("Can't find package " + src + "/" + name); } -fn cmd_install(c: cargo, argv: [str]) unsafe { +fn cmd_install(c: cargo) unsafe { // cargo install - if vec::len(argv) < 3u { + if vec::len(c.opts.free) < 3u { cmd_usage(); ret; } - let target = argv[2]; - // TODO: getopts - if vec::len(argv) > 3u && argv[2] == "--test" { - c.test = true; - target = argv[3]; - } + let target = c.opts.free[2]; let wd = alt tempfile::mkdtemp(c.workdir + fs::path_sep(), "") { some(_wd) { _wd } @@ -671,9 +698,9 @@ fn sync_one(c: cargo, name: str, src: source) { run::run_program("cp", [pkgfile, destpkgfile]); } -fn cmd_sync(c: cargo, argv: [str]) { - if vec::len(argv) == 3u { - sync_one(c, argv[2], c.sources.get(argv[2])); +fn cmd_sync(c: cargo) { + if vec::len(c.opts.free) == 3u { + sync_one(c, c.opts.free[2], c.sources.get(c.opts.free[2])); } else { cargo_suggestion(c, true, { || } ); c.sources.items { |k, v| @@ -721,22 +748,22 @@ fn print_pkg(s: source, p: package) { print(" >> " + p.description + "\n") } } -fn cmd_list(c: cargo, argv: [str]) { +fn cmd_list(c: cargo) { for_each_package(c, { |s, p| - if vec::len(argv) <= 2u || argv[2] == s.name { + if vec::len(c.opts.free) <= 2u || c.opts.free[2] == s.name { print_pkg(s, p); } }); } -fn cmd_search(c: cargo, argv: [str]) { - if vec::len(argv) < 3u { +fn cmd_search(c: cargo) { + if vec::len(c.opts.free) < 3u { cmd_usage(); ret; } let n = 0; - let name = argv[2]; - let tags = vec::slice(argv, 3u, vec::len(argv)); + let name = c.opts.free[2]; + let tags = vec::slice(c.opts.free, 3u, vec::len(c.opts.free)); for_each_package(c, { |s, p| if (str::contains(p.name, name) || name == "*") && vec::all(tags, { |t| vec::member(t, p.tags) }) { @@ -749,7 +776,7 @@ fn cmd_search(c: cargo, argv: [str]) { fn cmd_usage() { print("Usage: cargo [args...]"); - print(" init Set up ~/.cargo"); + print(" init Set up .cargo"); print(" install [--test] [source/]package-name Install by name"); print(" install [--test] uuid:[source/]package-uuid Install by uuid"); print(" list [source] List packages"); @@ -759,17 +786,21 @@ fn cmd_usage() { } fn main(argv: [str]) { - if vec::len(argv) < 2u { + let o = build_cargo_options(argv); + + if vec::len(o.free) < 2u { cmd_usage(); ret; } - let c = configure(); - alt argv[1] { + + let c = configure(o); + + alt o.free[1] { "init" { cmd_init(c); } - "install" { cmd_install(c, argv); } - "list" { cmd_list(c, argv); } - "search" { cmd_search(c, argv); } - "sync" { cmd_sync(c, argv); } + "install" { cmd_install(c); } + "list" { cmd_list(c); } + "search" { cmd_search(c); } + "sync" { cmd_sync(c); } "usage" { cmd_usage(); } _ { cmd_usage(); } } diff --git a/src/comp/util/filesearch.rs b/src/comp/util/filesearch.rs index 0e4c3671bf118..26b47004bead6 100644 --- a/src/comp/util/filesearch.rs +++ b/src/comp/util/filesearch.rs @@ -16,6 +16,7 @@ export pick_file; export search; export relative_target_lib_path; export get_cargo_root; +export get_cargo_root_nearest; export libdir; type pick = fn(path: fs::path) -> option; @@ -43,6 +44,10 @@ fn mk_filesearch(maybe_sysroot: option, fn lib_search_paths() -> [fs::path] { self.addl_lib_search_paths + [make_target_lib_path(self.sysroot, self.target_triple)] + + alt get_cargo_lib_path_nearest() { + result::ok(p) { [p] } + result::err(p) { [] } + } + alt get_cargo_lib_path() { result::ok(p) { [p] } result::err(p) { [] } @@ -121,12 +126,44 @@ fn get_cargo_root() -> result::t { } } +fn get_cargo_root_nearest() -> result::t { + result::chain(get_cargo_root()) { |p| + let cwd = os::getcwd(); + let dirname = fs::dirname(cwd); + let dirpath = fs::split(dirname); + let cwd_cargo = fs::connect(cwd, ".cargo"); + let par_cargo = fs::connect(dirname, ".cargo"); + + // FIXME: this duplicates lib path + if cwd_cargo == p { + ret result::ok(p); + } + + while vec::is_not_empty(dirpath) && par_cargo != p { + if fs::path_is_dir(par_cargo) { + ret result::ok(par_cargo); + } + vec::pop(dirpath); + dirname = fs::dirname(dirname); + par_cargo = fs::connect(dirname, ".cargo"); + } + + result::ok(cwd_cargo) + } +} + fn get_cargo_lib_path() -> result::t { result::chain(get_cargo_root()) { |p| result::ok(fs::connect(p, libdir())) } } +fn get_cargo_lib_path_nearest() -> result::t { + result::chain(get_cargo_root_nearest()) { |p| + result::ok(fs::connect(p, libdir())) + } +} + // The name of the directory rustc expects libraries to be located. // On Unix should be "lib", on windows "bin" fn libdir() -> str { From da5dd18d87d738b7d0f014c3738c9e07403e1cb2 Mon Sep 17 00:00:00 2001 From: Tycho Sci Date: Tue, 7 Feb 2012 17:15:39 +0900 Subject: [PATCH 2/2] cargo: 2 modes -> 3 modes, and clarify them * -g or --mode=user to create/use .cargo under $HOME * -G or --mode=system to create/use .cargo under sysroot * by default, `cargo` uses .cargo under current working directory --- src/cargo/cargo.rs | 78 +++++++++++++++++++++++++++---------- src/comp/util/filesearch.rs | 12 ++++-- 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/src/cargo/cargo.rs b/src/cargo/cargo.rs index 0056059b1c8fb..c168b2c45502c 100644 --- a/src/cargo/cargo.rs +++ b/src/cargo/cargo.rs @@ -5,7 +5,8 @@ use std; import rustc::syntax::{ast, codemap}; import rustc::syntax::parse::parser; -import rustc::util::filesearch::{get_cargo_root, get_cargo_root_nearest}; +import rustc::util::filesearch::{get_cargo_root, get_cargo_root_nearest, + get_cargo_sysroot}; import rustc::driver::diagnostic; import std::fs; @@ -20,7 +21,7 @@ import str; import std::tempfile; import vec; import std::getopts; -import getopts::{optflag, opt_present}; +import getopts::{optflag, optopt, opt_present}; enum _src { /* Break cycles in package <-> source */ @@ -69,12 +70,14 @@ type pkg = { type options = { test: bool, - cwd: bool, + mode: mode, free: [str], }; +enum mode { system_mode, user_mode, local_mode } + fn opts() -> [getopts::opt] { - [optflag("g"), optflag("global"), optflag("test")] + [optflag("g"), optflag("G"), optopt("mode"), optflag("test")] } fn info(msg: str) { @@ -343,21 +346,40 @@ fn build_cargo_options(argv: [str]) -> options { }; let test = opt_present(match, "test"); - let cwd = !(opt_present(match, "g") || opt_present(match, "global")); + let mode = if opt_present(match, "G") { + if opt_present(match, "mode") { fail "--mode and -G both provided"; } + if opt_present(match, "g") { fail "-G and -g both provided"; } + system_mode + } else if opt_present(match, "g") { + if opt_present(match, "mode") { fail "--mode and -g both provided"; } + if opt_present(match, "G") { fail "-G and -g both provided"; } + user_mode + } else if opt_present(match, "mode") { + alt getopts::opt_str(match, "mode") { + "system" { system_mode } + "user" { user_mode } + "local" { local_mode } + _ { fail "argument to `mode` must be one of `system`" + + ", `user`, or `normal`"; + } + } + } else { + local_mode + }; - {test: test, cwd: cwd, free: match.free} + {test: test, mode: mode, free: match.free} } fn configure(opts: options) -> cargo { - let get_cargo_dir = if opts.cwd { - get_cargo_root_nearest - } else { - get_cargo_root + let get_cargo_dir = alt opts.mode { + system_mode { get_cargo_sysroot } + user_mode { get_cargo_root } + local_mode { get_cargo_root_nearest } }; let p = alt get_cargo_dir() { - result::ok(p) { p } - result::err(e) { fail e } + result::ok(p) { p } + result::err(e) { fail e } }; let sources = map::new_str_hash::(); @@ -736,6 +758,8 @@ fn cmd_init(c: cargo) { } info(#fmt["signature ok for sources.json"]); run::run_program("cp", [srcfile, destsrcfile]); + + info(#fmt["Initialized .cargo in %s", c.root]); } fn print_pkg(s: source, p: package) { @@ -775,14 +799,28 @@ fn cmd_search(c: cargo) { } fn cmd_usage() { - print("Usage: cargo [args...]"); - print(" init Set up .cargo"); - print(" install [--test] [source/]package-name Install by name"); - print(" install [--test] uuid:[source/]package-uuid Install by uuid"); - print(" list [source] List packages"); - print(" search [tags...] Search packages"); - print(" sync Sync all sources"); - print(" usage This"); + print("Usage: cargo [options] [args...]" + + " + + init Set up .cargo + install [--test] [source/]package-name Install by name + install [--test] uuid:[source/]package-uuid Install by uuid + list [source] List packages + search [tags...] Search packages + sync Sync all sources + usage This + +Options: + + --mode=[system,user,local] change mode as (system/user/local) + -g equivalent to --mode=user + -G equivalent to --mode=system + +NOTE: +This command creates/uses local-level .cargo by default. +To create/use user-level .cargo, use option -g/--mode=user. +To create/use system-level .cargo, use option -G/--mode=system. +"); } fn main(argv: [str]) { diff --git a/src/comp/util/filesearch.rs b/src/comp/util/filesearch.rs index 26b47004bead6..a7419e6a14165 100644 --- a/src/comp/util/filesearch.rs +++ b/src/comp/util/filesearch.rs @@ -15,6 +15,7 @@ export pick; export pick_file; export search; export relative_target_lib_path; +export get_cargo_sysroot; export get_cargo_root; export get_cargo_root_nearest; export libdir; @@ -52,6 +53,8 @@ fn mk_filesearch(maybe_sysroot: option, result::ok(p) { [p] } result::err(p) { [] } } + + [fs::connect(fs::connect(self.sysroot, ".cargo"), + libdir())] } fn get_target_lib_path() -> fs::path { make_target_lib_path(self.sysroot, self.target_triple) @@ -114,6 +117,10 @@ fn get_sysroot(maybe_sysroot: option) -> fs::path { } } +fn get_cargo_sysroot() -> result::t { + result::ok(fs::connect(get_default_sysroot(), ".cargo")) +} + fn get_cargo_root() -> result::t { alt generic_os::getenv("CARGO_ROOT") { some(_p) { result::ok(_p) } @@ -134,9 +141,8 @@ fn get_cargo_root_nearest() -> result::t { let cwd_cargo = fs::connect(cwd, ".cargo"); let par_cargo = fs::connect(dirname, ".cargo"); - // FIXME: this duplicates lib path - if cwd_cargo == p { - ret result::ok(p); + if fs::path_is_dir(cwd_cargo) || cwd_cargo == p { + ret result::ok(cwd_cargo); } while vec::is_not_empty(dirpath) && par_cargo != p {