Implemented long output and inode output for rbls

This commit is contained in:
Egor 2024-04-27 01:17:50 +03:00
parent bf36e496c4
commit 792536d683
3 changed files with 249 additions and 13 deletions

176
Cargo.lock generated
View file

@ -2,6 +2,21 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.6.13"
@ -50,6 +65,44 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "autocfg"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "cc"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "clap"
version = "4.5.4"
@ -109,6 +162,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "encode_unicode"
version = "0.3.6"
@ -121,6 +180,38 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "iana-time-zone"
version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "js-sys"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -133,6 +224,27 @@ version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "num-traits"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "proc-macro2"
version = "1.0.81"
@ -155,6 +267,7 @@ dependencies = [
name = "rbutils"
version = "0.1.0"
dependencies = [
"chrono",
"clap",
"console",
]
@ -194,6 +307,69 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "wasm-bindgen"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.52.0"

View file

@ -6,5 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = "0.4.38"
clap = { version = "4.5.4", features = ["derive"] }
console = "0.15.8"

View file

@ -1,8 +1,9 @@
use clap::Parser;
use chrono::{Local, TimeZone};
use std::io::{self, ErrorKind::*};
use std::fs::{self, DirEntry, Metadata};
use std::os::unix::fs::{FileTypeExt, MetadataExt};
// TODO: implement more options (-l, -i, etc.)
fn main() {
let cli = Cli::parse();
let mut non_dirs = Vec::<FileInfo>::new();
@ -28,12 +29,17 @@ fn main() {
};
dirs.push(DirInfo::new(file_name, file_infos));
}
let (dirs_len, non_dirs_len) = (dirs.len(), non_dirs.len());
if !non_dirs.is_empty() {
let non_dirs_filtered = transform_file_infos(non_dirs, &cli);
let non_dirs_output = format_output(non_dirs_filtered, &cli);
println!("{}", non_dirs_output);
}
let dirs_output = if dirs.len() > 1 {
if dirs.is_empty() { return; }
let dirs_output = if dirs_len + non_dirs_len > 1 {
dirs.into_iter()
.map(|dir| {
let files_filtered = transform_file_infos(dir.file_infos, &cli);
@ -46,6 +52,8 @@ fn main() {
let files_filtered = transform_file_infos(dir.file_infos, &cli);
format_output(files_filtered, &cli)
};
if non_dirs_len > 0 { println!(); }
println!("{}", dirs_output);
}
@ -76,28 +84,79 @@ fn transform_file_infos(file_infos: Vec<FileInfo>, options: &Cli) -> Vec<String>
filtered_file_infos.sort_by(|fi1, fi2| fi1.name.to_lowercase().cmp(&fi2.name.to_lowercase()));
return filtered_file_infos.into_iter()
.map(|file_info| {
let mut file_name = file_info.name;
if file_info.metadata.is_dir() { file_name.push('/') }
return file_name;
return format_file_info(file_info, options);
})
.collect();
}
fn format_output(file_names: Vec<String>, options: &Cli) -> String {
let term = console::Term::stdout();
if term.is_term() { return format_tabular(file_names, options, term.size().1); }
else { return file_names.join(" "); }
fn format_file_info(file_info: FileInfo, options: &Cli) -> String {
let mut entry = String::new();
if options.inode {
entry.push_str(&file_info.metadata.ino().to_string());
entry.push(' ');
}
if options.long {
entry.push_str(&long_format(&file_info))
} else {
entry.push_str(&file_info.name)
}
if file_info.metadata.is_dir() { entry.push('/') }
return entry;
}
fn format_tabular(mut file_names: Vec<String>, options: &Cli, term_width: u16) -> String {
let max_file_name_len = file_names.iter().map(|n| n.len()).max().unwrap();
fn long_format(file_info: &FileInfo) -> String {
format!("{} {} {} {} {} {} {}", permissions_str(&file_info.metadata), file_info.metadata.nlink(),
file_info.metadata.uid(), file_info.metadata.gid(), file_info.metadata.size(),
modified_str(&file_info.metadata), file_info.name)
}
fn modified_str(metadata: &Metadata) -> String {
let date_time = Local.timestamp_opt(metadata.mtime(), 0).unwrap();
return date_time.format("%b %d %H:%M").to_string();
}
fn permissions_str(metadata: &Metadata) -> String {
let ftype = metadata.file_type();
let mut result = String::with_capacity(10);
result.push(
if ftype.is_dir() { 'd' }
else if ftype.is_symlink() { 'l' }
else if ftype.is_block_device() { 'b' }
else if ftype.is_char_device() { 'c' }
else if ftype.is_fifo() { 'p' }
else if ftype.is_socket() { 's' }
else { '-' }
);
let permission_chars: Vec<char> = vec!['r', 'w', 'x'];
let permissions = metadata.mode();
for i in 0..9 {
let bit = permissions >> (8 - i) & 1;
result.push(
if bit > 0 { permission_chars[i % 3] }
else { '-' }
);
}
return result;
}
fn format_output(file_names: Vec<String>, options: &Cli) -> String {
let term = console::Term::stdout();
if term.is_term() && !options.long { return format_tabular(file_names, term.size().1); }
return file_names.join("\n");
}
fn format_tabular(mut entries: Vec<String>, term_width: u16) -> String {
if entries.is_empty() { return String::new(); }
let max_file_name_len = entries.iter().map(|n| n.len()).max().unwrap();
let elem_width = max_file_name_len + 2;
let row_elems_amount = (term_width as usize / elem_width).max(1);
for (i, name) in file_names.iter_mut().enumerate() {
for (i, name) in entries.iter_mut().enumerate() {
name.push_str(&" ".repeat(max_file_name_len - name.len() + 2));
if (i + 1) % row_elems_amount == 0 { name.push('\n'); }
}
return file_names.join("").trim_end().to_string();
return entries.join("").trim_end().to_string();
}
struct DirInfo {