mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
Add a cargo run
command
This currently only supports executing the `src/main.rs` convention, no other. Close #149
This commit is contained in:
parent
ec0895b460
commit
a64b9073f4
1
Makefile
1
Makefile
@ -22,6 +22,7 @@ BINS = cargo \
|
||||
cargo-verify-project \
|
||||
cargo-git-checkout \
|
||||
cargo-test \
|
||||
cargo-run
|
||||
|
||||
SRC = $(shell find src -name '*.rs' -not -path 'src/bin*')
|
||||
|
||||
|
@ -56,7 +56,7 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
|
||||
"compile"
|
||||
};
|
||||
|
||||
let opts = CompileOptions {
|
||||
let mut opts = CompileOptions {
|
||||
update: options.update_remotes,
|
||||
env: env,
|
||||
shell: shell,
|
||||
@ -64,7 +64,7 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
|
||||
target: options.target.as_ref().map(|t| t.as_slice()),
|
||||
};
|
||||
|
||||
ops::compile(&root, opts).map(|_| None).map_err(|err| {
|
||||
ops::compile(&root, &mut opts).map(|_| None).map_err(|err| {
|
||||
CliError::from_boxed(err, 101)
|
||||
})
|
||||
}
|
||||
|
69
src/bin/cargo-run.rs
Normal file
69
src/bin/cargo-run.rs
Normal file
@ -0,0 +1,69 @@
|
||||
#![crate_name = "cargo-run"]
|
||||
#![feature(phase)]
|
||||
|
||||
#[phase(plugin, link)]
|
||||
extern crate cargo;
|
||||
extern crate serialize;
|
||||
|
||||
#[phase(plugin, link)]
|
||||
extern crate hammer;
|
||||
|
||||
use std::os;
|
||||
use std::io::process::ExitStatus;
|
||||
|
||||
use cargo::ops;
|
||||
use cargo::{execute_main_without_stdin};
|
||||
use cargo::core::{MultiShell};
|
||||
use cargo::util::{CliResult, CliError};
|
||||
use cargo::util::important_paths::find_project_manifest;
|
||||
|
||||
#[deriving(PartialEq,Clone,Decodable)]
|
||||
struct Options {
|
||||
manifest_path: Option<String>,
|
||||
jobs: Option<uint>,
|
||||
update: bool,
|
||||
rest: Vec<String>,
|
||||
}
|
||||
|
||||
hammer_config!(Options "Run the package's main executable", |c| {
|
||||
c.short("jobs", 'j').short("update", 'u')
|
||||
})
|
||||
|
||||
fn main() {
|
||||
execute_main_without_stdin(execute);
|
||||
}
|
||||
|
||||
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
|
||||
let root = match options.manifest_path {
|
||||
Some(path) => Path::new(path),
|
||||
None => try!(find_project_manifest(&os::getcwd(), "Cargo.toml")
|
||||
.map_err(|_| {
|
||||
CliError::new("Could not find Cargo.toml in this \
|
||||
directory or any parent directory",
|
||||
102)
|
||||
}))
|
||||
};
|
||||
|
||||
let mut compile_opts = ops::CompileOptions {
|
||||
update: options.update,
|
||||
env: "compile",
|
||||
shell: shell,
|
||||
jobs: options.jobs,
|
||||
target: None,
|
||||
};
|
||||
|
||||
let err = try!(ops::run(&root, &mut compile_opts,
|
||||
options.rest.as_slice()).map_err(|err| {
|
||||
CliError::from_boxed(err, 101)
|
||||
}));
|
||||
match err {
|
||||
None => Ok(None),
|
||||
Some(err) => {
|
||||
Err(match err.exit {
|
||||
Some(ExitStatus(i)) => CliError::from_boxed(box err, i as uint),
|
||||
_ => CliError::from_boxed(box err, 101),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
|
||||
}))
|
||||
};
|
||||
|
||||
let compile_opts = ops::CompileOptions {
|
||||
let mut compile_opts = ops::CompileOptions {
|
||||
update: options.update,
|
||||
env: "test",
|
||||
shell: shell,
|
||||
@ -52,7 +52,8 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
|
||||
target: None,
|
||||
};
|
||||
|
||||
let test_executables = try!(ops::compile(&root, compile_opts).map_err(|err| {
|
||||
let test_executables = try!(ops::compile(&root,
|
||||
&mut compile_opts).map_err(|err| {
|
||||
CliError::from_boxed(err, 101)
|
||||
}));
|
||||
|
||||
|
@ -51,8 +51,10 @@ fn execute() {
|
||||
println!("Commands:");
|
||||
println!(" build # compile the current project");
|
||||
println!(" test # run the tests");
|
||||
println!(" clean # remove the target directory\n");
|
||||
|
||||
println!(" clean # remove the target directory");
|
||||
println!(" run # build and execute src/main.rs");
|
||||
println!("");
|
||||
|
||||
|
||||
let (_, options) = hammer::usage::<GlobalFlags>(false);
|
||||
println!("Options (for all commands):\n\n{}", options);
|
||||
|
@ -38,8 +38,9 @@ pub struct CompileOptions<'a> {
|
||||
pub target: Option<&'a str>,
|
||||
}
|
||||
|
||||
pub fn compile(manifest_path: &Path, options: CompileOptions) -> CargoResult<Vec<String>> {
|
||||
let CompileOptions { update, env, shell, jobs, target } = options;
|
||||
pub fn compile(manifest_path: &Path,
|
||||
options: &mut CompileOptions) -> CargoResult<Vec<String>> {
|
||||
let CompileOptions { update, env, ref mut shell, jobs, target } = *options;
|
||||
let target = target.map(|s| s.to_string());
|
||||
|
||||
log!(4, "compile; manifest-path={}", manifest_path.display());
|
||||
@ -60,7 +61,7 @@ pub fn compile(manifest_path: &Path, options: CompileOptions) -> CargoResult<Vec
|
||||
let source_ids = package.get_source_ids();
|
||||
|
||||
let (packages, resolve) = {
|
||||
let mut config = try!(Config::new(shell, update, jobs, target.clone()));
|
||||
let mut config = try!(Config::new(*shell, update, jobs, target.clone()));
|
||||
|
||||
let mut registry =
|
||||
try!(PackageRegistry::new(source_ids, override_ids, &mut config));
|
||||
@ -83,7 +84,7 @@ pub fn compile(manifest_path: &Path, options: CompileOptions) -> CargoResult<Vec
|
||||
target.get_profile().get_env() == env
|
||||
}).collect::<Vec<&Target>>();
|
||||
|
||||
let mut config = try!(Config::new(shell, update, jobs, target));
|
||||
let mut config = try!(Config::new(*shell, update, jobs, target));
|
||||
|
||||
try!(ops::compile_targets(env.as_slice(), targets.as_slice(), &package,
|
||||
&PackageSet::new(packages.as_slice()), &resolve, &mut config));
|
||||
|
23
src/cargo/ops/cargo_run.rs
Normal file
23
src/cargo/ops/cargo_run.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use std::os;
|
||||
|
||||
use ops;
|
||||
use util::{CargoResult, human, process, ProcessError};
|
||||
|
||||
pub fn run(manifest_path: &Path,
|
||||
options: &mut ops::CompileOptions,
|
||||
args: &[String]) -> CargoResult<Option<ProcessError>> {
|
||||
if !manifest_path.dir_path().join("src").join("main.rs").exists() {
|
||||
return Err(human("`src/main.rs` must be present for `cargo run`"))
|
||||
}
|
||||
|
||||
try!(ops::compile(manifest_path, options));
|
||||
let exe = manifest_path.dir_path().join("target/main");
|
||||
let exe = match exe.path_relative_from(&os::getcwd()) {
|
||||
Some(path) => path,
|
||||
None => exe,
|
||||
};
|
||||
let process = process(exe).args(args);
|
||||
|
||||
try!(options.shell.status("Running", process.to_string()));
|
||||
Ok(process.exec().err())
|
||||
}
|
@ -2,8 +2,10 @@ pub use self::cargo_clean::clean;
|
||||
pub use self::cargo_compile::{compile, CompileOptions};
|
||||
pub use self::cargo_read_manifest::{read_manifest,read_package,read_packages};
|
||||
pub use self::cargo_rustc::compile_targets;
|
||||
pub use self::cargo_run::run;
|
||||
|
||||
mod cargo_clean;
|
||||
mod cargo_compile;
|
||||
mod cargo_read_manifest;
|
||||
mod cargo_rustc;
|
||||
mod cargo_run;
|
||||
|
84
tests/test_cargo_run.rs
Normal file
84
tests/test_cargo_run.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use std::path;
|
||||
|
||||
use support::{project, execs};
|
||||
use support::{COMPILING, RUNNING};
|
||||
use hamcrest::{assert_that, existing_file};
|
||||
|
||||
fn setup() {
|
||||
}
|
||||
|
||||
test!(simple {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
"#)
|
||||
.file("src/main.rs", r#"
|
||||
fn main() { println!("hello"); }
|
||||
"#);
|
||||
|
||||
assert_that(p.cargo_process("cargo-run"),
|
||||
execs().with_status(0).with_stdout(format!("\
|
||||
{compiling} foo v0.0.1 (file:{dir})
|
||||
{running} `target{sep}main`
|
||||
hello
|
||||
",
|
||||
compiling = COMPILING,
|
||||
running = RUNNING,
|
||||
dir = p.root().display(),
|
||||
sep = path::SEP).as_slice()));
|
||||
assert_that(&p.bin("main"), existing_file());
|
||||
})
|
||||
|
||||
test!(simple_with_args {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
"#)
|
||||
.file("src/main.rs", r#"
|
||||
fn main() {
|
||||
assert_eq!(std::os::args().get(1).as_slice(), "hello");
|
||||
assert_eq!(std::os::args().get(2).as_slice(), "world");
|
||||
}
|
||||
"#);
|
||||
|
||||
assert_that(p.cargo_process("cargo-run").arg("hello").arg("world"),
|
||||
execs().with_status(0));
|
||||
})
|
||||
|
||||
test!(exit_code {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
"#)
|
||||
.file("src/main.rs", r#"
|
||||
fn main() { std::os::set_exit_status(2); }
|
||||
"#);
|
||||
|
||||
assert_that(p.cargo_process("cargo-run"),
|
||||
execs().with_status(2));
|
||||
})
|
||||
|
||||
test!(no_main_file {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
"#)
|
||||
.file("src/lib.rs", "");
|
||||
|
||||
assert_that(p.cargo_process("cargo-run"),
|
||||
execs().with_status(101)
|
||||
.with_stderr("`src/main.rs` must be present for \
|
||||
`cargo run`\n"));
|
||||
})
|
@ -27,3 +27,4 @@ mod test_cargo_compile_path_deps;
|
||||
mod test_cargo_test;
|
||||
mod test_shell;
|
||||
mod test_cargo_cross_compile;
|
||||
mod test_cargo_run;
|
||||
|
Loading…
x
Reference in New Issue
Block a user