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
183
184
185
186
187
188
189
190
191
//! Helpers for merging the selected clap subcommand configuration.
//!
//! Applications often parse a root CLI struct with `clap` and then need to load
//! configuration defaults for the selected subcommand from the `[cmds.<name>]`
//! namespace (plus `PREFIX_CMDS_<NAME>_*` environment variables). Doing this at
//! the call-site tends to produce repetitive `match` scaffolding that mirrors
//! the subcommand enum variants.
//!
//! This module provides:
//! - [`SelectedSubcommandMerge`], implemented by derive on a `clap::Subcommand`
//! enum, to merge the selected subcommand in one call; and
//! - [`load_globals_and_merge_selected_subcommand`], a small convenience helper
//! that couples global configuration loading with subcommand merging so
//! callers can resolve both in a single expression.
use ArgMatches;
use Arc;
use Error;
use crateOrthoError;
/// Errors raised while merging configuration for a selected subcommand enum.
/// Trait for merging configuration defaults for the selected subcommand enum.
///
/// Prefer deriving this trait on your `clap::Subcommand` enum. The derive
/// generates the internal match that maps each variant to its corresponding
/// `load_and_merge()` (or `load_and_merge_with_matches()`) call.
///
/// # Examples
///
/// ```rust,no_run
/// use clap::{CommandFactory, FromArgMatches, Parser, Subcommand};
/// use ortho_config::{OrthoConfig, SelectedSubcommandMerge};
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Debug, Parser)]
/// struct Cli {
/// #[command(subcommand)]
/// command: Commands,
/// }
///
/// #[derive(Debug, Subcommand, ortho_config_macros::SelectedSubcommandMerge)]
/// enum Commands {
/// Run(RunArgs),
/// }
///
/// #[derive(Debug, Deserialize, Serialize, Parser, OrthoConfig, Default)]
/// #[command(name = "run")]
/// #[ortho_config(prefix = "APP_")]
/// struct RunArgs {
/// #[arg(long)]
/// level: Option<u8>,
/// }
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let cmd = Cli::command();
/// let matches = cmd.get_matches();
/// let cli = Cli::from_arg_matches(&matches)?;
/// let _merged = cli.command.load_and_merge_selected(&matches)?;
/// # Ok(())
/// # }
/// ```
/// Errors raised by [`load_globals_and_merge_selected_subcommand`].
/// Loads global configuration and merges configuration defaults for the selected subcommand.
///
/// This helper exists to reduce boilerplate in entry points:
/// callers often need to resolve global configuration and the selected
/// subcommand configuration together, but the subcommand merge depends on the
/// already-parsed `ArgMatches`.
///
/// # Examples
///
/// ```rust,no_run
/// use clap::{CommandFactory, FromArgMatches, Parser, Subcommand};
/// use ortho_config::{OrthoConfig, SelectedSubcommandMerge, load_globals_and_merge_selected_subcommand};
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Debug, Parser)]
/// struct Cli {
/// #[command(subcommand)]
/// command: Commands,
/// }
///
/// #[derive(Debug, Subcommand, ortho_config_macros::SelectedSubcommandMerge)]
/// enum Commands {
/// Run(RunArgs),
/// }
///
/// #[derive(Debug, Deserialize, Serialize, Parser, OrthoConfig, Default)]
/// #[command(name = "run")]
/// #[ortho_config(prefix = "APP_")]
/// struct RunArgs {
/// #[arg(long)]
/// level: Option<u8>,
/// }
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let cmd = Cli::command();
/// let matches = cmd.get_matches();
/// let cli = Cli::from_arg_matches(&matches)?;
/// let (globals, merged) = load_globals_and_merge_selected_subcommand(
/// &matches,
/// cli.command,
/// || Ok::<_, std::io::Error>(()),
/// )?;
/// let _ = globals;
/// let _ = merged;
/// # Ok(())
/// # }
/// ```
///
/// # Errors
///
/// Returns [`LoadGlobalsAndSelectedSubcommandError::Globals`] when `load_globals`
/// fails, or [`LoadGlobalsAndSelectedSubcommandError::Subcommand`] when the
/// selected subcommand cannot be merged.