1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 12:37:49 +00:00

Merge pull request #2703 from thomasqueirozb/base_uresult

base32 + base64 + basenc: use UResult
This commit is contained in:
Sylvestre Ledru 2021-10-03 17:34:56 +02:00 committed by GitHub
commit 368fa54520
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 85 additions and 96 deletions

View file

@ -11,7 +11,7 @@ extern crate uucore;
use std::io::{stdin, Read}; use std::io::{stdin, Read};
use clap::App; use clap::App;
use uucore::encoding::Format; use uucore::{encoding::Format, error::UResult};
pub mod base_common; pub mod base_common;
@ -24,27 +24,22 @@ static ABOUT: &str = "
to attempt to recover from any other non-alphabet bytes in the to attempt to recover from any other non-alphabet bytes in the
encoded stream. encoded stream.
"; ";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static BASE_CMD_PARSE_ERROR: i32 = 1;
fn usage() -> String { fn usage() -> String {
format!("{0} [OPTION]... [FILE]", uucore::execution_phrase()) format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
} }
pub fn uumain(args: impl uucore::Args) -> i32 { #[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let format = Format::Base32; let format = Format::Base32;
let usage = usage(); let usage = usage();
let name = uucore::util_name();
let config_result: Result<base_common::Config, String> = let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, &usage)?;
base_common::parse_base_cmd_args(args, name, VERSION, ABOUT, &usage);
let config = config_result.unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s));
// Create a reference to stdin so we can return a locked stdin from // Create a reference to stdin so we can return a locked stdin from
// parse_base_cmd_args // parse_base_cmd_args
let stdin_raw = stdin(); let stdin_raw = stdin();
let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw); let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw)?;
base_common::handle_input( base_common::handle_input(
&mut input, &mut input,
@ -52,12 +47,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
config.wrap_cols, config.wrap_cols,
config.ignore_garbage, config.ignore_garbage,
config.decode, config.decode,
name, )
);
0
} }
pub fn uu_app() -> App<'static, 'static> { pub fn uu_app() -> App<'static, 'static> {
base_common::base_app(uucore::util_name(), VERSION, ABOUT) base_common::base_app(ABOUT)
} }

View file

@ -11,13 +11,16 @@ use std::io::{stdout, Read, Write};
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::encoding::{wrap_print, Data, Format}; use uucore::encoding::{wrap_print, Data, Format};
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
use std::fs::File; use std::fs::File;
use std::io::{BufReader, Stdin}; use std::io::{BufReader, Stdin};
use std::path::Path; use std::path::Path;
use clap::{App, Arg}; use clap::{crate_version, App, Arg};
pub static BASE_CMD_PARSE_ERROR: i32 = 1;
// Config. // Config.
pub struct Config { pub struct Config {
@ -35,15 +38,14 @@ pub mod options {
} }
impl Config { impl Config {
pub fn from(app_name: &str, options: &clap::ArgMatches) -> Result<Config, String> { pub fn from(options: &clap::ArgMatches) -> UResult<Config> {
let file: Option<String> = match options.values_of(options::FILE) { let file: Option<String> = match options.values_of(options::FILE) {
Some(mut values) => { Some(mut values) => {
let name = values.next().unwrap(); let name = values.next().unwrap();
if let Some(extra_op) = values.next() { if let Some(extra_op) = values.next() {
return Err(format!( return Err(UUsageError::new(
"extra operand {}\nTry '{} --help' for more information.", BASE_CMD_PARSE_ERROR,
extra_op.quote(), format!("extra operand {}", extra_op.quote(),),
app_name
)); ));
} }
@ -51,7 +53,10 @@ impl Config {
None None
} else { } else {
if !Path::exists(Path::new(name)) { if !Path::exists(Path::new(name)) {
return Err(format!("{}: No such file or directory", name.maybe_quote())); return Err(USimpleError::new(
BASE_CMD_PARSE_ERROR,
format!("{}: No such file or directory", name.maybe_quote()),
));
} }
Some(name.to_owned()) Some(name.to_owned())
} }
@ -62,8 +67,12 @@ impl Config {
let cols = options let cols = options
.value_of(options::WRAP) .value_of(options::WRAP)
.map(|num| { .map(|num| {
num.parse::<usize>() num.parse::<usize>().map_err(|_| {
.map_err(|_| format!("invalid wrap size: {}", num.quote())) USimpleError::new(
BASE_CMD_PARSE_ERROR,
format!("invalid wrap size: {}", num.quote()),
)
})
}) })
.transpose()?; .transpose()?;
@ -76,23 +85,17 @@ impl Config {
} }
} }
pub fn parse_base_cmd_args( pub fn parse_base_cmd_args(args: impl uucore::Args, about: &str, usage: &str) -> UResult<Config> {
args: impl uucore::Args, let app = base_app(about).usage(usage);
name: &str,
version: &str,
about: &str,
usage: &str,
) -> Result<Config, String> {
let app = base_app(name, version, about).usage(usage);
let arg_list = args let arg_list = args
.collect_str(InvalidEncodingHandling::ConvertLossy) .collect_str(InvalidEncodingHandling::ConvertLossy)
.accept_any(); .accept_any();
Config::from(name, &app.get_matches_from(arg_list)) Config::from(&app.get_matches_from(arg_list))
} }
pub fn base_app<'a>(name: &str, version: &'a str, about: &'a str) -> App<'static, 'a> { pub fn base_app<'a>(about: &'a str) -> App<'static, 'a> {
App::new(name) App::new(uucore::util_name())
.version(version) .version(crate_version!())
.about(about) .about(about)
// Format arguments. // Format arguments.
.arg( .arg(
@ -121,14 +124,15 @@ pub fn base_app<'a>(name: &str, version: &'a str, about: &'a str) -> App<'static
.arg(Arg::with_name(options::FILE).index(1).multiple(true)) .arg(Arg::with_name(options::FILE).index(1).multiple(true))
} }
pub fn get_input<'a>(config: &Config, stdin_ref: &'a Stdin) -> Box<dyn Read + 'a> { pub fn get_input<'a>(config: &Config, stdin_ref: &'a Stdin) -> UResult<Box<dyn Read + 'a>> {
match &config.to_read { match &config.to_read {
Some(name) => { Some(name) => {
let file_buf = crash_if_err!(1, File::open(Path::new(name))); let file_buf =
Box::new(BufReader::new(file_buf)) // as Box<dyn Read> File::open(Path::new(name)).map_err_context(|| name.maybe_quote().to_string())?;
Ok(Box::new(BufReader::new(file_buf))) // as Box<dyn Read>
} }
None => { None => {
Box::new(stdin_ref.lock()) // as Box<dyn Read> Ok(Box::new(stdin_ref.lock())) // as Box<dyn Read>
} }
} }
} }
@ -139,8 +143,7 @@ pub fn handle_input<R: Read>(
line_wrap: Option<usize>, line_wrap: Option<usize>,
ignore_garbage: bool, ignore_garbage: bool,
decode: bool, decode: bool,
name: &str, ) -> UResult<()> {
) {
let mut data = Data::new(input, format).ignore_garbage(ignore_garbage); let mut data = Data::new(input, format).ignore_garbage(ignore_garbage);
if let Some(wrap) = line_wrap { if let Some(wrap) = line_wrap {
data = data.line_wrap(wrap); data = data.line_wrap(wrap);
@ -150,28 +153,23 @@ pub fn handle_input<R: Read>(
match data.encode() { match data.encode() {
Ok(s) => { Ok(s) => {
wrap_print(&data, s); wrap_print(&data, s);
Ok(())
} }
Err(_) => { Err(_) => Err(USimpleError::new(
eprintln!( 1,
"{}: error: invalid input (length must be multiple of 4 characters)", "error: invalid input (length must be multiple of 4 characters)",
name )),
);
exit!(1)
}
} }
} else { } else {
match data.decode() { match data.decode() {
Ok(s) => { Ok(s) => {
if stdout().write_all(&s).is_err() { if stdout().write_all(&s).is_err() {
// on windows console, writing invalid utf8 returns an error // on windows console, writing invalid utf8 returns an error
eprintln!("{}: error: Cannot write non-utf8 data", name); return Err(USimpleError::new(1, "error: cannot write non-utf8 data"));
exit!(1)
} }
Ok(())
} }
Err(_) => { Err(_) => Err(USimpleError::new(1, "error: invalid input")),
eprintln!("{}: error: invalid input", name);
exit!(1)
}
} }
} }
} }

View file

@ -12,7 +12,7 @@ extern crate uucore;
use uu_base32::base_common; use uu_base32::base_common;
pub use uu_base32::uu_app; pub use uu_base32::uu_app;
use uucore::encoding::Format; use uucore::{encoding::Format, error::UResult};
use std::io::{stdin, Read}; use std::io::{stdin, Read};
@ -25,26 +25,22 @@ static ABOUT: &str = "
to attempt to recover from any other non-alphabet bytes in the to attempt to recover from any other non-alphabet bytes in the
encoded stream. encoded stream.
"; ";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static BASE_CMD_PARSE_ERROR: i32 = 1;
fn usage() -> String { fn usage() -> String {
format!("{0} [OPTION]... [FILE]", uucore::execution_phrase()) format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
} }
pub fn uumain(args: impl uucore::Args) -> i32 { #[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let format = Format::Base64; let format = Format::Base64;
let usage = usage(); let usage = usage();
let name = uucore::util_name();
let config_result: Result<base_common::Config, String> = let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, &usage)?;
base_common::parse_base_cmd_args(args, name, VERSION, ABOUT, &usage);
let config = config_result.unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s));
// Create a reference to stdin so we can return a locked stdin from // Create a reference to stdin so we can return a locked stdin from
// parse_base_cmd_args // parse_base_cmd_args
let stdin_raw = stdin(); let stdin_raw = stdin();
let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw); let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw)?;
base_common::handle_input( base_common::handle_input(
&mut input, &mut input,
@ -52,8 +48,5 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
config.wrap_cols, config.wrap_cols,
config.ignore_garbage, config.ignore_garbage,
config.decode, config.decode,
name, )
);
0
} }

View file

@ -11,10 +11,14 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{App, Arg};
use uu_base32::base_common::{self, Config}; use uu_base32::base_common::{self, Config, BASE_CMD_PARSE_ERROR};
use uucore::{encoding::Format, InvalidEncodingHandling}; use uucore::{
encoding::Format,
error::{UResult, UUsageError},
InvalidEncodingHandling,
};
use std::io::{stdin, Read}; use std::io::{stdin, Read};
@ -26,8 +30,6 @@ static ABOUT: &str = "
from any other non-alphabet bytes in the encoded stream. from any other non-alphabet bytes in the encoded stream.
"; ";
static BASE_CMD_PARSE_ERROR: i32 = 1;
const ENCODINGS: &[(&str, Format)] = &[ const ENCODINGS: &[(&str, Format)] = &[
("base64", Format::Base64), ("base64", Format::Base64),
("base64url", Format::Base64Url), ("base64url", Format::Base64Url),
@ -47,14 +49,14 @@ fn usage() -> String {
} }
pub fn uu_app() -> App<'static, 'static> { pub fn uu_app() -> App<'static, 'static> {
let mut app = base_common::base_app(uucore::util_name(), crate_version!(), ABOUT); let mut app = base_common::base_app(ABOUT);
for encoding in ENCODINGS { for encoding in ENCODINGS {
app = app.arg(Arg::with_name(encoding.0).long(encoding.0)); app = app.arg(Arg::with_name(encoding.0).long(encoding.0));
} }
app app
} }
fn parse_cmd_args(args: impl uucore::Args) -> (Config, Format) { fn parse_cmd_args(args: impl uucore::Args) -> UResult<(Config, Format)> {
let usage = usage(); let usage = usage();
let matches = uu_app().usage(&usage[..]).get_matches_from( let matches = uu_app().usage(&usage[..]).get_matches_from(
args.collect_str(InvalidEncodingHandling::ConvertLossy) args.collect_str(InvalidEncodingHandling::ConvertLossy)
@ -63,24 +65,19 @@ fn parse_cmd_args(args: impl uucore::Args) -> (Config, Format) {
let format = ENCODINGS let format = ENCODINGS
.iter() .iter()
.find(|encoding| matches.is_present(encoding.0)) .find(|encoding| matches.is_present(encoding.0))
.unwrap_or_else(|| { .ok_or_else(|| UUsageError::new(BASE_CMD_PARSE_ERROR, "missing encoding type"))?
show_usage_error!("missing encoding type");
std::process::exit(1)
})
.1; .1;
( let config = Config::from(&matches)?;
Config::from("basenc", &matches).unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s)), Ok((config, format))
format,
)
} }
pub fn uumain(args: impl uucore::Args) -> i32 { #[uucore_procs::gen_uumain]
let name = uucore::util_name(); pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let (config, format) = parse_cmd_args(args); let (config, format) = parse_cmd_args(args)?;
// Create a reference to stdin so we can return a locked stdin from // Create a reference to stdin so we can return a locked stdin from
// parse_base_cmd_args // parse_base_cmd_args
let stdin_raw = stdin(); let stdin_raw = stdin();
let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw); let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw)?;
base_common::handle_input( base_common::handle_input(
&mut input, &mut input,
@ -88,8 +85,5 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
config.wrap_cols, config.wrap_cols,
config.ignore_garbage, config.ignore_garbage,
config.decode, config.decode,
name, )
);
0
} }

View file

@ -113,12 +113,18 @@ fn test_wrap_bad_arg() {
#[test] #[test]
fn test_base32_extra_operand() { fn test_base32_extra_operand() {
let ts = TestScenario::new(util_name!());
// Expect a failure when multiple files are specified. // Expect a failure when multiple files are specified.
new_ucmd!() ts.ucmd()
.arg("a.txt") .arg("a.txt")
.arg("b.txt") .arg("b.txt")
.fails() .fails()
.stderr_only("base32: extra operand 'b.txt'\nTry 'base32 --help' for more information."); .stderr_only(format!(
"{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
ts.util_name,
ts.bin_path.to_string_lossy()
));
} }
#[test] #[test]

View file

@ -95,12 +95,18 @@ fn test_wrap_bad_arg() {
#[test] #[test]
fn test_base64_extra_operand() { fn test_base64_extra_operand() {
let ts = TestScenario::new(util_name!());
// Expect a failure when multiple files are specified. // Expect a failure when multiple files are specified.
new_ucmd!() ts.ucmd()
.arg("a.txt") .arg("a.txt")
.arg("b.txt") .arg("b.txt")
.fails() .fails()
.stderr_only("base64: extra operand 'b.txt'\nTry 'base64 --help' for more information."); .stderr_only(format!(
"{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
ts.util_name,
ts.bin_path.to_string_lossy()
));
} }
#[test] #[test]