I have an rsync-like rust program. The main user interface is something like program src dest
.
It needs to invoke itself on another machine over ssh in order to read or write files. This is an implementation detail, and I don't want to really expose it as a subcommand, and risk src
being misinterpreted.
I'd like to run these implementation details using flags.
program --read file
would start writing the file to stdout.program --write file
would start writing stdin to the file.program ./local user@remote:remote/file
would write./local
to the stdin ofssh user@remote program --write remote/file
.program user@remote:remote/file ./local
would write the stdout ofssh user@remote program --read file
to./local
.
I've tried using the clap derive API's group
feature for its ArgGroup
s. The derive tutorial example flattens structs.
use std::ffi::OsString;
use clap::{Args, Parser};
#[derive(Parser, Debug)]
struct RsyncExample {
#[command(flatten)]
inner_op: ImplOperation,
#[command(flatten)]
transfer: Option<FileTransfer>,
}
#[derive(Args, Clone, Debug)]
#[group(required = false, multiple = false, conflicts_with = "FileTransfer")]
struct ImplOperation {
#[arg(long)]
read: bool,
#[arg(long)]
write: bool,
}
#[derive(Args, Clone, Debug)]
struct FileTransfer {
from: OsString,
to: OsString,
}
fn main() {
let cli = RsyncExample::parse();
println!("{cli:?}");
}
While the following will rightly disallow specifying both --read --write
, and disallow --read file1 file2
, the error message is a bit confusing. It still specifies FROM
and TO
.
$ cargo run -- --read from
error: the argument '--read' cannot be used with:
<FROM>
<TO>
Usage: blktrans --read <FROM> <TO>
For more information, try '--help'.
And even with this, I can't figure out how to allow a single file with those flags.
I have considered linking to this program with a different name, and dispatching based on argv[0]
. But I'd like to avoid that if possible.