7
7
use std:: fs;
8
8
use std:: process:: Command ;
9
9
use std:: {
10
+ future:: Future ,
10
11
io:: { stdout, Write } ,
11
12
net:: { IpAddr , Ipv4Addr , SocketAddr } ,
12
13
os:: unix:: prelude:: AsRawFd ,
@@ -37,16 +38,16 @@ pub enum RunMode {
37
38
#[ derive( Parser ) ]
38
39
#[ clap( version = "0.1" ) ]
39
40
#[ clap( infer_subcommands = true , styles = oxide_cli_style( ) ) ]
40
- struct Opts {
41
+ pub struct Opts < T : clap :: Args > {
41
42
#[ clap( short, long, action = ArgAction :: Count ) ]
42
43
verbose : u8 ,
43
44
44
45
#[ clap( subcommand) ]
45
- subcmd : SubCommand ,
46
+ subcmd : SubCommand < T > ,
46
47
}
47
48
48
49
#[ derive( Parser ) ]
49
- enum SubCommand {
50
+ enum SubCommand < T : clap :: Args > {
50
51
#[ clap( about = "run topology preflight" ) ]
51
52
Preflight ( CmdPreflight ) ,
52
53
#[ clap( about = "launch topology" ) ]
@@ -71,6 +72,9 @@ enum SubCommand {
71
72
Snapshot ( CmdSnapshot ) ,
72
73
#[ clap( about = "execute a command on a node" ) ]
73
74
Exec ( CmdExec ) ,
75
+ /// Allow users of this library to add their own set of commands
76
+ #[ clap( about = "topology-specific commands" ) ]
77
+ Extra ( T ) ,
74
78
}
75
79
76
80
#[ derive( Parser ) ]
@@ -213,9 +217,71 @@ struct CmdExec {
213
217
/// run(&mut r);
214
218
/// ```
215
219
pub async fn run ( r : & mut Runner ) -> Result < RunMode , Error > {
220
+ #[ derive( Parser ) ]
221
+ struct Dummy { }
222
+ run_with_extra ( r, |_: & mut Runner , _: Dummy | std:: future:: ready ( Ok ( ( ) ) ) )
223
+ . await
224
+ }
225
+
226
+ /// Entry point for a command line application. Will parse command line
227
+ /// arguments (including any extra commands that users of this library add) and
228
+ /// take actions accordingly.
229
+ ///
230
+ /// # Examples
231
+ /// ```no_run
232
+ /// use libfalcon::{
233
+ /// cli::run_with_extra,
234
+ /// Runner,
235
+ /// error::Error,
236
+ /// };
237
+ /// use clap::Parser;
238
+ ///
239
+ /// #[derive(Parser)]
240
+ /// #[command(version = "0.1")]
241
+ /// struct OtherOpts {
242
+ /// #[clap(subcommand)]
243
+ /// subcmd: SubCommand,
244
+ /// }
245
+ ///
246
+ /// #[derive(Parser)]
247
+ /// enum SubCommand {
248
+ /// #[clap(about = "some topology specific command")]
249
+ /// Something,
250
+ /// }
251
+ ///
252
+ /// async fn extra_stuff(r: &mut Runner, opts: OtherOpts) -> Result<(), Error> {
253
+ /// match opts.subcmd {
254
+ /// SubCommand::Something => {
255
+ /// // some topology specific command!
256
+ /// }
257
+ /// }
258
+ ///
259
+ /// Ok(())
260
+ /// }
261
+ ///
262
+ /// let mut r = Runner::new("duo");
263
+ ///
264
+ /// // nodes
265
+ /// let violin = r.node("violin", "helios-2.5", 1, 1024);
266
+ /// let piano = r.node("piano", "helios-2.5", 1, 1024);
267
+ ///
268
+ /// // links
269
+ /// r.link(violin, piano);
270
+ ///
271
+ /// run_with_extra(&mut r, extra_stuff);
272
+ /// ```
273
+ pub async fn run_with_extra < ' a , T , F , O > (
274
+ r : & ' a mut Runner ,
275
+ extra : F ,
276
+ ) -> Result < RunMode , Error >
277
+ where
278
+ T : clap:: Args ,
279
+ F : FnOnce ( & ' a mut Runner , T ) -> O ,
280
+ O : Future < Output = Result < ( ) , Error > > ,
281
+ {
216
282
r. persistent = true ;
217
283
218
- let opts: Opts = Opts :: parse ( ) ;
284
+ let opts: Opts < T > = Opts :: < T > :: parse ( ) ;
219
285
match opts. subcmd {
220
286
SubCommand :: Preflight ( p) => {
221
287
r. falcon_dir = p. falcon_dir ;
@@ -305,6 +371,10 @@ pub async fn run(r: &mut Runner) -> Result<RunMode, Error> {
305
371
exec ( r, & c. node , & c. command ) . await ?;
306
372
Ok ( RunMode :: Unspec )
307
373
}
374
+ SubCommand :: Extra ( c) => {
375
+ extra ( r, c) . await ?;
376
+ Ok ( RunMode :: Unspec )
377
+ }
308
378
}
309
379
}
310
380
0 commit comments