mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 10:04:12 +02:00
support selecting a file from an archive
This commit is contained in:
parent
4f3d6a17ab
commit
9634736d8c
5 changed files with 94 additions and 22 deletions
64
Cargo.lock
generated
64
Cargo.lock
generated
|
|
@ -231,6 +231,19 @@ dependencies = [
|
|||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"unicode-width 0.1.14",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.3.1"
|
||||
|
|
@ -386,6 +399,19 @@ dependencies = [
|
|||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dialoguer"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de"
|
||||
dependencies = [
|
||||
"console",
|
||||
"shell-words",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
|
|
@ -414,6 +440,12 @@ version = "1.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
|
|
@ -430,6 +462,12 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.25"
|
||||
|
|
@ -607,6 +645,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.161"
|
||||
|
|
@ -661,6 +705,7 @@ dependencies = [
|
|||
"bzip2-rs",
|
||||
"clap",
|
||||
"derive_more",
|
||||
"dialoguer",
|
||||
"flate2",
|
||||
"hdrhistogram",
|
||||
"itertools",
|
||||
|
|
@ -1091,6 +1136,12 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
|
|
@ -1212,6 +1263,19 @@ dependencies = [
|
|||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ flate2 = "1.0.31"
|
|||
xz2 = "0.1.7"
|
||||
bzip2-rs = "0.1.2"
|
||||
ruzstd = "0.7.2"
|
||||
dialoguer = "0.11.0"
|
||||
|
||||
[target.'cfg(not(target_os = "windows"))'.dependencies]
|
||||
tikv-jemallocator = "0.6.0"
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ pub enum ReadError {
|
|||
Zip(#[from] ZipError),
|
||||
#[error(transparent)]
|
||||
Zstd(#[from] FrameDecoderError),
|
||||
#[error("archive contains multiple files")]
|
||||
MultipleFiles,
|
||||
#[error("archive contains no files")]
|
||||
NoFiles,
|
||||
#[error("log file contained non-utf8 characters: {0:#}")]
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ mod archive;
|
|||
use crate::error::ReadError;
|
||||
use crate::logfile::archive::{Archive, ArchiveEntry, TarArchive, ZipArchive};
|
||||
use bzip2_rs::DecoderReader;
|
||||
use dialoguer::Select;
|
||||
use flate2::read::GzDecoder;
|
||||
use ruzstd::StreamingDecoder;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read};
|
||||
use std::io::{Cursor, Read, Seek};
|
||||
use xz2::read::XzDecoder;
|
||||
|
||||
pub struct LogFile {
|
||||
|
|
@ -14,14 +14,10 @@ pub struct LogFile {
|
|||
}
|
||||
|
||||
impl LogFile {
|
||||
pub fn open(path: &str) -> Result<LogFile, ReadError> {
|
||||
let file = File::open(path)?;
|
||||
let file = BufReader::new(file);
|
||||
pub fn open<R: Read + Seek>(path: &str, file: R) -> Result<LogFile, ReadError> {
|
||||
if path.ends_with(".zip") {
|
||||
let mut zip = ZipArchive::new(file)?;
|
||||
let content = select_file(&mut zip)?;
|
||||
|
||||
return Ok(LogFile { content });
|
||||
return select_file(&mut zip);
|
||||
}
|
||||
|
||||
if let Some(path) = path.strip_suffix(".gz") {
|
||||
|
|
@ -44,9 +40,7 @@ impl LogFile {
|
|||
fn open_no_seek<R: Read>(path: &str, mut file: R) -> Result<LogFile, ReadError> {
|
||||
if path.ends_with(".tar") {
|
||||
let mut zip = TarArchive::new(file)?;
|
||||
let content = select_file(&mut zip)?;
|
||||
|
||||
Ok(LogFile { content })
|
||||
select_file(&mut zip)
|
||||
} else {
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content)?;
|
||||
|
|
@ -64,21 +58,32 @@ impl LogFile {
|
|||
}
|
||||
}
|
||||
|
||||
fn select_file<A: Archive>(archive: &mut A) -> Result<String, ReadError> {
|
||||
fn select_file<A: Archive>(archive: &mut A) -> Result<LogFile, ReadError> {
|
||||
let entry = {
|
||||
let mut entries = archive
|
||||
.entries()
|
||||
.filter(|entry| !entry.name().starts_with("__MACOSX"))
|
||||
.filter(|entry| !entry.name().starts_with("__MACOSX") && !entry.name().ends_with('/'))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// todo: present a picker instead
|
||||
if entries.len() > 1 {
|
||||
return Err(ReadError::MultipleFiles);
|
||||
} else if entries.is_empty() {
|
||||
if entries.is_empty() {
|
||||
return Err(ReadError::NoFiles);
|
||||
}
|
||||
entries.pop().unwrap()
|
||||
|
||||
let index = if entries.len() == 1 {
|
||||
0usize
|
||||
} else {
|
||||
let names = entries.iter().map(A::Entry::name).collect::<Vec<_>>();
|
||||
Select::new()
|
||||
.with_prompt("Select file to load?")
|
||||
.items(&names)
|
||||
.interact()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
entries.remove(index)
|
||||
};
|
||||
let name = entry.name().to_string();
|
||||
let raw = entry.extract()?;
|
||||
Ok(String::from_utf8(raw)?)
|
||||
|
||||
LogFile::open(&name, Cursor::new(raw))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ use main_error::MainResult;
|
|||
use rayon::prelude::*;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::iter::once;
|
||||
|
||||
mod app;
|
||||
|
|
@ -39,7 +41,9 @@ struct Args {
|
|||
fn main() -> MainResult {
|
||||
let args = Args::parse();
|
||||
|
||||
let log_file = LogFile::open(&args.file).map_err(|err| LogError::Read {
|
||||
let file = File::open(&args.file)?;
|
||||
let file = BufReader::new(file);
|
||||
let log_file = LogFile::open(&args.file, file).map_err(|err| LogError::Read {
|
||||
err,
|
||||
path: args.file,
|
||||
})?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue