Fix issue with = in command line parsing

This commit is contained in:
Caelan Sayler
2024-11-28 22:12:55 +00:00
committed by Caelan
parent f0a0888461
commit de6206d87f
5 changed files with 76 additions and 45 deletions

View File

@@ -54,7 +54,10 @@ pub fn header_offset_and_length() -> (i64, i64) {
fn main() -> Result<()> {
windows::mitigate::pre_main_sideload_mitigation();
shared::cli_host::clap_run_main("Setup", main_inner)
}
fn main_inner() -> Result<()> {
#[rustfmt::skip]
let mut arg_config = Command::new("Setup")
.about(format!("Velopack Setup ({}) installs applications.\nhttps://github.com/velopack/velopack", env!("NGBV_VERSION")))
@@ -69,38 +72,19 @@ fn main() -> Result<()> {
.arg(arg!(-d --debug <FILE> "Debug mode, install from a nupkg file").required(false).value_parser(value_parser!(PathBuf)));
}
if let Err(e) = run_inner(arg_config) {
let error_string = format!("An error has occurred: {:?}", e);
if let Ok(downcast) = e.downcast::<clap::Error>() {
let output_string = downcast.to_string();
match downcast.kind() {
clap::error::ErrorKind::DisplayHelp => { println!("{output_string}"); return Ok(()); }
clap::error::ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand => { println!("{output_string}"); return Ok(()); }
clap::error::ErrorKind::DisplayVersion => { println!("{output_string}"); return Ok(()); }
_ => {}
}
}
error!("{}", error_string);
dialogs::show_error("Setup Error", None, &error_string);
}
Ok(())
}
fn run_inner(arg_config: Command) -> Result<()>
{
let matches = arg_config.try_get_matches()?;
let silent = matches.get_flag("silent");
dialogs::set_silent(silent);
let verbose = matches.get_flag("verbose");
let debug = matches.get_one::<PathBuf>("debug");
let logfile = matches.get_one::<PathBuf>("log");
logging::setup_logging("setup", logfile, true, verbose)?;
let debug = matches.get_one::<PathBuf>("debug");
let install_to = matches.get_one::<PathBuf>("installto");
let exe_args: Option<Vec<&str>> = matches.get_many::<String>("EXE_ARGS").map(|v| v.map(|f| f.as_str()).collect());
dialogs::set_silent(silent);
logging::setup_logging("setup", logfile, true, verbose)?;
info!("Starting Velopack Setup ({})", env!("NGBV_VERSION"));
info!(" Location: {:?}", env::current_exe()?);
info!(" Silent: {}", silent);
@@ -152,4 +136,3 @@ fn run_inner(arg_config: Command) -> Result<()>
bail!("Could not find embedded zip file. Please contact the application author.");
}

View File

@@ -0,0 +1,35 @@
pub fn clap_run_main(program_name: &str, main_inner: fn() -> anyhow::Result<()>) -> anyhow::Result<()> {
if let Err(e) = main_inner() {
let error_string = format!("An error has occurred: {:?}", e);
match e.downcast::<clap::Error>() {
Ok(downcast) => {
let output_string = downcast.to_string();
match downcast.kind() {
clap::error::ErrorKind::DisplayHelp => {
println!("{output_string}");
return Ok(());
}
clap::error::ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand => {
println!("{output_string}");
return Ok(());
}
clap::error::ErrorKind::DisplayVersion => {
println!("{output_string}");
return Ok(());
}
_ => {
error!("{}", error_string);
crate::dialogs::show_error(format!("{program_name} Error").as_str(), None, &error_string);
return Err(anyhow::Error::from(downcast));
}
}
}
Err(e) => {
error!("{}", error_string);
crate::dialogs::show_error(format!("{program_name} Error").as_str(), None, &error_string);
return Err(e);
}
}
}
Ok(())
}

View File

@@ -1,4 +1,5 @@
pub mod runtime_arch;
pub mod cli_host;
mod dialogs_const;
mod dialogs_common;

View File

@@ -45,8 +45,10 @@ fn main() -> ExitCode {
match Process::new(update_exe).args(args).creation_flags(CREATE_NO_WINDOW).spawn() {
Ok(res) => {
let _ = unsafe { AllowSetForegroundWindow(res.id()) };
info!("Successfully started Update.exe");
ExitCode::SUCCESS
}, Err(e) => {
}
Err(e) => {
error!("Stub failed to start Update.exe: {}", e);
ExitCode::FAILURE
}

View File

@@ -7,8 +7,7 @@ extern crate log;
use anyhow::{anyhow, bail, Result};
use clap::{arg, value_parser, ArgMatches, Command};
use std::{env, path::PathBuf};
use velopack::locator;
use velopack::locator::{auto_locate_app_manifest, LocationContext};
use velopack::locator::{self, auto_locate_app_manifest, LocationContext};
use velopack_bins::*;
#[rustfmt::skip]
@@ -39,9 +38,6 @@ fn root_command() -> Command {
.arg(arg!(--patch <FILE> "The Zstd patch to apply to the old file").required(true).value_parser(value_parser!(PathBuf)))
.arg(arg!(--output <FILE> "The file to create with the patch applied").required(true).value_parser(value_parser!(PathBuf)))
)
.subcommand(Command::new("get-version")
.about("Prints the current version of the application")
)
.arg(arg!(--verbose "Print debug messages to console / log").global(true))
.arg(arg!(-s --silent "Don't show any prompts / dialogs").global(true))
.arg(arg!(-l --log <PATH> "Override the default log file location").global(true).value_parser(value_parser!(PathBuf)))
@@ -68,16 +64,18 @@ fn try_parse_command_line_matches(input_args: Vec<String>) -> Result<ArgMatches>
// Also, replace `--processStartAndWait` with `--processStart --wait`
let mut args = Vec::new();
let mut preserve = false;
let mut first = true;
for arg in input_args {
if preserve {
if preserve || first {
args.push(arg);
first = false;
} else if arg == "--" {
args.push("--".to_string());
preserve = true;
} else if arg.eq_ignore_ascii_case("--processStartAndWait") {
args.push("--processStart".to_string());
args.push("--wait".to_string());
} else if arg.starts_with("--processStartAndWait=") {
} else if arg.to_ascii_lowercase().starts_with("--processstartandwait=") {
let mut split_arg = arg.splitn(2, '=');
split_arg.next(); // Skip the `--processStartAndWait` part
args.push("--processStart".to_string());
@@ -85,10 +83,13 @@ fn try_parse_command_line_matches(input_args: Vec<String>) -> Result<ArgMatches>
if let Some(rest) = split_arg.next() {
args.push(rest.to_string());
}
} else if arg.contains('=') {
} else if arg.to_ascii_lowercase().starts_with("--processtart=") {
let mut split_arg = arg.splitn(2, '=');
args.push(split_arg.next().unwrap().to_string());
args.push(split_arg.next().unwrap().to_string());
split_arg.next(); // Skip the `--processStart` part
args.push("--processStart".to_string());
if let Some(rest) = split_arg.next() {
args.push(rest.to_string());
}
} else {
args.push(arg);
}
@@ -114,6 +115,10 @@ fn get_op_wait(matches: &ArgMatches) -> shared::OperationWait {
}
fn main() -> Result<()> {
shared::cli_host::clap_run_main("Update", main_inner)
}
fn main_inner() -> Result<()> {
#[cfg(windows)]
windows::mitigate::pre_main_sideload_mitigation();
@@ -122,13 +127,11 @@ fn main() -> Result<()> {
#[cfg(unix)]
let matches = root_command().try_get_matches()?;
let (subcommand, subcommand_matches) = matches.subcommand().ok_or_else(|| anyhow!("No subcommand was used. Try `--help` for more information."))?;
let silent = get_flag_or_false(&matches, "silent");
dialogs::set_silent(silent);
let verbose = get_flag_or_false(&matches, "verbose");
let silent = get_flag_or_false(&matches, "silent");
let log_file = matches.get_one("log");
dialogs::set_silent(silent);
let desired_log_file = log_file.cloned().unwrap_or(locator::default_log_location(LocationContext::IAmUpdateExe));
logging::setup_logging("update", Some(&desired_log_file), true, verbose)?;
@@ -145,6 +148,9 @@ fn main() -> Result<()> {
info!(" Silent: {}", silent);
info!(" Log File: {:?}", log_file);
let (subcommand, subcommand_matches) =
matches.subcommand().ok_or_else(|| anyhow!("No known subcommand was used. Try `--help` for more information."))?;
let result = match subcommand {
#[cfg(target_os = "windows")]
"uninstall" => uninstall(subcommand_matches).map_err(|e| anyhow!("Uninstall error: {}", e)),
@@ -163,16 +169,20 @@ fn main() -> Result<()> {
}
fn patch(matches: &ArgMatches) -> Result<()> {
let old_file = matches.get_one::<PathBuf>("old").unwrap();
let patch_file = matches.get_one::<PathBuf>("patch").unwrap();
let output_file = matches.get_one::<PathBuf>("output").unwrap();
let old_file = matches.get_one::<PathBuf>("old");
let patch_file = matches.get_one::<PathBuf>("patch");
let output_file = matches.get_one::<PathBuf>("output");
info!("Command: Patch");
info!(" Old File: {:?}", old_file);
info!(" Patch File: {:?}", patch_file);
info!(" Output File: {:?}", output_file);
velopack::delta::zstd_patch_single(old_file, patch_file, output_file)?;
if old_file.is_none() || patch_file.is_none() || output_file.is_none() {
bail!("Missing required arguments. Please provide --old, --patch, and --output.");
}
velopack::delta::zstd_patch_single(old_file.unwrap(), patch_file.unwrap(), output_file.unwrap())?;
Ok(())
}
@@ -208,7 +218,7 @@ fn start(matches: &ArgMatches) -> Result<()> {
info!(" Legacy Args: {:?}", legacy_args);
warn!("Legacy args format is deprecated and will be removed in a future release. Please update your application to use the new format.");
}
commands::start(wait, exe_name, exe_args, legacy_args)
}