mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-04 00:21:57 +00:00
DirWriterLister now requires an ExactSizeIterator.
`DirWriter::write` now doesn't collect all entries initially.
This commit is contained in:
parent
136af25359
commit
252330391b
@ -1,6 +1,6 @@
|
||||
#![doc(include = "lib.md")]
|
||||
// Features
|
||||
#![feature(external_doc, seek_stream_len, try_blocks)]
|
||||
#![feature(external_doc, seek_stream_len, try_blocks, associated_type_bounds)]
|
||||
// Lints
|
||||
#![warn(clippy::restriction, clippy::pedantic, clippy::nursery)]
|
||||
// We'll disable the ones we don't need
|
||||
|
||||
@ -10,7 +10,9 @@ use std::{
|
||||
};
|
||||
|
||||
/// A directory lister
|
||||
pub trait DirWriterLister: Sized + IntoIterator<Item = Result<DirEntryWriter<Self>, Self::Error>> {
|
||||
pub trait DirWriterLister:
|
||||
Sized + IntoIterator<Item = Result<DirEntryWriter<Self>, Self::Error>, IntoIter: ExactSizeIterator>
|
||||
{
|
||||
/// File type
|
||||
type FileReader: io::Read;
|
||||
|
||||
@ -69,11 +71,7 @@ impl<L: DirWriterLister> DirWriter<L> {
|
||||
// Note: We on the directory after this directory.
|
||||
// Note: `+1` for the null entry.
|
||||
// Note: `+2047` is to pad this directory to the next sector, if not empty.
|
||||
let entries: Vec<DirEntryWriter<L>> = self
|
||||
.entries
|
||||
.into_iter()
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(WriteDirError::GetEntry)?;
|
||||
let entries = self.entries.into_iter();
|
||||
let entries_len: u32 = entries
|
||||
.len()
|
||||
.try_into()
|
||||
@ -82,8 +80,10 @@ impl<L: DirWriterLister> DirWriter<L> {
|
||||
|
||||
// Write each entry and map it so we can write it later
|
||||
let entries: Vec<_> = entries
|
||||
.into_iter()
|
||||
.map(|entry| {
|
||||
// Get the entry
|
||||
let entry = entry.map_err(WriteDirError::GetEntry)?;
|
||||
|
||||
// Seek to the entry
|
||||
writer
|
||||
.seek(SeekFrom::Start(u64::from(cur_sector_pos) * 2048))
|
||||
|
||||
@ -12,6 +12,8 @@ dcb-drv = { path = "../../dcb-drv" }
|
||||
# Util
|
||||
filetime = "0.2.14"
|
||||
chrono = "0.4.19"
|
||||
size_format = "1.0.2"
|
||||
itertools = "0.10.0"
|
||||
|
||||
# Cmd
|
||||
clap = "2.33.3"
|
||||
|
||||
@ -54,12 +54,9 @@ impl CliData {
|
||||
let output_file = match matches.value_of("OUTPUT") {
|
||||
Some(output) => PathBuf::from(output),
|
||||
None => {
|
||||
let extension = match input_dir.extension() {
|
||||
Some(extension) => format!("{}.drv", extension.to_string_lossy()),
|
||||
None => "drv".to_string(),
|
||||
};
|
||||
|
||||
input_dir.with_extension(extension)
|
||||
let mut path = input_dir.clone().into_os_string();
|
||||
path.push(".drv");
|
||||
PathBuf::from(path)
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -3,15 +3,17 @@
|
||||
// Modules
|
||||
pub mod error;
|
||||
|
||||
use dcb_drv::{DirEntryWriter, DirEntryWriterKind, DirWriter, DirWriterLister};
|
||||
// Exports
|
||||
pub use error::{NewError, NextError, ReadEntryError};
|
||||
|
||||
// Imports
|
||||
use dcb_drv::{DirEntryWriter, DirEntryWriterKind, DirWriter, DirWriterLister};
|
||||
use itertools::{Itertools, Position};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
convert::{TryFrom, TryInto},
|
||||
fs,
|
||||
io::Seek,
|
||||
path::{Path, PathBuf},
|
||||
time::SystemTime,
|
||||
};
|
||||
@ -21,6 +23,9 @@ use std::{
|
||||
pub struct DirLister {
|
||||
/// All entries
|
||||
entries: Vec<DirEntry>,
|
||||
|
||||
/// Depth
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
/// Directory entry
|
||||
@ -35,7 +40,7 @@ pub struct DirEntry {
|
||||
|
||||
impl DirLister {
|
||||
/// Creates a new iterator from a path
|
||||
pub fn new(path: &Path) -> Result<Self, NewError> {
|
||||
pub fn new(path: &Path, depth: usize) -> Result<Self, NewError> {
|
||||
// Read the directory entries
|
||||
let mut entries = fs::read_dir(path)
|
||||
.map_err(|err| NewError::ReadDir(path.to_path_buf(), err))?
|
||||
@ -49,11 +54,6 @@ impl DirLister {
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|err| NewError::ReadEntries(path.to_path_buf(), err))?;
|
||||
|
||||
// If there are too many entries, return Err
|
||||
if u32::try_from(entries.len()).is_err() {
|
||||
return Err(NewError::TooManyEntries);
|
||||
}
|
||||
|
||||
// Then sort them by type and then name
|
||||
entries.sort_by(|lhs, rhs| {
|
||||
// Get if they're a directory
|
||||
@ -71,7 +71,7 @@ impl DirLister {
|
||||
lhs.path.file_name().cmp(&rhs.path.file_name())
|
||||
});
|
||||
|
||||
Ok(Self { entries })
|
||||
Ok(Self { entries, depth })
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,10 +83,18 @@ impl DirWriterLister for DirLister {
|
||||
impl IntoIterator for DirLister {
|
||||
type Item = Result<DirEntryWriter<Self>, <Self as DirWriterLister>::Error>;
|
||||
|
||||
type IntoIter = impl Iterator<Item = Self::Item>;
|
||||
type IntoIter = impl Iterator<Item = Self::Item> + ExactSizeIterator;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.entries.into_iter().map(|entry| {
|
||||
let depth = self.depth;
|
||||
self.entries.into_iter().with_position().map(move |entry| {
|
||||
let (entry, is_last) = {
|
||||
match entry {
|
||||
Position::First(entry) | Position::Middle(entry) => (entry, false),
|
||||
Position::Last(entry) | Position::Only(entry) => (entry, true),
|
||||
}
|
||||
};
|
||||
|
||||
// Read the entry and it's metadata
|
||||
let name = entry
|
||||
.path
|
||||
@ -109,20 +117,43 @@ impl IntoIterator for DirLister {
|
||||
// Check if it's a directory or file
|
||||
let kind = match entry.metadata.is_dir() {
|
||||
false => {
|
||||
let reader = fs::File::open(&entry.path).map_err(NextError::OpenFile)?;
|
||||
let mut reader = fs::File::open(&entry.path).map_err(NextError::OpenFile)?;
|
||||
let extension = entry
|
||||
.path
|
||||
.extension()
|
||||
.ok_or(NextError::NoFileExtension)?
|
||||
.try_into()
|
||||
.map_err(NextError::InvalidFileExtension)?;
|
||||
let size = reader.stream_len().ok();
|
||||
|
||||
println!("{}", entry.path.display());
|
||||
let prefix = dcb_util::DisplayWrapper::new(|f| {
|
||||
match depth {
|
||||
0 => (),
|
||||
_ => {
|
||||
for _ in 0..(depth - 1) {
|
||||
write!(f, "│ ")?;
|
||||
}
|
||||
match is_last {
|
||||
true => write!(f, "└──")?,
|
||||
false => write!(f, "├──")?,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let size = dcb_util::DisplayWrapper::new(|f| match size {
|
||||
Some(size) => write!(f, "{}B", size_format::SizeFormatterSI::new(size)),
|
||||
None => write!(f, "Unknown Size"),
|
||||
});
|
||||
|
||||
println!("{}{} ({})", prefix, name, size,);
|
||||
|
||||
DirEntryWriterKind::File { extension, reader }
|
||||
},
|
||||
true => {
|
||||
let entries = Self::new(&entry.path).map_err(NextError::OpenDir)?;
|
||||
let entries = Self::new(&entry.path, depth + 1).map_err(NextError::OpenDir)?;
|
||||
|
||||
println!("{} ({} entries)", entry.path.display(), entries.entries.len());
|
||||
|
||||
|
||||
@ -13,10 +13,6 @@ pub enum NewError {
|
||||
/// Unable to read entry
|
||||
#[error("Unable to read entry in {}", _0.display())]
|
||||
ReadEntries(PathBuf, #[source] ReadEntryError),
|
||||
|
||||
/// Too many entries in directory
|
||||
#[error("Too many entries in directory")]
|
||||
TooManyEntries,
|
||||
}
|
||||
|
||||
/// Error for [`DirList::new`](super::DirLister::new)'s entry reading
|
||||
|
||||
@ -26,19 +26,19 @@ fn main() -> Result<(), anyhow::Error> {
|
||||
let cli::CliData { input_dir, output_file } = cli::CliData::new();
|
||||
|
||||
// Try to pack the filesystem
|
||||
self::pack_filesystem(&input_dir, &output_file).context("Unable to pack `drv` file")?;
|
||||
self::write_fs(&input_dir, &output_file).context("Unable to pack `drv` file")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Extracts a `.drv` file to `output_dir`.
|
||||
fn pack_filesystem(input_dir: &Path, output_file: &Path) -> Result<(), anyhow::Error> {
|
||||
/// Writes a `.drv` filesystem to `output_file`.
|
||||
pub fn write_fs(input_dir: &Path, output_file: &Path) -> Result<(), anyhow::Error> {
|
||||
// Create the output file
|
||||
let mut output_file = fs::File::create(output_file).context("Unable to create output file")?;
|
||||
|
||||
// Create the filesystem writer
|
||||
let root_entries =
|
||||
dir_lister::DirLister::new(input_dir).context("Unable to create new dir lister for root directory")?;
|
||||
dir_lister::DirLister::new(input_dir, 0).context("Unable to create new dir lister for root directory")?;
|
||||
DirWriter::new(root_entries)
|
||||
.write(DirPtr::root(), &mut output_file)
|
||||
.context("Unable to write filesystem")?;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user