rustpkg: Add do command and get cmd listeners working correctly

This commit is contained in:
Zack Corr 2013-01-23 12:41:11 +10:00 committed by Graydon Hoare
parent 7079441843
commit e34e072d17
4 changed files with 119 additions and 25 deletions

View file

@ -19,21 +19,29 @@ pub struct Crate {
}
pub struct Listener {
cmd: ~str,
cmds: ~[~str],
cb: fn~()
}
pub fn run(listeners: ~[Listener]) {
io::println(src_dir().to_str());
io::println(work_dir().to_str());
let cmd = os::args()[1];
let rcmd = os::args()[2];
let mut found = false;
for listeners.each |listener| {
if listener.cmd == cmd {
(listener.cb)();
for listener.cmds.each |&cmd| {
if cmd == rcmd {
(listener.cb)();
found = true;
break;
}
}
}
if !found {
os::set_exit_status(1);
}
}
pub impl Crate {
@ -108,19 +116,22 @@ pub fn build(crates: ~[Crate]) -> bool {
let dir = src_dir();
let work_dir = work_dir();
let mut success = true;
let sysroot = Path(os::args()[1]);
for crates.each |&crate| {
let path = &dir.push_rel(&Path(crate.file)).normalize();
note(fmt!("compiling %s", path.to_str()));
success = compile_crate(path, &work_dir, crate.flags, crate.cfgs,
success = compile_crate(Some(sysroot), path, &work_dir, crate.flags, crate.cfgs,
false, false);
if !success { break; }
}
os::set_exit_status(101);
if !success {
os::set_exit_status(2);
}
success
}

View file

@ -30,6 +30,7 @@ use io::{ReaderUtil, WriterUtil};
use std::getopts;
use std::net::url;
use send_map::linear::LinearMap;
use rustc::metadata::filesearch;
use rustc::driver::{driver, session};
use syntax::{ast, attr, codemap, diagnostic, parse, visit};
use semver::Version;
@ -184,7 +185,11 @@ impl PackageScript {
// the build API.
for crate.node.module.items.each |i| {
match i.node {
ast::item_fn(_, _, _, _) => custom = true,
ast::item_fn(_, _, _, _) => {
custom = true;
break;
}
_ => {}
}
}
@ -228,10 +233,11 @@ impl PackageScript {
let outputs = driver::build_output_filenames(input, &Some(work_dir),
&None, sess);
let exe = work_dir.push(~"package" + 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(), ~[cmd])
run::run_program(exe.to_str(), ~[root.to_str(), cmd])
}
fn hash() -> ~str {
@ -282,6 +288,13 @@ impl Ctx {
~"clean" => {
self.clean();
}
~"do" => {
if args.len() < 1 {
return usage::do_cmd();
}
self.do_cmd(args[0]);
}
~"install" => {
self.install(if args.len() >= 1 { Some(args[0]) }
else { None },
@ -322,6 +335,33 @@ impl Ctx {
}
}
fn do_cmd(cmd: ~str) -> bool {
if cmd == ~"build" {
util::error(~"the build cmd is reserved");
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);
if status == 1 {
util::error(~"no fns are listening for that cmd");
return false;
}
status == 0
}
fn build(dir: &Path, verbose: bool, opt: bool,
test: bool) -> Option<PackageScript> {
let cwd = &os::getcwd();
@ -399,7 +439,7 @@ impl Ctx {
fn compile(crate: &Path, dir: &Path, flags: ~[~str],
cfgs: ~[~str], opt: bool, test: bool) -> bool {
util::compile_crate(crate, dir, flags, cfgs, opt, test)
util::compile_crate(None, crate, dir, flags, cfgs, opt, test)
}
fn clean() -> bool {
@ -759,6 +799,7 @@ pub fn main() {
return match cmd {
~"build" => usage::build(),
~"clean" => usage::clean(),
~"do" => usage::do_cmd(),
~"install" => usage::install(),
~"prefer" => usage::prefer(),
~"test" => usage::test(),

View file

@ -39,6 +39,13 @@ Remove all build files in the work cache for the package in the current
directory.");
}
pub fn do_cmd() {
io::println(~"rustpkg do <cmd>
Runs a command in the package script. You can listen to a command
by tagging a function with the attribute `#[pkg_do(cmd)]`.");
}
pub fn install() {
io::println(~"rustpkg [options..] install [url] [target]

View file

@ -34,8 +34,8 @@ pub fn root() -> Path {
}
pub fn is_cmd(cmd: ~str) -> bool {
let cmds = &[~"build", ~"clean", ~"install", ~"prefer", ~"test",
~"uninstall", ~"unprefer"];
let cmds = &[~"build", ~"clean", ~"do", ~"install", ~"prefer",
~"test", ~"uninstall", ~"unprefer"];
vec::contains(cmds, &cmd)
}
@ -74,6 +74,7 @@ fn mk_rustpkg_use(ctx: @ReadyCtx) -> @ast::view_item {
}
struct ListenerFn {
cmds: ~[~str],
span: codemap::span,
path: ~[ast::ident]
}
@ -119,8 +120,27 @@ fn fold_item(ctx: @ReadyCtx, &&item: @ast::item,
ctx.path.push(item.ident);
if attr::find_attrs_by_name(item.attrs, ~"pkg_do").is_not_empty() {
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 {
ast::meta_word(cmd) => cmds.push(cmd),
_ => {}
};
}
}
_ => cmds.push(~"build")
};
}
ctx.fns.push(ListenerFn {
cmds: cmds,
span: item.span,
path: /*bad*/copy ctx.path
});
@ -284,13 +304,26 @@ fn mk_listener_vec(ctx: @ReadyCtx) -> @ast::expr {
fn mk_listener_rec(ctx: @ReadyCtx, listener: ListenerFn) -> @ast::expr {
let span = listener.span;
let path = /*bad*/copy listener.path;
let cmd_lit = no_span(ast::lit_str(@path_name_i(path,
ctx.sess.parse_sess.interner)));
let descs = do listener.cmds.map |&cmd| {
let inner = @{
id: ctx.sess.next_node_id(),
callee_id: ctx.sess.next_node_id(),
node: ast::expr_lit(@no_span(ast::lit_str(@cmd))),
span: span
};
@{
id: ctx.sess.next_node_id(),
callee_id: ctx.sess.next_node_id(),
node: ast::expr_vstore(inner, ast::expr_vstore_uniq),
span: dummy_sp()
}
};
let cmd_expr_inner = @{
id: ctx.sess.next_node_id(),
callee_id: ctx.sess.next_node_id(),
node: ast::expr_lit(@cmd_lit),
span: span
node: ast::expr_vec(descs, ast::m_imm),
span: dummy_sp()
};
let cmd_expr = {
id: ctx.sess.next_node_id(),
@ -300,7 +333,7 @@ fn mk_listener_rec(ctx: @ReadyCtx, listener: ListenerFn) -> @ast::expr {
};
let cmd_field = no_span(ast::field_ {
mutbl: ast::m_imm,
ident: ctx.sess.ident_of(~"cmd"),
ident: ctx.sess.ident_of(~"cmds"),
expr: @cmd_expr,
});
@ -827,7 +860,7 @@ pub fn remove_pkg(pkg: &Package) -> bool {
true
}
pub fn compile_input(input: driver::input, dir: &Path,
pub fn compile_input(sysroot: Option<Path>, input: driver::input, dir: &Path,
flags: ~[~str], cfgs: ~[~str], opt: bool, test: bool) -> bool {
let lib_dir = dir.push(~"lib");
let bin_dir = dir.push(~"bin");
@ -838,6 +871,7 @@ pub fn compile_input(input: driver::input, dir: &Path,
crate_type: session::unknown_crate,
optimize: if opt { session::Aggressive } else { session::No },
test: test,
maybe_sysroot: sysroot,
.. *session::basic_options()
};
let sess = driver::build_session(options, diagnostic::emit);
@ -966,14 +1000,14 @@ pub fn exe_suffix() -> ~str { ~".exe" }
#[cfg(target_os = "macos")]
pub fn exe_suffix() -> ~str { ~"" }
pub fn compile_crate(crate: &Path, dir: &Path, flags: ~[~str],
pub fn compile_crate(sysroot: Option<Path>, crate: &Path, dir: &Path, flags: ~[~str],
cfgs: ~[~str], opt: bool, test: bool) -> bool {
compile_input(driver::file_input(*crate), dir, flags, cfgs, opt, test)
compile_input(sysroot, driver::file_input(*crate), dir, flags, cfgs, opt, test)
}
pub fn compile_str(code: ~str, dir: &Path, flags: ~[~str],
pub fn compile_str(sysroot: Option<Path>, code: ~str, dir: &Path, flags: ~[~str],
cfgs: ~[~str], opt: bool, test: bool) -> bool {
compile_input(driver::str_input(code), dir, flags, cfgs, opt, test)
compile_input(sysroot, driver::str_input(code), dir, flags, cfgs, opt, test)
}
#[cfg(windows)]
@ -1002,6 +1036,7 @@ pub fn link_exe(src: &Path, dest: &Path) -> bool unsafe {
fn test_is_cmd() {
assert is_cmd(~"build");
assert is_cmd(~"clean");
assert is_cmd(~"do");
assert is_cmd(~"install");
assert is_cmd(~"prefer");
assert is_cmd(~"test");