2013-02-28 07:15:32 -06:00
|
|
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
2013-01-14 04:55:47 -06:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
// rustpkg - a purely function package manager and build system
|
|
|
|
|
|
|
|
#[link(name = "rustpkg",
|
|
|
|
vers = "0.6",
|
|
|
|
uuid = "25de5e6e-279e-4a20-845c-4cabae92daaf",
|
|
|
|
url = "https://github.com/mozilla/rust/tree/master/src/librustpkg")];
|
|
|
|
|
2013-03-01 10:41:31 -06:00
|
|
|
#[license = "MIT/ASL2"];
|
2013-01-14 04:55:47 -06:00
|
|
|
#[crate_type = "lib"];
|
|
|
|
#[no_core];
|
2013-01-16 05:59:37 -06:00
|
|
|
#[allow(vecs_implicitly_copyable,
|
|
|
|
non_implicitly_copyable_typarams)];
|
2013-01-14 04:55:47 -06:00
|
|
|
|
|
|
|
extern mod core(vers = "0.6");
|
|
|
|
extern mod std(vers = "0.6");
|
|
|
|
extern mod rustc(vers = "0.6");
|
|
|
|
extern mod syntax(vers = "0.6");
|
|
|
|
|
2013-01-15 07:57:03 -06:00
|
|
|
use core::*;
|
2013-03-01 12:44:43 -06:00
|
|
|
use core::hashmap::linear::LinearMap;
|
|
|
|
use core::io::{ReaderUtil, WriterUtil};
|
2013-01-18 02:31:43 -06:00
|
|
|
use rustc::driver::{driver, session};
|
2013-03-01 12:44:43 -06:00
|
|
|
use rustc::metadata::filesearch;
|
|
|
|
use std::net::url;
|
|
|
|
use std::{json, semver, getopts};
|
2013-02-04 19:12:31 -06:00
|
|
|
use syntax::codemap::spanned;
|
2013-03-01 12:44:43 -06:00
|
|
|
use syntax::{ast, attr, codemap, diagnostic, parse, visit};
|
2013-03-05 16:49:03 -06:00
|
|
|
use core::container::Map;
|
2013-01-14 04:55:47 -06:00
|
|
|
|
2013-01-15 07:57:03 -06:00
|
|
|
mod usage;
|
|
|
|
mod util;
|
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
use util::Package;
|
|
|
|
|
2013-01-16 05:59:37 -06:00
|
|
|
struct PackageScript {
|
|
|
|
id: ~str,
|
|
|
|
name: ~str,
|
2013-01-23 03:25:03 -06:00
|
|
|
vers: semver::Version,
|
2013-01-17 03:05:19 -06:00
|
|
|
crates: ~[~str],
|
2013-01-22 19:19:13 -06:00
|
|
|
deps: ~[(~str, Option<~str>)],
|
|
|
|
input: driver::input,
|
|
|
|
sess: session::Session,
|
|
|
|
cfg: ast::crate_cfg,
|
|
|
|
crate: @ast::crate,
|
|
|
|
custom: bool
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PackageScript {
|
2013-03-22 14:56:10 -05:00
|
|
|
fn parse(parent: &Path) -> Result<PackageScript, ~str> {
|
2013-01-25 20:08:31 -06:00
|
|
|
let script = parent.push(~"pkg.rs");
|
2013-01-16 05:59:37 -06:00
|
|
|
|
|
|
|
if !os::path_exists(&script) {
|
2013-01-25 20:08:31 -06:00
|
|
|
return result::Err(~"no pkg.rs file");
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
let binary = os::args()[0];
|
2013-02-19 02:01:03 -06:00
|
|
|
let options = @session::options {
|
2013-01-22 19:19:13 -06:00
|
|
|
binary: binary,
|
|
|
|
crate_type: session::bin_crate,
|
|
|
|
.. *session::basic_options()
|
|
|
|
};
|
|
|
|
let input = driver::file_input(script);
|
|
|
|
let sess = driver::build_session(options, diagnostic::emit);
|
|
|
|
let cfg = driver::build_configuration(sess, binary, input);
|
2013-02-19 02:01:03 -06:00
|
|
|
let (crate, _) = driver::compile_upto(sess, cfg, input,
|
2013-01-22 19:19:13 -06:00
|
|
|
driver::cu_parse, None);
|
2013-01-16 05:59:37 -06:00
|
|
|
let mut id = None;
|
|
|
|
let mut vers = None;
|
2013-01-17 03:05:19 -06:00
|
|
|
let mut crates = ~[];
|
|
|
|
let mut deps = ~[];
|
2013-01-16 05:59:37 -06:00
|
|
|
|
|
|
|
fn load_pkg_attr(mis: ~[@ast::meta_item]) -> (Option<~str>,
|
|
|
|
Option<~str>) {
|
|
|
|
let mut id = None;
|
|
|
|
let mut vers = None;
|
|
|
|
|
|
|
|
for mis.each |a| {
|
|
|
|
match a.node {
|
2013-02-04 19:12:31 -06:00
|
|
|
ast::meta_name_value(v, spanned {
|
2013-01-16 05:59:37 -06:00
|
|
|
node: ast::lit_str(s),
|
|
|
|
span: _}) => {
|
2013-02-14 09:34:21 -06:00
|
|
|
match *v {
|
2013-01-16 05:59:37 -06:00
|
|
|
~"id" => id = Some(*s),
|
|
|
|
~"vers" => vers = Some(*s),
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(id, vers)
|
|
|
|
}
|
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
fn load_pkg_dep_attr(mis: ~[@ast::meta_item]) -> (Option<~str>,
|
|
|
|
Option<~str>) {
|
|
|
|
let mut url = None;
|
|
|
|
let mut target = None;
|
|
|
|
|
|
|
|
for mis.each |a| {
|
|
|
|
match a.node {
|
2013-02-04 19:12:31 -06:00
|
|
|
ast::meta_name_value(v, spanned {
|
2013-01-17 03:05:19 -06:00
|
|
|
node: ast::lit_str(s),
|
|
|
|
span: _}) => {
|
2013-02-14 09:34:21 -06:00
|
|
|
match *v {
|
2013-01-17 03:05:19 -06:00
|
|
|
~"url" => url = Some(*s),
|
|
|
|
~"target" => target = Some(*s),
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(url, target)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn load_pkg_crate_attr(mis: ~[@ast::meta_item]) -> Option<~str> {
|
|
|
|
let mut file = None;
|
|
|
|
|
|
|
|
for mis.each |a| {
|
|
|
|
match a.node {
|
2013-02-04 19:12:31 -06:00
|
|
|
ast::meta_name_value(v, spanned {
|
2013-01-17 03:05:19 -06:00
|
|
|
node: ast::lit_str(s),
|
|
|
|
span: _}) => {
|
2013-02-14 09:34:21 -06:00
|
|
|
match *v {
|
2013-01-17 03:05:19 -06:00
|
|
|
~"file" => file = Some(*s),
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file
|
|
|
|
}
|
|
|
|
|
2013-01-16 05:59:37 -06:00
|
|
|
for crate.node.attrs.each |a| {
|
|
|
|
match a.node.value.node {
|
|
|
|
ast::meta_list(v, mis) => {
|
2013-02-14 09:34:21 -06:00
|
|
|
match *v {
|
2013-01-16 05:59:37 -06:00
|
|
|
~"pkg" => {
|
|
|
|
let (i, v) = load_pkg_attr(mis);
|
|
|
|
|
|
|
|
id = i;
|
|
|
|
vers = v;
|
|
|
|
}
|
2013-01-17 03:05:19 -06:00
|
|
|
~"pkg_dep" => {
|
|
|
|
let (u, t) = load_pkg_dep_attr(mis);
|
|
|
|
|
|
|
|
if u.is_none() {
|
2013-02-04 19:12:31 -06:00
|
|
|
fail!(~"pkg_dep attr without a url value");
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
deps.push((u.get(), t));
|
|
|
|
}
|
|
|
|
~"pkg_crate" => {
|
|
|
|
let f = load_pkg_crate_attr(mis);
|
|
|
|
|
|
|
|
if f.is_none() {
|
2013-02-04 19:12:31 -06:00
|
|
|
fail!(~"pkg_file attr without a file value");
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
crates.push(f.get());
|
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
let mut custom = false;
|
|
|
|
|
|
|
|
// If we hit a function, we assume they want to use
|
|
|
|
// the build API.
|
|
|
|
for crate.node.module.items.each |i| {
|
|
|
|
match i.node {
|
2013-01-22 20:41:11 -06:00
|
|
|
ast::item_fn(_, _, _, _) => {
|
|
|
|
custom = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2013-01-22 19:19:13 -06:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-16 05:59:37 -06:00
|
|
|
if id.is_none() || vers.is_none() {
|
2013-01-22 19:19:13 -06:00
|
|
|
return result::Err(~"pkg attr without (id, vers) values");
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
let id = id.get();
|
2013-01-19 03:59:19 -06:00
|
|
|
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)
|
|
|
|
};
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
result::Ok(PackageScript {
|
2013-01-16 05:59:37 -06:00
|
|
|
id: id,
|
2013-01-19 03:59:19 -06:00
|
|
|
name: name,
|
|
|
|
vers: vers,
|
2013-01-17 03:05:19 -06:00
|
|
|
crates: crates,
|
2013-01-22 19:19:13 -06:00
|
|
|
deps: deps,
|
|
|
|
input: input,
|
|
|
|
sess: sess,
|
|
|
|
cfg: cfg,
|
|
|
|
crate: crate,
|
|
|
|
custom: custom
|
2013-01-18 02:31:43 -06:00
|
|
|
})
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
// Build the bootstrap and run a command
|
2013-01-23 03:25:03 -06:00
|
|
|
// FIXME (#4432): Use workcache to only compile the script when changed
|
2013-02-04 19:12:31 -06:00
|
|
|
fn run(&self, cmd: ~str, test: bool) -> int {
|
2013-01-22 19:19:13 -06:00
|
|
|
let work_dir = self.work_dir();
|
|
|
|
let input = self.input;
|
|
|
|
let sess = self.sess;
|
|
|
|
let cfg = self.cfg;
|
|
|
|
let crate = util::ready_crate(sess, self.crate);
|
|
|
|
let outputs = driver::build_output_filenames(input, &Some(work_dir),
|
|
|
|
&None, sess);
|
2013-01-26 06:00:39 -06:00
|
|
|
let exe = work_dir.push(~"pkg" + util::exe_suffix());
|
2013-01-22 20:41:11 -06:00
|
|
|
let root = filesearch::get_rustpkg_sysroot().get().pop().pop();
|
2013-01-22 19:19:13 -06:00
|
|
|
|
|
|
|
driver::compile_rest(sess, cfg, driver::cu_parse,
|
2013-01-26 06:00:39 -06:00
|
|
|
Some(outputs), Some(crate));
|
|
|
|
run::run_program(exe.to_str(), ~[root.to_str(), cmd, test.to_str()])
|
2013-01-22 19:19:13 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn hash(&self) -> ~str {
|
2013-01-22 19:19:13 -06:00
|
|
|
fmt!("%s-%s-%s", self.name, util::hash(self.id + self.vers.to_str()),
|
|
|
|
self.vers.to_str())
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn work_dir(&self) -> Path {
|
2013-01-17 03:05:19 -06:00
|
|
|
util::root().push(~"work").push(self.hash())
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Ctx {
|
2013-01-22 19:19:13 -06:00
|
|
|
cfgs: ~[~str],
|
2013-01-26 02:35:10 -06:00
|
|
|
json: bool,
|
2013-02-21 20:41:33 -06:00
|
|
|
dep_cache: @mut LinearMap<~str, bool>
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Ctx {
|
2013-02-04 19:12:31 -06:00
|
|
|
fn run(&self, cmd: ~str, args: ~[~str]) {
|
2013-01-17 03:05:19 -06:00
|
|
|
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"));
|
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
fn sep_name_vers(in: ~str) -> (Option<~str>, Option<~str>) {
|
|
|
|
let mut name = None;
|
|
|
|
let mut vers = None;
|
|
|
|
|
2013-03-25 22:39:10 -05:00
|
|
|
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; }
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
(name, vers)
|
|
|
|
}
|
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
match cmd {
|
2013-01-22 19:19:13 -06:00
|
|
|
~"build" => {
|
|
|
|
self.build(&os::getcwd(), true, false, false);
|
|
|
|
}
|
|
|
|
~"clean" => {
|
|
|
|
self.clean();
|
|
|
|
}
|
2013-01-22 20:41:11 -06:00
|
|
|
~"do" => {
|
|
|
|
if args.len() < 1 {
|
|
|
|
return usage::do_cmd();
|
|
|
|
}
|
|
|
|
|
|
|
|
self.do_cmd(args[0]);
|
|
|
|
}
|
2013-01-26 02:35:10 -06:00
|
|
|
~"info" => {
|
|
|
|
self.info();
|
|
|
|
}
|
2013-01-18 02:31:43 -06:00
|
|
|
~"install" => {
|
|
|
|
self.install(if args.len() >= 1 { Some(args[0]) }
|
2013-01-23 00:38:05 -06:00
|
|
|
else { None },
|
2013-01-18 02:31:43 -06:00
|
|
|
if args.len() >= 2 { Some(args[1]) }
|
2013-01-22 19:19:13 -06:00
|
|
|
else { None }, false);
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
|
|
|
~"prefer" => {
|
|
|
|
if args.len() < 1 {
|
|
|
|
return usage::uninstall();
|
|
|
|
}
|
|
|
|
|
|
|
|
let (name, vers) = sep_name_vers(args[0]);
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
self.prefer(name.get(), vers);
|
|
|
|
}
|
|
|
|
~"test" => {
|
|
|
|
self.test();
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
|
|
|
~"uninstall" => {
|
|
|
|
if args.len() < 1 {
|
|
|
|
return usage::uninstall();
|
|
|
|
}
|
|
|
|
|
|
|
|
let (name, vers) = sep_name_vers(args[0]);
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
self.uninstall(name.get(), vers);
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
|
|
|
~"unprefer" => {
|
|
|
|
if args.len() < 1 {
|
|
|
|
return usage::uninstall();
|
|
|
|
}
|
|
|
|
|
|
|
|
let (name, vers) = sep_name_vers(args[0]);
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
self.unprefer(name.get(), vers);
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
2013-02-04 19:12:31 -06:00
|
|
|
_ => fail!(~"reached an unhandled command")
|
2013-01-22 19:19:13 -06:00
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn do_cmd(&self, cmd: ~str) -> bool {
|
2013-01-26 06:00:39 -06:00
|
|
|
match cmd {
|
|
|
|
~"build" | ~"test" => {
|
|
|
|
util::error(~"that command cannot be manually called");
|
2013-01-22 20:41:11 -06:00
|
|
|
|
2013-01-26 06:00:39 -06:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
_ => {}
|
2013-01-22 20:41:11 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
let cwd = &os::getcwd();
|
|
|
|
let script = match PackageScript::parse(cwd) {
|
|
|
|
result::Ok(script) => script,
|
|
|
|
result::Err(err) => {
|
|
|
|
util::error(err);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
2013-01-26 06:00:39 -06:00
|
|
|
let status = script.run(cmd, false);
|
2013-01-22 20:41:11 -06:00
|
|
|
|
2013-01-26 06:00:39 -06:00
|
|
|
if status == 42 {
|
2013-01-22 20:41:11 -06:00
|
|
|
util::error(~"no fns are listening for that cmd");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
status == 0
|
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn build(&self, dir: &Path, verbose: bool, opt: bool,
|
2013-01-22 19:19:13 -06:00
|
|
|
test: bool) -> Option<PackageScript> {
|
|
|
|
let cwd = &os::getcwd();
|
2013-01-18 02:31:43 -06:00
|
|
|
let script = match PackageScript::parse(dir) {
|
|
|
|
result::Ok(script) => script,
|
|
|
|
result::Err(err) => {
|
|
|
|
util::error(err);
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
return None;
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let work_dir = script.work_dir();
|
2013-01-17 03:05:19 -06:00
|
|
|
let mut success = true;
|
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
util::need_dir(&work_dir);
|
2013-01-17 03:05:19 -06:00
|
|
|
|
|
|
|
if script.deps.len() >= 1 {
|
2013-01-18 02:31:43 -06:00
|
|
|
util::note(~"installing dependencies");
|
2013-01-17 03:05:19 -06:00
|
|
|
|
|
|
|
for script.deps.each |&dep| {
|
|
|
|
let (url, target) = dep;
|
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
success = self.install(Some(url), target, true);
|
2013-01-17 03:05:19 -06:00
|
|
|
|
|
|
|
if !success { break; }
|
|
|
|
}
|
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
if !success {
|
2013-01-23 00:38:05 -06:00
|
|
|
util::error(
|
|
|
|
fmt!("building %s v%s failed: a dep wasn't installed",
|
|
|
|
script.name, script.vers.to_str()));
|
2013-01-17 03:05:19 -06:00
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
return None;
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
util::note(~"installed dependencies");
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
// Build imperative crates
|
|
|
|
os::change_dir(dir);
|
2013-01-17 03:05:19 -06:00
|
|
|
|
2013-01-26 06:00:39 -06:00
|
|
|
if script.custom {
|
|
|
|
let status = script.run(~"build", test);
|
2013-01-17 03:05:19 -06:00
|
|
|
|
2013-01-26 06:00:39 -06:00
|
|
|
if status != 0 && status != 42 {
|
|
|
|
util::error(
|
|
|
|
fmt!("building %s v%s failed: custom logic failed (%d)",
|
|
|
|
script.name, script.vers.to_str(), status));
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
os::change_dir(cwd);
|
2013-01-18 02:31:43 -06:00
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
for script.crates.each |&crate| {
|
|
|
|
let crate = &dir.push_rel(&Path(crate)).normalize();
|
2013-01-18 02:31:43 -06:00
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
util::note(fmt!("compiling %s", crate.to_str()));
|
2013-01-18 02:31:43 -06:00
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
success = self.compile(crate, &work_dir, ~[],
|
|
|
|
~[], opt, test);
|
2013-01-18 02:31:43 -06:00
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
if !success { break; }
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
if !success {
|
2013-01-23 00:38:05 -06:00
|
|
|
util::error(
|
|
|
|
fmt!("building %s v%s failed: a crate failed to compile",
|
|
|
|
script.name, script.vers.to_str()));
|
2013-01-18 02:31:43 -06:00
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
return None;
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
2013-01-18 02:31:43 -06:00
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
if verbose {
|
2013-01-23 00:38:05 -06:00
|
|
|
util::note(fmt!("built %s v%s", script.name,
|
|
|
|
script.vers.to_str()));
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
Some(script)
|
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn compile(&self, crate: &Path, dir: &Path, flags: ~[~str],
|
2013-01-22 19:19:13 -06:00
|
|
|
cfgs: ~[~str], opt: bool, test: bool) -> bool {
|
2013-01-22 20:41:11 -06:00
|
|
|
util::compile_crate(None, crate, dir, flags, cfgs, opt, test)
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn clean(&self) -> bool {
|
2013-01-22 19:19:13 -06:00
|
|
|
let script = match PackageScript::parse(&os::getcwd()) {
|
2013-01-18 02:31:43 -06:00
|
|
|
result::Ok(script) => script,
|
|
|
|
result::Err(err) => {
|
|
|
|
util::error(err);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
2013-01-17 03:05:19 -06:00
|
|
|
let dir = script.work_dir();
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
util::note(fmt!("cleaning %s v%s (%s)", script.name,
|
|
|
|
script.vers.to_str(), script.id));
|
2013-01-17 03:05:19 -06:00
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
if os::path_exists(&dir) {
|
|
|
|
util::remove_dir_r(&dir);
|
|
|
|
util::note(fmt!("removed %s", dir.to_str()));
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
util::note(fmt!("cleaned %s v%s", script.name,
|
|
|
|
script.vers.to_str()));
|
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
true
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn info(&self) {
|
2013-01-26 02:35:10 -06:00
|
|
|
if self.json {
|
|
|
|
match PackageScript::parse(&os::getcwd()) {
|
|
|
|
result::Ok(script) => {
|
2013-02-04 19:12:31 -06:00
|
|
|
let mut map = ~LinearMap::new();
|
2013-01-26 02:35:10 -06:00
|
|
|
|
|
|
|
map.insert(~"id", json::String(script.id));
|
|
|
|
map.insert(~"name", json::String(script.name));
|
|
|
|
map.insert(~"vers", json::String(script.vers.to_str()));
|
|
|
|
map.insert(~"deps", json::List(do script.deps.map |&dep| {
|
|
|
|
let (url, target) = dep;
|
2013-02-04 19:12:31 -06:00
|
|
|
let mut inner = ~LinearMap::new();
|
2013-01-26 02:35:10 -06:00
|
|
|
|
|
|
|
inner.insert(~"url", json::String(url));
|
|
|
|
|
|
|
|
if !target.is_none() {
|
2013-02-04 19:12:31 -06:00
|
|
|
inner.insert(~"target",
|
|
|
|
json::String(target.get()));
|
2013-01-26 02:35:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
json::Object(inner)
|
|
|
|
}));
|
|
|
|
|
|
|
|
io::println(json::to_pretty_str(&json::Object(map)));
|
|
|
|
}
|
|
|
|
result::Err(_) => io::println(~"{}")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let script = match PackageScript::parse(&os::getcwd()) {
|
|
|
|
result::Ok(script) => script,
|
|
|
|
result::Err(err) => {
|
|
|
|
util::error(err);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
util::note(fmt!("id: %s", script.id));
|
|
|
|
util::note(fmt!("name: %s", script.name));
|
|
|
|
util::note(fmt!("vers: %s", script.vers.to_str()));
|
2013-02-04 19:12:31 -06:00
|
|
|
util::note(fmt!("deps: %s",
|
|
|
|
if script.deps.len() > 0 {
|
|
|
|
~""
|
|
|
|
} else {
|
|
|
|
~"none"
|
|
|
|
}));
|
2013-01-26 02:35:10 -06:00
|
|
|
|
|
|
|
for script.deps.each |&dep| {
|
|
|
|
let (url, target) = dep;
|
|
|
|
|
|
|
|
util::note(fmt!(" <%s> (%s)", url, match target {
|
|
|
|
Some(target) => target,
|
|
|
|
None => ~""
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn install(&self, url: Option<~str>,
|
|
|
|
target: Option<~str>, cache: bool) -> bool {
|
2013-01-23 00:38:05 -06:00
|
|
|
let mut success;
|
2013-01-17 03:05:19 -06:00
|
|
|
let mut dir;
|
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
if url.is_none() {
|
|
|
|
util::note(~"installing from the cwd");
|
2013-01-17 03:05:19 -06:00
|
|
|
|
|
|
|
dir = os::getcwd();
|
|
|
|
} else {
|
2013-01-18 02:31:43 -06:00
|
|
|
let url = url.get();
|
2013-01-22 19:19:13 -06:00
|
|
|
let hash = util::hash(if !target.is_none() { url + target.get() }
|
|
|
|
else { url });
|
2013-01-17 03:05:19 -06:00
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
if self.dep_cache.contains_key(&hash) {
|
|
|
|
util::warn(~"already installed dep this run");
|
2013-01-17 03:05:19 -06:00
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
return true;
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
self.dep_cache.insert(hash, true);
|
|
|
|
|
|
|
|
dir = util::root().push(~"tmp").push(hash);
|
2013-01-18 02:31:43 -06:00
|
|
|
|
|
|
|
if cache && os::path_exists(&dir) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
success = self.fetch(&dir, url, target);
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
if !success {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
let script = match self.build(&dir, false, true, false) {
|
|
|
|
Some(script) => script,
|
|
|
|
None => {
|
2013-01-18 02:31:43 -06:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let work_dir = script.work_dir();
|
2013-01-19 03:59:19 -06:00
|
|
|
let from_bin_dir = work_dir.push(~"bin");
|
|
|
|
let from_lib_dir = work_dir.push(~"lib");
|
2013-01-18 02:31:43 -06:00
|
|
|
let to_bin_dir = util::root().push(~"bin");
|
|
|
|
let to_lib_dir = util::root().push(~"lib");
|
2013-01-19 03:59:19 -06:00
|
|
|
let mut bins = ~[];
|
|
|
|
let mut libs = ~[];
|
2013-01-18 02:31:43 -06:00
|
|
|
|
|
|
|
for os::walk_dir(&from_bin_dir) |bin| {
|
|
|
|
let to = to_bin_dir.push_rel(&bin.file_path());
|
|
|
|
|
|
|
|
os::copy_file(bin, &to);
|
2013-01-19 03:59:19 -06:00
|
|
|
bins.push(to.to_str());
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
2013-01-19 03:59:19 -06:00
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
for os::walk_dir(&from_lib_dir) |lib| {
|
|
|
|
let to = to_lib_dir.push_rel(&lib.file_path());
|
|
|
|
|
|
|
|
os::copy_file(lib, &to);
|
2013-01-19 03:59:19 -06:00
|
|
|
libs.push(to.to_str());
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
let package = Package {
|
|
|
|
id: script.id,
|
|
|
|
vers: script.vers,
|
|
|
|
bins: bins,
|
|
|
|
libs: libs
|
|
|
|
};
|
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
util::note(fmt!("installed %s v%s", script.name,
|
2013-01-17 03:05:19 -06:00
|
|
|
script.vers.to_str()));
|
2013-01-19 03:59:19 -06:00
|
|
|
util::add_pkg(&package);
|
2013-01-17 03:05:19 -06:00
|
|
|
|
|
|
|
true
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn fetch(&self, dir: &Path, url: ~str, target: Option<~str>) -> bool {
|
2013-01-23 00:38:05 -06:00
|
|
|
let url = if str::find_str(url, "://").is_none() {
|
|
|
|
~"http://" + url }
|
|
|
|
else { url };
|
|
|
|
let url = match url::from_str(url) {
|
2013-01-18 02:31:43 -06:00
|
|
|
result::Ok(url) => url,
|
|
|
|
result::Err(err) => {
|
|
|
|
util::error(fmt!("failed parsing %s", err.to_lower()));
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let str = url.to_str();
|
|
|
|
|
|
|
|
match Path(url.path).filetype() {
|
|
|
|
Some(ext) => {
|
|
|
|
if ext == ~".git" {
|
|
|
|
return self.fetch_git(dir, str, target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
match url.scheme {
|
|
|
|
~"git" => self.fetch_git(dir, str, target),
|
|
|
|
~"http" | ~"ftp" | ~"file" => self.fetch_curl(dir, str),
|
|
|
|
_ => {
|
|
|
|
util::warn(~"unknown url scheme to fetch, using curl");
|
|
|
|
self.fetch_curl(dir, str)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn fetch_curl(&self, dir: &Path, url: ~str) -> bool {
|
2013-01-18 02:31:43 -06:00
|
|
|
util::note(fmt!("fetching from %s using curl", url));
|
|
|
|
|
|
|
|
let tar = dir.dir_path().push(&dir.file_path().to_str() + ~".tar");
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
if run::program_output(~"curl", ~[~"-f", ~"-s",
|
|
|
|
~"-o", tar.to_str(),
|
|
|
|
url]).status != 0 {
|
2013-01-18 02:31:43 -06:00
|
|
|
util::error(~"fetching failed: downloading using curl failed");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
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?)");
|
2013-01-18 02:31:43 -06:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn fetch_git(&self, dir: &Path, url: ~str, target: Option<~str>) -> bool {
|
2013-01-18 02:31:43 -06:00
|
|
|
util::note(fmt!("fetching from %s using git", url));
|
|
|
|
|
|
|
|
// Git can't clone into a non-empty directory
|
2013-01-19 03:59:19 -06:00
|
|
|
util::remove_dir_r(dir);
|
2013-01-18 02:31:43 -06:00
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
if run::program_output(~"git", ~[~"clone", url,
|
|
|
|
dir.to_str()]).status != 0 {
|
2013-01-18 02:31:43 -06:00
|
|
|
util::error(~"fetching failed: can't clone repository");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if !target.is_none() {
|
|
|
|
let mut success = true;
|
|
|
|
|
|
|
|
do util::temp_change_dir(dir) {
|
2013-01-23 00:38:05 -06:00
|
|
|
success = run::program_output(~"git",
|
|
|
|
~[~"checkout",
|
|
|
|
target.get()]).status != 0
|
2013-01-18 02:31:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if !success {
|
|
|
|
util::error(~"fetching failed: can't checkout target");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
true
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn prefer(&self, id: ~str, vers: Option<~str>) -> bool {
|
2013-01-19 03:59:19 -06:00
|
|
|
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);
|
2013-03-25 22:39:10 -05:00
|
|
|
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());
|
2013-01-19 03:59:19 -06:00
|
|
|
|
|
|
|
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()));
|
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
true
|
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn test(&self) -> bool {
|
2013-01-22 19:19:13 -06:00
|
|
|
let script = match self.build(&os::getcwd(), false, false, true) {
|
|
|
|
Some(script) => script,
|
|
|
|
None => {
|
|
|
|
return false;
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let work_dir = script.work_dir();
|
|
|
|
let test_dir = work_dir.push(~"test");
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-26 06:00:39 -06:00
|
|
|
// Run custom test listener
|
|
|
|
if script.custom {
|
|
|
|
let status = script.run(~"test", false);
|
|
|
|
|
|
|
|
if status != 0 && status != 42 {
|
|
|
|
util::error(
|
|
|
|
fmt!("testing %s v%s failed: custom logic failed (%d)",
|
|
|
|
script.name, script.vers.to_str(), status));
|
|
|
|
|
|
|
|
os::set_exit_status(status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
util::note(fmt!("tested %s v%s", script.name, script.vers.to_str()));
|
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
true
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn uninstall(&self, id: ~str, vers: Option<~str>) -> bool {
|
2013-01-19 03:59:19 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
util::note(fmt!("uninstalling %s v%s (%s)", name,
|
|
|
|
package.vers.to_str(), package.id));
|
2013-01-19 03:59:19 -06:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
true
|
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
fn unprefer(&self, id: ~str, vers: Option<~str>) -> bool {
|
2013-01-19 03:59:19 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
util::note(fmt!("unpreferring %s v%s (%s)", name,
|
|
|
|
package.vers.to_str(), package.id));
|
2013-01-19 03:59:19 -06:00
|
|
|
|
|
|
|
let bin_dir = util::root().push(~"bin");
|
|
|
|
|
|
|
|
for package.bins.each |&bin| {
|
|
|
|
let path = Path(bin);
|
2013-03-25 22:39:10 -05:00
|
|
|
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());
|
2013-01-19 03:59:19 -06:00
|
|
|
|
|
|
|
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()));
|
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
true
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
}
|
2013-01-15 07:57:03 -06:00
|
|
|
|
2013-01-14 04:55:47 -06:00
|
|
|
pub fn main() {
|
2013-03-20 13:44:01 -05:00
|
|
|
io::println("WARNING: The Rust package manager is experimental and may");
|
|
|
|
io::println("be unstable.");
|
|
|
|
|
2013-01-15 07:57:03 -06:00
|
|
|
let args = os::args();
|
2013-01-16 05:59:37 -06:00
|
|
|
let opts = ~[getopts::optflag(~"h"), getopts::optflag(~"help"),
|
2013-01-26 02:35:10 -06:00
|
|
|
getopts::optflag(~"j"), getopts::optflag(~"json"),
|
2013-01-19 03:59:19 -06:00
|
|
|
getopts::optmulti(~"c"), getopts::optmulti(~"cfg")];
|
2013-01-15 07:57:03 -06:00
|
|
|
let matches = &match getopts::getopts(args, opts) {
|
|
|
|
result::Ok(m) => m,
|
|
|
|
result::Err(f) => {
|
2013-01-19 03:59:19 -06:00
|
|
|
util::error(fmt!("%s", getopts::fail_str(f)));
|
|
|
|
|
|
|
|
return;
|
2013-01-15 07:57:03 -06:00
|
|
|
}
|
|
|
|
};
|
2013-01-16 05:59:37 -06:00
|
|
|
let help = getopts::opt_present(matches, ~"h") ||
|
|
|
|
getopts::opt_present(matches, ~"help");
|
2013-01-26 02:35:10 -06:00
|
|
|
let json = getopts::opt_present(matches, ~"j") ||
|
|
|
|
getopts::opt_present(matches, ~"json");
|
2013-01-22 19:19:13 -06:00
|
|
|
let cfgs = vec::append(getopts::opt_strs(matches, ~"cfg"),
|
2013-01-16 05:59:37 -06:00
|
|
|
getopts::opt_strs(matches, ~"c"));
|
2013-01-15 07:57:03 -06:00
|
|
|
let mut args = copy matches.free;
|
|
|
|
|
|
|
|
args.shift();
|
2013-01-14 04:55:47 -06:00
|
|
|
|
2013-01-15 07:57:03 -06:00
|
|
|
if (args.len() < 1) {
|
|
|
|
return usage::general();
|
|
|
|
}
|
|
|
|
|
2013-01-16 05:59:37 -06:00
|
|
|
let cmd = args.shift();
|
2013-01-15 07:57:03 -06:00
|
|
|
|
2013-01-16 05:59:37 -06:00
|
|
|
if !util::is_cmd(cmd) {
|
2013-01-15 07:57:03 -06:00
|
|
|
return usage::general();
|
|
|
|
} else if help {
|
2013-01-16 05:59:37 -06:00
|
|
|
return match cmd {
|
2013-01-15 07:57:03 -06:00
|
|
|
~"build" => usage::build(),
|
|
|
|
~"clean" => usage::clean(),
|
2013-01-22 20:41:11 -06:00
|
|
|
~"do" => usage::do_cmd(),
|
2013-01-26 02:35:10 -06:00
|
|
|
~"info" => usage::info(),
|
2013-01-15 07:57:03 -06:00
|
|
|
~"install" => usage::install(),
|
|
|
|
~"prefer" => usage::prefer(),
|
|
|
|
~"test" => usage::test(),
|
|
|
|
~"uninstall" => usage::uninstall(),
|
|
|
|
~"unprefer" => usage::unprefer(),
|
|
|
|
_ => usage::general()
|
2013-01-16 05:59:37 -06:00
|
|
|
};
|
2013-01-15 07:57:03 -06:00
|
|
|
}
|
|
|
|
|
2013-01-16 05:59:37 -06:00
|
|
|
Ctx {
|
2013-01-22 19:19:13 -06:00
|
|
|
cfgs: cfgs,
|
2013-01-26 02:35:10 -06:00
|
|
|
json: json,
|
2013-02-21 20:41:33 -06:00
|
|
|
dep_cache: @mut LinearMap::new()
|
2013-01-17 03:05:19 -06:00
|
|
|
}.run(cmd, args);
|
2013-01-14 04:55:47 -06:00
|
|
|
}
|
2013-01-15 07:57:03 -06:00
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
/// A crate is a unit of Rust code to be compiled into a binary or library
|
|
|
|
pub struct Crate {
|
|
|
|
file: ~str,
|
|
|
|
flags: ~[~str],
|
|
|
|
cfgs: ~[~str]
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Listener {
|
|
|
|
cmds: ~[~str],
|
2013-03-01 18:02:22 -06:00
|
|
|
cb: ~fn()
|
2013-01-23 00:38:05 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn run(listeners: ~[Listener]) {
|
|
|
|
let rcmd = 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 {
|
2013-01-26 06:00:39 -06:00
|
|
|
os::set_exit_status(42);
|
2013-01-23 00:38:05 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub impl Crate {
|
2013-02-04 19:12:31 -06:00
|
|
|
pub fn flag(&self, flag: ~str) -> Crate {
|
2013-01-23 00:38:05 -06:00
|
|
|
Crate {
|
|
|
|
flags: vec::append(copy self.flags, ~[flag]),
|
2013-02-04 19:12:31 -06:00
|
|
|
.. copy *self
|
2013-01-23 00:38:05 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
pub fn flags(&self, flags: ~[~str]) -> Crate {
|
2013-01-23 00:38:05 -06:00
|
|
|
Crate {
|
|
|
|
flags: vec::append(copy self.flags, flags),
|
2013-02-04 19:12:31 -06:00
|
|
|
.. copy *self
|
2013-01-23 00:38:05 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
pub fn cfg(&self, cfg: ~str) -> Crate {
|
2013-01-23 00:38:05 -06:00
|
|
|
Crate {
|
|
|
|
cfgs: vec::append(copy self.cfgs, ~[cfg]),
|
2013-02-04 19:12:31 -06:00
|
|
|
.. copy *self
|
2013-01-23 00:38:05 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
pub fn cfgs(&self, cfgs: ~[~str]) -> Crate {
|
2013-01-23 00:38:05 -06:00
|
|
|
Crate {
|
|
|
|
cfgs: vec::append(copy self.cfgs, cfgs),
|
2013-02-04 19:12:31 -06:00
|
|
|
.. copy *self
|
2013-01-23 00:38:05 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a crate target from a source file
|
|
|
|
pub fn Crate(file: ~str) -> Crate {
|
|
|
|
Crate {
|
|
|
|
file: file,
|
|
|
|
flags: ~[],
|
|
|
|
cfgs: ~[]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the working directory of the package script.
|
|
|
|
* Assumes that the package script has been compiled
|
|
|
|
* in is the working directory.
|
|
|
|
*/
|
2013-01-26 02:35:10 -06:00
|
|
|
pub fn work_dir() -> Path {
|
2013-01-23 00:38:05 -06:00
|
|
|
os::self_exe_path().get()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the source directory of the package (i.e.
|
|
|
|
* where the crates are located). Assumes
|
|
|
|
* that the cwd is changed to it before
|
|
|
|
* running this executable.
|
|
|
|
*/
|
2013-01-26 02:35:10 -06:00
|
|
|
pub fn src_dir() -> Path {
|
2013-01-23 00:38:05 -06:00
|
|
|
os::getcwd()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Build a set of crates, should be called once
|
|
|
|
pub fn build(crates: ~[Crate]) -> bool {
|
2013-01-26 06:00:39 -06:00
|
|
|
let args = os::args();
|
2013-01-23 00:38:05 -06:00
|
|
|
let dir = src_dir();
|
|
|
|
let work_dir = work_dir();
|
|
|
|
let mut success = true;
|
2013-01-26 06:00:39 -06:00
|
|
|
let sysroot = Path(args[1]);
|
|
|
|
let test = args[3] == ~"true";
|
2013-01-23 00:38:05 -06:00
|
|
|
|
|
|
|
for crates.each |&crate| {
|
|
|
|
let path = &dir.push_rel(&Path(crate.file)).normalize();
|
|
|
|
|
|
|
|
util::note(fmt!("compiling %s", path.to_str()));
|
|
|
|
|
|
|
|
success = util::compile_crate(Some(sysroot), path, &work_dir,
|
|
|
|
crate.flags, crate.cfgs,
|
2013-01-26 06:00:39 -06:00
|
|
|
false, test);
|
2013-01-23 00:38:05 -06:00
|
|
|
|
|
|
|
if !success { break; }
|
|
|
|
}
|
|
|
|
|
|
|
|
if !success {
|
2013-01-26 06:00:39 -06:00
|
|
|
os::set_exit_status(101);
|
2013-01-23 00:38:05 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
success
|
|
|
|
}
|