rust/src/librustpkg/rustpkg.rc

1042 lines
30 KiB
Plaintext
Raw Normal View History

2013-02-28 07:15:32 -06:00
// Copyright 2012-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.
// 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")];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
#[no_core];
2013-01-16 05:59:37 -06:00
#[allow(vecs_implicitly_copyable,
non_implicitly_copyable_typarams)];
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::*;
use core::hashmap::linear::LinearMap;
use core::io::{ReaderUtil, WriterUtil};
use rustc::driver::{driver, session};
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;
use syntax::{ast, attr, codemap, diagnostic, parse, visit};
use core::container::Map;
2013-01-15 07:57:03 -06:00
mod usage;
mod util;
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,
crates: ~[~str],
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 {
fn parse(parent: &Path) -> Result<PackageScript, ~str> {
let script = parent.push(~"pkg.rs");
2013-01-16 05:59:37 -06:00
if !os::path_exists(&script) {
return result::Err(~"no pkg.rs file");
2013-01-16 05:59:37 -06:00
}
let binary = os::args()[0];
2013-02-19 02:01:03 -06:00
let options = @session::options {
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,
driver::cu_parse, None);
2013-01-16 05:59:37 -06:00
let mut id = None;
let mut vers = None;
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)
}
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 {
node: ast::lit_str(s),
span: _}) => {
2013-02-14 09:34:21 -06:00
match *v {
~"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 {
node: ast::lit_str(s),
span: _}) => {
2013-02-14 09:34:21 -06:00
match *v {
~"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;
}
~"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");
}
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");
}
crates.push(f.get());
}
2013-01-16 05:59:37 -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 {
ast::item_fn(_, _, _, _) => {
custom = true;
break;
}
_ => {}
}
}
2013-01-16 05:59:37 -06:00
if id.is_none() || vers.is_none() {
return result::Err(~"pkg attr without (id, vers) values");
2013-01-16 05:59:37 -06:00
}
let id = id.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)
};
2013-01-16 05:59:37 -06:00
result::Ok(PackageScript {
2013-01-16 05:59:37 -06:00
id: id,
name: name,
vers: vers,
crates: crates,
deps: deps,
input: input,
sess: sess,
cfg: cfg,
crate: crate,
custom: custom
})
2013-01-16 05:59:37 -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 {
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);
let exe = work_dir.push(~"pkg" + util::exe_suffix());
let root = filesearch::get_rustpkg_sysroot().get().pop().pop();
driver::compile_rest(sess, cfg, driver::cu_parse,
Some(outputs), Some(crate));
run::run_program(exe.to_str(), ~[root.to_str(), cmd, test.to_str()])
}
2013-02-04 19:12:31 -06:00
fn hash(&self) -> ~str {
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 {
util::root().push(~"work").push(self.hash())
2013-01-16 05:59:37 -06:00
}
}
struct Ctx {
cfgs: ~[~str],
json: bool,
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]) {
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"));
fn sep_name_vers(in: ~str) -> (Option<~str>, Option<~str>) {
let mut name = None;
let mut vers = None;
let parts = str::split_char(in, '@');
if parts.len() >= 1 {
name = Some(parts[0]);
if parts.len() >= 2 {
vers = Some(parts[1]);
}
}
(name, vers)
}
match cmd {
~"build" => {
self.build(&os::getcwd(), true, false, false);
}
~"clean" => {
self.clean();
}
~"do" => {
if args.len() < 1 {
return usage::do_cmd();
}
self.do_cmd(args[0]);
}
~"info" => {
self.info();
}
~"install" => {
self.install(if args.len() >= 1 { Some(args[0]) }
2013-01-23 00:38:05 -06:00
else { None },
if args.len() >= 2 { Some(args[1]) }
else { None }, false);
}
~"prefer" => {
if args.len() < 1 {
return usage::uninstall();
}
let (name, vers) = sep_name_vers(args[0]);
self.prefer(name.get(), vers);
}
~"test" => {
self.test();
}
~"uninstall" => {
if args.len() < 1 {
return usage::uninstall();
}
let (name, vers) = sep_name_vers(args[0]);
self.uninstall(name.get(), vers);
}
~"unprefer" => {
if args.len() < 1 {
return usage::uninstall();
}
let (name, vers) = sep_name_vers(args[0]);
self.unprefer(name.get(), vers);
}
2013-02-04 19:12:31 -06:00
_ => fail!(~"reached an unhandled command")
}
2013-01-16 05:59:37 -06:00
}
2013-02-04 19:12:31 -06:00
fn do_cmd(&self, cmd: ~str) -> bool {
match cmd {
~"build" | ~"test" => {
util::error(~"that command cannot be manually called");
return false;
}
_ => {}
}
let cwd = &os::getcwd();
let script = match PackageScript::parse(cwd) {
result::Ok(script) => script,
result::Err(err) => {
util::error(err);
return false;
}
};
let status = script.run(cmd, false);
if status == 42 {
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,
test: bool) -> Option<PackageScript> {
let cwd = &os::getcwd();
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;
}
};
let work_dir = script.work_dir();
let mut success = true;
util::need_dir(&work_dir);
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 {
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()));
return None;
}
util::note(~"installed dependencies");
}
// Build imperative crates
os::change_dir(dir);
if script.custom {
let status = script.run(~"build", test);
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-16 05:59:37 -06:00
os::change_dir(cwd);
for script.crates.each |&crate| {
let crate = &dir.push_rel(&Path(crate)).normalize();
util::note(fmt!("compiling %s", crate.to_str()));
success = self.compile(crate, &work_dir, ~[],
~[], opt, test);
if !success { break; }
}
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()));
return None;
}
if verbose {
2013-01-23 00:38:05 -06:00
util::note(fmt!("built %s v%s", script.name,
script.vers.to_str()));
}
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],
cfgs: ~[~str], opt: bool, test: bool) -> bool {
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 {
let script = match PackageScript::parse(&os::getcwd()) {
result::Ok(script) => script,
result::Err(err) => {
util::error(err);
return false;
}
};
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));
if os::path_exists(&dir) {
util::remove_dir_r(&dir);
util::note(fmt!("removed %s", dir.to_str()));
}
2013-01-16 05:59:37 -06:00
util::note(fmt!("cleaned %s v%s", script.name,
script.vers.to_str()));
true
2013-01-16 05:59:37 -06:00
}
2013-02-04 19:12:31 -06:00
fn info(&self) {
if self.json {
match PackageScript::parse(&os::getcwd()) {
result::Ok(script) => {
2013-02-04 19:12:31 -06:00
let mut map = ~LinearMap::new();
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();
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()));
}
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"
}));
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;
let mut dir;
if url.is_none() {
util::note(~"installing from the cwd");
dir = os::getcwd();
} else {
let url = url.get();
let hash = util::hash(if !target.is_none() { url + target.get() }
else { url });
if self.dep_cache.contains_key(&hash) {
util::warn(~"already installed dep this run");
return true;
}
self.dep_cache.insert(hash, true);
dir = util::root().push(~"tmp").push(hash);
if cache && os::path_exists(&dir) {
return true;
}
success = self.fetch(&dir, url, target);
2013-01-16 05:59:37 -06:00
if !success {
return false;
}
}
let script = match self.build(&dir, false, true, false) {
Some(script) => script,
None => {
return false;
}
};
let work_dir = script.work_dir();
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
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) {
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 {
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 {
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?)");
return false;
}
true
}
2013-02-04 19:12:31 -06:00
fn fetch_git(&self, dir: &Path, url: ~str, target: Option<~str>) -> bool {
util::note(fmt!("fetching from %s using git", url));
// Git can't clone into a non-empty directory
util::remove_dir_r(dir);
2013-01-23 00:38:05 -06:00
if run::program_output(~"git", ~[~"clone", url,
dir.to_str()]).status != 0 {
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
}
if !success {
util::error(~"fetching failed: can't checkout target");
return false;
}
}
2013-01-16 05:59:37 -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 {
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
}
2013-01-16 05:59:37 -06:00
2013-02-04 19:12:31 -06:00
fn test(&self) -> bool {
let script = match self.build(&os::getcwd(), false, false, true) {
Some(script) => script,
None => {
return false;
}
};
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);
}
}
// 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);
}
}
util::note(fmt!("tested %s v%s", script.name, script.vers.to_str()));
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 {
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));
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
}
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 {
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));
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
2013-01-16 05:59:37 -06:00
}
}
2013-01-15 07:57:03 -06:00
pub fn main() {
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"),
getopts::optflag(~"j"), getopts::optflag(~"json"),
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) => {
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");
let json = getopts::opt_present(matches, ~"j") ||
getopts::opt_present(matches, ~"json");
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-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(),
~"do" => usage::do_cmd(),
~"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 {
cfgs: cfgs,
json: json,
dep_cache: @mut LinearMap::new()
}.run(cmd, args);
}
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],
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 {
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.
*/
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.
*/
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 {
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;
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,
false, test);
2013-01-23 00:38:05 -06:00
if !success { break; }
}
if !success {
os::set_exit_status(101);
2013-01-23 00:38:05 -06:00
}
success
}