lifecycle_hooks_demo/
lifecycle_hooks_demo.rs

1//! Demonstrates lifecycle hooks (`PreRun`, `PostRun`, `PersistentPreRun`, `PersistentPostRun`)
2//!
3//! This example shows how to use lifecycle hooks that execute before and after
4//! command execution, similar to Cobra's hook system.
5
6use flag_rs::{CommandBuilder, Flag, FlagType};
7use std::sync::atomic::{AtomicU32, Ordering};
8
9// Counter to track hook execution order
10static COUNTER: AtomicU32 = AtomicU32::new(0);
11
12fn log_hook(name: &str) {
13    let count = COUNTER.fetch_add(1, Ordering::SeqCst);
14    println!("[{:02}] {}", count + 1, name);
15}
16
17fn main() {
18    let app = CommandBuilder::new("lifecycle-demo")
19        .short("Demonstrates lifecycle hooks")
20        .long("This example shows how lifecycle hooks execute in the proper order")
21        .flag(
22            Flag::new("verbose")
23                .short('v')
24                .usage("Enable verbose output")
25                .value_type(FlagType::Bool),
26        )
27        // Persistent hooks run for this command and all subcommands
28        .persistent_pre_run(|ctx| {
29            log_hook("Root PersistentPreRun");
30            if ctx.flag("verbose").is_some() {
31                println!("     -> Verbose mode enabled globally");
32            }
33            Ok(())
34        })
35        .persistent_post_run(|ctx| {
36            log_hook("Root PersistentPostRun");
37            if ctx.flag("verbose").is_some() {
38                println!("     -> Cleaning up verbose logging");
39            }
40            Ok(())
41        })
42        .subcommand(
43            CommandBuilder::new("server")
44                .short("Server management commands")
45                .persistent_pre_run(|_ctx| {
46                    log_hook("Server PersistentPreRun");
47                    println!("     -> Initializing server module");
48                    Ok(())
49                })
50                .persistent_post_run(|_ctx| {
51                    log_hook("Server PersistentPostRun");
52                    println!("     -> Cleaning up server module");
53                    Ok(())
54                })
55                .subcommand(
56                    CommandBuilder::new("start")
57                        .short("Start the server")
58                        .flag(
59                            Flag::new("port")
60                                .short('p')
61                                .usage("Port to listen on")
62                                .value_type(FlagType::Int),
63                        )
64                        .pre_run(|ctx| {
65                            log_hook("Start PreRun");
66                            let port = ctx
67                                .flag("port")
68                                .and_then(|s| s.parse::<u16>().ok())
69                                .unwrap_or(8080);
70                            println!("     -> Validating port {}", port);
71                            Ok(())
72                        })
73                        .run(|ctx| {
74                            log_hook("Start Run");
75                            let port = ctx
76                                .flag("port")
77                                .and_then(|s| s.parse::<u16>().ok())
78                                .unwrap_or(8080);
79                            println!("     -> Starting server on port {}", port);
80                            Ok(())
81                        })
82                        .post_run(|_ctx| {
83                            log_hook("Start PostRun");
84                            println!("     -> Server started successfully");
85                            Ok(())
86                        })
87                        .build(),
88                )
89                .subcommand(
90                    CommandBuilder::new("stop")
91                        .short("Stop the server")
92                        .pre_run(|_ctx| {
93                            log_hook("Stop PreRun");
94                            println!("     -> Checking if server is running");
95                            Ok(())
96                        })
97                        .run(|_ctx| {
98                            log_hook("Stop Run");
99                            println!("     -> Stopping server");
100                            Ok(())
101                        })
102                        .post_run(|_ctx| {
103                            log_hook("Stop PostRun");
104                            println!("     -> Server stopped");
105                            Ok(())
106                        })
107                        .build(),
108                )
109                .build(),
110        )
111        .subcommand(
112            CommandBuilder::new("database")
113                .short("Database management commands")
114                .persistent_pre_run(|_ctx| {
115                    log_hook("Database PersistentPreRun");
116                    println!("     -> Connecting to database");
117                    Ok(())
118                })
119                .persistent_post_run(|_ctx| {
120                    log_hook("Database PersistentPostRun");
121                    println!("     -> Closing database connection");
122                    Ok(())
123                })
124                .subcommand(
125                    CommandBuilder::new("migrate")
126                        .short("Run database migrations")
127                        .pre_run(|_ctx| {
128                            log_hook("Migrate PreRun");
129                            println!("     -> Checking migration status");
130                            Ok(())
131                        })
132                        .run(|_ctx| {
133                            log_hook("Migrate Run");
134                            println!("     -> Running migrations");
135                            Ok(())
136                        })
137                        .post_run(|_ctx| {
138                            log_hook("Migrate PostRun");
139                            println!("     -> Migrations completed");
140                            Ok(())
141                        })
142                        .build(),
143                )
144                .build(),
145        )
146        .build();
147
148    println!("=== Lifecycle Hooks Demo ===\n");
149    println!("This demo shows the execution order of lifecycle hooks.");
150    println!("Try these commands to see different hook patterns:\n");
151    println!(
152        "1. {} server start",
153        std::env::args().next().unwrap_or_default()
154    );
155    println!(
156        "2. {} -v server start -p 3000",
157        std::env::args().next().unwrap_or_default()
158    );
159    println!(
160        "3. {} database migrate",
161        std::env::args().next().unwrap_or_default()
162    );
163    println!("\n---\n");
164
165    // Reset counter before execution
166    COUNTER.store(0, Ordering::SeqCst);
167
168    let args: Vec<String> = std::env::args().skip(1).collect();
169    if let Err(e) = app.execute(args) {
170        eprintln!("Error: {}", e);
171        std::process::exit(1);
172    }
173
174    println!("\n=== Hook Execution Summary ===");
175    println!("Total hooks executed: {}", COUNTER.load(Ordering::SeqCst));
176    println!("\nExecution order:");
177    println!("1. Parent PersistentPreRun (root → child)");
178    println!("2. Command PreRun");
179    println!("3. Command Run");
180    println!("4. Command PostRun");
181    println!("5. Parent PersistentPostRun (child → root)");
182}