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

0xmichalis / nftbk / 18721432523

22 Oct 2025 03:29PM UTC coverage: 44.911% (-0.03%) from 44.936%
18721432523

push

github

0xmichalis
chore: remove --dry-run from server delete

1 of 2 new or added lines in 2 files covered. (50.0%)

2140 of 4765 relevant lines covered (44.91%)

7.79 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
pub mod x402;
11

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

19
    /// Disable colored log output. NO_COLOR and FORCE_COLOR environment variables take precedence.
20
    #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
21
    pub no_color: bool,
22

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

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

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

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

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

47
        /// Exit on the first error encountered
48
        #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
49
        exit_on_error: bool,
50
    },
51
    /// Server-related operations
52
    Server {
53
        #[command(subcommand)]
54
        command: ServerCommands,
55
    },
56
}
57

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

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

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

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

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

82
        /// Request server to pin downloaded assets on IPFS
83
        #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
84
        pin_on_ipfs: bool,
85

86
        /// Polling interval in milliseconds for checking backup status
87
        #[arg(long, default_value = "10000")]
88
        polling_interval_ms: u64,
89
    },
90
    /// List existing backups on the server
91
    List {
92
        /// The server address to request backups from
93
        #[arg(long, default_value = "http://127.0.0.1:8080")]
94
        server_address: String,
95

96
        /// Show error details in the output table
97
        #[arg(long, default_value_t = false, action = clap::ArgAction::Set)]
98
        show_errors: bool,
99
    },
100
    /// Delete a backup from the server
101
    Delete {
102
        /// The server address to request backups from
103
        #[arg(long, default_value = "http://127.0.0.1:8080")]
104
        server_address: String,
105

106
        /// The task ID of the backup to delete
107
        #[arg(short = 't', long)]
108
        task_id: String,
109
    },
110
}
111

112
impl Cli {
113
    pub async fn run(self) -> Result<()> {
×
114
        match self.command {
×
115
            Commands::Create {
116
                config_path,
×
117
                tokens_config_path,
×
118
                output_path,
×
119
                prune_redundant,
×
120
                exit_on_error,
×
121
            } => {
122
                commands::create::run(
123
                    config_path,
×
124
                    tokens_config_path,
×
125
                    output_path,
×
126
                    prune_redundant,
×
127
                    exit_on_error,
×
128
                )
129
                .await
×
130
            }
131
            Commands::Server { command } => match command {
×
132
                ServerCommands::Create {
133
                    tokens_config_path,
×
134
                    server_address,
×
135
                    output_path,
×
136
                    force,
×
137
                    user_agent,
×
138
                    pin_on_ipfs,
×
139
                    polling_interval_ms,
×
140
                } => {
141
                    commands::server::create::run(
142
                        tokens_config_path,
×
143
                        server_address,
×
144
                        output_path,
×
145
                        force,
×
146
                        user_agent,
×
147
                        pin_on_ipfs,
×
148
                        Some(polling_interval_ms),
×
149
                    )
150
                    .await
×
151
                }
152
                ServerCommands::List {
153
                    server_address,
×
154
                    show_errors,
×
155
                } => commands::server::list::run(server_address, show_errors).await,
×
156
                ServerCommands::Delete {
157
                    server_address,
×
158
                    task_id,
×
NEW
159
                } => commands::server::delete::run(server_address, task_id).await,
×
160
            },
161
        }
162
    }
163
}
164

165
#[cfg(test)]
166
mod tests {
167
    use super::*;
168
    use clap::Parser;
169

170
    mod cli_parsing_tests {
171
        use super::*;
172

173
        #[test]
174
        fn parses_create_command_with_defaults() {
175
            let args = vec!["nftbk-cli", "create"];
176
            let cli = Cli::try_parse_from(args).unwrap();
177

178
            assert_eq!(cli.log_level, LogLevel::Info);
179
            assert!(!cli.no_color);
180
            match cli.command {
181
                Commands::Create {
182
                    config_path,
183
                    tokens_config_path,
184
                    output_path,
185
                    prune_redundant,
186
                    exit_on_error,
187
                } => {
188
                    assert_eq!(config_path, PathBuf::from("config.toml"));
189
                    assert_eq!(tokens_config_path, PathBuf::from("config_tokens.toml"));
190
                    assert_eq!(output_path, Some(PathBuf::from("nft_backup")));
191
                    assert!(!prune_redundant);
192
                    assert!(!exit_on_error);
193
                }
194
                _ => panic!("Expected Create command"),
195
            }
196
        }
197

198
        #[test]
199
        fn parses_create_command_with_custom_options() {
200
            let args = vec![
201
                "nftbk-cli",
202
                "--log-level",
203
                "debug",
204
                "--no-color",
205
                "true",
206
                "create",
207
                "--config-path",
208
                "custom_config.toml",
209
                "--tokens-config-path",
210
                "custom_tokens.toml",
211
                "--output-path",
212
                "/tmp/backup",
213
                "--prune-redundant",
214
                "true",
215
                "--exit-on-error",
216
                "true",
217
            ];
218
            let cli = Cli::try_parse_from(args).unwrap();
219

220
            assert_eq!(cli.log_level, LogLevel::Debug);
221
            assert!(cli.no_color);
222
            match cli.command {
223
                Commands::Create {
224
                    config_path,
225
                    tokens_config_path,
226
                    output_path,
227
                    prune_redundant,
228
                    exit_on_error,
229
                } => {
230
                    assert_eq!(config_path, PathBuf::from("custom_config.toml"));
231
                    assert_eq!(tokens_config_path, PathBuf::from("custom_tokens.toml"));
232
                    assert_eq!(output_path, Some(PathBuf::from("/tmp/backup")));
233
                    assert!(prune_redundant);
234
                    assert!(exit_on_error);
235
                }
236
                _ => panic!("Expected Create command"),
237
            }
238
        }
239

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

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

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

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

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

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

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

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

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

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

382
        #[test]
383
        fn parses_server_delete_command_with_defaults() {
384
            let args = vec![
385
                "nftbk-cli",
386
                "server",
387
                "delete",
388
                "--task-id",
389
                "test-task-123",
390
            ];
391
            let cli = Cli::try_parse_from(args).unwrap();
392

393
            match cli.command {
394
                Commands::Server { command } => match command {
395
                    ServerCommands::Delete {
396
                        server_address,
397
                        task_id,
398
                    } => {
399
                        assert_eq!(server_address, "http://127.0.0.1:8080");
400
                        assert_eq!(task_id, "test-task-123");
401
                    }
402
                    _ => panic!("Expected Server Delete command"),
403
                },
404
                _ => panic!("Expected Server command"),
405
            }
406
        }
407

408
        #[test]
409
        fn parses_server_delete_command_with_custom_options() {
410
            let args = vec![
411
                "nftbk-cli",
412
                "server",
413
                "delete",
414
                "--server-address",
415
                "https://api.example.com",
416
                "--task-id",
417
                "custom-task-456",
418
            ];
419
            let cli = Cli::try_parse_from(args).unwrap();
420

421
            match cli.command {
422
                Commands::Server { command } => match command {
423
                    ServerCommands::Delete {
424
                        server_address,
425
                        task_id,
426
                    } => {
427
                        assert_eq!(server_address, "https://api.example.com");
428
                        assert_eq!(task_id, "custom-task-456");
429
                    }
430
                    _ => panic!("Expected Server Delete command"),
431
                },
432
                _ => panic!("Expected Server command"),
433
            }
434
        }
435

436
        #[test]
437
        fn parses_all_log_levels() {
438
            for (level_str, expected_level) in [
439
                ("debug", LogLevel::Debug),
440
                ("info", LogLevel::Info),
441
                ("warn", LogLevel::Warn),
442
                ("error", LogLevel::Error),
443
            ] {
444
                let args = vec!["nftbk-cli", "--log-level", level_str, "create"];
445
                let cli = Cli::try_parse_from(args).unwrap();
446
                assert_eq!(cli.log_level, expected_level);
447
            }
448
        }
449

450
        #[test]
451
        fn handles_no_color_flag() {
452
            let args = vec!["nftbk-cli", "--no-color", "true", "create"];
453
            let cli = Cli::try_parse_from(args).unwrap();
454
            assert!(cli.no_color);
455

456
            let args = vec!["nftbk-cli", "--no-color", "false", "create"];
457
            let cli = Cli::try_parse_from(args).unwrap();
458
            assert!(!cli.no_color);
459
        }
460

461
        #[test]
462
        fn requires_subcommand() {
463
            let args = vec!["nftbk-cli"];
464
            let result = Cli::try_parse_from(args);
465
            assert!(result.is_err());
466
        }
467

468
        #[test]
469
        fn validates_log_level_enum() {
470
            let args = vec!["nftbk-cli", "--log-level", "invalid", "create"];
471
            let result = Cli::try_parse_from(args);
472
            assert!(result.is_err());
473
        }
474
    }
475
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc