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