Implement rev (#56)

* Implement `rev`

* Use uucore facility for error reporting
This commit is contained in:
sisungo
2024-06-28 22:23:50 +08:00
committed by GitHub
parent fd14cb7db2
commit 69d9c6e4a5
8 changed files with 133 additions and 0 deletions

9
Cargo.lock generated
View File

@@ -644,6 +644,7 @@ dependencies = [
"uu_ctrlaltdel", "uu_ctrlaltdel",
"uu_lscpu", "uu_lscpu",
"uu_mountpoint", "uu_mountpoint",
"uu_rev",
"uucore", "uucore",
"xattr", "xattr",
] ]
@@ -674,6 +675,14 @@ dependencies = [
"uucore", "uucore",
] ]
[[package]]
name = "uu_rev"
version = "0.0.1"
dependencies = [
"clap",
"uucore",
]
[[package]] [[package]]
name = "uucore" name = "uucore"
version = "0.0.27" version = "0.0.27"

View File

@@ -28,6 +28,7 @@ feat_common_core = [
"mountpoint", "mountpoint",
"lscpu", "lscpu",
"ctrlaltdel", "ctrlaltdel",
"rev",
] ]
[workspace.dependencies] [workspace.dependencies]
@@ -58,6 +59,7 @@ textwrap = { workspace = true }
lscpu = { optional = true, version = "0.0.1", package = "uu_lscpu", path = "src/uu/lscpu" } lscpu = { optional = true, version = "0.0.1", package = "uu_lscpu", path = "src/uu/lscpu" }
mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", path = "src/uu/mountpoint" } mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", path = "src/uu/mountpoint" }
ctrlaltdel = { optional = true, version = "0.0.1", package = "uu_ctrlaltdel", path = "src/uu/ctrlaltdel" } ctrlaltdel = { optional = true, version = "0.0.1", package = "uu_ctrlaltdel", path = "src/uu/ctrlaltdel" }
rev = { optional = true, version = "0.0.1", package = "uu_rev", path = "src/uu/rev" }
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1" pretty_assertions = "1"

17
src/uu/rev/Cargo.toml Normal file
View File

@@ -0,0 +1,17 @@
[package]
name = "uu_rev"
version = "0.0.1"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
uucore = { workspace = true }
clap = { workspace = true }
[lib]
path = "src/rev.rs"
[[bin]]
name = "rev"
path = "src/main.rs"

7
src/uu/rev/rev.md Normal file
View File

@@ -0,0 +1,7 @@
# rev
```
rev [options] [file ...]
```
Reverse lines characterwise.

1
src/uu/rev/src/main.rs Normal file
View File

@@ -0,0 +1 @@
uucore::bin!(uu_rev);

81
src/uu/rev/src/rev.rs Normal file
View File

@@ -0,0 +1,81 @@
// This file is part of the uutils util-linux package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use clap::{crate_version, Command};
use clap::{Arg, ArgAction};
use std::env;
use std::io::{BufRead, BufReader, Read, Write};
use uucore::{error::UResult, format_usage, help_about, help_usage};
const ABOUT: &str = help_about!("rev.md");
const USAGE: &str = help_usage!("rev.md");
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
let files = matches.get_many::<String>("file");
match files {
Some(files) => {
for path in files {
let file = match std::fs::File::open(path) {
Ok(val) => val,
Err(err) => {
uucore::error::set_exit_code(1);
uucore::show_error!("cannot open {}: {}", path, err);
continue;
}
};
if let Err(err) = rev_stream(file) {
uucore::error::set_exit_code(1);
uucore::show_error!("cannot read {}: {}", path, err);
}
}
}
None => {
let stdin = std::io::stdin().lock();
let _ = rev_stream(stdin);
}
}
Ok(())
}
fn rev_stream(stream: impl Read) -> std::io::Result<()> {
let mut stdout = std::io::stdout().lock();
let mut stream = BufReader::new(stream);
let mut buf = Vec::with_capacity(4096);
loop {
buf.clear();
stream.read_until(b'\n', &mut buf)?;
if buf.last().copied() != Some(b'\n') {
buf.reverse();
stdout.write_all(&buf)?;
break;
} else {
buf.pop();
buf.reverse();
buf.push(b'\n');
stdout.write_all(&buf)?;
}
}
Ok(())
}
pub fn uu_app() -> Command {
Command::new(uucore::util_name())
.version(crate_version!())
.about(ABOUT)
.override_usage(format_usage(USAGE))
.infer_long_args(true)
.arg(
Arg::new("file")
.value_name("FILE")
.help("Paths of files to reverse")
.index(1)
.action(ArgAction::Set)
.num_args(1..),
)
}

12
tests/by-util/test_rev.rs Normal file
View File

@@ -0,0 +1,12 @@
// This file is part of the uutils util-linux package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) symdir somefakedir
use crate::common::util::TestScenario;
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}

View File

@@ -16,3 +16,7 @@ mod test_mountpoint;
#[cfg(feature = "ctrlaltdel")] #[cfg(feature = "ctrlaltdel")]
#[path = "by-util/test_ctrlaltdel.rs"] #[path = "by-util/test_ctrlaltdel.rs"]
mod test_ctrlaltdel; mod test_ctrlaltdel;
#[cfg(feature = "rev")]
#[path = "by-util/test_rev.rs"]
mod test_rev;