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