ev3_runner/
cli.rs

1pub use clap::Parser;
2use std::path::PathBuf;
3
4#[derive(Debug, clap::Parser)]
5#[command(
6    name = "ev3-runner",
7    version,
8    about = "Upload and run binaries on LEGO EV3 robots",
9    long_about = "A tool to upload and execute programs on LEGO EV3 robots running ev3dev.\n\
10                  Uses hash-based deduplication to skip uploads when files haven't changed.\n\
11                  Supports password protection and real-time output streaming."
12)]
13pub struct Cli {
14    #[clap(
15        short,
16        long,
17        global = true,
18        action = clap::ArgAction::Count,
19        help = "Increase logging verbosity (-v: INFO, -vv: DEBUG, -vvv: TRACE)"
20    )]
21    pub verbose: u8,
22    #[command(subcommand)]
23    pub command: Commands,
24}
25
26#[derive(Debug, clap::Subcommand)]
27pub enum Commands {
28    /// Run as server (typically on the EV3)
29    #[command(
30        long_about = "Start the server to accept file uploads and execute programs.\n\
31                            This mode should be run on the EV3 robot."
32    )]
33    Server(Server),
34    /// Run as client (on your development machine)
35    #[command(
36        long_about = "Connect to a server to upload files or execute programs.\n\
37                            This mode should be run on your development machine."
38    )]
39    Client(Client),
40}
41
42#[derive(Debug, clap::Args)]
43pub struct Client {
44    #[command(subcommand)]
45    pub action: Action,
46}
47
48#[derive(Debug, clap::Subcommand)]
49pub enum Action {
50    /// Upload a file to the server
51    #[command(long_about = "Upload a file to the server without executing it.\n\
52                            The file will be made executable on the server.")]
53    Upload(ClientArgs),
54    /// Upload and run a file on the server
55    #[command(
56        long_about = "Upload a file to the server and execute it immediately.\n\
57                            Output from the program will be streamed back in real-time.\n\
58                            If the file hash matches what's already on the server, upload is skipped."
59    )]
60    Run(ClientArgs),
61}
62
63#[derive(Debug, clap::Args)]
64pub struct ClientArgs {
65    /// Path to the local file to upload
66    #[arg(value_name = "FILE")]
67    pub filepath: PathBuf,
68
69    /// Server address and port
70    #[clap(
71        long,
72        default_value = "127.0.0.1:6767",
73        value_name = "HOST:PORT",
74        help = "Server address in format IP:PORT"
75    )]
76    pub host: String,
77
78    /// Where to save the file on the server
79    #[clap(
80        short,
81        long,
82        value_name = "PATH",
83        help = "Remote file path (default: same filename as local)"
84    )]
85    pub remote_path: Option<PathBuf>,
86
87    /// Password for authentication
88    #[clap(
89        short,
90        long,
91        default_value = "maker",
92        value_name = "PASSWORD",
93        help = "Password to authenticate with the server"
94    )]
95    pub password: String,
96
97    /// Use brickrun
98    #[clap(short, long, help = "If the program should be started using brickrun")]
99    pub brickrun: bool,
100
101    /// If compression should be used to send the file
102    #[clap(short, long, help = "If compression should be used to send the file")]
103    pub compression: bool,
104}
105
106#[derive(Debug, clap::Args)]
107pub struct Server {
108    /// Port to listen on
109    #[clap(
110        short,
111        long,
112        default_value = "6767",
113        value_name = "PORT",
114        help = "TCP port for incoming connections"
115    )]
116    pub server_port: u16,
117
118    /// Server password
119    #[clap(
120        short,
121        long,
122        default_value = "maker",
123        value_name = "PASSWORD",
124        help = "Password required for client authentication"
125    )]
126    pub password: String,
127}