Custom help message when using argh

Help messages generated from argh is nearly useless and very hard to
customize. Fork argh and disable all code for generating help messages.

Use a closure to print the help message when handling EarlyExit.
This commit is contained in:
topjohnwu 2023-07-05 17:05:39 -07:00
parent 5ee6daf126
commit d778b0b0a7
7 changed files with 79 additions and 77 deletions

3
.gitmodules vendored
View File

@ -46,3 +46,6 @@
[submodule "termux-elf-cleaner"] [submodule "termux-elf-cleaner"]
path = tools/termux-elf-cleaner path = tools/termux-elf-cleaner
url = https://github.com/termux/termux-elf-cleaner.git url = https://github.com/termux/termux-elf-cleaner.git
[submodule "argh"]
path = native/src/external/argh
url = https://github.com/topjohnwu/argh.git

6
native/src/Cargo.lock generated
View File

@ -23,8 +23,6 @@ dependencies = [
[[package]] [[package]]
name = "argh" name = "argh"
version = "0.1.10" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab257697eb9496bf75526f0217b5ed64636a9cfafa78b8365c71bd283fcef93e"
dependencies = [ dependencies = [
"argh_derive", "argh_derive",
"argh_shared", "argh_shared",
@ -33,8 +31,6 @@ dependencies = [
[[package]] [[package]]
name = "argh_derive" name = "argh_derive"
version = "0.1.10" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b382dbd3288e053331f03399e1db106c9fb0d8562ad62cb04859ae926f324fa6"
dependencies = [ dependencies = [
"argh_shared", "argh_shared",
"proc-macro2", "proc-macro2",
@ -45,8 +41,6 @@ dependencies = [
[[package]] [[package]]
name = "argh_shared" name = "argh_shared"
version = "0.1.10" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f"
[[package]] [[package]]
name = "atty" name = "atty"

View File

@ -6,6 +6,7 @@ resolver = "2"
[workspace.dependencies] [workspace.dependencies]
cxx = { path = "external/cxx-rs" } cxx = { path = "external/cxx-rs" }
cxx-gen = { path = "external/cxx-rs/gen/lib" } cxx-gen = { path = "external/cxx-rs/gen/lib" }
argh = { path = "external/argh/argh" }
libc = "0.2" libc = "0.2"
cfg-if = "1.0" cfg-if = "1.0"
num-traits = "0.2" num-traits = "0.2"
@ -13,7 +14,6 @@ num-derive = "0.3"
thiserror = "1.0" thiserror = "1.0"
byteorder = "1" byteorder = "1"
size = "0.4" size = "0.4"
argh = "0.1.10"
sha1 = "0.10" sha1 = "0.10"
sha2 = "0.10" sha2 = "0.10"
digest = "0.10" digest = "0.10"

View File

@ -382,20 +382,21 @@ pub fn map_args<'a>(argc: i32, argv: *const *const c_char) -> Result<Vec<&'a Utf
} }
pub trait EarlyExitExt<T> { pub trait EarlyExitExt<T> {
fn early_exit(self) -> T; fn on_early_exit<F: FnOnce()>(self, print_help_msg: F) -> T;
} }
impl<T> EarlyExitExt<T> for Result<T, EarlyExit> { impl<T> EarlyExitExt<T> for Result<T, EarlyExit> {
fn early_exit(self) -> T { fn on_early_exit<F: FnOnce()>(self, print_help_msg: F) -> T {
match self { match self {
Ok(t) => t, Ok(t) => t,
Err(EarlyExit { output, status }) => match status { Err(EarlyExit { output, status }) => match status {
Ok(_) => { Ok(_) => {
eprintln!("{}", output); print_help_msg();
exit(0) exit(0)
} }
Err(_) => { Err(_) => {
eprintln!("{}", output); eprintln!("{}", output);
print_help_msg();
exit(1) exit(1)
} }
}, },

View File

@ -23,7 +23,6 @@ use base::{
use crate::ramdisk::MagiskCpio; use crate::ramdisk::MagiskCpio;
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh(description = "Manipulate cpio archives; <command> --help for more info.")]
struct CpioCli { struct CpioCli {
#[argh(subcommand)] #[argh(subcommand)]
command: CpioCommands, command: CpioCommands,
@ -47,66 +46,42 @@ enum CpioCommands {
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "test")]
subcommand,
name = "test",
description = "Test the cpio's status; return value is 0 or bitwise or-ed of following values: 0x1:Magisk; 0x2:unsupported; 0x4:Sony"
)]
struct Test {} struct Test {}
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "restore")]
subcommand,
name = "restore",
description = "Restore ramdisk from ramdisk backup stored within incpio"
)]
struct Restore {} struct Restore {}
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "patch")]
subcommand,
name = "patch",
description = "Apply ramdisk patches; configure with env variables: KEEPVERITY KEEPFORCEENCRYPT"
)]
struct Patch {} struct Patch {}
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "exists")]
subcommand,
name = "exists",
description = "Return 0 if <entry> exists, otherwise return 1"
)]
struct Exists { struct Exists {
#[argh(positional, arg_name = "entry")] #[argh(positional, arg_name = "entry")]
path: String, path: String,
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "backup")]
subcommand,
name = "backup",
description = "Create ramdisk backups from <orig>"
)]
struct Backup { struct Backup {
#[argh(positional, arg_name = "orig")] #[argh(positional, arg_name = "orig")]
origin: String, origin: String,
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "rm")]
subcommand,
name = "rm",
description = "Remove <entry>; specify [-r] to remove recursively"
)]
struct Remove { struct Remove {
#[argh(positional, arg_name = "entry")] #[argh(positional, arg_name = "entry")]
path: String, path: String,
#[argh(switch, short = 'r', description = "recursive")] #[argh(switch, short = 'r')]
recursive: bool, recursive: bool,
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh(subcommand, name = "mv", description = "Move <source> to <dest>")] #[argh(subcommand, name = "mv")]
struct Move { struct Move {
#[argh(positional, arg_name = "source")] #[argh(positional, arg_name = "source")]
from: String, from: String,
@ -115,22 +90,14 @@ struct Move {
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "extract")]
subcommand,
name = "extract",
description = "Extract <paths[0]> to <paths[1]>, or extract all entries to current directory if <paths> is not given"
)]
struct Extract { struct Extract {
#[argh(positional, greedy)] #[argh(positional, greedy)]
paths: Vec<String>, paths: Vec<String>,
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "mkdir")]
subcommand,
name = "mkdir",
description = "Create directory <entry> in permissions <mode> (in octal)"
)]
struct MakeDir { struct MakeDir {
#[argh(positional, from_str_fn(parse_mode))] #[argh(positional, from_str_fn(parse_mode))]
mode: mode_t, mode: mode_t,
@ -139,11 +106,7 @@ struct MakeDir {
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "ln")]
subcommand,
name = "ln",
description = "Create a symlink to <target> with the name <entry>"
)]
struct Link { struct Link {
#[argh(positional, arg_name = "entry")] #[argh(positional, arg_name = "entry")]
src: String, src: String,
@ -152,11 +115,7 @@ struct Link {
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "add")]
subcommand,
name = "add",
description = "Add <infile> as <entry> in permissions <mode> (in octal); replace <entry> if exists"
)]
struct Add { struct Add {
#[argh(positional, from_str_fn(parse_mode))] #[argh(positional, from_str_fn(parse_mode))]
mode: mode_t, mode: mode_t,
@ -167,18 +126,53 @@ struct Add {
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(subcommand, name = "ls")]
subcommand,
name = "ls",
description = r#"List [<path>] ("/" by default); specifly [-r] to recursively list sub-directories"#
)]
struct List { struct List {
#[argh(positional, default = r#"String::from("/")"#)] #[argh(positional, default = r#"String::from("/")"#)]
path: String, path: String,
#[argh(switch, short = 'r', description = "recursive")] #[argh(switch, short = 'r')]
recursive: bool, recursive: bool,
} }
fn print_cpio_usage() {
eprintln!(
r#"Usage: magiskboot cpio <incpio> [commands...]
Do cpio commands to <incpio> (modifications are done in-place).
Each command is a single argument; add quotes for each command.
Supported commands:
exists ENTRY
Return 0 if ENTRY exists, else return 1
ls [-r] [PATH]
List PATH ("/" by default); specify [-r] to list recursively
rm [-r] ENTRY
Remove ENTRY, specify [-r] to remove recursively
mkdir MODE ENTRY
Create directory ENTRY with permissions MODE
ln TARGET ENTRY
Create a symlink to TARGET with the name ENTRY
mv SOURCE DEST
Move SOURCE to DEST
add MODE ENTRY INFILE
Add INFILE as ENTRY with permissions MODE; replaces ENTRY if exists
extract [ENTRY OUT]
Extract ENTRY to OUT, or extract all entries to current directory
test
Test the cpio's status
Return value is 0 or bitwise or-ed of following values:
0x1:Magisk 0x2:unsupported 0x4:Sony
patch
Apply ramdisk patches
Configure with env variables: KEEPVERITY KEEPFORCEENCRYPT
backup ORIG
Create ramdisk backups from ORIG
restore
Restore ramdisk from ramdisk backup stored within incpio
"#
)
}
#[repr(C, packed)] #[repr(C, packed)]
struct CpioHeader { struct CpioHeader {
magic: [u8; 6], magic: [u8; 6],
@ -523,11 +517,20 @@ impl Display for CpioEntry {
pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool { pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool {
fn inner(argc: i32, argv: *const *const c_char) -> LoggedResult<()> { fn inner(argc: i32, argv: *const *const c_char) -> LoggedResult<()> {
if argc < 1 { if argc < 1 {
return Err(log_err!("no arguments")); return Err(log_err!("No arguments"));
} }
let cmds = map_args(argc, argv)?; let cmds = map_args(argc, argv)?;
if cmds[0] == "--help" {
print_cpio_usage();
exit(0);
}
if argc < 2 {
return Err(log_err!("No commands"));
}
let file = cmds[0]; let file = cmds[0];
let mut cpio = if Path::new(file).exists() { let mut cpio = if Path::new(file).exists() {
Cpio::load_from_file(file)? Cpio::load_from_file(file)?
@ -546,12 +549,12 @@ pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice(), .as_slice(),
) )
.early_exit(); .on_early_exit(print_cpio_usage);
match &mut cli.command { match &mut cli.command {
CpioCommands::Test(Test {}) => exit(cpio.test()), CpioCommands::Test(_) => exit(cpio.test()),
CpioCommands::Restore(Restore {}) => cpio.restore()?, CpioCommands::Restore(_) => cpio.restore()?,
CpioCommands::Patch(Patch {}) => cpio.patch(), CpioCommands::Patch(_) => cpio.patch(),
CpioCommands::Exists(Exists { path }) => { CpioCommands::Exists(Exists { path }) => {
if cpio.exists(path) { if cpio.exists(path) {
exit(0); exit(0);

View File

@ -57,9 +57,9 @@ Supported actions:
Search <hexpattern1> in <file>, and replace it with <hexpattern2> Search <hexpattern1> in <file>, and replace it with <hexpattern2>
cpio <incpio> [commands...] cpio <incpio> [commands...]
Do cpio commands to <incpio> (modifications are done in-place) Do cpio commands to <incpio> (modifications are done in-place).
Each command is a single argument, add quotes for each command. Each command is a single argument; add quotes for each command.
See "cpio <incpio> --help" for supported commands. See "cpio --help" for supported commands.
dtb <file> <action> [args...] dtb <file> <action> [args...]
Do dtb related actions to <file> Do dtb related actions to <file>

1
native/src/external/argh vendored Submodule

@ -0,0 +1 @@
Subproject commit 2fecd81d606364a8b07b942ed01697bbd3a62193