• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

0xmichalis / nftbk / 18683453038

21 Oct 2025 12:14PM UTC coverage: 40.026% (+0.3%) from 39.734%
18683453038

push

github

0xmichalis
chore: log network on x402 config load

0 of 1 new or added line in 1 file covered. (0.0%)

19 existing lines in 2 files now uncovered.

1846 of 4612 relevant lines covered (40.03%)

7.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/cli/mod.rs
1
use std::path::PathBuf;
2

3
use anyhow::Result;
4
use clap::{Parser, Subcommand};
5

6
use crate::logging::LogLevel;
7

8
pub mod commands;
9
pub mod config;
10

11
#[derive(Parser, Debug)]
12
#[command(author, version, about, long_about = None)]
13
pub struct Cli {
14
    /// Set the log level
15
    #[arg(short, long, value_enum, default_value = "info")]
16
    pub log_level: LogLevel,
17

18
    /// Disable colored log output
19
    #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
20
    pub no_color: bool,
21

22
    #[command(subcommand)]
23
    pub command: Commands,
24
}
25

26
#[derive(Subcommand, Debug)]
27
pub enum Commands {
28
    /// Create a backup locally
29
    Create {
30
        /// The path to the chains configuration file
31
        #[arg(short = 'c', long, default_value = "config_chains.toml")]
32
        chains_config_path: PathBuf,
33

34
        /// The path to the tokens configuration file
35
        #[arg(short = 't', long, default_value = "config_tokens.toml")]
36
        tokens_config_path: PathBuf,
37

38
        /// The directory to save the backup to
39
        #[arg(short, long, default_value = "nft_backup")]
40
        output_path: Option<PathBuf>,
41

42
        /// Delete redundant files in the backup folder
43
        #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
44
        prune_redundant: bool,
45

46
        /// Exit on the first error encountered
47
        #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
48
        exit_on_error: bool,
49

50
        /// Path to a TOML file with IPFS provider configuration
51
        #[arg(long)]
52
        ipfs_config: Option<String>,
53
    },
54
    /// Server-related operations
55
    Server {
56
        #[command(subcommand)]
57
        command: ServerCommands,
58
    },
59
}
60

61
#[derive(Subcommand, Debug)]
62
pub enum ServerCommands {
63
    /// Create a backup on the server
64
    Create {
65
        /// The path to the tokens configuration file
66
        #[arg(short = 't', long, default_value = "config_tokens.toml")]
67
        tokens_config_path: PathBuf,
68

69
        /// The server address to request backups from
70
        #[arg(long, default_value = "http://127.0.0.1:8080")]
71
        server_address: String,
72

73
        /// The directory to save the backup to
74
        #[arg(short, long, default_value = "nft_backup")]
75
        output_path: Option<PathBuf>,
76

77
        /// Force rerunning a completed backup task
78
        #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
79
        force: bool,
80

81
        /// User-Agent to send to the server (affects archive format)
82
        #[arg(long, default_value = "Linux")]
83
        user_agent: String,
84

85
        /// Path to a TOML file with IPFS provider configuration
86
        #[arg(long)]
87
        ipfs_config: Option<String>,
88

89
        /// Request server to pin downloaded assets on IPFS
90
        #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
91
        pin_on_ipfs: bool,
92
    },
93
    /// List existing backups on the server
94
    List {
95
        /// The server address to request backups from
96
        #[arg(long, default_value = "http://127.0.0.1:8080")]
97
        server_address: String,
98

99
        /// Show error details in the output table
100
        #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
101
        show_errors: bool,
102
    },
103
}
104

105
impl Cli {
106
    pub async fn run(self) -> Result<()> {
×
107
        match self.command {
×
108
            Commands::Create {
109
                chains_config_path,
×
110
                tokens_config_path,
×
UNCOV
111
                output_path,
×
UNCOV
112
                prune_redundant,
×
113
                exit_on_error,
×
114
                ipfs_config,
×
115
            } => {
116
                commands::create::run(
117
                    chains_config_path,
×
118
                    tokens_config_path,
×
UNCOV
119
                    output_path,
×
120
                    prune_redundant,
×
UNCOV
121
                    exit_on_error,
×
122
                    ipfs_config,
×
123
                )
124
                .await
×
125
            }
126
            Commands::Server { command } => match command {
×
127
                ServerCommands::Create {
128
                    tokens_config_path,
×
129
                    server_address,
×
130
                    output_path,
×
UNCOV
131
                    force,
×
UNCOV
132
                    user_agent,
×
133
                    ipfs_config,
×
134
                    pin_on_ipfs,
×
135
                } => {
136
                    commands::server::create::run(
137
                        tokens_config_path,
×
138
                        server_address,
×
139
                        output_path,
×
UNCOV
140
                        force,
×
141
                        user_agent,
×
UNCOV
142
                        ipfs_config,
×
143
                        pin_on_ipfs,
×
144
                    )
UNCOV
145
                    .await
×
146
                }
147
                ServerCommands::List {
UNCOV
148
                    server_address,
×
UNCOV
149
                    show_errors,
×
UNCOV
150
                } => commands::server::list::run(server_address, show_errors).await,
×
151
            },
152
        }
153
    }
154
}
155

156
#[cfg(test)]
157
mod tests {
158
    use super::*;
159
    use clap::Parser;
160

161
    mod cli_parsing_tests {
162
        use super::*;
163

164
        #[test]
165
        fn parses_create_command_with_defaults() {
166
            let args = vec!["nftbk-cli", "create"];
167
            let cli = Cli::try_parse_from(args).unwrap();
168

169
            assert_eq!(cli.log_level, LogLevel::Info);
170
            assert!(!cli.no_color);
171
            match cli.command {
172
                Commands::Create {
173
                    chains_config_path,
174
                    tokens_config_path,
175
                    output_path,
176
                    prune_redundant,
177
                    exit_on_error,
178
                    ipfs_config,
179
                } => {
180
                    assert_eq!(chains_config_path, PathBuf::from("config_chains.toml"));
181
                    assert_eq!(tokens_config_path, PathBuf::from("config_tokens.toml"));
182
                    assert_eq!(output_path, Some(PathBuf::from("nft_backup")));
183
                    assert!(!prune_redundant);
184
                    assert!(!exit_on_error);
185
                    assert!(ipfs_config.is_none());
186
                }
187
                _ => panic!("Expected Create command"),
188
            }
189
        }
190

191
        #[test]
192
        fn parses_create_command_with_custom_options() {
193
            let args = vec![
194
                "nftbk-cli",
195
                "--log-level",
196
                "debug",
197
                "--no-color",
198
                "true",
199
                "create",
200
                "--chains-config-path",
201
                "custom_chains.toml",
202
                "--tokens-config-path",
203
                "custom_tokens.toml",
204
                "--output-path",
205
                "/tmp/backup",
206
                "--prune-redundant",
207
                "true",
208
                "--exit-on-error",
209
                "true",
210
                "--ipfs-config",
211
                "ipfs.toml",
212
            ];
213
            let cli = Cli::try_parse_from(args).unwrap();
214

215
            assert_eq!(cli.log_level, LogLevel::Debug);
216
            assert!(cli.no_color);
217
            match cli.command {
218
                Commands::Create {
219
                    chains_config_path,
220
                    tokens_config_path,
221
                    output_path,
222
                    prune_redundant,
223
                    exit_on_error,
224
                    ipfs_config,
225
                } => {
226
                    assert_eq!(chains_config_path, PathBuf::from("custom_chains.toml"));
227
                    assert_eq!(tokens_config_path, PathBuf::from("custom_tokens.toml"));
228
                    assert_eq!(output_path, Some(PathBuf::from("/tmp/backup")));
229
                    assert!(prune_redundant);
230
                    assert!(exit_on_error);
231
                    assert_eq!(ipfs_config, Some("ipfs.toml".to_string()));
232
                }
233
                _ => panic!("Expected Create command"),
234
            }
235
        }
236

237
        #[test]
238
        fn parses_server_create_command_with_defaults() {
239
            let args = vec!["nftbk-cli", "server", "create"];
240
            let cli = Cli::try_parse_from(args).unwrap();
241

242
            match cli.command {
243
                Commands::Server { command } => match command {
244
                    ServerCommands::Create {
245
                        tokens_config_path,
246
                        server_address,
247
                        output_path,
248
                        force,
249
                        user_agent,
250
                        ipfs_config,
251
                        pin_on_ipfs,
252
                    } => {
253
                        assert_eq!(tokens_config_path, PathBuf::from("config_tokens.toml"));
254
                        assert_eq!(server_address, "http://127.0.0.1:8080");
255
                        assert_eq!(output_path, Some(PathBuf::from("nft_backup")));
256
                        assert!(!force);
257
                        assert_eq!(user_agent, "Linux");
258
                        assert!(ipfs_config.is_none());
259
                        assert!(!pin_on_ipfs);
260
                    }
261
                    _ => panic!("Expected Server Create command"),
262
                },
263
                _ => panic!("Expected Server command"),
264
            }
265
        }
266

267
        #[test]
268
        fn parses_server_create_command_with_custom_options() {
269
            let args = vec![
270
                "nftbk-cli",
271
                "server",
272
                "create",
273
                "--tokens-config-path",
274
                "custom_tokens.toml",
275
                "--server-address",
276
                "https://api.example.com",
277
                "--output-path",
278
                "/tmp/server_backup",
279
                "--force",
280
                "true",
281
                "--user-agent",
282
                "CustomAgent/1.0",
283
                "--ipfs-config",
284
                "ipfs.toml",
285
                "--pin-on-ipfs",
286
                "true",
287
            ];
288
            let cli = Cli::try_parse_from(args).unwrap();
289

290
            match cli.command {
291
                Commands::Server { command } => match command {
292
                    ServerCommands::Create {
293
                        tokens_config_path,
294
                        server_address,
295
                        output_path,
296
                        force,
297
                        user_agent,
298
                        ipfs_config,
299
                        pin_on_ipfs,
300
                    } => {
301
                        assert_eq!(tokens_config_path, PathBuf::from("custom_tokens.toml"));
302
                        assert_eq!(server_address, "https://api.example.com");
303
                        assert_eq!(output_path, Some(PathBuf::from("/tmp/server_backup")));
304
                        assert!(force);
305
                        assert_eq!(user_agent, "CustomAgent/1.0");
306
                        assert_eq!(ipfs_config, Some("ipfs.toml".to_string()));
307
                        assert!(pin_on_ipfs);
308
                    }
309
                    _ => panic!("Expected Server Create command"),
310
                },
311
                _ => panic!("Expected Server command"),
312
            }
313
        }
314

315
        #[test]
316
        fn parses_server_list_command_with_defaults() {
317
            let args = vec!["nftbk-cli", "server", "list"];
318
            let cli = Cli::try_parse_from(args).unwrap();
319

320
            match cli.command {
321
                Commands::Server { command } => match command {
322
                    ServerCommands::List {
323
                        server_address,
324
                        show_errors,
325
                    } => {
326
                        assert_eq!(server_address, "http://127.0.0.1:8080");
327
                        assert!(!show_errors);
328
                    }
329
                    _ => panic!("Expected Server List command"),
330
                },
331
                _ => panic!("Expected Server command"),
332
            }
333
        }
334

335
        #[test]
336
        fn parses_server_list_command_with_custom_server() {
337
            let args = vec![
338
                "nftbk-cli",
339
                "server",
340
                "list",
341
                "--server-address",
342
                "https://api.example.com",
343
            ];
344
            let cli = Cli::try_parse_from(args).unwrap();
345

346
            match cli.command {
347
                Commands::Server { command } => match command {
348
                    ServerCommands::List {
349
                        server_address,
350
                        show_errors,
351
                    } => {
352
                        assert_eq!(server_address, "https://api.example.com");
353
                        assert!(!show_errors);
354
                    }
355
                    _ => panic!("Expected Server List command"),
356
                },
357
                _ => panic!("Expected Server command"),
358
            }
359
        }
360

361
        #[test]
362
        fn parses_server_list_command_with_show_errors() {
363
            let args = vec!["nftbk-cli", "server", "list", "--show-errors", "true"];
364
            let cli = Cli::try_parse_from(args).unwrap();
365

366
            match cli.command {
367
                Commands::Server { command } => match command {
368
                    ServerCommands::List {
369
                        server_address,
370
                        show_errors,
371
                    } => {
372
                        assert_eq!(server_address, "http://127.0.0.1:8080");
373
                        assert!(show_errors);
374
                    }
375
                    _ => panic!("Expected Server List command"),
376
                },
377
                _ => panic!("Expected Server command"),
378
            }
379
        }
380

381
        #[test]
382
        fn parses_all_log_levels() {
383
            for (level_str, expected_level) in [
384
                ("debug", LogLevel::Debug),
385
                ("info", LogLevel::Info),
386
                ("warn", LogLevel::Warn),
387
                ("error", LogLevel::Error),
388
            ] {
389
                let args = vec!["nftbk-cli", "--log-level", level_str, "create"];
390
                let cli = Cli::try_parse_from(args).unwrap();
391
                assert_eq!(cli.log_level, expected_level);
392
            }
393
        }
394

395
        #[test]
396
        fn handles_no_color_flag() {
397
            let args = vec!["nftbk-cli", "--no-color", "true", "create"];
398
            let cli = Cli::try_parse_from(args).unwrap();
399
            assert!(cli.no_color);
400

401
            let args = vec!["nftbk-cli", "--no-color", "false", "create"];
402
            let cli = Cli::try_parse_from(args).unwrap();
403
            assert!(!cli.no_color);
404
        }
405

406
        #[test]
407
        fn requires_subcommand() {
408
            let args = vec!["nftbk-cli"];
409
            let result = Cli::try_parse_from(args);
410
            assert!(result.is_err());
411
        }
412

413
        #[test]
414
        fn validates_log_level_enum() {
415
            let args = vec!["nftbk-cli", "--log-level", "invalid", "create"];
416
            let result = Cli::try_parse_from(args);
417
            assert!(result.is_err());
418
        }
419
    }
420
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc