2013-01-22 19:19:13 -06:00
|
|
|
// Copyright 2012 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.
|
|
|
|
|
2013-01-16 05:59:37 -06:00
|
|
|
use core::*;
|
2013-03-26 15:38:07 -05:00
|
|
|
use core::hash::Streaming;
|
2013-04-03 08:28:36 -05:00
|
|
|
use core::hashmap::HashMap;
|
2013-01-22 19:19:13 -06:00
|
|
|
use rustc::driver::{driver, session};
|
2013-03-01 12:44:43 -06:00
|
|
|
use rustc::metadata::filesearch;
|
|
|
|
use std::getopts::groups::getopts;
|
2013-01-23 03:25:03 -06:00
|
|
|
use std::semver;
|
2013-01-22 21:29:47 -06:00
|
|
|
use std::{json, term, sort, getopts};
|
2013-03-01 12:44:43 -06:00
|
|
|
use syntax::ast_util::*;
|
2013-03-26 15:38:07 -05:00
|
|
|
use syntax::codemap::{dummy_sp, spanned};
|
2013-02-04 19:12:31 -06:00
|
|
|
use syntax::ext::base::{mk_ctxt, ext_ctxt};
|
|
|
|
use syntax::ext::build;
|
2013-03-26 15:38:07 -05:00
|
|
|
use syntax::{ast, attr, codemap, diagnostic, fold};
|
2013-02-04 19:12:31 -06:00
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
pub struct Package {
|
|
|
|
id: ~str,
|
2013-01-23 03:25:03 -06:00
|
|
|
vers: semver::Version,
|
2013-01-19 03:59:19 -06:00
|
|
|
bins: ~[~str],
|
|
|
|
libs: ~[~str],
|
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
|
|
|
|
pub fn root() -> Path {
|
|
|
|
match filesearch::get_rustpkg_root() {
|
|
|
|
result::Ok(path) => path,
|
2013-02-04 19:12:31 -06:00
|
|
|
result::Err(err) => fail!(err)
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-15 07:57:03 -06:00
|
|
|
pub fn is_cmd(cmd: ~str) -> bool {
|
2013-01-26 02:35:10 -06:00
|
|
|
let cmds = &[~"build", ~"clean", ~"do", ~"info", ~"install", ~"prefer",
|
2013-01-22 20:41:11 -06:00
|
|
|
~"test", ~"uninstall", ~"unprefer"];
|
2013-01-15 07:57:03 -06:00
|
|
|
|
|
|
|
vec::contains(cmds, &cmd)
|
|
|
|
}
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
pub fn parse_name(id: ~str) -> result::Result<~str, ~str> {
|
2013-03-25 22:39:10 -05:00
|
|
|
let mut last_part = None;
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-03-25 22:39:10 -05:00
|
|
|
for str::each_split_char(id, '.') |part| {
|
|
|
|
for str::each_char(part) |char| {
|
2013-01-16 05:59:37 -06:00
|
|
|
if char::is_whitespace(char) {
|
2013-01-23 00:38:05 -06:00
|
|
|
return result::Err(
|
|
|
|
~"could not parse id: contains whitespace");
|
2013-01-16 05:59:37 -06:00
|
|
|
} else if char::is_uppercase(char) {
|
2013-01-23 00:38:05 -06:00
|
|
|
return result::Err(
|
|
|
|
~"could not parse id: should be all lowercase");
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
}
|
2013-03-25 22:39:10 -05:00
|
|
|
last_part = Some(part.to_owned());
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
2013-03-25 22:39:10 -05:00
|
|
|
if last_part.is_none() { return result::Err(~"could not parse id: is empty"); }
|
2013-01-16 05:59:37 -06:00
|
|
|
|
2013-03-25 22:39:10 -05:00
|
|
|
result::Ok(last_part.unwrap())
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
struct ListenerFn {
|
2013-01-22 20:41:11 -06:00
|
|
|
cmds: ~[~str],
|
2013-01-22 19:19:13 -06:00
|
|
|
span: codemap::span,
|
|
|
|
path: ~[ast::ident]
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ReadyCtx {
|
|
|
|
sess: session::Session,
|
|
|
|
crate: @ast::crate,
|
2013-03-12 15:00:50 -05:00
|
|
|
ext_cx: @ext_ctxt,
|
2013-02-21 20:41:33 -06:00
|
|
|
path: ~[ast::ident],
|
|
|
|
fns: ~[ListenerFn]
|
2013-01-22 19:19:13 -06:00
|
|
|
}
|
|
|
|
|
2013-03-12 15:00:50 -05:00
|
|
|
fn fold_mod(_ctx: @mut ReadyCtx,
|
|
|
|
m: &ast::_mod,
|
|
|
|
fold: @fold::ast_fold) -> ast::_mod {
|
2013-01-22 19:19:13 -06:00
|
|
|
fn strip_main(item: @ast::item) -> @ast::item {
|
|
|
|
@ast::item {
|
|
|
|
attrs: do item.attrs.filtered |attr| {
|
2013-02-14 22:19:27 -06:00
|
|
|
*attr::get_attr_name(attr) != ~"main"
|
2013-01-22 19:19:13 -06:00
|
|
|
},
|
|
|
|
.. copy *item
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-18 00:20:36 -06:00
|
|
|
fold::noop_fold_mod(&ast::_mod {
|
|
|
|
items: do m.items.map |item| {
|
2013-01-22 19:19:13 -06:00
|
|
|
strip_main(*item)
|
2013-02-04 19:12:31 -06:00
|
|
|
},
|
2013-02-18 00:20:36 -06:00
|
|
|
.. copy *m
|
2013-01-22 19:19:13 -06:00
|
|
|
}, fold)
|
|
|
|
}
|
|
|
|
|
2013-03-12 15:00:50 -05:00
|
|
|
fn fold_item(ctx: @mut ReadyCtx,
|
|
|
|
item: @ast::item,
|
|
|
|
fold: @fold::ast_fold) -> Option<@ast::item> {
|
2013-01-22 19:19:13 -06:00
|
|
|
ctx.path.push(item.ident);
|
|
|
|
|
2013-01-22 20:41:11 -06:00
|
|
|
let attrs = attr::find_attrs_by_name(item.attrs, ~"pkg_do");
|
|
|
|
|
|
|
|
if attrs.len() > 0 {
|
|
|
|
let mut cmds = ~[];
|
|
|
|
|
|
|
|
for attrs.each |attr| {
|
|
|
|
match attr.node.value.node {
|
|
|
|
ast::meta_list(_, mis) => {
|
|
|
|
for mis.each |mi| {
|
|
|
|
match mi.node {
|
2013-02-14 09:34:21 -06:00
|
|
|
ast::meta_word(cmd) => cmds.push(copy *cmd),
|
2013-01-22 20:41:11 -06:00
|
|
|
_ => {}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => cmds.push(~"build")
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2013-01-22 19:19:13 -06:00
|
|
|
ctx.fns.push(ListenerFn {
|
2013-01-22 20:41:11 -06:00
|
|
|
cmds: cmds,
|
2013-01-22 19:19:13 -06:00
|
|
|
span: item.span,
|
|
|
|
path: /*bad*/copy ctx.path
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let res = fold::noop_fold_item(item, fold);
|
|
|
|
|
|
|
|
ctx.path.pop();
|
|
|
|
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
2013-02-21 20:41:33 -06:00
|
|
|
fn add_pkg_module(ctx: @mut ReadyCtx, m: ast::_mod) -> ast::_mod {
|
2013-02-04 19:12:31 -06:00
|
|
|
let listeners = mk_listener_vec(ctx);
|
|
|
|
let ext_cx = ctx.ext_cx;
|
|
|
|
let item = quote_item! (
|
|
|
|
mod __pkg {
|
|
|
|
extern mod rustpkg (vers="0.6");
|
2013-03-22 16:00:15 -05:00
|
|
|
static listeners : &[rustpkg::Listener] = $listeners;
|
2013-02-04 19:12:31 -06:00
|
|
|
#[main]
|
|
|
|
fn main() {
|
|
|
|
rustpkg::run(listeners);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
2013-01-23 00:38:05 -06:00
|
|
|
ast::_mod {
|
2013-02-04 19:12:31 -06:00
|
|
|
items: vec::append_one(/*bad*/copy m.items, item.get()),
|
2013-01-22 19:19:13 -06:00
|
|
|
.. m
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-21 20:41:33 -06:00
|
|
|
fn mk_listener_vec(ctx: @mut ReadyCtx) -> @ast::expr {
|
2013-01-22 19:19:13 -06:00
|
|
|
let fns = ctx.fns;
|
|
|
|
let descs = do fns.map |listener| {
|
|
|
|
mk_listener_rec(ctx, *listener)
|
|
|
|
};
|
2013-02-21 20:41:33 -06:00
|
|
|
let ext_cx = ctx.ext_cx;
|
|
|
|
build::mk_slice_vec_e(ext_cx, dummy_sp(), descs)
|
2013-01-22 19:19:13 -06:00
|
|
|
}
|
|
|
|
|
2013-02-21 20:41:33 -06:00
|
|
|
fn mk_listener_rec(ctx: @mut ReadyCtx, listener: ListenerFn) -> @ast::expr {
|
2013-01-22 19:19:13 -06:00
|
|
|
let span = listener.span;
|
2013-02-04 19:12:31 -06:00
|
|
|
let cmds = do listener.cmds.map |&cmd| {
|
2013-02-21 20:41:33 -06:00
|
|
|
let ext_cx = ctx.ext_cx;
|
|
|
|
build::mk_base_str(ext_cx, span, cmd)
|
2013-01-22 19:19:13 -06:00
|
|
|
};
|
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
let ext_cx = ctx.ext_cx;
|
2013-02-21 20:41:33 -06:00
|
|
|
let cmds_expr = build::mk_slice_vec_e(ext_cx, span, cmds);
|
|
|
|
let cb_expr = build::mk_path(ext_cx, span, copy listener.path);
|
2013-01-22 19:19:13 -06:00
|
|
|
|
2013-02-04 19:12:31 -06:00
|
|
|
quote_expr!(
|
|
|
|
Listener {
|
|
|
|
cmds: $cmds_expr,
|
|
|
|
cb: $cb_expr
|
|
|
|
}
|
|
|
|
)
|
2013-01-22 19:19:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate/filter main function, add the list of commands, etc.
|
|
|
|
pub fn ready_crate(sess: session::Session,
|
|
|
|
crate: @ast::crate) -> @ast::crate {
|
2013-02-21 20:41:33 -06:00
|
|
|
let ctx = @mut ReadyCtx {
|
2013-01-22 19:19:13 -06:00
|
|
|
sess: sess,
|
|
|
|
crate: crate,
|
2013-02-04 19:12:31 -06:00
|
|
|
ext_cx: mk_ctxt(sess.parse_sess, copy sess.opts.cfg),
|
2013-02-21 20:41:33 -06:00
|
|
|
path: ~[],
|
|
|
|
fns: ~[]
|
2013-01-22 19:19:13 -06:00
|
|
|
};
|
|
|
|
let precursor = @fold::AstFoldFns {
|
2013-02-04 19:12:31 -06:00
|
|
|
// fold_crate: fold::wrap(|a, b| fold_crate(ctx, a, b)),
|
2013-01-22 19:19:13 -06:00
|
|
|
fold_item: |a, b| fold_item(ctx, a, b),
|
|
|
|
fold_mod: |a, b| fold_mod(ctx, a, b),
|
|
|
|
.. *fold::default_ast_fold()
|
|
|
|
};
|
|
|
|
|
|
|
|
let fold = fold::make_fold(precursor);
|
|
|
|
|
2013-02-18 00:20:36 -06:00
|
|
|
@fold.fold_crate(crate)
|
2013-01-22 19:19:13 -06:00
|
|
|
}
|
|
|
|
|
2013-01-23 03:25:03 -06:00
|
|
|
pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> {
|
2013-01-16 05:59:37 -06:00
|
|
|
match semver::parse(vers) {
|
2013-01-19 03:59:19 -06:00
|
|
|
Some(vers) => result::Ok(vers),
|
|
|
|
None => result::Err(~"could not parse version: invalid")
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-17 03:05:19 -06:00
|
|
|
pub fn need_dir(s: &Path) {
|
|
|
|
if !os::path_is_dir(s) && !os::make_dir(s, 493_i32) {
|
2013-02-04 19:12:31 -06:00
|
|
|
fail!(fmt!("can't create dir: %s", s.to_str()));
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-18 02:31:43 -06:00
|
|
|
pub fn note(msg: ~str) {
|
2013-01-17 03:05:19 -06:00
|
|
|
let out = io::stdout();
|
|
|
|
|
|
|
|
if term::color_supported() {
|
|
|
|
term::fg(out, term::color_green);
|
2013-01-18 02:31:43 -06:00
|
|
|
out.write_str(~"note: ");
|
2013-01-17 03:05:19 -06:00
|
|
|
term::reset(out);
|
|
|
|
out.write_line(msg);
|
2013-02-04 19:12:31 -06:00
|
|
|
} else {
|
|
|
|
out.write_line(~"note: " + msg);
|
|
|
|
}
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn warn(msg: ~str) {
|
|
|
|
let out = io::stdout();
|
|
|
|
|
|
|
|
if term::color_supported() {
|
|
|
|
term::fg(out, term::color_yellow);
|
|
|
|
out.write_str(~"warning: ");
|
|
|
|
term::reset(out);
|
|
|
|
out.write_line(msg);
|
2013-02-04 19:12:31 -06:00
|
|
|
} else {
|
|
|
|
out.write_line(~"warning: " + msg);
|
|
|
|
}
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn error(msg: ~str) {
|
|
|
|
let out = io::stdout();
|
|
|
|
|
|
|
|
if term::color_supported() {
|
|
|
|
term::fg(out, term::color_red);
|
|
|
|
out.write_str(~"error: ");
|
|
|
|
term::reset(out);
|
|
|
|
out.write_line(msg);
|
2013-02-04 19:12:31 -06:00
|
|
|
} else {
|
|
|
|
out.write_line(~"error: " + msg);
|
2013-01-17 03:05:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
pub fn hash(data: ~str) -> ~str {
|
2013-03-06 03:00:25 -06:00
|
|
|
let hasher = &hash::default_state();
|
2013-01-19 03:59:19 -06:00
|
|
|
|
|
|
|
hasher.write_str(data);
|
|
|
|
hasher.result_str()
|
|
|
|
}
|
|
|
|
|
2013-03-07 16:38:38 -06:00
|
|
|
pub fn temp_change_dir<T>(dir: &Path, cb: &fn() -> T) {
|
2013-01-18 02:31:43 -06:00
|
|
|
let cwd = os::getcwd();
|
|
|
|
|
|
|
|
os::change_dir(dir);
|
|
|
|
cb();
|
|
|
|
os::change_dir(&cwd);
|
|
|
|
}
|
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
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| {
|
2013-02-04 19:12:31 -06:00
|
|
|
match &package {
|
|
|
|
&json::Object(ref map) => {
|
2013-01-19 03:59:19 -06:00
|
|
|
let mut has_id = false;
|
|
|
|
|
|
|
|
match map.get(&~"id") {
|
2013-02-04 19:12:31 -06:00
|
|
|
&json::String(ref str) => {
|
|
|
|
if pkg.id == *str {
|
2013-01-19 03:59:19 -06:00
|
|
|
has_id = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
match map.get(&~"vers") {
|
2013-02-04 19:12:31 -06:00
|
|
|
&json::String(ref str) => {
|
|
|
|
if has_id && pkg.vers.to_str() == *str {
|
|
|
|
return copy packages;
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut map = ~HashMap::new();
|
2013-01-19 03:59:19 -06:00
|
|
|
|
|
|
|
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] {
|
2013-02-04 19:12:31 -06:00
|
|
|
do packages.filter_mapped |&package| {
|
|
|
|
match &package {
|
|
|
|
&json::Object(ref map) => {
|
2013-01-19 03:59:19 -06:00
|
|
|
let mut has_id = false;
|
|
|
|
|
|
|
|
match map.get(&~"id") {
|
2013-02-04 19:12:31 -06:00
|
|
|
&json::String(str) => {
|
2013-01-19 03:59:19 -06:00
|
|
|
if pkg.id == str {
|
|
|
|
has_id = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
match map.get(&~"vers") {
|
2013-02-04 19:12:31 -06:00
|
|
|
&json::String(ref str) => {
|
|
|
|
if has_id && pkg.vers.to_str() == *str {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(copy package)
|
|
|
|
}
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
2013-02-04 19:12:31 -06:00
|
|
|
_ => { Some(copy package) }
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
}
|
2013-02-04 19:12:31 -06:00
|
|
|
_ => { Some(copy package) }
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
return result::Err(
|
|
|
|
~"package db's json is not a list");
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result::Err(err) => {
|
|
|
|
os::remove_file(&db_lock);
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
return result::Err(
|
|
|
|
fmt!("failed to parse package db: %s",
|
|
|
|
err.to_str()));
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result::Err(err) => {
|
|
|
|
os::remove_file(&db_lock);
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
return result::Err(fmt!("failed to read package db: %s",
|
|
|
|
err));
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { ~[] };
|
|
|
|
|
|
|
|
os::remove_file(&db_lock);
|
|
|
|
|
|
|
|
result::Ok(packages)
|
|
|
|
}
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
pub fn get_pkg(id: ~str,
|
|
|
|
vers: Option<~str>) -> result::Result<Package, ~str> {
|
2013-01-19 03:59:19 -06:00
|
|
|
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") {
|
2013-02-04 19:12:31 -06:00
|
|
|
&json::String(str) => str,
|
2013-01-19 03:59:19 -06:00
|
|
|
_ => loop
|
|
|
|
};
|
|
|
|
let pname = match parse_name(pid) {
|
|
|
|
result::Ok(pname) => pname,
|
|
|
|
result::Err(perr) => {
|
|
|
|
err = Some(perr);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let pvers = match map.get(&~"vers") {
|
2013-02-04 19:12:31 -06:00
|
|
|
&json::String(str) => str,
|
2013-01-19 03:59:19 -06:00
|
|
|
_ => loop
|
|
|
|
};
|
|
|
|
if pid == id || pname == name {
|
|
|
|
let bins = match map.get(&~"bins") {
|
2013-02-04 19:12:31 -06:00
|
|
|
&json::List(ref list) => {
|
2013-01-19 03:59:19 -06:00
|
|
|
do list.map |&bin| {
|
|
|
|
match bin {
|
|
|
|
json::String(str) => str,
|
|
|
|
_ => ~""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => ~[]
|
|
|
|
};
|
|
|
|
let libs = match map.get(&~"libs") {
|
2013-02-04 19:12:31 -06:00
|
|
|
&json::List(ref list) => {
|
2013-01-19 03:59:19 -06:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2013-03-05 21:39:18 -06:00
|
|
|
let possibs = sort::merge_sort(possibs, |v1, v2| {
|
2013-01-19 03:59:19 -06:00
|
|
|
v1.vers <= v2.vers
|
2013-03-05 21:39:18 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
result::Ok(copy *possibs.last())
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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) => {
|
2013-01-23 00:38:05 -06:00
|
|
|
writer.write_line(json::to_pretty_str(&json::List(
|
|
|
|
_add_pkg(packages, pkg))));
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
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) => {
|
2013-01-23 00:38:05 -06:00
|
|
|
writer.write_line(json::to_pretty_str(&json::List(
|
|
|
|
_rm_pkg(packages, pkg))));
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2013-01-22 20:41:11 -06:00
|
|
|
pub fn compile_input(sysroot: Option<Path>, input: driver::input, dir: &Path,
|
2013-01-22 19:19:13 -06:00
|
|
|
flags: ~[~str], cfgs: ~[~str], opt: bool, test: bool) -> bool {
|
|
|
|
let lib_dir = dir.push(~"lib");
|
|
|
|
let bin_dir = dir.push(~"bin");
|
|
|
|
let test_dir = dir.push(~"test");
|
|
|
|
let binary = os::args()[0];
|
2013-01-22 21:29:47 -06:00
|
|
|
let matches = getopts(flags, driver::optgroups()).get();
|
2013-02-19 02:01:03 -06:00
|
|
|
let options = @session::options {
|
2013-01-23 00:38:05 -06:00
|
|
|
crate_type: session::unknown_crate,
|
|
|
|
optimize: if opt { session::Aggressive } else { session::No },
|
|
|
|
test: test,
|
|
|
|
maybe_sysroot: sysroot,
|
|
|
|
.. *driver::build_session_options(binary, &matches, diagnostic::emit)
|
|
|
|
};
|
|
|
|
let mut crate_cfg = options.cfg;
|
2013-01-22 21:29:47 -06:00
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
for cfgs.each |&cfg| {
|
2013-02-14 22:19:27 -06:00
|
|
|
crate_cfg.push(attr::mk_word_item(@cfg));
|
2013-01-23 00:38:05 -06:00
|
|
|
}
|
2013-01-22 21:29:47 -06:00
|
|
|
|
2013-02-19 02:01:03 -06:00
|
|
|
let options = @session::options {
|
2013-01-23 00:38:05 -06:00
|
|
|
cfg: vec::append(options.cfg, crate_cfg),
|
|
|
|
.. *options
|
|
|
|
};
|
2013-01-22 19:19:13 -06:00
|
|
|
let sess = driver::build_session(options, diagnostic::emit);
|
|
|
|
let cfg = driver::build_configuration(sess, binary, input);
|
|
|
|
let mut outputs = driver::build_output_filenames(input, &None, &None,
|
|
|
|
sess);
|
2013-02-19 02:01:03 -06:00
|
|
|
let (crate, _) = driver::compile_upto(sess, cfg, input, driver::cu_parse,
|
2013-01-22 19:19:13 -06:00
|
|
|
Some(outputs));
|
|
|
|
|
|
|
|
let mut name = None;
|
|
|
|
let mut vers = None;
|
|
|
|
let mut uuid = None;
|
|
|
|
let mut crate_type = None;
|
|
|
|
|
|
|
|
fn load_link_attr(mis: ~[@ast::meta_item]) -> (Option<~str>,
|
|
|
|
Option<~str>,
|
|
|
|
Option<~str>) {
|
|
|
|
let mut name = None;
|
|
|
|
let mut vers = None;
|
|
|
|
let mut uuid = None;
|
|
|
|
|
|
|
|
for mis.each |a| {
|
|
|
|
match a.node {
|
2013-02-04 19:12:31 -06:00
|
|
|
ast::meta_name_value(v, spanned {node: ast::lit_str(s),
|
2013-01-22 19:19:13 -06:00
|
|
|
span: _}) => {
|
2013-02-14 09:34:21 -06:00
|
|
|
match *v {
|
2013-01-22 19:19:13 -06:00
|
|
|
~"name" => name = Some(*s),
|
|
|
|
~"vers" => vers = Some(*s),
|
|
|
|
~"uuid" => uuid = Some(*s),
|
|
|
|
_ => { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(name, vers, uuid)
|
|
|
|
}
|
|
|
|
|
|
|
|
for crate.node.attrs.each |a| {
|
|
|
|
match a.node.value.node {
|
2013-02-04 19:12:31 -06:00
|
|
|
ast::meta_name_value(v, spanned {node: ast::lit_str(s),
|
2013-01-22 19:19:13 -06:00
|
|
|
span: _}) => {
|
2013-02-14 09:34:21 -06:00
|
|
|
match *v {
|
2013-01-22 19:19:13 -06:00
|
|
|
~"crate_type" => crate_type = Some(*s),
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::meta_list(v, mis) => {
|
2013-02-14 09:34:21 -06:00
|
|
|
match *v {
|
2013-01-22 19:19:13 -06:00
|
|
|
~"link" => {
|
|
|
|
let (n, v, u) = load_link_attr(mis);
|
|
|
|
|
|
|
|
name = n;
|
|
|
|
vers = v;
|
|
|
|
uuid = u;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if name.is_none() || vers.is_none() || uuid.is_none() {
|
|
|
|
error(~"link attr without (name, vers, uuid) values");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let name = name.get();
|
|
|
|
let vers = vers.get();
|
|
|
|
let uuid = uuid.get();
|
|
|
|
|
|
|
|
let is_bin = match crate_type {
|
|
|
|
Some(crate_type) => {
|
|
|
|
match crate_type {
|
|
|
|
~"bin" => true,
|
|
|
|
~"lib" => false,
|
|
|
|
_ => {
|
|
|
|
warn(~"unknown crate_type, falling back to lib");
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
warn(~"missing crate_type attr, assuming lib");
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if test {
|
|
|
|
need_dir(&test_dir);
|
|
|
|
|
|
|
|
outputs = driver::build_output_filenames(input, &Some(test_dir),
|
|
|
|
&None, sess)
|
|
|
|
}
|
|
|
|
else if is_bin {
|
|
|
|
need_dir(&bin_dir);
|
|
|
|
|
|
|
|
let path = bin_dir.push(fmt!("%s-%s-%s%s", name,
|
|
|
|
hash(name + uuid + vers),
|
|
|
|
vers, exe_suffix()));
|
2013-01-23 00:38:05 -06:00
|
|
|
outputs = driver::build_output_filenames(input, &None, &Some(path),
|
|
|
|
sess);
|
2013-01-22 19:19:13 -06:00
|
|
|
} else {
|
|
|
|
need_dir(&lib_dir);
|
|
|
|
|
|
|
|
outputs = driver::build_output_filenames(input, &Some(lib_dir),
|
|
|
|
&None, sess)
|
|
|
|
}
|
|
|
|
|
|
|
|
driver::compile_rest(sess, cfg, driver::cu_everything,
|
|
|
|
Some(outputs), Some(crate));
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
pub fn exe_suffix() -> ~str { ~".exe" }
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
#[cfg(target_os = "freebsd")]
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
pub fn exe_suffix() -> ~str { ~"" }
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
|
2013-01-23 03:25:03 -06:00
|
|
|
// FIXME (#4432): Use workcache to only compile when needed
|
2013-01-23 00:38:05 -06:00
|
|
|
pub fn compile_crate(sysroot: Option<Path>, crate: &Path, dir: &Path,
|
|
|
|
flags: ~[~str], cfgs: ~[~str], opt: bool,
|
|
|
|
test: bool) -> bool {
|
|
|
|
compile_input(sysroot, driver::file_input(*crate), dir, flags, cfgs,
|
|
|
|
opt, test)
|
2013-01-22 19:19:13 -06:00
|
|
|
}
|
|
|
|
|
2013-01-23 00:38:05 -06:00
|
|
|
pub fn compile_str(sysroot: Option<Path>, code: ~str, dir: &Path,
|
|
|
|
flags: ~[~str], cfgs: ~[~str], opt: bool,
|
|
|
|
test: bool) -> bool {
|
|
|
|
compile_input(sysroot, driver::str_input(code), dir, flags, cfgs,
|
|
|
|
opt, test)
|
2013-01-22 19:19:13 -06:00
|
|
|
}
|
|
|
|
|
2013-01-19 03:59:19 -06:00
|
|
|
#[cfg(windows)]
|
2013-01-23 00:38:05 -06:00
|
|
|
pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
|
2013-01-23 03:25:03 -06:00
|
|
|
/* FIXME (#1768): Investigate how to do this on win32
|
2013-01-19 03:59:19 -06:00
|
|
|
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")]
|
2013-02-04 19:12:31 -06:00
|
|
|
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
|
|
|
|
}
|
2013-01-19 03:59:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-16 05:59:37 -06:00
|
|
|
#[test]
|
|
|
|
fn test_is_cmd() {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(is_cmd(~"build"));
|
|
|
|
assert!(is_cmd(~"clean"));
|
|
|
|
assert!(is_cmd(~"do"));
|
|
|
|
assert!(is_cmd(~"info"));
|
|
|
|
assert!(is_cmd(~"install"));
|
|
|
|
assert!(is_cmd(~"prefer"));
|
|
|
|
assert!(is_cmd(~"test"));
|
|
|
|
assert!(is_cmd(~"uninstall"));
|
|
|
|
assert!(is_cmd(~"unprefer"));
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-01-19 03:59:19 -06:00
|
|
|
fn test_parse_name() {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(parse_name(~"org.mozilla.servo").get() == ~"servo");
|
|
|
|
assert!(parse_name(~"org. mozilla.servo 2131").is_err());
|
2013-01-16 05:59:37 -06:00
|
|
|
}
|