Skip to content

Commit 030c9b3

Browse files
committed
Make spacetime version always succeed
1 parent 78b64b3 commit 030c9b3

File tree

3 files changed

+81
-37
lines changed

3 files changed

+81
-37
lines changed

crates/update/src/cli.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl Args {
3333
if let Some(root_dir) = &self.root_dir {
3434
cli_args.insert(0, OsString::from_iter(["--root-dir=".as_ref(), root_dir.as_ref()]));
3535
}
36-
crate::proxy::run_cli(&paths, None, cli_args)
36+
crate::proxy::run_cli(Some(&paths), None, cli_args)
3737
}
3838
Subcommand::Version(version) => version.exec(&paths).map(|()| ExitCode::SUCCESS),
3939
}

crates/update/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn main() -> anyhow::Result<ExitCode> {
1919
if cmd == "spacetimedb-update" {
2020
spacetimedb_update_main()
2121
} else if cmd == "spacetime" {
22-
proxy::spacetimedb_cli_proxy(Some(argv0.as_os_str()), args.collect())
22+
proxy::run_cli(None, Some(argv0.as_os_str()), args.collect())
2323
} else {
2424
anyhow::bail!(
2525
"unknown command name for spacetimedb-update multicall binary: {}",

crates/update/src/proxy.rs

+79-35
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,26 @@ use std::path::PathBuf;
66
use std::process::Command;
77
use std::process::ExitCode;
88

9-
pub(super) fn spacetimedb_cli_proxy(argv0: Option<&OsStr>, args: Vec<OsString>) -> anyhow::Result<ExitCode> {
10-
let paths = match extract_root_dir_arg(&args)? {
11-
Some(root_dir) => SpacetimePaths::from_root_dir(&root_dir),
12-
None => SpacetimePaths::platform_defaults()?,
9+
pub(crate) fn run_cli(
10+
paths: Option<&SpacetimePaths>,
11+
argv0: Option<&OsStr>,
12+
args: Vec<OsString>,
13+
) -> anyhow::Result<ExitCode> {
14+
let parse_args = || PartialCliArgs::parse(&args);
15+
let mut is_version_subcommand = None;
16+
let paths_;
17+
let paths = match paths {
18+
Some(paths) => paths,
19+
None => {
20+
let partial_args = parse_args()?;
21+
is_version_subcommand = Some(partial_args.is_version_subcommand());
22+
paths_ = match partial_args.root_dir {
23+
Some(root_dir) => SpacetimePaths::from_root_dir(&root_dir),
24+
None => SpacetimePaths::platform_defaults()?,
25+
};
26+
&paths_
27+
}
1328
};
14-
run_cli(&paths, argv0, args)
15-
}
16-
pub(crate) fn run_cli(paths: &SpacetimePaths, argv0: Option<&OsStr>, args: Vec<OsString>) -> anyhow::Result<ExitCode> {
1729
let cli_path = if let Some(artifact_dir) = running_from_target_dir() {
1830
let cli_path = spacetimedb_paths::cli::VersionBinDir::from_path_unchecked(artifact_dir).spacetimedb_cli();
1931
anyhow::ensure!(
@@ -25,10 +37,11 @@ pub(crate) fn run_cli(paths: &SpacetimePaths, argv0: Option<&OsStr>, args: Vec<O
2537
} else {
2638
paths.cli_bin_dir.current_version_dir().spacetimedb_cli()
2739
};
40+
2841
let mut cmd = Command::new(&cli_path);
29-
cmd.args(args);
42+
cmd.args(&args);
3043
#[cfg(unix)]
31-
let result = {
44+
let exec_result = {
3245
use std::os::unix::process::CommandExt;
3346
if let Some(argv0) = argv0 {
3447
cmd.arg0(argv0);
@@ -37,9 +50,22 @@ pub(crate) fn run_cli(paths: &SpacetimePaths, argv0: Option<&OsStr>, args: Vec<O
3750
Err::<std::process::ExitStatus, _>(err)
3851
};
3952
#[cfg(windows)]
40-
let result = cmd.status();
41-
let status = result.context(format!("exec failed for {}", bin_path.display()))?;
42-
Ok(ExitCode::from(status.code().unwrap_or(1).try_into().unwrap_or(1)))
53+
let exec_result = cmd.status();
54+
let exec_err = match exec_result {
55+
Ok(status) => return Ok(ExitCode::from(status.code().unwrap_or(1).try_into().unwrap_or(1))),
56+
Err(err) => err,
57+
};
58+
// if we failed to exec cli and it seems like the user is trying to run `spacetime version`,
59+
// patch them through directly.
60+
if is_version_subcommand.unwrap_or_else(|| parse_args().is_ok_and(|a| a.is_version_subcommand())) {
61+
return crate::spacetimedb_update_main();
62+
}
63+
Err(exec_err)
64+
.context(format!("exec failed for {}", cli_path.display()))
65+
.context(
66+
"It seems like the spacetime version set as current may not exist. Try using `spacetime version`\n\
67+
to set a different version as default or to install a new version altogether.",
68+
)
4369
}
4470

4571
/// Checks to see if we're running from a subdirectory of a `target` dir that has a `Cargo.toml`
@@ -62,31 +88,49 @@ pub(crate) fn running_from_target_dir() -> Option<PathBuf> {
6288
.map(|_| artifact_dir)
6389
}
6490

65-
fn extract_root_dir_arg(args: &[OsString]) -> anyhow::Result<Option<RootDir>> {
66-
let mut args = args.iter();
67-
let mut root_dir = None;
68-
while let Some(arg) = args.next() {
69-
let is_arg_value = |s: &OsStr| !os_str_starts_with(arg, "-") || s == "-";
70-
// "parse" only up to the first subcommand
71-
if is_arg_value(arg) || arg == "--" {
72-
break;
91+
struct PartialCliArgs<'a> {
92+
root_dir: Option<RootDir>,
93+
maybe_subcommand: Option<&'a OsStr>,
94+
}
95+
96+
impl<'a> PartialCliArgs<'a> {
97+
fn is_version_subcommand(&self) -> bool {
98+
self.maybe_subcommand.is_some_and(|s| s == "version")
99+
}
100+
101+
fn parse(args: &'a [OsString]) -> anyhow::Result<Self> {
102+
let mut args = args.iter();
103+
let mut root_dir = None;
104+
let mut maybe_subcommand = None;
105+
while let Some(arg) = args.next() {
106+
let is_arg_value = |s: &OsStr| !os_str_starts_with(arg, "-") || s == "-";
107+
// "parse" only up to the first subcommand
108+
if is_arg_value(arg) {
109+
maybe_subcommand = Some(&**arg);
110+
break;
111+
} else if arg == "--" {
112+
break;
113+
}
114+
let root_dir_arg = if arg == "--root-dir" {
115+
args.next()
116+
.filter(|s| is_arg_value(s))
117+
.context("a value is required for '--root-dir <root_dir>' but none was supplied")?
118+
} else if let Some(arg) = os_str_strip_prefix(arg, "--root-dir=") {
119+
arg
120+
} else {
121+
continue;
122+
};
123+
anyhow::ensure!(
124+
root_dir.is_none(),
125+
"the argument '--root-dir <root_dir>' cannot be used multiple times"
126+
);
127+
root_dir = Some(RootDir(root_dir_arg.into()));
73128
}
74-
let root_dir_arg = if arg == "--root-dir" {
75-
args.next()
76-
.filter(|s| is_arg_value(s))
77-
.context("a value is required for '--root-dir <root_dir>' but none was supplied")?
78-
} else if let Some(arg) = os_str_strip_prefix(arg, "--root-dir=") {
79-
arg
80-
} else {
81-
continue;
82-
};
83-
anyhow::ensure!(
84-
root_dir.is_none(),
85-
"the argument '--root-dir <root_dir>' cannot be used multiple times"
86-
);
87-
root_dir = Some(RootDir(root_dir_arg.into()));
129+
Ok(Self {
130+
root_dir,
131+
maybe_subcommand,
132+
})
88133
}
89-
Ok(root_dir)
90134
}
91135

92136
fn os_str_starts_with(s: &OsStr, pref: &str) -> bool {

0 commit comments

Comments
 (0)