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