wasi_worker_cli/
cli.rs

1use super::gc;
2use std::fs;
3use std::io;
4use std::path::Path;
5use std::process::{Command, Stdio};
6use structopt::StructOpt;
7use toml_edit::{array, value, Document, Item, Table};
8
9fn worker_table() -> Table {
10    let mut table = Table::new();
11    table["name"] = value("worker");
12    table["path"] = value("src/bin/worker.rs");
13    table
14}
15
16const WASI_WORKER_VERSION: &str = "0.5";
17
18/// Install JavaScript glue code and WASM toolset for wasi-worker browser worker to function.
19///
20/// Details https://crates.io/crates/wasi-worker
21#[derive(Debug, StructOpt)]
22pub enum Cli {
23    /// Install static files and worker.rs template in current crate.
24    ///
25    /// Note! it adds [[bin]] target to ./Cargo.toml and sets wasi-worker dependency
26    Install,
27    /// Executes `cargo build --bin worker` and deploys with glue code under ./dist
28    Deploy,
29}
30
31impl Cli {
32    const WORKER_JS: &'static [u8] = include_bytes!("../js/dist/worker.js");
33    const WORKER_RS: &'static [u8] = include_bytes!("../worker/worker.rs");
34    pub fn exec(&self) -> io::Result<()> {
35        match self {
36            Self::Install => self.install(),
37            Self::Deploy => self.deploy(),
38        }
39    }
40    fn install(&self) -> io::Result<()> {
41        Self::install_worker()
42    }
43    fn deploy(&self) -> io::Result<()> {
44        println!("Building worker with release settings");
45        Self::build_worker()?;
46        println!("Output will go to ./dist");
47        fs::create_dir_all("dist")?;
48        println!("Copying target/wasm32-wasi/release/worker.wasm");
49        fs::copy("target/wasm32-wasi/release/worker.wasm", "dist/worker.wasm")?;
50        println!("Cleaning worker.wasm with wasm-gc");
51        gc("dist/worker.wasm")?;
52        println!("Deploying JavaScript glue code under dist/worker.js");
53        fs::write("dist/worker.js", Self::WORKER_JS)?;
54        Ok(())
55    }
56
57    fn install_worker() -> io::Result<()> {
58        // if the submodule has not been checked out, the build will stall
59        if !Path::new("./Cargo.toml").exists() {
60            panic!("Current dir is not cargo package");
61        }
62        println!("Copying worker.rs template to src/bin/worker.rs");
63        fs::create_dir_all("src/bin")?;
64        fs::write("src/bin/worker.rs", Self::WORKER_RS)?;
65
66        println!("Checking Cargo.toml for bin worker target...");
67        let cargo_toml = fs::read_to_string("./Cargo.toml")?;
68        let mut toml = cargo_toml
69            .parse::<Document>()
70            .expect("Invalid Cargo.toml, bin target not installed but can be built");
71        // Insert only when there is no existing bin target with name worker
72        let changed = match &mut toml["bin"] {
73            Item::ArrayOfTables(tables) => {
74                if tables
75                    .iter()
76                    .filter(|table| {
77                        table["name"]
78                            .as_str()
79                            .filter(|val| val == &"worker")
80                            .is_some()
81                    })
82                    .count()
83                    == 0
84                {
85                    tables.append(worker_table());
86                    true
87                } else {
88                    false
89                }
90            }
91            _ => {
92                toml["bin"] = array();
93                toml["bin"]
94                    .as_array_of_tables_mut()
95                    .map(|arr| arr.append(worker_table()));
96                true
97            }
98        };
99        toml["dependencies"]["wasi-worker"] = value(WASI_WORKER_VERSION);
100        if changed {
101            // Note: it will overwrite Cargo.toml file
102            println!("Adding bin worker target to Cargo.toml");
103            fs::write("./Cargo.toml", toml.to_string())?;
104        }
105        Ok(())
106    }
107
108    fn build_worker() -> io::Result<()> {
109        // if the submodule has not been checked out, the build will stall
110        if !Path::new("./Cargo.toml").exists() {
111            panic!("Current dir is not cargo package");
112        }
113
114        let mut cmd = Command::new("cargo");
115        cmd.args(&[
116            "build",
117            "--bin=worker",
118            "--release",
119            "--target=wasm32-wasi",
120            "--target-dir=./target",
121        ])
122        .stdout(Stdio::inherit())
123        .stderr(Stdio::inherit());
124        let output = cmd.output()?;
125
126        let status = output.status;
127        if !status.success() {
128            panic!(
129                "Building worker failed: exit code: {}",
130                status.code().unwrap()
131            );
132        }
133
134        Ok(())
135    }
136}