spacetimedb_cli/subcommands/
start.rs1use std::ffi::OsString;
2use std::io;
3use std::process::{Command, ExitCode};
4
5use anyhow::Context;
6use clap::{Arg, ArgMatches};
7use spacetimedb_paths::SpacetimePaths;
8
9use crate::util::resolve_sibling_binary;
10
11pub fn cli() -> clap::Command {
12 clap::Command::new("start")
13 .about("Start a local SpacetimeDB instance")
14 .long_about(
15 "\
16Start a local SpacetimeDB instance
17
18Run `spacetime start --help` to see all options.",
19 )
20 .disable_help_flag(true)
21 .arg(
22 Arg::new("edition")
23 .long("edition")
24 .help("The edition of SpacetimeDB to start up")
25 .value_parser(clap::value_parser!(Edition))
26 .default_value("standalone"),
27 )
28 .arg(
29 Arg::new("args")
30 .help("The args to pass to `spacetimedb-{edition} start`")
31 .value_parser(clap::value_parser!(OsString))
32 .allow_hyphen_values(true)
33 .num_args(0..),
34 )
35}
36
37#[derive(clap::ValueEnum, Clone, Copy)]
38enum Edition {
39 Standalone,
40 Cloud,
41}
42
43pub async fn exec(paths: &SpacetimePaths, args: &ArgMatches) -> anyhow::Result<ExitCode> {
44 let edition = args.get_one::<Edition>("edition").unwrap();
45 let args = args.get_many::<OsString>("args").unwrap_or_default();
46 let bin_name = match edition {
47 Edition::Standalone => "spacetimedb-standalone",
48 Edition::Cloud => "spacetimedb-cloud",
49 };
50 let bin_path = resolve_sibling_binary(bin_name)?;
51 let mut cmd = Command::new(&bin_path);
52 cmd.arg("start")
53 .arg("--data-dir")
54 .arg(&paths.data_dir)
55 .arg("--jwt-key-dir")
56 .arg(&paths.cli_config_dir)
57 .args(args);
58
59 exec_replace(&mut cmd).with_context(|| format!("exec failed for {}", bin_path.display()))
60}
61
62pub(crate) fn exec_replace(cmd: &mut Command) -> io::Result<ExitCode> {
80 #[cfg(unix)]
81 {
82 use std::os::unix::process::CommandExt;
83 let err = cmd.exec();
85 Err(err)
86 }
87 #[cfg(windows)]
88 {
89 use windows_sys::Win32::Foundation::{BOOL, FALSE, TRUE};
90 use windows_sys::Win32::System::Console::SetConsoleCtrlHandler;
91
92 unsafe extern "system" fn ctrlc_handler(_: u32) -> BOOL {
93 TRUE
95 }
96 unsafe {
97 if SetConsoleCtrlHandler(Some(ctrlc_handler), TRUE) == FALSE {
98 return Err(io::Error::new(io::ErrorKind::Other, "Unable to set console handler"));
99 }
100 }
101
102 cmd.status()
103 .map(|status| ExitCode::from(status.code().unwrap_or(1).try_into().unwrap_or(1)))
104 }
105}