Skip to content

Commit

Permalink
Updated xtask
Browse files Browse the repository at this point in the history
  • Loading branch information
nanoqsh committed Apr 24, 2024
1 parent 29f691a commit 2365fe5
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
/bin
/target
/Cargo.lock
.crates.toml
.crates2.json
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,17 @@ For more examples using the window, see the [examples](https://github.com/nanoqs
cargo run -p <example_name>
```

To build and run a wasm example, make sure [`wasm-pack`](https://github.com/rustwasm/wasm-pack) is installed and then run:
To build and run a wasm example:
```sh
cargo xtask <example_name>
cargo xtask build <example_name>
cargo xtask serve <example_name>
```
It will start a local server and you can open http://localhost:3000 in your browser to see the application running. For the web, only [WebGPU](https://gpuweb.github.io/gpuweb/) backend is supported, so make sure your browser supports it.

If [`wasm-pack`](https://github.com/rustwasm/wasm-pack) is already installed on the system, the build script will find it and use it to compile a wasm artifact. Otherwise, `wasm-pack` will be installed locally. To prevent this behavior add the `no-install` flag:
```sh
cargo xtask --no-install build <example_name>
```

Eventually it will start a local server and you can open http://localhost:3000 in your browser to see the application running. For the web, only [WebGPU](https://gpuweb.github.io/gpuweb/) backend is supported, so make sure your browser supports it.

Also see the [test](https://github.com/nanoqsh/dunge/tree/main/dunge/tests) directory for small examples of creation a single image.
172 changes: 147 additions & 25 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,165 @@
type Error = Box<dyn std::error::Error>;
use std::{
env, error,
io::ErrorKind,
path::{Path, PathBuf},
process::{Command, ExitCode},
};

fn main() {
if let Err(err) = run() {
eprintln!("error: {err}");
type Error = Box<dyn error::Error>;

fn main() -> ExitCode {
let (opts, mode) = match parse() {
Ok(ok) => ok,
Err(err) => {
eprintln!("args error: {err}");
return ExitCode::FAILURE;
}
};

match start(opts, mode) {
Ok(()) => ExitCode::SUCCESS,
Err(err) => {
eprintln!("error: {err}");
ExitCode::FAILURE
}
}
}

fn run() -> Result<(), Error> {
use std::{env, path::Path, process::Command};
fn parse() -> Result<(Opts, Mode), &'static str> {
const MODEERR: &str = "undefined mode";
const MODLERR: &str = "undefined module";

let mut args = env::args().skip(1);
let mut no_install = false;
let mode = loop {
match args.next().ok_or(MODEERR)?.as_str() {
"build" => break Mode::Build,
"serve" => break Mode::Serve,
opt => match opt.strip_prefix("--") {
Some("no-install") => no_install = true,
_ => return Err(MODEERR),
},
}
};

let opts = Opts {
module: args.next().ok_or(MODLERR)?,
no_install,
};

Ok((opts, mode))
}

struct Opts {
module: String,
no_install: bool,
}

enum Mode {
Build,
Serve,
}

let module = env::args().nth(1).ok_or("no module specified")?;
fn start(opts: Opts, mode: Mode) -> Result<(), Error> {
match mode {
Mode::Build => build(opts),
Mode::Serve => serve(opts),
}
}

fn build(opts: Opts) -> Result<(), Error> {
let root = Path::new(&env!("CARGO_MANIFEST_DIR"))
.parent()
.ok_or("root dir not found")?;

let status = Command::new("wasm-pack")
.current_dir(root)
let mut cmd = Command::new("wasm-pack");
cmd.args([
"build",
"examples/wasm",
"--no-pack",
"--no-typescript",
"--target",
"web",
])
.arg("--out-dir")
.arg(root.join("xtask/web").join(&opts.module))
.args(["-F", &opts.module]);

install_and_run(&mut cmd, opts.no_install)
}

fn install_and_run(cmd: &mut Command, no_install: bool) -> Result<(), Error> {
add_bin_path(cmd);
let name = cmd.get_program().to_string_lossy().into_owned();
match run(cmd, &name) {
Run::Ok => return Ok(()),
Run::NotFound if no_install => {}
Run::NotFound => {
eprintln!("{name} not found, installing..");
install(&name)?;
}
Run::Failed(s) => return Err(Error::from(s)),
}

match run(cmd, &name) {
Run::Ok => Ok(()),
Run::NotFound if no_install => Err(Error::from(format!("{name} not found"))),
Run::NotFound => Err(Error::from(format!("failed to install {name}"))),
Run::Failed(s) => Err(Error::from(s)),
}
}

fn add_bin_path(cmd: &mut Command) {
let bin_path = PathBuf::from("./bin");
let mut paths: Vec<_> = env::var_os("PATH")
.map(|path| env::split_paths(&path).collect())
.unwrap_or_default();

if !paths.contains(&bin_path) {
paths.push(bin_path);
}

let paths = env::join_paths(paths).expect("join paths");
cmd.env("PATH", paths);
}

enum Run {
Ok,
NotFound,
Failed(String),
}

fn run(cmd: &mut Command, name: &str) -> Run {
match cmd.status() {
Ok(status) if status.success() => Run::Ok,
Ok(_) => Run::Failed(format!("execution of {name} failed")),
Err(err) if err.kind() == ErrorKind::NotFound => Run::NotFound,
Err(err) => Run::Failed(format!("failed to run {name}: {err}")),
}
}

fn install(name: &str) -> Result<(), Error> {
let status = Command::new("cargo")
.args([
"build",
"examples/wasm",
"--no-pack",
"--no-typescript",
"--target",
"web",
"install",
"--root",
".",
"--target-dir",
"target",
"--locked",
])
.arg("--out-dir")
.arg(root.join("xtask/web").join(&module))
.args(["-F", &module])
.arg(name)
.status()
.map_err(|err| format!("failed to run wasm-pack: {err}"))?;
.map_err(|err| format!("failed to run cargo: {err}"))?;

if !status.success() {
return Err(Error::from("wasm-pack build failed"));
if status.success() {
Ok(())
} else {
Err(Error::from(format!("failed to install {name}")))
}

serv(&module)
}

fn serv(module: &str) -> Result<(), Error> {
fn serve(Opts { module, .. }: Opts) -> Result<(), Error> {
use {
askama::Template,
helpers::serv::{self, Page},
Expand All @@ -51,7 +173,7 @@ fn serv(module: &str) -> Result<(), Error> {
module: &'a str,
}

Index { module }
Index { module: &module }
};

let html = index.render()?.leak();
Expand Down

0 comments on commit 2365fe5

Please sign in to comment.