@@ -3,14 +3,14 @@ mod sqlite_statements;
3
3
mod summary;
4
4
5
5
use std:: future:: Future ;
6
- use std:: path:: { Path , PathBuf } ;
6
+ use std:: path:: PathBuf ;
7
7
8
8
use anyhow:: { Context , Result } ;
9
9
use clap:: { Args , IntoApp , Parser } ;
10
10
use spin_app:: App ;
11
+ use spin_common:: sloth;
11
12
use spin_common:: ui:: quoted_path;
12
13
use spin_common:: url:: parse_file_url;
13
- use spin_common:: { arg_parser:: parse_kv, sloth} ;
14
14
use spin_core:: async_trait;
15
15
use spin_factors:: RuntimeFactors ;
16
16
use spin_factors_executor:: { ComponentLoader , FactorsExecutor } ;
@@ -20,7 +20,6 @@ use summary::{
20
20
summarize_runtime_config, KeyValueDefaultStoreSummaryHook , SqliteDefaultStoreSummaryHook ,
21
21
} ;
22
22
23
- use crate :: factors:: { TriggerFactors , TriggerFactorsRuntimeConfig } ;
24
23
use crate :: stdio:: { FollowComponents , StdioLoggingExecutorHooks } ;
25
24
use crate :: { Trigger , TriggerApp } ;
26
25
pub use launch_metadata:: LaunchMetadata ;
@@ -40,9 +39,9 @@ pub const SPIN_WORKING_DIR: &str = "SPIN_WORKING_DIR";
40
39
#[ derive( Parser , Debug ) ]
41
40
#[ clap(
42
41
usage = "spin [COMMAND] [OPTIONS]" ,
43
- next_help_heading = help_heading:: <T , F >( )
42
+ next_help_heading = help_heading:: <T , B :: Factors >( )
44
43
) ]
45
- pub struct FactorsTriggerCommand < T : Trigger < F > , F : RuntimeFactors > {
44
+ pub struct FactorsTriggerCommand < T : Trigger < B :: Factors > , B : RuntimeFactorsBuilder > {
46
45
/// Log directory for the stdout and stderr of components. Setting to
47
46
/// the empty string disables logging to disk.
48
47
#[ clap(
@@ -117,16 +116,8 @@ pub struct FactorsTriggerCommand<T: Trigger<F>, F: RuntimeFactors> {
117
116
#[ clap( flatten) ]
118
117
pub trigger_args : T :: CliArgs ,
119
118
120
- /// Set a key/value pair (key=value) in the application's
121
- /// default store. Any existing value will be overwritten.
122
- /// Can be used multiple times.
123
- #[ clap( long = "key-value" , parse( try_from_str = parse_kv) ) ]
124
- key_values : Vec < ( String , String ) > ,
125
-
126
- /// Run a SQLite statement such as a migration against the default database.
127
- /// To run from a file, prefix the filename with @ e.g. spin up --sqlite @migration.sql
128
- #[ clap( long = "sqlite" ) ]
129
- sqlite_statements : Vec < String > ,
119
+ #[ clap( flatten) ]
120
+ pub builder_args : B :: Options ,
130
121
131
122
#[ clap( long = "help-args-only" , hide = true ) ]
132
123
pub help_args_only : bool ,
@@ -135,16 +126,33 @@ pub struct FactorsTriggerCommand<T: Trigger<F>, F: RuntimeFactors> {
135
126
pub launch_metadata_only : bool ,
136
127
}
137
128
129
+ /// Configuration options that are common to all triggers.
130
+ #[ derive( Debug ) ]
131
+ pub struct CommonTriggerOptions {
132
+ /// The Spin working directory.
133
+ pub working_dir : PathBuf ,
134
+ /// Path to the runtime config file.
135
+ pub runtime_config_file : Option < PathBuf > ,
136
+ /// Path to the state directory.
137
+ pub state_dir : Option < String > ,
138
+ /// Path to the local app directory.
139
+ pub local_app_dir : Option < String > ,
140
+ /// Whether to allow transient writes to mounted files
141
+ pub allow_transient_write : bool ,
142
+ /// Which components should have their logs followed.
143
+ pub follow_components : FollowComponents ,
144
+ /// Log directory for component stdout/stderr.
145
+ pub log_dir : Option < PathBuf > ,
146
+ }
147
+
138
148
/// An empty implementation of clap::Args to be used as TriggerExecutor::RunConfig
139
149
/// for executors that do not need additional CLI args.
140
150
#[ derive( Args ) ]
141
151
pub struct NoCliArgs ;
142
152
143
- impl < T : Trigger < F > , F : RuntimeFactors > FactorsTriggerCommand < T , F > {
153
+ impl < T : Trigger < B :: Factors > , B : RuntimeFactorsBuilder > FactorsTriggerCommand < T , B > {
144
154
/// Create a new TriggerExecutorBuilder from this TriggerExecutorCommand.
145
- pub async fn run < B : RuntimeFactorsBuilder < Factors = F , Options = TriggerAppOptions > > (
146
- self ,
147
- ) -> Result < ( ) > {
155
+ pub async fn run ( self ) -> Result < ( ) > {
148
156
// Handle --help-args-only
149
157
if self . help_args_only {
150
158
Self :: command ( )
@@ -156,7 +164,7 @@ impl<T: Trigger<F>, F: RuntimeFactors> FactorsTriggerCommand<T, F> {
156
164
157
165
// Handle --launch-metadata-only
158
166
if self . launch_metadata_only {
159
- let lm = LaunchMetadata :: infer :: < T , F > ( ) ;
167
+ let lm = LaunchMetadata :: infer :: < T , B > ( ) ;
160
168
let json = serde_json:: to_string_pretty ( & lm) ?;
161
169
eprintln ! ( "{json}" ) ;
162
170
return Ok ( ( ) ) ;
@@ -185,8 +193,7 @@ impl<T: Trigger<F>, F: RuntimeFactors> FactorsTriggerCommand<T, F> {
185
193
}
186
194
187
195
let trigger = T :: new ( self . trigger_args , & app) ?;
188
- let mut builder: TriggerAppBuilder < T , B > =
189
- TriggerAppBuilder :: new ( trigger, PathBuf :: from ( working_dir) ) ;
196
+ let mut builder: TriggerAppBuilder < T , B > = TriggerAppBuilder :: new ( trigger) ;
190
197
let config = builder. engine_config ( ) ;
191
198
192
199
// Apply --cache / --disable-cache
@@ -198,21 +205,16 @@ impl<T: Trigger<F>, F: RuntimeFactors> FactorsTriggerCommand<T, F> {
198
205
config. disable_pooling ( ) ;
199
206
}
200
207
201
- let run_fut = builder
202
- . run (
203
- app,
204
- TriggerAppOptions {
205
- runtime_config_file : self . runtime_config_file . clone ( ) ,
206
- state_dir : self . state_dir . clone ( ) ,
207
- local_app_dir : local_app_dir. clone ( ) ,
208
- initial_key_values : self . key_values ,
209
- sqlite_statements : self . sqlite_statements ,
210
- allow_transient_write : self . allow_transient_write ,
211
- follow_components,
212
- log_dir : self . log ,
213
- } ,
214
- )
215
- . await ?;
208
+ let common_options = CommonTriggerOptions {
209
+ working_dir : PathBuf :: from ( working_dir) ,
210
+ runtime_config_file : self . runtime_config_file . clone ( ) ,
211
+ state_dir : self . state_dir . clone ( ) ,
212
+ local_app_dir : local_app_dir. clone ( ) ,
213
+ allow_transient_write : self . allow_transient_write ,
214
+ follow_components,
215
+ log_dir : self . log ,
216
+ } ;
217
+ let run_fut = builder. run ( app, common_options, self . builder_args ) . await ?;
216
218
217
219
let ( abortable, abort_handle) = futures:: future:: abortable ( run_fut) ;
218
220
ctrlc:: set_handler ( move || abort_handle. abort ( ) ) ?;
@@ -271,37 +273,14 @@ fn help_heading<T: Trigger<F>, F: RuntimeFactors>() -> Option<&'static str> {
271
273
/// A builder for a [`TriggerApp`].
272
274
pub struct TriggerAppBuilder < T , F > {
273
275
engine_config : spin_core:: Config ,
274
- working_dir : PathBuf ,
275
276
pub trigger : T ,
276
277
_factors : std:: marker:: PhantomData < F > ,
277
278
}
278
279
279
- /// Options for building a [`TriggerApp`].
280
- #[ derive( Default ) ]
281
- pub struct TriggerAppOptions {
282
- /// Path to the runtime config file.
283
- pub runtime_config_file : Option < PathBuf > ,
284
- /// Path to the state directory.
285
- pub state_dir : Option < String > ,
286
- /// Path to the local app directory.
287
- pub local_app_dir : Option < String > ,
288
- /// Initial key/value pairs to set in the app's default store.
289
- pub initial_key_values : Vec < ( String , String ) > ,
290
- /// SQLite statements to run.
291
- pub sqlite_statements : Vec < String > ,
292
- /// Whether to allow transient writes to mounted files
293
- pub allow_transient_write : bool ,
294
- /// Which components should have their logs followed.
295
- pub follow_components : FollowComponents ,
296
- /// Log directory for component stdout/stderr.
297
- pub log_dir : Option < PathBuf > ,
298
- }
299
-
300
- impl < T : Trigger < F :: Factors > , F : RuntimeFactorsBuilder > TriggerAppBuilder < T , F > {
301
- pub fn new ( trigger : T , working_dir : PathBuf ) -> Self {
280
+ impl < T : Trigger < B :: Factors > , B : RuntimeFactorsBuilder > TriggerAppBuilder < T , B > {
281
+ pub fn new ( trigger : T ) -> Self {
302
282
Self {
303
283
engine_config : spin_core:: Config :: default ( ) ,
304
- working_dir,
305
284
trigger,
306
285
_factors : Default :: default ( ) ,
307
286
}
@@ -315,16 +294,17 @@ impl<T: Trigger<F::Factors>, F: RuntimeFactorsBuilder> TriggerAppBuilder<T, F> {
315
294
pub async fn build (
316
295
& mut self ,
317
296
app : App ,
318
- options : F :: Options ,
319
- ) -> anyhow:: Result < TriggerApp < T , F :: Factors > > {
297
+ common_options : CommonTriggerOptions ,
298
+ options : B :: Options ,
299
+ ) -> anyhow:: Result < TriggerApp < T , B :: Factors > > {
320
300
let mut core_engine_builder = {
321
301
self . trigger . update_core_config ( & mut self . engine_config ) ?;
322
302
323
303
spin_core:: Engine :: builder ( & self . engine_config ) ?
324
304
} ;
325
305
self . trigger . add_to_linker ( core_engine_builder. linker ( ) ) ?;
326
306
327
- let ( factors, runtime_config) = F :: new ( ) . build ( self . working_dir . clone ( ) , options) ?;
307
+ let ( factors, runtime_config) = B :: build ( common_options , options) ?;
328
308
329
309
// TODO: port the rest of the component loader logic
330
310
struct SimpleComponentLoader ;
@@ -409,24 +389,20 @@ impl<T: Trigger<F::Factors>, F: RuntimeFactorsBuilder> TriggerAppBuilder<T, F> {
409
389
pub async fn run (
410
390
mut self ,
411
391
app : App ,
412
- options : F :: Options ,
392
+ common_options : CommonTriggerOptions ,
393
+ options : B :: Options ,
413
394
) -> anyhow:: Result < impl Future < Output = anyhow:: Result < ( ) > > > {
414
- let configured_app = self . build ( app, options) . await ?;
395
+ let configured_app = self . build ( app, common_options , options) . await ?;
415
396
Ok ( self . trigger . run ( configured_app) )
416
397
}
417
398
}
418
399
419
400
pub trait RuntimeFactorsBuilder {
420
- type Options ;
401
+ type Options : clap :: Args ;
421
402
type Factors : RuntimeFactors ;
422
403
423
- fn new ( ) -> Self
424
- where
425
- Self : Sized ;
426
-
427
404
fn build (
428
- self ,
429
- working_dir : PathBuf ,
405
+ common_options : CommonTriggerOptions ,
430
406
options : Self :: Options ,
431
407
) -> anyhow:: Result < (
432
408
Self :: Factors ,
0 commit comments