Move File fields to their own module

This commit is contained in:
Ben S 2015-05-12 03:33:40 +01:00
parent 2a3045ddfa
commit 085067d18e
4 changed files with 141 additions and 136 deletions

View File

@ -1,6 +1,5 @@
use feature::Git;
use file::File;
use file;
use file::{File, fields};
use std::io;
use std::fs;
@ -65,11 +64,11 @@ impl Dir {
}
/// Get a string describing the Git status of the given file.
pub fn git_status(&self, path: &Path, prefix_lookup: bool) -> file::Git {
pub fn git_status(&self, path: &Path, prefix_lookup: bool) -> fields::Git {
match (&self.git, prefix_lookup) {
(&Some(ref git), false) => git.status(path),
(&Some(ref git), true) => git.dir_status(path),
(&None, _) => file::Git::empty()
(&None, _) => fields::Git::empty()
}
}
}

View File

@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
use git2;
use file;
use file::fields;
/// Container of Git statuses for all the files in this folder's Git repository.
pub struct Git {
@ -28,48 +28,48 @@ impl Git {
}
/// Get the status for the file at the given path, if present.
pub fn status(&self, path: &Path) -> file::Git {
pub fn status(&self, path: &Path) -> fields::Git {
let status = self.statuses.iter()
.find(|p| p.0.as_path() == path);
match status {
Some(&(_, s)) => file::Git { staged: index_status(s), unstaged: working_tree_status(s) },
None => file::Git { staged: file::GitStatus::NotModified, unstaged: file::GitStatus::NotModified }
Some(&(_, s)) => fields::Git { staged: index_status(s), unstaged: working_tree_status(s) },
None => fields::Git { staged: fields::GitStatus::NotModified, unstaged: fields::GitStatus::NotModified }
}
}
/// Get the combined status for all the files whose paths begin with the
/// path that gets passed in. This is used for getting the status of
/// directories, which don't really have an 'official' status.
pub fn dir_status(&self, dir: &Path) -> file::Git {
pub fn dir_status(&self, dir: &Path) -> fields::Git {
let s = self.statuses.iter()
.filter(|p| p.0.starts_with(dir))
.fold(git2::Status::empty(), |a, b| a | b.1);
file::Git { staged: index_status(s), unstaged: working_tree_status(s) }
fields::Git { staged: index_status(s), unstaged: working_tree_status(s) }
}
}
/// The character to display if the file has been modified, but not staged.
fn working_tree_status(status: git2::Status) -> file::GitStatus {
fn working_tree_status(status: git2::Status) -> fields::GitStatus {
match status {
s if s.contains(git2::STATUS_WT_NEW) => file::GitStatus::New,
s if s.contains(git2::STATUS_WT_MODIFIED) => file::GitStatus::Modified,
s if s.contains(git2::STATUS_WT_DELETED) => file::GitStatus::Deleted,
s if s.contains(git2::STATUS_WT_RENAMED) => file::GitStatus::Renamed,
s if s.contains(git2::STATUS_WT_TYPECHANGE) => file::GitStatus::TypeChange,
_ => file::GitStatus::NotModified,
s if s.contains(git2::STATUS_WT_NEW) => fields::GitStatus::New,
s if s.contains(git2::STATUS_WT_MODIFIED) => fields::GitStatus::Modified,
s if s.contains(git2::STATUS_WT_DELETED) => fields::GitStatus::Deleted,
s if s.contains(git2::STATUS_WT_RENAMED) => fields::GitStatus::Renamed,
s if s.contains(git2::STATUS_WT_TYPECHANGE) => fields::GitStatus::TypeChange,
_ => fields::GitStatus::NotModified,
}
}
/// The character to display if the file has been modified, and the change
/// has been staged.
fn index_status(status: git2::Status) -> file::GitStatus {
fn index_status(status: git2::Status) -> fields::GitStatus {
match status {
s if s.contains(git2::STATUS_INDEX_NEW) => file::GitStatus::New,
s if s.contains(git2::STATUS_INDEX_MODIFIED) => file::GitStatus::Modified,
s if s.contains(git2::STATUS_INDEX_DELETED) => file::GitStatus::Deleted,
s if s.contains(git2::STATUS_INDEX_RENAMED) => file::GitStatus::Renamed,
s if s.contains(git2::STATUS_INDEX_TYPECHANGE) => file::GitStatus::TypeChange,
_ => file::GitStatus::NotModified,
s if s.contains(git2::STATUS_INDEX_NEW) => fields::GitStatus::New,
s if s.contains(git2::STATUS_INDEX_MODIFIED) => fields::GitStatus::Modified,
s if s.contains(git2::STATUS_INDEX_DELETED) => fields::GitStatus::Deleted,
s if s.contains(git2::STATUS_INDEX_RENAMED) => fields::GitStatus::Renamed,
s if s.contains(git2::STATUS_INDEX_TYPECHANGE) => fields::GitStatus::TypeChange,
_ => fields::GitStatus::NotModified,
}
}

View File

@ -3,7 +3,6 @@ use std::env::current_dir;
use std::fs;
use std::io;
use std::os::unix;
use std::os::unix::raw::{blkcnt_t, gid_t, ino_t, nlink_t, time_t, uid_t};
use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::{Component, Path, PathBuf};
@ -13,66 +12,7 @@ use dir::Dir;
use options::TimeType;
use feature::Attribute;
pub enum Type {
File, Directory, Pipe, Link, Special,
}
pub struct Permissions {
pub file_type: Type,
pub user_read: bool,
pub user_write: bool,
pub user_execute: bool,
pub group_read: bool,
pub group_write: bool,
pub group_execute: bool,
pub other_read: bool,
pub other_write: bool,
pub other_execute: bool,
pub attribute: bool,
}
pub struct Links {
pub count: nlink_t,
pub multiple: bool,
}
pub struct Inode(pub ino_t);
pub enum Blocks {
Some(blkcnt_t),
None,
}
pub struct User(pub uid_t);
pub struct Group(pub gid_t);
pub enum Size {
Some(u64),
None,
}
pub struct Time(pub time_t);
pub enum GitStatus {
NotModified,
New,
Modified,
Deleted,
Renamed,
TypeChange,
}
pub struct Git {
pub staged: GitStatus,
pub unstaged: GitStatus,
}
impl Git {
pub fn empty() -> Git {
Git { staged: GitStatus::NotModified, unstaged: GitStatus::NotModified }
}
}
use self::fields as f;
/// A **File** is a wrapper around one of Rust's Path objects, along with
/// associated data about the file.
@ -222,34 +162,34 @@ impl<'a> File<'a> {
/// This is important, because a file with multiple links is uncommon,
/// while you can come across directories and other types with multiple
/// links much more often.
pub fn links(&self) -> Links {
pub fn links(&self) -> f::Links {
let count = self.stat.as_raw().nlink();
Links {
f::Links {
count: count,
multiple: self.is_file() && count > 1,
}
}
pub fn inode(&self) -> Inode {
Inode(self.stat.as_raw().ino())
pub fn inode(&self) -> f::Inode {
f::Inode(self.stat.as_raw().ino())
}
pub fn blocks(&self) -> Blocks {
pub fn blocks(&self) -> f::Blocks {
if self.is_file() || self.is_link() {
Blocks::Some(self.stat.as_raw().blocks())
f::Blocks::Some(self.stat.as_raw().blocks())
}
else {
Blocks::None
f::Blocks::None
}
}
pub fn user(&self) -> User {
User(self.stat.as_raw().uid())
pub fn user(&self) -> f::User {
f::User(self.stat.as_raw().uid())
}
pub fn group(&self) -> Group {
Group(self.stat.as_raw().gid())
pub fn group(&self) -> f::Group {
f::Group(self.stat.as_raw().gid())
}
/// This file's size, formatted using the given way, as a coloured string.
@ -258,52 +198,52 @@ impl<'a> File<'a> {
/// some filesystems, I've never looked at one of those numbers and gained
/// any information from it, so by emitting "-" instead, the table is less
/// cluttered with numbers.
pub fn size(&self) -> Size {
pub fn size(&self) -> f::Size {
if self.is_directory() {
Size::None
f::Size::None
}
else {
Size::Some(self.stat.len())
f::Size::Some(self.stat.len())
}
}
pub fn timestamp(&self, time_type: TimeType) -> Time {
pub fn timestamp(&self, time_type: TimeType) -> f::Time {
let time_in_seconds = match time_type {
TimeType::FileAccessed => self.stat.as_raw().atime(),
TimeType::FileModified => self.stat.as_raw().mtime(),
TimeType::FileCreated => self.stat.as_raw().ctime(),
};
Time(time_in_seconds)
f::Time(time_in_seconds)
}
/// This file's type, represented by a coloured character.
///
/// Although the file type can usually be guessed from the colour of the
/// file, `ls` puts this character there, so people will expect it.
fn type_char(&self) -> Type {
fn type_char(&self) -> f::Type {
if self.is_file() {
Type::File
f::Type::File
}
else if self.is_directory() {
Type::Directory
f::Type::Directory
}
else if self.is_pipe() {
Type::Pipe
f::Type::Pipe
}
else if self.is_link() {
Type::Link
f::Type::Link
}
else {
Type::Special
f::Type::Special
}
}
pub fn permissions(&self) -> Permissions {
pub fn permissions(&self) -> f::Permissions {
let bits = self.stat.permissions().mode();
let has_bit = |bit| { bits & bit == bit };
Permissions {
f::Permissions {
file_type: self.type_char(),
user_read: has_bit(unix::fs::USER_READ),
user_write: has_bit(unix::fs::USER_WRITE),
@ -364,9 +304,9 @@ impl<'a> File<'a> {
choices.contains(&&self.name[..])
}
pub fn git_status(&self) -> Git {
pub fn git_status(&self) -> f::Git {
match self.dir {
None => Git { staged: GitStatus::NotModified, unstaged: GitStatus::NotModified },
None => f::Git { staged: f::GitStatus::NotModified, unstaged: f::GitStatus::NotModified },
Some(d) => {
let cwd = match current_dir() {
Err(_) => Path::new(".").join(&self.path),
@ -404,6 +344,71 @@ fn ext<'a>(name: &'a str) -> Option<String> {
name.rfind('.').map(|p| name[p+1..].to_ascii_lowercase())
}
pub mod fields {
use std::os::unix::raw::{blkcnt_t, gid_t, ino_t, nlink_t, time_t, uid_t};
pub enum Type {
File, Directory, Pipe, Link, Special,
}
pub struct Permissions {
pub file_type: Type,
pub user_read: bool,
pub user_write: bool,
pub user_execute: bool,
pub group_read: bool,
pub group_write: bool,
pub group_execute: bool,
pub other_read: bool,
pub other_write: bool,
pub other_execute: bool,
pub attribute: bool,
}
pub struct Links {
pub count: nlink_t,
pub multiple: bool,
}
pub struct Inode(pub ino_t);
pub enum Blocks {
Some(blkcnt_t),
None,
}
pub struct User(pub uid_t);
pub struct Group(pub gid_t);
pub enum Size {
Some(u64),
None,
}
pub struct Time(pub time_t);
pub enum GitStatus {
NotModified,
New,
Modified,
Deleted,
Renamed,
TypeChange,
}
pub struct Git {
pub staged: GitStatus,
pub unstaged: GitStatus,
}
impl Git {
pub fn empty() -> Git {
Git { staged: GitStatus::NotModified, unstaged: GitStatus::NotModified }
}
}
}
#[cfg(broken_test)]
pub mod test {
pub use super::*;

View File

@ -2,7 +2,8 @@ use colours::Colours;
use column::{Alignment, Column, Cell};
use feature::Attribute;
use dir::Dir;
use file::{Blocks, File, Git, GitStatus, Group, Inode, Links, Permissions, Size, Time, Type, User};
use file::File;
use file::fields as f;
use options::{Columns, FileFilter, RecurseOptions, SizeFormat};
use users::{OSUsers, Users};
@ -197,21 +198,21 @@ impl Table {
}
}
fn render_permissions(&self, permissions: Permissions) -> Cell {
fn render_permissions(&self, permissions: f::Permissions) -> Cell {
let c = self.colours.perms;
let bit = |bit, chr: &'static str, style: Style| {
if bit { style.paint(chr) } else { self.colours.punctuation.paint("-") }
};
let file_type = match permissions.file_type {
Type::File => self.colours.filetypes.normal.paint("."),
Type::Directory => self.colours.filetypes.directory.paint("d"),
Type::Pipe => self.colours.filetypes.special.paint("|"),
Type::Link => self.colours.filetypes.symlink.paint("l"),
Type::Special => self.colours.filetypes.special.paint("?"),
f::Type::File => self.colours.filetypes.normal.paint("."),
f::Type::Directory => self.colours.filetypes.directory.paint("d"),
f::Type::Pipe => self.colours.filetypes.special.paint("|"),
f::Type::Link => self.colours.filetypes.symlink.paint("l"),
f::Type::Special => self.colours.filetypes.special.paint("?"),
};
let x_colour = if let Type::File = permissions.file_type { c.user_execute_file }
let x_colour = if let f::Type::File = permissions.file_type { c.user_execute_file }
else { c.user_execute_other };
let string = ANSIStrings( &[
@ -234,26 +235,26 @@ impl Table {
}
}
fn render_links(&self, links: Links) -> Cell {
fn render_links(&self, links: f::Links) -> Cell {
let style = if links.multiple { self.colours.links.multi_link_file }
else { self.colours.links.normal };
Cell::paint(style, &self.numeric.format_int(links.count))
}
fn render_blocks(&self, blocks: Blocks) -> Cell {
fn render_blocks(&self, blocks: f::Blocks) -> Cell {
match blocks {
Blocks::Some(blocks) => Cell::paint(self.colours.blocks, &blocks.to_string()),
Blocks::None => Cell::paint(self.colours.punctuation, "-"),
f::Blocks::Some(blocks) => Cell::paint(self.colours.blocks, &blocks.to_string()),
f::Blocks::None => Cell::paint(self.colours.punctuation, "-"),
}
}
fn render_inode(&self, inode: Inode) -> Cell {
fn render_inode(&self, inode: f::Inode) -> Cell {
Cell::paint(self.colours.inode, &inode.0.to_string())
}
fn render_size(&self, size: Size, size_format: SizeFormat) -> Cell {
if let Size::Some(offset) = size {
fn render_size(&self, size: f::Size, size_format: SizeFormat) -> Cell {
if let f::Size::Some(offset) = size {
let result = match size_format {
SizeFormat::DecimalBytes => decimal_prefix(offset as f64),
SizeFormat::BinaryBytes => binary_prefix(offset as f64),
@ -278,7 +279,7 @@ impl Table {
}
}
fn render_time(&self, timestamp: Time) -> Cell {
fn render_time(&self, timestamp: f::Time) -> Cell {
let date = LocalDateTime::at(timestamp.0);
let format = if date.year() == self.current_year {
@ -291,15 +292,15 @@ impl Table {
Cell::paint(self.colours.date, &format.format(date, &self.time))
}
fn render_git_status(&self, git: Git) -> Cell {
fn render_git_status(&self, git: f::Git) -> Cell {
let render_char = |chr| {
match chr {
GitStatus::NotModified => self.colours.punctuation.paint("-"),
GitStatus::New => self.colours.git.renamed.paint("N"),
GitStatus::Modified => self.colours.git.renamed.paint("M"),
GitStatus::Deleted => self.colours.git.renamed.paint("D"),
GitStatus::Renamed => self.colours.git.renamed.paint("R"),
GitStatus::TypeChange => self.colours.git.renamed.paint("T"),
f::GitStatus::NotModified => self.colours.punctuation.paint("-"),
f::GitStatus::New => self.colours.git.renamed.paint("N"),
f::GitStatus::Modified => self.colours.git.renamed.paint("M"),
f::GitStatus::Deleted => self.colours.git.renamed.paint("D"),
f::GitStatus::Renamed => self.colours.git.renamed.paint("R"),
f::GitStatus::TypeChange => self.colours.git.renamed.paint("T"),
}
};
@ -309,7 +310,7 @@ impl Table {
}
}
fn render_user(&mut self, user: User) -> Cell {
fn render_user(&mut self, user: f::User) -> Cell {
let user_name = match self.users.get_user_by_uid(user.0) {
Some(user) => user.name,
None => user.0.to_string(),
@ -320,7 +321,7 @@ impl Table {
Cell::paint(style, &*user_name)
}
fn render_group(&mut self, group: Group) -> Cell {
fn render_group(&mut self, group: f::Group) -> Cell {
let mut style = self.colours.users.group_not_yours;
let group_name = match self.users.get_group_by_gid(group.0) {