1#![deny(
4    missing_debug_implementations,
5    trivial_numeric_casts,
6    unstable_features,
7    unused_import_braces,
8    unused_qualifications
9)]
10
11#[macro_use]
12extern crate structopt;
13extern crate clap;
14extern crate digest;
15extern crate futures;
16extern crate http;
17extern crate hyper;
18extern crate libflate;
19extern crate notify;
20extern crate pbr;
21extern crate reqwest;
22extern crate serde;
23extern crate sha1;
24extern crate sha2;
25extern crate tar;
26extern crate tempfile;
27extern crate toml;
28#[macro_use]
29extern crate serde_derive;
30#[macro_use]
31extern crate serde_json;
32extern crate base_x;
33extern crate handlebars;
34extern crate indexmap;
35extern crate regex;
36extern crate unicode_categories;
37extern crate walkdir;
38extern crate websocket;
39#[macro_use]
40extern crate lazy_static;
41extern crate directories;
42extern crate percent_encoding;
43
44extern crate parity_wasm;
45#[macro_use]
46extern crate log;
47extern crate env_logger;
48extern crate rustc_demangle;
49
50extern crate ansi_term;
51extern crate cargo_metadata;
52
53extern crate memmap;
54extern crate semver;
55
56extern crate atty;
57extern crate open;
58#[macro_use]
59extern crate failure;
60extern crate mime_guess;
61
62mod cargo_shim;
63
64#[macro_use]
65mod utils;
66mod build;
67mod chrome_devtools;
68mod cmd_build;
69mod cmd_deploy;
70mod cmd_prepare_emscripten;
71mod cmd_start;
72mod cmd_test;
73mod config;
74mod deployment;
75mod emscripten;
76mod error;
77mod http_utils;
78mod package;
79mod project_dirs;
80mod test_chromium;
81mod wasm;
82mod wasm_context;
83mod wasm_export_main;
84mod wasm_export_table;
85mod wasm_gc;
86mod wasm_hook_grow;
87mod wasm_inline_js;
88mod wasm_intrinsics;
89mod wasm_js_export;
90mod wasm_js_snippet;
91mod wasm_runtime;
92
93use std::ffi::OsStr;
94use std::net::{IpAddr, ToSocketAddrs};
95use std::path::PathBuf;
96
97use build::{Backend, BuildArgs};
98use cargo_shim::MessageFormat;
99use error::Error;
100use wasm_runtime::RuntimeKind;
101
102#[derive(Debug, StructOpt)]
104#[structopt(name = "cargo-web")]
105#[structopt(about = "A `cargo` subcommand for the client-side web.")]
106#[structopt(raw(global_setting = "structopt::clap::AppSettings::ColoredHelp"))]
107#[structopt(raw(setting = "structopt::clap::AppSettings::VersionlessSubcommands"))]
108#[structopt(rename_all = "kebab-case")]
109pub enum CargoWebOpts {
110    Build(BuildOpts),
112    Check(CheckOpts),
114    Deploy(DeployOpts),
116    PrepareEmscripten(PrepareEmscriptenOpts),
118    Start(StartOpts),
120    Test(TestOpts),
122    #[doc(hidden)]
123    #[structopt(raw(setting = "structopt::clap::AppSettings::Hidden"))]
124    __Nonexhaustive,
125}
126
127pub fn run(cfg: CargoWebOpts) -> Result<(), Error> {
129    match cfg {
130        CargoWebOpts::Build(BuildOpts {
131            build_args,
132            build_target,
133            ext,
134        }) => cmd_build::command_build(BuildArgs::new(build_args, ext, build_target)?),
135        CargoWebOpts::Check(CheckOpts {
136            build_args,
137            build_target,
138            ext,
139        }) => cmd_build::command_check(BuildArgs::new(build_args, ext, build_target)?),
140        CargoWebOpts::Deploy(DeployOpts { build_args, output }) => {
141            cmd_deploy::command_deploy(build_args.into(), output)
142        }
143        CargoWebOpts::PrepareEmscripten(_) => cmd_prepare_emscripten::command_prepare_emscripten(),
144        CargoWebOpts::Start(StartOpts {
145            build_args,
146            build_target,
147            auto_reload,
148            open,
149            port,
150            host,
151        }) => cmd_start::command_start(
152            BuildArgs::from(build_args).with_target(build_target),
153            host,
154            port,
155            open,
156            auto_reload,
157        ),
158        CargoWebOpts::Test(TestOpts {
159            build_args,
160            nodejs,
161            no_run,
162            passthrough,
163        }) => {
164            let pass_os = passthrough.iter().map(OsStr::new).collect::<Vec<_>>();
165            cmd_test::command_test(build_args.into(), nodejs, no_run, &pass_os)
166        }
167        CargoWebOpts::__Nonexhaustive => unreachable!(),
168    }
169}
170
171#[derive(Debug, StructOpt)]
173#[structopt(rename_all = "kebab-case")]
174pub struct BuildOpts {
175    #[structopt(flatten)]
176    build_args: Build,
177    #[structopt(flatten)]
178    ext: BuildExt,
179    #[structopt(flatten)]
180    build_target: Target,
181}
182
183#[derive(Debug, StructOpt)]
185#[structopt(rename_all = "kebab-case")]
186pub struct CheckOpts {
187    #[structopt(flatten)]
188    build_args: Build,
189    #[structopt(flatten)]
190    ext: BuildExt,
191    #[structopt(flatten)]
192    build_target: Target,
193}
194
195#[derive(Debug, StructOpt)]
197#[structopt(rename_all = "kebab-case")]
198pub struct DeployOpts {
199    #[structopt(short = "o", long, parse(from_os_str))]
201    output: Option<PathBuf>,
202    #[structopt(flatten)]
203    build_args: Build,
204}
205
206#[derive(Debug, StructOpt)]
208#[structopt(rename_all = "kebab-case")]
209pub struct PrepareEmscriptenOpts {
210    #[doc(hidden)]
211    #[structopt(raw(set = "structopt::clap::ArgSettings::Hidden"))]
212    __reserved: bool,
213}
214
215#[derive(Debug, StructOpt)]
217#[structopt(rename_all = "kebab-case")]
218pub struct StartOpts {
219    #[structopt(
221        long,
222        parse(try_from_str = "resolve_host"),
223        default_value = "localhost"
224    )]
225    host: IpAddr,
226    #[structopt(long, default_value = "8000")]
228    port: u16,
229    #[structopt(long)]
231    open: bool,
232    #[structopt(long)]
234    auto_reload: bool,
235    #[structopt(flatten)]
236    build_target: Target,
237    #[structopt(flatten)]
238    build_args: Build,
239}
240
241#[derive(Debug, StructOpt)]
243#[structopt(rename_all = "kebab-case")]
244pub struct TestOpts {
245    #[structopt(long)]
247    no_run: bool,
248    #[structopt(long)]
250    nodejs: bool,
251    #[structopt(flatten)]
252    build_args: Build,
253    passthrough: Vec<String>,
255}
256
257#[derive(Debug, StructOpt)]
259#[structopt(rename_all = "kebab-case")]
260struct Target {
261    #[structopt(long, group = "target_type")]
263    lib: bool,
264    #[structopt(long, group = "target_type")]
266    bin: Option<String>,
267    #[structopt(long, group = "target_type")]
269    example: Option<String>,
270    #[structopt(long, group = "target_type")]
272    test: Option<String>,
273    #[structopt(long, group = "target_type")]
275    bench: Option<String>,
276}
277
278impl Default for Target {
279    fn default() -> Self {
280        Self {
281            lib: false,
282            bin: None,
283            example: None,
284            test: None,
285            bench: None,
286        }
287    }
288}
289
290#[derive(Debug, StructOpt)]
292#[structopt(rename_all = "kebab-case")]
293struct BuildExt {
294    #[structopt(
296        long,
297        default_value = "human",
298        parse(try_from_str),
299        raw(possible_values = "&[\"human\", \"json\"]"),
300        raw(set = "structopt::clap::ArgSettings::NextLineHelp")
301    )]
302    message_format: MessageFormat,
303    #[structopt(
307        long,
308        parse(try_from_str),
309        raw(set = "structopt::clap::ArgSettings::NextLineHelp")
310    )]
311    runtime: Option<RuntimeKind>,
312}
313
314impl Default for BuildExt {
315    fn default() -> Self {
316        Self {
317            message_format: MessageFormat::Json,
318            runtime: None,
319        }
320    }
321}
322
323#[derive(Debug, StructOpt)]
325#[structopt(rename_all = "kebab-case")]
326struct Build {
327    #[structopt(short = "p", long)]
329    pub package: Option<String>,
330    #[structopt(long, group = "build_features")]
332    pub features: Option<String>,
333    #[structopt(long, group = "build_features")]
335    pub all_features: bool,
336    #[structopt(long)]
338    pub no_default_features: bool,
339    #[structopt(long)]
341    pub use_system_emscripten: bool,
342    #[structopt(long)]
344    pub release: bool,
345    #[structopt(
348        long,
349        parse(try_from_str),
350        raw(
351            possible_values = "&[\"wasm32-unknown-unknown\", \"wasm32-unknown-emscripten\", \"asmjs-unknown-emscripten\"]"
352        ),
353        raw(set = "structopt::clap::ArgSettings::NextLineHelp")
354    )]
355    pub target: Option<Backend>,
356    #[structopt(short = "v", long)]
358    pub verbose: bool,
359}
360
361impl Default for Build {
362    fn default() -> Self {
368        Self {
369            package: None,
370            features: None,
371            all_features: false,
372            no_default_features: false,
373            use_system_emscripten: false,
374            release: false,
375            target: None,
376            verbose: false,
377        }
378    }
379}
380
381fn resolve_host(host: &str) -> std::io::Result<IpAddr> {
383    (host, 0)
384        .to_socket_addrs()
385        .map(|itr| itr.map(|a| a.ip()).collect::<Vec<_>>()[0])
386}