spacetimedb_cli/subcommands/
version.rs

1use std::ffi::OsString;
2use std::path::PathBuf;
3use std::process::{Command, ExitCode};
4
5use anyhow::Context;
6use clap::{ArgMatches, Args};
7use spacetimedb_paths::cli::BinFile;
8use spacetimedb_paths::{FromPathUnchecked, RootDir, SpacetimePaths};
9
10pub fn cli() -> clap::Command {
11    Version::augment_args(clap::Command::new("version"))
12}
13
14/// Manage installed spacetime versions
15///
16/// Run `spacetime version --help` to see all options.
17#[derive(clap::Args)]
18#[command(disable_help_flag = true)]
19struct Version {
20    /// The args to pass to spacetimedb-update
21    #[arg(allow_hyphen_values = true, num_args = 0..)]
22    args: Vec<OsString>,
23}
24
25pub async fn exec(paths: &SpacetimePaths, root_dir: Option<&RootDir>, args: &ArgMatches) -> anyhow::Result<ExitCode> {
26    let args = args.get_many::<OsString>("args").unwrap_or_default();
27    let bin_path;
28    let bin_path = if let Some(artifact_dir) = running_from_target_dir() {
29        let update_path = artifact_dir
30            .join("spacetimedb-update")
31            .with_extension(std::env::consts::EXE_EXTENSION);
32        anyhow::ensure!(
33            update_path.exists(),
34            "running `spacetime version` from a target/ directory, but the spacetimedb-update
35             binary doesn't exist. try running `cargo build -p spacetimedb-update`"
36        );
37        bin_path = BinFile::from_path_unchecked(update_path);
38        &bin_path
39    } else {
40        &paths.cli_bin_file
41    };
42    let mut cmd = Command::new(bin_path);
43    if let Some(root_dir) = root_dir {
44        cmd.arg("--root-dir").arg(root_dir);
45    }
46    cmd.arg("version").args(args);
47    let applet = "spacetimedb-update";
48    #[cfg(unix)]
49    {
50        use std::os::unix::process::CommandExt;
51        cmd.arg0(applet);
52    }
53    #[cfg(windows)]
54    cmd.env("SPACETIMEDB_UPDATE_MULTICALL_APPLET", applet);
55    super::start::exec_replace(&mut cmd).with_context(|| format!("exec failed for {}", bin_path.display()))
56}
57
58/// Checks to see if we're running from a subdirectory of a `target` dir that has a `Cargo.toml`
59/// as a sibling, and returns the containing directory of the current executable if so.
60fn running_from_target_dir() -> Option<PathBuf> {
61    let mut exe_path = std::env::current_exe().ok()?;
62    exe_path.pop();
63    let artifact_dir = exe_path;
64    // check for target/debug/spacetimedb-update and target/x86_64-unknown-foobar/debug/spacetimedb-update
65    let target_dir = artifact_dir
66        .ancestors()
67        .skip(1)
68        .take(2)
69        .find(|p| p.file_name() == Some("target".as_ref()))?;
70    target_dir
71        .parent()?
72        .join("Cargo.toml")
73        .try_exists()
74        .ok()
75        .map(|_| artifact_dir)
76}