Rust · 3204 bytes Raw Blame History
1 //! WANDA CLI - WeMod launcher for Linux
2
3 mod commands;
4
5 use clap::{Parser, Subcommand};
6 use std::path::PathBuf;
7 use tracing_subscriber::{fmt, prelude::*, EnvFilter};
8
9 #[derive(Parser)]
10 #[command(name = "wanda")]
11 #[command(author = "WANDA Contributors")]
12 #[command(version)]
13 #[command(about = "WeMod launcher for Linux", long_about = None)]
14 struct Cli {
15 /// Increase verbosity (-v, -vv, -vvv)
16 #[arg(short, long, action = clap::ArgAction::Count, global = true)]
17 verbose: u8,
18
19 /// Suppress non-essential output
20 #[arg(short, long, global = true)]
21 quiet: bool,
22
23 /// Output in JSON format
24 #[arg(long, global = true)]
25 json: bool,
26
27 /// Use a custom config file
28 #[arg(long, global = true)]
29 config: Option<PathBuf>,
30
31 #[command(subcommand)]
32 command: Commands,
33 }
34
35 #[derive(Subcommand)]
36 enum Commands {
37 /// Initialize WANDA and set up WeMod prefix
38 Init(commands::init::InitArgs),
39
40 /// Scan for Steam games
41 Scan(commands::scan::ScanArgs),
42
43 /// Launch a game with WeMod
44 Launch(commands::launch::LaunchArgs),
45
46 /// Manage Wine/Proton prefixes
47 #[command(subcommand)]
48 Prefix(commands::prefix::PrefixCommands),
49
50 /// Manage WeMod installation
51 #[command(subcommand)]
52 Wemod(commands::wemod::WemodCommands),
53
54 /// Manage configuration
55 #[command(subcommand)]
56 Config(commands::config::ConfigCommands),
57
58 /// Diagnose issues and generate reports
59 Doctor(commands::doctor::DoctorArgs),
60
61 /// Kill stale Wine/WeMod processes
62 Cleanup(commands::cleanup::CleanupArgs),
63
64 /// Steam launch option wrapper — injects WeMod into the game's Proton session
65 ///
66 /// Set Steam launch options to: wanda inject %command%
67 Inject(commands::inject::InjectArgs),
68 }
69
70 fn setup_logging(verbose: u8, quiet: bool) {
71 let filter = if quiet {
72 "warn"
73 } else {
74 match verbose {
75 0 => "info",
76 1 => "debug",
77 _ => "trace",
78 }
79 };
80
81 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(filter));
82
83 tracing_subscriber::registry()
84 .with(fmt::layer().with_target(false).without_time())
85 .with(filter)
86 .init();
87 }
88
89 #[tokio::main]
90 async fn main() {
91 let cli = Cli::parse();
92
93 setup_logging(cli.verbose, cli.quiet);
94
95 let result = match cli.command {
96 Commands::Init(args) => commands::init::run(args, cli.config).await,
97 Commands::Scan(args) => commands::scan::run(args, cli.config).await,
98 Commands::Launch(args) => commands::launch::run(args, cli.config).await,
99 Commands::Prefix(cmd) => commands::prefix::run(cmd, cli.config).await,
100 Commands::Wemod(cmd) => commands::wemod::run(cmd, cli.config).await,
101 Commands::Config(cmd) => commands::config::run(cmd, cli.config).await,
102 Commands::Doctor(args) => commands::doctor::run(args, cli.config).await,
103 Commands::Cleanup(args) => commands::cleanup::run(args, cli.config).await,
104 Commands::Inject(args) => commands::inject::run(args, cli.config).await,
105 };
106
107 if let Err(e) = result {
108 eprintln!("Error: {}", e.user_message());
109 std::process::exit(1);
110 }
111 }
112