mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Add CLI subcommands roc run
and roc build
This commit is contained in:
parent
ee481e6713
commit
d4a45ed489
5 changed files with 64 additions and 59 deletions
|
@ -1,15 +0,0 @@
|
||||||
# Interpreter
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ roc FILENAME.roc
|
|
||||||
```
|
|
||||||
|
|
||||||
When building from Rust source, use `cargo run -- FILENAME.roc` instead of `roc FILENAME.roc`.
|
|
||||||
|
|
||||||
For example, here's how to run the "EchoName" example this way:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cargo run -- examples/EchoName.roc
|
|
||||||
```
|
|
|
@ -32,19 +32,17 @@ use target_lexicon::{Architecture, OperatingSystem, Triple, Vendor};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::runtime::Builder;
|
use tokio::runtime::Builder;
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
|
||||||
run(build_app().get_matches())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static FLAG_OPTIMIZE: &str = "optimize";
|
pub static FLAG_OPTIMIZE: &str = "optimize";
|
||||||
pub static FLAG_ROC_FILE: &str = "ROC_FILE";
|
pub static FLAG_ROC_FILE: &str = "ROC_FILE";
|
||||||
|
|
||||||
pub fn build_app<'a>() -> App<'a> {
|
pub fn build_app<'a>() -> App<'a> {
|
||||||
App::new("roc")
|
App::new("roc")
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
|
.subcommand(App::new("build")
|
||||||
|
.about("Build a program")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(FLAG_ROC_FILE)
|
Arg::with_name(FLAG_ROC_FILE)
|
||||||
.help("The .roc file to compile and run")
|
.help("The .roc file to build")
|
||||||
.required(true),
|
.required(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -53,10 +51,34 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
.subcommand(App::new("run")
|
||||||
|
.about("Build and run a program")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(FLAG_ROC_FILE)
|
||||||
|
.help("The .roc file to build and run")
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(FLAG_OPTIMIZE)
|
||||||
|
.long(FLAG_OPTIMIZE)
|
||||||
|
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the CLI. This is separate from main() so that tests can call it directly.
|
fn main() -> io::Result<()> {
|
||||||
pub fn run(matches: ArgMatches) -> io::Result<()> {
|
let matches = build_app().get_matches();
|
||||||
|
|
||||||
|
match matches.subcommand_name() {
|
||||||
|
Some("build") => build(matches.subcommand_matches("build").unwrap(), false),
|
||||||
|
Some("run") => build(matches.subcommand_matches("run").unwrap(), true),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(matches: &ArgMatches, run_after_build: bool) -> io::Result<()> {
|
||||||
let filename = matches.value_of(FLAG_ROC_FILE).unwrap();
|
let filename = matches.value_of(FLAG_ROC_FILE).unwrap();
|
||||||
let opt_level = if matches.is_present(FLAG_OPTIMIZE) {
|
let opt_level = if matches.is_present(FLAG_OPTIMIZE) {
|
||||||
OptLevel::Optimize
|
OptLevel::Optimize
|
||||||
|
@ -92,18 +114,32 @@ pub fn run(matches: ArgMatches) -> io::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let loaded = rt.block_on(load_file(src_dir, path, opt_level));
|
let binary_path = rt
|
||||||
|
.block_on(build_file(src_dir, path, opt_level))
|
||||||
|
.expect("TODO gracefully handle block_on failing");
|
||||||
|
|
||||||
loaded.expect("TODO gracefully handle LoadingProblem");
|
if run_after_build {
|
||||||
|
// Run the compiled app
|
||||||
|
rt.block_on(async {
|
||||||
|
Command::new(binary_path)
|
||||||
|
.spawn()
|
||||||
|
.unwrap_or_else(|err| panic!("Failed to run app after building it: {:?}", err))
|
||||||
|
.await
|
||||||
|
.map_err(|_| {
|
||||||
|
todo!("gracefully handle error after `app` spawned");
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.expect("TODO gracefully handle block_on failing");
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_file(
|
async fn build_file(
|
||||||
src_dir: PathBuf,
|
src_dir: PathBuf,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
opt_level: OptLevel,
|
opt_level: OptLevel,
|
||||||
) -> Result<(), LoadingProblem> {
|
) -> Result<PathBuf, LoadingProblem> {
|
||||||
let compilation_start = SystemTime::now();
|
let compilation_start = SystemTime::now();
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
|
|
||||||
|
@ -176,22 +212,7 @@ async fn load_file(
|
||||||
todo!("gracefully handle error after `rustc` spawned");
|
todo!("gracefully handle error after `rustc` spawned");
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Step 4: Run the compiled app
|
Ok(binary_path)
|
||||||
Command::new(binary_path)
|
|
||||||
.spawn()
|
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
panic!(
|
|
||||||
"{} failed to run: {:?}",
|
|
||||||
cwd.join("app").to_str().unwrap(),
|
|
||||||
err
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.map_err(|_| {
|
|
||||||
todo!("gracefully handle error after `app` spawned");
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen(
|
fn gen(
|
||||||
|
|
|
@ -92,13 +92,12 @@ mod cli_run {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn run_hello_world() {
|
fn run_hello_world() {
|
||||||
let out = run_roc(&[example_file("hello-world", "Hello.roc").to_str().unwrap()]);
|
let out = run_roc(&[
|
||||||
|
"run",
|
||||||
|
example_file("hello-world", "Hello.roc").to_str().unwrap(),
|
||||||
|
]);
|
||||||
|
|
||||||
assert_eq!(&out.stderr, "");
|
assert_eq!(&out.stderr, "");
|
||||||
|
|
||||||
// TODO make separate `roc build` and `roc run` commands, and here do
|
|
||||||
// `roc build` followed by manually executing the compiled `app` binary
|
|
||||||
// and doing an `assert_eq!` on the entire stdout of that compiled `app` binary
|
|
||||||
assert!(&out.stdout.ends_with("Hello, World!\n"));
|
assert!(&out.stdout.ends_with("Hello, World!\n"));
|
||||||
assert!(out.status.success());
|
assert!(out.status.success());
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
To run:
|
To run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cargo run hello.roc
|
$ cargo run run Hello.roc
|
||||||
```
|
```
|
||||||
|
|
||||||
To run in release mode instead, do:
|
To run in release mode instead, do:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cargo run --release hello.roc
|
$ cargo run --release run Hello.roc
|
||||||
```
|
```
|
||||||
|
|
||||||
## Design Notes
|
## Design Notes
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
To run:
|
To run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cargo run qs.roc
|
$ cargo run run Quicksort.roc
|
||||||
```
|
```
|
||||||
|
|
||||||
To run in release mode instead, do:
|
To run in release mode instead, do:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cargo run --release qs.roc
|
$ cargo run --release run Quicksort.roc
|
||||||
```
|
```
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue