Support optional trailing positional arguments

This commit is contained in:
topjohnwu
2025-10-19 03:53:53 -07:00
committed by John Wu
parent 57d9fc6099
commit 536e50c6e0
2 changed files with 39 additions and 53 deletions

View File

@@ -279,7 +279,7 @@ fn impl_from_args_struct(
.collect(); .collect();
ensure_unique_names(errors, &fields); ensure_unique_names(errors, &fields);
ensure_only_last_positional_is_optional(errors, &fields); ensure_only_trailing_positionals_are_optional(errors, &fields);
let impl_span = Span::call_site(); let impl_span = Span::call_site();
@@ -441,17 +441,22 @@ fn get_help_triggers(type_attrs: &TypeAttrs) -> Vec<String> {
}) })
} }
/// Ensures that only the last positional arg is non-required. /// Ensures that only trailing positional args are non-required.
fn ensure_only_last_positional_is_optional(errors: &Errors, fields: &[StructField<'_>]) { fn ensure_only_trailing_positionals_are_optional(errors: &Errors, fields: &[StructField<'_>]) {
let mut first_non_required_span = None; let mut first_non_required_span = None;
for field in fields { for field in fields {
if field.kind == FieldKind::Positional { if field.kind == FieldKind::Positional {
if let Some(first) = first_non_required_span { if let Some(first) = first_non_required_span
&& field.optionality.is_required()
{
errors.err_span( errors.err_span(
first, first,
"Only the last positional argument may be `Option`, `Vec`, or defaulted.", "Only trailing positional arguments may be `Option`, `Vec`, or defaulted.",
);
errors.err(
&field.field,
"Later non-optional positional argument declared here.",
); );
errors.err(&field.field, "Later positional argument declared here.");
return; return;
} }
if !field.optionality.is_required() { if !field.optionality.is_required() {

View File

@@ -58,8 +58,8 @@ struct Repack {
no_compress: bool, no_compress: bool,
#[argh(positional)] #[argh(positional)]
img: Utf8CString, img: Utf8CString,
#[argh(positional, default = r#"Utf8CString::from("new-boot.img")"#)] #[argh(positional)]
out: Utf8CString, out: Option<Utf8CString>,
} }
#[derive(FromArgs)] #[derive(FromArgs)]
@@ -77,33 +77,24 @@ struct Sign {
#[argh(positional)] #[argh(positional)]
img: Utf8CString, img: Utf8CString,
#[argh(positional)] #[argh(positional)]
args: Vec<Utf8CString>, name: Option<Utf8CString>,
#[argh(positional)]
cert: Option<Utf8CString>,
#[argh(positional)]
key: Option<Utf8CString>,
} }
#[derive(FromArgs)]
#[argh(subcommand, name = "extract")]
struct Extract { struct Extract {
#[argh(positional)]
payload: Utf8CString, payload: Utf8CString,
#[argh(positional)]
partition: Option<Utf8CString>, partition: Option<Utf8CString>,
#[argh(positional)]
outfile: Option<Utf8CString>, outfile: Option<Utf8CString>,
} }
impl FromArgs for Extract {
fn from_args(_command_name: &[&str], args: &[&str]) -> Result<Self, EarlyExit> {
let mut parse = PositionalArgParser(args.iter());
Ok(Extract {
payload: parse.required("payload.bin")?,
partition: parse.optional(),
outfile: parse.last_optional()?,
})
}
}
impl SubCommand for Extract {
const COMMAND: &'static CommandInfo = &CommandInfo {
name: "extract",
description: "",
};
}
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh(subcommand, name = "hexpatch")] #[argh(subcommand, name = "hexpatch")]
struct HexPatch { struct HexPatch {
@@ -186,28 +177,15 @@ impl SubCommand for Compress {
}; };
} }
#[derive(FromArgs)]
#[argh(subcommand, name = "decompress")]
struct Decompress { struct Decompress {
#[argh(positional)]
file: Utf8CString, file: Utf8CString,
#[argh(positional)]
out: Option<Utf8CString>, out: Option<Utf8CString>,
} }
impl FromArgs for Decompress {
fn from_args(_command_name: &[&str], args: &[&str]) -> Result<Self, EarlyExit> {
let mut iter = PositionalArgParser(args.iter());
Ok(Decompress {
file: iter.required("infile")?,
out: iter.last_optional()?,
})
}
}
impl SubCommand for Decompress {
const COMMAND: &'static CommandInfo = &CommandInfo {
name: "decompress",
description: "",
};
}
fn print_usage(cmd: &str) { fn print_usage(cmd: &str) {
eprintln!( eprintln!(
r#"MagiskBoot - Boot Image Modification Tool r#"MagiskBoot - Boot Image Modification Tool
@@ -386,21 +364,24 @@ fn boot_main(cmds: CmdArgs) -> LoggedResult<i32> {
img, img,
out, out,
}) => { }) => {
repack(&img, &out, no_compress); repack(
&img,
out.as_deref().unwrap_or(cstr!("new-boot.img")),
no_compress,
);
} }
Action::Verify(Verify { img, cert }) => { Action::Verify(Verify { img, cert }) => {
if !verify_cmd(&img, cert.as_deref()) { if !verify_cmd(&img, cert.as_deref()) {
return log_err!(); return log_err!();
} }
} }
Action::Sign(Sign { img, args }) => { Action::Sign(Sign {
let mut iter = args.iter(); img,
sign_cmd( name,
&img, cert,
iter.next().map(AsRef::as_ref), key,
iter.next().map(AsRef::as_ref), }) => {
iter.next().map(AsRef::as_ref), sign_cmd(&img, name.as_deref(), cert.as_deref(), key.as_deref())?;
)?;
} }
Action::Extract(Extract { Action::Extract(Extract {
payload, payload,