Skip to content

Commit

Permalink
first draft with Directory trait for Archive and Dir
Browse files Browse the repository at this point in the history
  • Loading branch information
taminob committed Jan 23, 2024
1 parent 29366eb commit 3677d9f
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 23 deletions.
54 changes: 33 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ phf = { version = "0.11.2", features = ["macros"] }
plist = { version = "1.6.0", default-features = false }
scoped_threadpool = "0.1"
uutils_term_grid = "0.3"
tar = "0.4.40"
terminal_size = "0.3.0"
timeago = { version = "0.4.2", default-features = false }
unicode-width = "0.1"
Expand Down
144 changes: 144 additions & 0 deletions src/fs/archive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use crate::fs::feature::git::GitCache;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use log::*;

use crate::fs::dir::{DotFilter, Files};
use crate::fs::File;

pub trait Directory: Sized {
/// Create a new Dir object filled with all the files in the directory
/// pointed to by the given path. Fails if the directory can’t be read, or
/// isn’t actually a directory, or if there’s an IO error that occurs at
/// any point.
///
/// The `read_dir` iterator doesn’t actually yield the `.` and `..`
/// entries, so if the user wants to see them, we’ll have to add them
/// ourselves after the files have been read.
fn read_dir(path: PathBuf) -> io::Result<Self>;

/// Produce an iterator of IO results of trying to read all the files in
/// this directory.
fn files<'dir, 'ig>(
&'dir self,
dots: DotFilter,
git: Option<&'ig GitCache>,
git_ignoring: bool,
deref_links: bool,
total_size: bool,
) -> Files<'dir, 'ig>;

/// Whether this directory contains a file with the given path.
fn contains(&self, path: &Path) -> bool;
/// Append a path onto the path specified by this directory.
fn join(&self, child: &Path) -> PathBuf;
}

struct ArchiveEntry {
// name: String,
path: String,
size: u64,
// permissions
// owner
// file type
// mtime
}

pub enum ArchiveFormat {
Tar,
Unknown,
}

trait ArchiveReader {
fn read_dir(path: &PathBuf) -> io::Result<Vec<ArchiveEntry>>;
}

struct TarReader {}

impl ArchiveReader for TarReader {
fn read_dir(path: &PathBuf) -> io::Result<Vec<ArchiveEntry>> {
let result = Vec::new();
let file_content = fs::File::open(path)?;
tar::Archive::new(file_content).entries().map(|entries| {
for entry in entries {
if let Ok(e) = entry {
let path = e.path().expect("TODO").to_string_lossy().to_string();
let size = e.size();
result.push(ArchiveEntry { path, size });
}
}
})?;
Ok(result)
}
}

impl ArchiveFormat {
pub fn from_extension(extension: &str) -> Option<ArchiveFormat> {
match extension {
".tar" => Some(ArchiveFormat::Tar),
_ => None,
}
}
}

pub struct Archive {
//pub file: &'a File<'dir>,
pub format: ArchiveFormat,

contents: Vec<ArchiveEntry>,
pub path: PathBuf,
}

impl Directory for Archive {
fn read_dir(path: PathBuf) -> io::Result<Self> {
let extension = path
.extension()
.unwrap_or(std::ffi::OsStr::new(""))
.to_string_lossy();
let format =
ArchiveFormat::from_extension(extension.as_ref()).unwrap_or(ArchiveFormat::Unknown);
let contents = match format {
ArchiveFormat::Tar => TarReader::read_dir(&path),
ArchiveFormat::Unknown => {
return Err(io::Error::new(
io::ErrorKind::Unsupported,
"Unsupported archive format",
))
}
}?;
Ok(Archive {
path,
contents,
format,
})
}

/// Produce an iterator of IO results of trying to read all the files in
/// this directory.
fn files<'dir, 'ig>(
&'dir self,
dots: DotFilter,
git: Option<&'ig GitCache>,
git_ignoring: bool,
deref_links: bool,
total_size: bool,
) -> Files<'dir, 'ig> {
Files {
inner: self.contents.iter(),
dir: self,
dotfiles: dots.shows_dotfiles(),
dots: dots.dots(),
git,
git_ignoring,
deref_links,
total_size,
}
}

/// Whether this directory contains a file with the given path.
fn contains(&self, path: &Path) -> bool {}
/// Append a path onto the path specified by this directory.
fn join(&self, child: &Path) -> PathBuf {}
}
5 changes: 3 additions & 2 deletions src/fs/dir.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::fs::archive::{Archive, ArchiveFormat};
use crate::fs::feature::git::GitCache;
use crate::fs::fields::GitStatus;
use std::fs;
Expand Down Expand Up @@ -223,7 +224,7 @@ impl Default for DotFilter {

impl DotFilter {
/// Whether this filter should show dotfiles in a listing.
fn shows_dotfiles(self) -> bool {
pub fn shows_dotfiles(self) -> bool {
match self {
Self::JustFiles => false,
Self::Dotfiles => true,
Expand All @@ -232,7 +233,7 @@ impl DotFilter {
}

/// Whether this filter should add dot directories to a listing.
fn dots(self) -> DotsNext {
pub fn dots(self) -> DotsNext {
match self {
Self::JustFiles => DotsNext::Files,
Self::Dotfiles => DotsNext::Files,
Expand Down
18 changes: 18 additions & 0 deletions src/fs/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use log::*;
#[cfg(unix)]
use once_cell::sync::Lazy;

use crate::fs::archive::{Archive, ArchiveFormat};
use crate::fs::dir::Dir;
use crate::fs::feature::xattr;
use crate::fs::feature::xattr::{Attribute, FileAttributes};
Expand Down Expand Up @@ -431,6 +432,23 @@ impl<'dir> File<'dir> {
}
}

/// Interpret file as archive
pub fn archive(&self) -> Option<Archive<'_, 'dir>> {
let extension = &self
.path
.extension()
.unwrap_or(std::ffi::OsStr::new(""))
.to_string_lossy();
if let Some(archive_format) = ArchiveFormat::from_extension(extension.as_ref()) {
Some(Archive {
file: &self,
format: archive_format,
})
} else {
None
}
}

/// Assuming this file is a symlink, follows that link and any further
/// links recursively, returning the result from following the trail.
///
Expand Down
1 change: 1 addition & 0 deletions src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub use self::dir::{Dir, DotFilter};
mod file;
pub use self::file::{File, FileTarget};

pub mod archive;
pub mod dir_action;
pub mod feature;
pub mod fields;
Expand Down
9 changes: 9 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ impl<'args> Exa<'args> {
debug!("Running with options: {:#?}", self.options);

let mut files = Vec::new();
let mut archives = Vec::new();
let mut dirs = Vec::new();
let mut exit_status = 0;

Expand Down Expand Up @@ -290,6 +291,14 @@ impl<'args> Exa<'args> {
}
}

if !self.options.dir_action.treat_dirs_as_files() {
for f in &files {
if let Some(archive) = f.archive() {
archives.push(archive);
}
}
}

// We want to print a directory’s name before we list it, *except* in
// the case where it’s the only directory, *except* if there are any
// files to print as well. (It’s a double negative)
Expand Down
18 changes: 18 additions & 0 deletions src/options/archive_inspection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use crate::options::parser::MatchedFlags;
use crate::options::{flags, OptionsError};

#[derive(Debug, PartialEq)]
pub enum ArchiveInspection {
Always,
Never,
}

impl ArchiveInspection {
pub fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
Ok(if matches.has(&flags::INSPECT_ARCHIVES)? {
ArchiveInspection::Always
} else {
ArchiveInspection::Never
})
}
}
1 change: 1 addition & 0 deletions src/options/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pub static OCTAL: Arg = Arg { short: Some(b'o'), long: "octal-permis
pub static SECURITY_CONTEXT: Arg = Arg { short: Some(b'Z'), long: "context", takes_value: TakesValue::Forbidden };
pub static STDIN: Arg = Arg { short: None, long: "stdin", takes_value: TakesValue::Forbidden };
pub static FILE_FLAGS: Arg = Arg { short: Some(b'O'), long: "flags", takes_value: TakesValue::Forbidden };
pub static INSPECT_ARCHIVES: Arg = Arg { short: Some(b'q'), long: "quasi", takes_value: TakesValue::Forbidden };

pub static ALL_ARGS: Args = Args(&[
&VERSION, &HELP,
Expand Down
1 change: 1 addition & 0 deletions src/options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ use crate::options::stdin::FilesInput;
use crate::output::{details, grid_details, Mode, View};
use crate::theme::Options as ThemeOptions;

mod archive_inspection;
mod dir_action;
mod file_name;
mod filter;
Expand Down

0 comments on commit 3677d9f

Please sign in to comment.