Compare commits

...

2 Commits

Author SHA1 Message Date
Nathan Fisher 22faadc34e Add verbose option for extracting and creating archives to list files
(to be implemented)
2024-03-31 23:17:59 -04:00
Nathan Fisher 3bc8b9aa80 Use `Listing` as message type for parallel actions 2024-03-31 23:12:07 -04:00
4 changed files with 73 additions and 134 deletions

View File

@ -27,6 +27,11 @@ pub fn extract() -> Command {
.long("quiet") .long("quiet")
.visible_alias("silent") .visible_alias("silent")
.action(ArgAction::SetFalse), .action(ArgAction::SetFalse),
Arg::new("verbose")
.help("List the extracted files")
.short('v')
.long("verbose")
.action(ArgAction::SetTrue),
Arg::new("stdin") Arg::new("stdin")
.help("Read archive from stdin") .help("Read archive from stdin")
.short('i') .short('i')
@ -99,6 +104,11 @@ pub fn create() -> Command {
.long("quiet") .long("quiet")
.visible_alias("silent") .visible_alias("silent")
.action(ArgAction::SetFalse), .action(ArgAction::SetFalse),
Arg::new("verbose")
.help("List the archived files")
.short('v')
.long("verbose")
.action(ArgAction::SetTrue),
Arg::new("stdout") Arg::new("stdout")
.help("Write archive to stdout") .help("Write archive to stdout")
.short('o') .short('o')

View File

@ -95,13 +95,13 @@ fn create(matches: &ArgMatches) -> Result<(), haggis::Error> {
handle = Some(thread::spawn(move || { handle = Some(thread::spawn(move || {
for msg in &receiver { for msg in &receiver {
match msg { match msg {
Message::NodeCreated(s) => { Message::NodeSaved(n) => {
pb.set_prefix(s.split('/').last().unwrap().to_string()); let name = n.name.split('/').last().unwrap();
pb.inc(1); if let ListingKind::Normal(size) = n.kind {
} pb.set_prefix(format!("{name} added, {size} bytes"));
Message::NodeSaved { name, size } => { } else {
let name = name.split('/').last().unwrap(); pb.set_prefix(format!("{name} added"));
pb.set_prefix(format!("{name} added, {size} bytes")); }
pb.inc(1); pb.inc(1);
} }
Message::Eof => { Message::Eof => {
@ -242,27 +242,37 @@ fn progress(file: &str, receiver: &mpsc::Receiver<StreamMessage>, len: u64) -> u
pb.println(format!("Extracting archive {file}")); pb.println(format!("Extracting archive {file}"));
for msg in receiver { for msg in receiver {
match msg { match msg {
StreamMessage::FileExtracted { name, size } => { StreamMessage::NodeExtracted(n) => {
let name = name.split('/').last().unwrap(); let name = n.name.split('/').last().unwrap();
pb.set_prefix(format!("{name} extracted, {size} bytes")); match n.kind {
pb.inc(1); ListingKind::Normal(size) => {
total += size; pb.set_prefix(format!("{name} extracted, {size} bytes"));
} pb.inc(1);
StreamMessage::LinkCreated { name, target } => { total += size;
let name = name.split('/').last().unwrap(); }
let target = target.split('/').last().unwrap(); ListingKind::SoftLink(t)
pb.set_prefix(format!("{name} -> {target}")); | ListingKind::HardLink(t) => {
pb.inc(1); pb.set_prefix(format!("{name} -> {t}"));
} pb.inc(1);
StreamMessage::DirectoryCreated { name } => { }
let name = name.split('/').last().unwrap(); ListingKind::Directory => {
pb.set_prefix(format!("mkdir {name}")); pb.set_prefix(format!("mkdir {name}"));
pb.inc(1); pb.inc(1);
} }
StreamMessage::DeviceCreated { name } => { ListingKind::Block(_d)
let name = name.split('/').last().unwrap(); | ListingKind::Character(_d) => {
pb.set_prefix(format!("mknod {name}")); pb.set_prefix(format!("mknod {name}"));
pb.inc(1); pb.inc(1);
}
ListingKind::Fifo => {
pb.set_prefix(format!("mkfifo {name}"));
pb.inc(1);
}
ListingKind::Eof => {
pb.finish_and_clear();
break;
}
}
} }
StreamMessage::Eof => { StreamMessage::Eof => {
pb.finish_and_clear(); pb.finish_and_clear();

View File

@ -137,18 +137,8 @@ pub fn stream_archive<W: Write>(
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
#[derive(Debug)] #[derive(Debug)]
pub enum Message { pub enum Message {
/// A `Node` has successfully been created from this path
NodeCreated(
/// The path of the created `Node`
String,
),
/// The `Node` has successfully been written into the writer /// The `Node` has successfully been written into the writer
NodeSaved { NodeSaved(Listing),
/// The path of the saved `Node`
name: String,
/// The size in bytes of the created `Node`
size: u64,
},
/// An error occurred creating or writing out the node /// An error occurred creating or writing out the node
Err { Err {
/// The pathname of the node /// The pathname of the node
@ -241,17 +231,7 @@ pub fn par_stream_archive<W: Write + Send>(
}) })
.map_err(|_| Error::SenderError)?; .map_err(|_| Error::SenderError)?;
} }
match node.filetype { s.send(Message::NodeSaved(node.into())).map_err(|_| Error::SenderError)?;
FileType::Normal(n) => s
.send(Message::NodeSaved {
name: node.name.clone(),
size: n.len,
})
.map_err(|_| Error::SenderError)?,
_ => s
.send(Message::NodeCreated(node.name.clone()))
.map_err(|_| Error::SenderError)?,
}
Ok(()) Ok(())
} else { } else {
Err(Error::MutexError) Err(Error::MutexError)

View File

@ -2,7 +2,7 @@
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
use { use {
crate::FileType, crate::{ FileType, Listing },
rayon::{iter::ParallelBridge, prelude::ParallelIterator}, rayon::{iter::ParallelBridge, prelude::ParallelIterator},
std::sync::mpsc::Sender, std::sync::mpsc::Sender,
}; };
@ -44,30 +44,8 @@ impl<R: Read> Iterator for Stream<R> {
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
#[derive(Debug)] #[derive(Debug)]
pub enum Message { pub enum Message {
/// A File node has been successfully extracted /// A Node has been successfully extracted
FileExtracted { NodeExtracted(Listing),
/// The path of the extracted `Node`
name: String,
/// The size in bytes of the created file
size: u64,
},
/// A link has been created from a `Node`
LinkCreated {
/// The path of the link
name: String,
/// The path to this link's target
target: String,
},
/// A directory has been created from this `Node`
DirectoryCreated {
/// The directory's path
name: String,
},
/// A device file has been created from this `Node`
DeviceCreated {
/// The path of the device file
name: String,
},
/// An error occurred while extracting this `Node` /// An error occurred while extracting this `Node`
Err { Err {
/// The pathame of the `Node` being extracted /// The pathame of the `Node` being extracted
@ -135,12 +113,12 @@ impl<R: Read> Stream<R> {
f: F, f: F,
) -> Result<(), Error> ) -> Result<(), Error>
where where
F: FnOnce(Node, Option<u32>, Option<u32>) + Copy, F: FnOnce(&Node, Option<u32>, Option<u32>) + Copy,
{ {
for node in self { for node in self {
let node = node?; let node = node?;
node.extract(prefix, uid, gid)?; node.extract(prefix, uid, gid)?;
f(node, uid, gid); f(&node, uid, gid);
} }
Ok(()) Ok(())
} }
@ -148,7 +126,7 @@ impl<R: Read> Stream<R> {
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
impl<R: Read + Send> Stream<R> { impl<R: Read + Send> Stream<R> {
/// Extracts and archive in parallel /// Extracts an archive in parallel
/// # Errors /// # Errors
/// Returns `crate::Error` if io fails or several other error conditions /// Returns `crate::Error` if io fails or several other error conditions
pub fn par_extract( pub fn par_extract(
@ -170,35 +148,12 @@ impl<R: Read + Send> Stream<R> {
return Err(error); return Err(error);
} }
match n.filetype { match n.filetype {
FileType::Normal(f) => {
s.send(Message::FileExtracted {
name: n.name.clone(),
size: f.len,
})
.map_err(|_| Error::SenderError)?;
}
FileType::SoftLink(t) | FileType::HardLink(t) => {
s.send(Message::LinkCreated {
name: n.name.clone(),
target: t.clone(),
})
.map_err(|_| Error::SenderError)?;
}
FileType::Directory => {
s.send(Message::DirectoryCreated {
name: n.name.clone(),
})
.map_err(|_| Error::SenderError)?;
}
FileType::Block(_) | FileType::Character(_) | FileType::Fifo => {
s.send(Message::DeviceCreated {
name: n.name.clone(),
})
.map_err(|_| Error::SenderError)?;
}
FileType::Eof => { FileType::Eof => {
s.send(Message::Eof).map_err(|_| Error::SenderError)?; s.send(Message::Eof).map_err(|_| Error::SenderError)?;
} }
_ => {
s.send(Message::NodeExtracted(n.into())).map_err(|_| Error::SenderError)?;
}
} }
Ok::<(), Error>(()) Ok::<(), Error>(())
})?; })?;
@ -206,7 +161,7 @@ impl<R: Read + Send> Stream<R> {
Ok(()) Ok(())
} }
/// Extracts and archive in parallel and runs the passed in function for /// Extracts an archive in parallel and runs the passed in function for
/// each `Node` /// each `Node`
/// # Errors /// # Errors
/// Returns `crate::Error` if io fails or several other error conditions /// Returns `crate::Error` if io fails or several other error conditions
@ -219,44 +174,28 @@ impl<R: Read + Send> Stream<R> {
f: F, f: F,
) -> Result<(), Error> ) -> Result<(), Error>
where where
F: FnOnce(Node, Option<u32>, Option<u32>) + Copy + Send + Sync, F: FnOnce(&Node, Option<u32>, Option<u32>) + Copy + Send + Sync,
{ {
let s = sender.clone(); let s = sender.clone();
self.into_iter().par_bridge().try_for_each_with(s, |s, n| { self.into_iter().par_bridge().try_for_each_with(s, |s, n| {
let n = n?; let n = n?;
n.extract(prefix, uid, gid)?; if let Err(error) = n.extract(prefix, uid, gid) {
s.send(Message::Err {
name: n.name.clone(),
error: error.clone(),
})
.map_err(|_| Error::SenderError)?;
return Err(error);
}
match n.filetype { match n.filetype {
FileType::Normal(ref f) => {
s.send(Message::FileExtracted {
name: n.name.clone(),
size: f.len,
})
.map_err(|_| Error::SenderError)?;
}
FileType::SoftLink(ref t) | FileType::HardLink(ref t) => {
s.send(Message::LinkCreated {
name: n.name.clone(),
target: t.clone(),
})
.map_err(|_| Error::SenderError)?;
}
FileType::Directory => {
s.send(Message::DirectoryCreated {
name: n.name.clone(),
})
.map_err(|_| Error::SenderError)?;
}
FileType::Block(_) | FileType::Character(_) | FileType::Fifo => {
s.send(Message::DeviceCreated {
name: n.name.clone(),
})
.map_err(|_| Error::SenderError)?;
}
FileType::Eof => { FileType::Eof => {
s.send(Message::Eof).map_err(|_| Error::SenderError)?; s.send(Message::Eof).map_err(|_| Error::SenderError)?;
} }
_ => {
f(&n, uid, gid);
s.send(Message::NodeExtracted(n.into())).map_err(|_| Error::SenderError)?;
}
} }
f(n, uid, gid);
Ok::<(), Error>(()) Ok::<(), Error>(())
})?; })?;
sender.send(Message::Eof).map_err(|_| Error::SenderError)?; sender.send(Message::Eof).map_err(|_| Error::SenderError)?;