@@ -6,14 +6,26 @@ use std::path::PathBuf;
6
6
use std:: process:: Command ;
7
7
use std:: process:: ExitCode ;
8
8
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
+ }
13
28
} ;
14
- run_cli ( & paths, argv0, args)
15
- }
16
- pub ( crate ) fn run_cli ( paths : & SpacetimePaths , argv0 : Option < & OsStr > , args : Vec < OsString > ) -> anyhow:: Result < ExitCode > {
17
29
let cli_path = if let Some ( artifact_dir) = running_from_target_dir ( ) {
18
30
let cli_path = spacetimedb_paths:: cli:: VersionBinDir :: from_path_unchecked ( artifact_dir) . spacetimedb_cli ( ) ;
19
31
anyhow:: ensure!(
@@ -25,10 +37,11 @@ pub(crate) fn run_cli(paths: &SpacetimePaths, argv0: Option<&OsStr>, args: Vec<O
25
37
} else {
26
38
paths. cli_bin_dir . current_version_dir ( ) . spacetimedb_cli ( )
27
39
} ;
40
+
28
41
let mut cmd = Command :: new ( & cli_path) ;
29
- cmd. args ( args) ;
42
+ cmd. args ( & args) ;
30
43
#[ cfg( unix) ]
31
- let result = {
44
+ let exec_result = {
32
45
use std:: os:: unix:: process:: CommandExt ;
33
46
if let Some ( argv0) = argv0 {
34
47
cmd. arg0 ( argv0) ;
@@ -37,9 +50,22 @@ pub(crate) fn run_cli(paths: &SpacetimePaths, argv0: Option<&OsStr>, args: Vec<O
37
50
Err :: < std:: process:: ExitStatus , _ > ( err)
38
51
} ;
39
52
#[ 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
+ )
43
69
}
44
70
45
71
/// 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> {
62
88
. map ( |_| artifact_dir)
63
89
}
64
90
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 ( ) ) ) ;
73
128
}
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
+ } )
88
133
}
89
- Ok ( root_dir)
90
134
}
91
135
92
136
fn os_str_starts_with ( s : & OsStr , pref : & str ) -> bool {
0 commit comments