sweet_cli/commands/
cmd_cargo.rs

1use beet::prelude::*;
2use clap::Parser;
3
4#[derive(Debug, Parser)]
5#[command(name = "test")]
6pub struct CargoTest {
7	#[command(flatten)]
8	cargo_runner: CargoCmdExtra,
9}
10impl CargoTest {
11	pub async fn run(mut self) -> Result {
12		self.cargo_runner.build_cmd.cmd = "test".to_string();
13		self.cargo_runner.run().await?;
14		Ok(())
15	}
16}
17
18#[derive(Debug, Parser)]
19#[command(name = "run")]
20pub struct CargoRun {
21	#[command(flatten)]
22	cargo_runner: CargoCmdExtra,
23}
24impl CargoRun {
25	pub async fn run(mut self) -> Result {
26		self.cargo_runner.build_cmd.cmd = "run".to_string();
27		self.cargo_runner.run().await?;
28		Ok(())
29	}
30}
31
32
33/// A cargo command with extra functionality like watch
34#[derive(Debug, Parser)]
35pub struct CargoCmdExtra {
36	/// the file passed in by cargo test.
37	///
38	/// It will look something like $CARGO_TARGET_DIR/wasm32-unknown-unknown/debug/deps/hello_test-c3298911e67ad05b.wasm
39	#[command(flatten)]
40	pub build_cmd: CargoBuildCmd,
41	#[arg(short, long)]
42	pub watch: bool,
43	#[arg(short, long)]
44	pub no_default_filters: bool,
45	#[command(flatten)]
46	pub filter: GlobFilter,
47}
48
49
50impl CargoCmdExtra {
51	pub async fn run(mut self) -> Result {
52		self.append_args();
53		self.run_binary()?;
54		if self.watch {
55			self.watch().await?;
56		}
57		Ok(())
58	}
59
60	fn append_args(&mut self) {
61		if self.no_default_filters == false {
62			self.filter
63				.include("**/*.rs")
64				.exclude("{.git,target,html}/**")
65				.exclude("*/codegen/*");
66		}
67		let is_upstream = self
68			.build_cmd
69			.package
70			.as_ref()
71			// these crates are upstream of sweet test so do not support the watch command
72			.map(|p| ["beet_utils"].contains(&p.as_str()))
73			.unwrap_or(false);
74		if self.watch && self.build_cmd.lib && !is_upstream {
75			// watching, only works if before any trailing args
76			self.build_cmd
77				.trailing_args
78				.insert(0, "--watch".to_string());
79		}
80	}
81	// 	--include '**/*.rs' \
82	// --exclude '{.git,target,html}/**' \
83	// --exclude '*/codegen/*' \
84
85	async fn watch(self) -> Result {
86		let mut rx = FsWatcher {
87			filter: self.filter.clone(),
88			..Default::default()
89		}
90		.watch()?;
91
92		while let Some(ev) = rx.recv().await? {
93			if !ev.has_mutate() {
94				continue;
95			}
96			self.run_binary()?;
97		}
98
99		Ok(())
100	}
101
102	/// run the binary:
103	/// ## Errors
104	/// Errors if not in watch mode and the command fails
105	fn run_binary(&self) -> Result {
106		if self.watch {
107			terminal::clear()?;
108			println!("\n🤘 sweet as 🤘\n");
109		}
110		let result = self.build_cmd.spawn();
111		// we only propagate command errors if not in watch mode,
112		// otherwise assume its been logged to the terminal
113		if !self.watch {
114			result?;
115		}
116		Ok(())
117	}
118}