mirror of
https://git.proxmox.com/git/vma-to-pbs
synced 2025-08-11 19:51:43 +00:00
switch argument handling from clap to pico-args
Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
This commit is contained in:
parent
715c658e0e
commit
80fb0a4a79
@ -7,7 +7,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
bincode = "1.3"
|
bincode = "1.3"
|
||||||
clap = { version = "4.0.32", features = ["cargo", "env"] }
|
pico-args = "0.4"
|
||||||
md5 = "0.7.0"
|
md5 = "0.7.0"
|
||||||
scopeguard = "1.1.0"
|
scopeguard = "1.1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
|
208
src/main.rs
208
src/main.rs
@ -1,91 +1,106 @@
|
|||||||
use anyhow::{Context, Error};
|
use std::ffi::OsString;
|
||||||
use clap::{command, Arg, ArgAction};
|
|
||||||
|
use anyhow::{bail, Context, Error};
|
||||||
use proxmox_sys::linux::tty;
|
use proxmox_sys::linux::tty;
|
||||||
|
|
||||||
mod vma;
|
mod vma;
|
||||||
mod vma2pbs;
|
mod vma2pbs;
|
||||||
use vma2pbs::{backup_vma_to_pbs, BackupVmaToPbsArgs};
|
use vma2pbs::{backup_vma_to_pbs, BackupVmaToPbsArgs};
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
const CMD_HELP: &str = "\
|
||||||
let matches = command!()
|
Usage: vma-to-pbs [OPTIONS] --repository <auth_id@host:port:datastore> --vmid <VMID> [vma_file]
|
||||||
.arg(
|
|
||||||
Arg::new("repository")
|
|
||||||
.long("repository")
|
|
||||||
.value_name("auth_id@host:port:datastore")
|
|
||||||
.help("Repository URL")
|
|
||||||
.required(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("vmid")
|
|
||||||
.long("vmid")
|
|
||||||
.value_name("VMID")
|
|
||||||
.help("Backup ID")
|
|
||||||
.required(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("fingerprint")
|
|
||||||
.long("fingerprint")
|
|
||||||
.value_name("FINGERPRINT")
|
|
||||||
.help("Proxmox Backup Server Fingerprint")
|
|
||||||
.env("PBS_FINGERPRINT"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("keyfile")
|
|
||||||
.long("keyfile")
|
|
||||||
.value_name("KEYFILE")
|
|
||||||
.help("Key file"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("master_keyfile")
|
|
||||||
.long("master_keyfile")
|
|
||||||
.value_name("MASTER_KEYFILE")
|
|
||||||
.help("Master key file"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("compress")
|
|
||||||
.long("compress")
|
|
||||||
.short('c')
|
|
||||||
.help("Compress the Backup")
|
|
||||||
.action(ArgAction::SetTrue),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("encrypt")
|
|
||||||
.long("encrypt")
|
|
||||||
.short('e')
|
|
||||||
.help("Encrypt the Backup")
|
|
||||||
.action(ArgAction::SetTrue),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("password-file")
|
|
||||||
.long("password-file")
|
|
||||||
.value_name("PASSWORD_FILE")
|
|
||||||
.help("Password file"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("key-password-file")
|
|
||||||
.long("key-password-file")
|
|
||||||
.value_name("KEY_PASSWORD_FILE")
|
|
||||||
.help("Key password file"),
|
|
||||||
)
|
|
||||||
.arg(Arg::new("vma_file"))
|
|
||||||
.get_matches();
|
|
||||||
|
|
||||||
let pbs_repository = matches.get_one::<String>("repository").unwrap().to_string();
|
Arguments:
|
||||||
let vmid = matches.get_one::<String>("vmid").unwrap().to_string();
|
[vma_file]
|
||||||
|
|
||||||
let fingerprint = matches
|
Options:
|
||||||
.get_one::<String>("fingerprint")
|
--repository <auth_id@host:port:datastore>
|
||||||
.context("Fingerprint not set. Use $PBS_FINGERPRINT or --fingerprint")?
|
Repository URL
|
||||||
.to_string();
|
--vmid <VMID>
|
||||||
|
Backup ID
|
||||||
|
--fingerprint <FINGERPRINT>
|
||||||
|
Proxmox Backup Server Fingerprint [env: PBS_FINGERPRINT=]
|
||||||
|
--keyfile <KEYFILE>
|
||||||
|
Key file
|
||||||
|
--master_keyfile <MASTER_KEYFILE>
|
||||||
|
Master key file
|
||||||
|
-c, --compress
|
||||||
|
Compress the Backup
|
||||||
|
-e, --encrypt
|
||||||
|
Encrypt the Backup
|
||||||
|
--password_file <PASSWORD_FILE>
|
||||||
|
Password file
|
||||||
|
--key_password_file <KEY_PASSWORD_FILE>
|
||||||
|
Key password file
|
||||||
|
-h, --help
|
||||||
|
Print help
|
||||||
|
-V, --version
|
||||||
|
Print version
|
||||||
|
";
|
||||||
|
|
||||||
let keyfile = matches.get_one::<String>("keyfile");
|
fn parse_args() -> Result<BackupVmaToPbsArgs, Error> {
|
||||||
let master_keyfile = matches.get_one::<String>("master_keyfile");
|
let mut args: Vec<_> = std::env::args_os().collect();
|
||||||
let compress = matches.get_flag("compress");
|
args.remove(0); // remove the executable path.
|
||||||
let encrypt = matches.get_flag("encrypt");
|
|
||||||
|
|
||||||
let vma_file_path = matches.get_one::<String>("vma_file");
|
let mut first_later_args_index = 0;
|
||||||
|
let options = ["-h", "--help", "-c", "--compress", "-e", "--encrypt"];
|
||||||
|
|
||||||
let password_file = matches.get_one::<String>("password-file");
|
for (i, arg) in args.iter().enumerate() {
|
||||||
|
if let Some(arg) = arg.to_str() {
|
||||||
|
if arg.starts_with('-') {
|
||||||
|
if arg == "--" {
|
||||||
|
args.remove(i);
|
||||||
|
first_later_args_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
first_later_args_index = i + 1;
|
||||||
|
|
||||||
|
if !options.contains(&arg) {
|
||||||
|
first_later_args_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let forwarded_args = if first_later_args_index > args.len() {
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
args.split_off(first_later_args_index)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut args = pico_args::Arguments::from_vec(args);
|
||||||
|
|
||||||
|
if args.contains(["-h", "--help"]) {
|
||||||
|
print!("{CMD_HELP}");
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pbs_repository = args.value_from_str("--repository")?;
|
||||||
|
let vmid = args.value_from_str("--vmid")?;
|
||||||
|
let fingerprint = args.opt_value_from_str("--fingerprint")?;
|
||||||
|
let keyfile = args.opt_value_from_str("--keyfile")?;
|
||||||
|
let master_keyfile = args.opt_value_from_str("--master_keyfile")?;
|
||||||
|
let compress = args.contains(["-c", "--compress"]);
|
||||||
|
let encrypt = args.contains(["-e", "--encrypt"]);
|
||||||
|
let password_file: Option<OsString> = args.opt_value_from_str("--password-file")?;
|
||||||
|
let key_password_file: Option<OsString> = args.opt_value_from_str("--key-password-file")?;
|
||||||
|
|
||||||
|
if !args.finish().is_empty() {
|
||||||
|
bail!("unexpected extra arguments, use '-h' for usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
let fingerprint = match fingerprint {
|
||||||
|
Some(v) => v,
|
||||||
|
None => std::env::var("PBS_FINGERPRINT")
|
||||||
|
.context("Fingerprint not set. Use $PBS_FINGERPRINT or --fingerprint")?,
|
||||||
|
};
|
||||||
|
|
||||||
|
if forwarded_args.len() > 1 {
|
||||||
|
bail!("too many arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
let vma_file_path = forwarded_args.first();
|
||||||
|
|
||||||
let pbs_password = match password_file {
|
let pbs_password = match password_file {
|
||||||
Some(password_file) => {
|
Some(password_file) => {
|
||||||
@ -101,14 +116,20 @@ fn main() -> Result<(), Error> {
|
|||||||
|
|
||||||
password
|
password
|
||||||
}
|
}
|
||||||
None => String::from_utf8(tty::read_password("Password: ")?)?,
|
None => {
|
||||||
|
if vma_file_path.is_none() {
|
||||||
|
bail!(
|
||||||
|
"Please use --password-file to provide the password \
|
||||||
|
when passing the VMA file to stdin"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::from_utf8(tty::read_password("Password: ")?)?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let key_password = match keyfile {
|
let key_password = match keyfile {
|
||||||
Some(_) => {
|
Some(_) => Some(match key_password_file {
|
||||||
let key_password_file = matches.get_one::<String>("key_password_file");
|
|
||||||
|
|
||||||
Some(match key_password_file {
|
|
||||||
Some(key_password_file) => {
|
Some(key_password_file) => {
|
||||||
let mut key_password = std::fs::read_to_string(key_password_file)
|
let mut key_password = std::fs::read_to_string(key_password_file)
|
||||||
.context("Could not read key password file")?;
|
.context("Could not read key password file")?;
|
||||||
@ -122,25 +143,38 @@ fn main() -> Result<(), Error> {
|
|||||||
|
|
||||||
key_password
|
key_password
|
||||||
}
|
}
|
||||||
None => String::from_utf8(tty::read_password("Key Password: ")?)?,
|
None => {
|
||||||
})
|
if vma_file_path.is_none() {
|
||||||
|
bail!(
|
||||||
|
"Please use --key-password-file to provide the password \
|
||||||
|
when passing the VMA file to stdin"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String::from_utf8(tty::read_password("Key Password: ")?)?
|
||||||
|
}
|
||||||
|
}),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let args = BackupVmaToPbsArgs {
|
let options = BackupVmaToPbsArgs {
|
||||||
vma_file_path: vma_file_path.cloned(),
|
vma_file_path: vma_file_path.cloned(),
|
||||||
pbs_repository,
|
pbs_repository,
|
||||||
backup_id: vmid,
|
backup_id: vmid,
|
||||||
pbs_password,
|
pbs_password,
|
||||||
keyfile: keyfile.cloned(),
|
keyfile,
|
||||||
key_password,
|
key_password,
|
||||||
master_keyfile: master_keyfile.cloned(),
|
master_keyfile,
|
||||||
fingerprint,
|
fingerprint,
|
||||||
compress,
|
compress,
|
||||||
encrypt,
|
encrypt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Ok(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let args = parse_args()?;
|
||||||
backup_vma_to_pbs(args)?;
|
backup_vma_to_pbs(args)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::{c_char, CStr, CString};
|
use std::ffi::{c_char, CStr, CString, OsString};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdin, BufRead, BufReader, Read};
|
use std::io::{stdin, BufRead, BufReader, Read};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
@ -22,7 +22,7 @@ use crate::vma::VmaReader;
|
|||||||
const VMA_CLUSTER_SIZE: usize = 65536;
|
const VMA_CLUSTER_SIZE: usize = 65536;
|
||||||
|
|
||||||
pub struct BackupVmaToPbsArgs {
|
pub struct BackupVmaToPbsArgs {
|
||||||
pub vma_file_path: Option<String>,
|
pub vma_file_path: Option<OsString>,
|
||||||
pub pbs_repository: String,
|
pub pbs_repository: String,
|
||||||
pub backup_id: String,
|
pub backup_id: String,
|
||||||
pub pbs_password: String,
|
pub pbs_password: String,
|
||||||
|
Loading…
Reference in New Issue
Block a user