Skip to main content

launcher/
cli.rs

1use std::path::PathBuf;
2
3#[derive(Debug, Clone)]
4pub struct CliArgs {
5    pub command: Option<Command>,
6}
7
8#[derive(Debug, Clone)]
9pub enum Command {
10    SelfUpdate,
11    NetworkFiles,
12    Snapshot(SnapshotCommand),
13}
14
15#[derive(Debug, Clone)]
16pub enum SnapshotCommand {
17    Create {
18        name: String,
19        description: Option<String>,
20        version: Option<String>,
21        compression: u32,
22        directory: Option<PathBuf>,
23    },
24    Restore {
25        profile: String,
26    },
27    List,
28}
29
30pub fn parse() -> CliArgs {
31    parse_from(std::env::args().skip(1))
32}
33
34/// Parse CLI arguments from an arbitrary iterator of strings.
35/// Separated from [`parse`] so tests can supply arguments directly without
36/// touching process state.
37pub fn parse_from(mut args: impl Iterator<Item = String>) -> CliArgs {
38    let mut command = None;
39
40    if let Some(arg) = args.next() {
41        if arg == "--self-update" {
42            command = Some(Command::SelfUpdate);
43        } else if arg == "network-files" {
44            // the DLL's networking daemon (all uploads and
45            // downloads for the game session, served over stdio pipes).
46            command = Some(Command::NetworkFiles);
47        } else if arg == "snapshot" {
48            if let Some(sub) = args.next() {
49                match sub.as_str() {
50                    "list" => {
51                        command = Some(Command::Snapshot(SnapshotCommand::List));
52                    }
53                    "restore" => {
54                        if let Some(profile) = args.next() {
55                            command = Some(Command::Snapshot(SnapshotCommand::Restore { profile }));
56                        } else {
57                            eprintln!("Error: Missing profile argument for snapshot restore");
58                            std::process::exit(1);
59                        }
60                    }
61                    "create" => {
62                        if let Some(name) = args.next() {
63                            let mut description = None;
64                            let mut version = None;
65                            let mut compression = 0;
66                            let mut directory = None;
67
68                            while let Some(flag) = args.next() {
69                                match flag.as_str() {
70                                    "--description" => {
71                                        description = args.next();
72                                    }
73                                    "--version" => {
74                                        version = args.next();
75                                    }
76                                    "--compression" => {
77                                        if let Some(val_str) = args.next() {
78                                            compression = val_str.parse().unwrap_or(0);
79                                        }
80                                    }
81                                    "--directory" => {
82                                        if let Some(dir_str) = args.next() {
83                                            directory = Some(PathBuf::from(dir_str));
84                                        }
85                                    }
86                                    _ => {
87                                        eprintln!("Error: Unknown flag: {}", flag);
88                                        std::process::exit(1);
89                                    }
90                                }
91                            }
92
93                            command = Some(Command::Snapshot(SnapshotCommand::Create {
94                                name,
95                                description,
96                                version,
97                                compression,
98                                directory,
99                            }));
100                        } else {
101                            eprintln!("Error: Missing name argument for snapshot create");
102                            std::process::exit(1);
103                        }
104                    }
105                    _ => {
106                        eprintln!("Error: Unknown snapshot subcommand: {}", sub);
107                        std::process::exit(1);
108                    }
109                }
110            } else {
111                eprintln!("Error: Missing snapshot subcommand (create, restore, list)");
112                std::process::exit(1);
113            }
114        } else if arg == "--help" || arg == "-h" {
115            print_usage();
116            std::process::exit(0);
117        } else {
118            eprintln!("Error: Unknown argument: {}", arg);
119            print_usage();
120            std::process::exit(1);
121        }
122    }
123
124    CliArgs { command }
125}
126
127fn print_usage() {
128    println!("Supreme Snowboarding Community Launcher CLI");
129    println!("Usage:");
130    println!("  Display_Config                              Launch the GUI app");
131    println!("  Display_Config --self-update                Run background self-update daemon");
132    println!(
133        "  Display_Config network-files               Serve the hook DLL's downloads and uploads (spawned by the DLL)"
134    );
135    println!("  Display_Config snapshot list                List local snapshots");
136    println!("  Display_Config snapshot create <name> [flags] Create a new snapshot");
137    println!("  Display_Config snapshot restore <profile>   Restore a snapshot");
138    println!();
139    println!("Create flags:");
140    println!("  --description <desc>    Snapshot description");
141    println!("  --version <ver>         Snapshot version");
142    println!("  --compression <0-8>     Compression level (default 0)");
143    println!("  --directory <path>      Custom game directory");
144}