2015-01-26 01:16:19 +00:00
|
|
|
use std::ascii::AsciiExt;
|
2015-04-03 22:14:49 +00:00
|
|
|
use std::env::current_dir;
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
use std::fs;
|
|
|
|
use std::io;
|
2015-05-03 10:55:10 +00:00
|
|
|
use std::os::unix;
|
2015-05-12 01:59:22 +00:00
|
|
|
use std::os::unix::raw::{blkcnt_t, gid_t, ino_t, nlink_t, time_t, uid_t};
|
2015-05-03 11:46:05 +00:00
|
|
|
use std::os::unix::fs::{MetadataExt, PermissionsExt};
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
use std::path::{Component, Path, PathBuf};
|
2014-05-04 20:33:14 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
use unicode_width::UnicodeWidthStr;
|
2014-07-01 18:00:36 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
use dir::Dir;
|
|
|
|
use options::TimeType;
|
|
|
|
use feature::Attribute;
|
2014-12-12 11:17:55 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub enum Type {
|
|
|
|
File, Directory, Pipe, Link, Special,
|
|
|
|
}
|
2015-04-23 12:46:37 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
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,
|
|
|
|
}
|
2015-02-10 16:08:10 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub struct Links {
|
|
|
|
pub count: nlink_t,
|
|
|
|
pub multiple: bool,
|
|
|
|
}
|
2014-12-18 07:00:31 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub struct Inode(pub ino_t);
|
2015-02-09 16:33:27 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
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 }
|
|
|
|
}
|
|
|
|
}
|
2014-06-16 23:27:05 +00:00
|
|
|
|
2015-01-24 12:38:05 +00:00
|
|
|
/// A **File** is a wrapper around one of Rust's Path objects, along with
|
|
|
|
/// associated data about the file.
|
|
|
|
///
|
|
|
|
/// Each file is definitely going to have its filename displayed at least
|
|
|
|
/// once, have its file extension extracted at least once, and have its stat
|
|
|
|
/// information queried at least once, so it makes sense to do all this at the
|
|
|
|
/// start and hold on to all the information.
|
2014-05-04 20:33:14 +00:00
|
|
|
pub struct File<'a> {
|
2014-06-29 20:02:14 +00:00
|
|
|
pub name: String,
|
2014-11-26 07:40:52 +00:00
|
|
|
pub dir: Option<&'a Dir>,
|
2014-06-29 20:02:14 +00:00
|
|
|
pub ext: Option<String>,
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
pub path: PathBuf,
|
|
|
|
pub stat: fs::Metadata,
|
2015-02-22 12:55:13 +00:00
|
|
|
pub xattrs: Vec<Attribute>,
|
2015-02-03 13:27:23 +00:00
|
|
|
pub this: Option<Dir>,
|
2014-05-04 20:33:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> File<'a> {
|
2015-01-24 12:38:05 +00:00
|
|
|
/// Create a new File object from the given Path, inside the given Dir, if
|
|
|
|
/// appropriate. Paths specified directly on the command-line have no Dirs.
|
|
|
|
///
|
2015-05-03 12:10:25 +00:00
|
|
|
/// This uses `symlink_metadata` instead of `metadata`, which doesn't
|
|
|
|
/// follow symbolic links.
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
pub fn from_path(path: &Path, parent: Option<&'a Dir>, recurse: bool) -> io::Result<File<'a>> {
|
2015-05-03 12:10:25 +00:00
|
|
|
fs::symlink_metadata(path).map(|stat| File::with_stat(stat, path, parent, recurse))
|
2014-11-25 01:27:26 +00:00
|
|
|
}
|
2014-11-25 20:50:23 +00:00
|
|
|
|
2015-01-24 12:38:05 +00:00
|
|
|
/// Create a new File object from the given Stat result, and other data.
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
pub fn with_stat(stat: fs::Metadata, path: &Path, parent: Option<&'a Dir>, recurse: bool) -> File<'a> {
|
2015-02-23 11:32:35 +00:00
|
|
|
let filename = path_filename(path);
|
2014-06-21 18:39:27 +00:00
|
|
|
|
2015-02-03 13:27:23 +00:00
|
|
|
// If we are recursing, then the `this` field contains a Dir object
|
|
|
|
// that represents the current File as a directory, if it is a
|
|
|
|
// directory. This is used for the --tree option.
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
let this = if recurse && stat.is_dir() {
|
2015-02-03 13:27:23 +00:00
|
|
|
Dir::readdir(path).ok()
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2014-12-12 11:17:55 +00:00
|
|
|
File {
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
path: path.to_path_buf(),
|
2015-02-23 14:52:07 +00:00
|
|
|
dir: parent,
|
|
|
|
stat: stat,
|
|
|
|
ext: ext(&filename),
|
2015-03-26 00:37:12 +00:00
|
|
|
xattrs: Attribute::llist(path).unwrap_or(Vec::new()),
|
2015-02-23 14:52:07 +00:00
|
|
|
name: filename.to_string(),
|
|
|
|
this: this,
|
2014-12-12 11:17:55 +00:00
|
|
|
}
|
2014-05-04 20:33:14 +00:00
|
|
|
}
|
|
|
|
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
pub fn is_directory(&self) -> bool {
|
|
|
|
self.stat.is_dir()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_file(&self) -> bool {
|
|
|
|
self.stat.is_file()
|
|
|
|
}
|
|
|
|
|
2015-05-07 21:27:33 +00:00
|
|
|
pub fn is_executable_file(&self) -> bool {
|
|
|
|
let bit = unix::fs::USER_EXECUTE;
|
|
|
|
self.is_file() && (self.stat.permissions().mode() & bit) == bit
|
|
|
|
}
|
|
|
|
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
pub fn is_link(&self) -> bool {
|
2015-05-03 12:10:25 +00:00
|
|
|
self.stat.file_type().is_symlink()
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_pipe(&self) -> bool {
|
2015-05-03 12:10:25 +00:00
|
|
|
false // TODO: Still waiting on this one...
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
}
|
|
|
|
|
2015-01-24 12:38:05 +00:00
|
|
|
/// Whether this file is a dotfile or not.
|
2014-05-05 09:51:24 +00:00
|
|
|
pub fn is_dotfile(&self) -> bool {
|
2015-02-22 17:11:33 +00:00
|
|
|
self.name.starts_with(".")
|
2014-05-05 09:51:24 +00:00
|
|
|
}
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn path_prefix(&self) -> String {
|
|
|
|
let path_bytes: Vec<Component> = self.path.components().collect();
|
|
|
|
let mut path_prefix = String::new();
|
2014-06-21 18:39:27 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
if !path_bytes.is_empty() {
|
|
|
|
// Use init() to add all but the last component of the
|
|
|
|
// path to the prefix. init() panics when given an
|
|
|
|
// empty list, hence the check.
|
|
|
|
for component in path_bytes.init().iter() {
|
|
|
|
path_prefix.push_str(&*component.as_os_str().to_string_lossy());
|
2015-01-24 17:32:30 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
if component != &Component::RootDir {
|
|
|
|
path_prefix.push_str("/");
|
|
|
|
}
|
2014-06-21 09:11:50 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-11 22:28:01 +00:00
|
|
|
|
|
|
|
path_prefix
|
2014-06-21 09:11:50 +00:00
|
|
|
}
|
2014-06-21 18:39:27 +00:00
|
|
|
|
2015-01-24 12:38:05 +00:00
|
|
|
/// The Unicode 'display width' of the filename.
|
|
|
|
///
|
|
|
|
/// This is related to the number of graphemes in the string: most
|
|
|
|
/// characters are 1 columns wide, but in some contexts, certain
|
|
|
|
/// characters are actually 2 columns wide.
|
2015-01-12 00:31:24 +00:00
|
|
|
pub fn file_name_width(&self) -> usize {
|
2015-04-23 12:46:37 +00:00
|
|
|
UnicodeWidthStr::width(&self.name[..])
|
2014-07-22 14:41:20 +00:00
|
|
|
}
|
|
|
|
|
2015-01-24 17:26:26 +00:00
|
|
|
/// Assuming the current file is a symlink, follows the link and
|
|
|
|
/// returns a File object from the path the link points to.
|
|
|
|
///
|
|
|
|
/// If statting the file fails (usually because the file on the
|
|
|
|
/// other end doesn't exist), returns the *filename* of the file
|
|
|
|
/// that should be there.
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn link_target(&self) -> Result<File, String> {
|
|
|
|
let path = match fs::read_link(&self.path) {
|
|
|
|
Ok(path) => path,
|
|
|
|
Err(_) => return Err(self.name.clone()),
|
|
|
|
};
|
|
|
|
|
|
|
|
let target_path = match self.dir {
|
|
|
|
Some(dir) => dir.join(&*path),
|
|
|
|
None => path
|
|
|
|
};
|
|
|
|
|
|
|
|
let filename = path_filename(&target_path);
|
2014-11-25 20:50:23 +00:00
|
|
|
|
2015-05-03 12:10:25 +00:00
|
|
|
// Use plain `metadata` instead of `symlink_metadata` - we *want* to follow links.
|
2015-05-11 22:28:01 +00:00
|
|
|
if let Ok(stat) = fs::metadata(&target_path) {
|
2015-01-24 17:26:26 +00:00
|
|
|
Ok(File {
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
path: target_path.to_path_buf(),
|
2015-02-23 14:52:07 +00:00
|
|
|
dir: self.dir,
|
|
|
|
stat: stat,
|
|
|
|
ext: ext(&filename),
|
2015-05-11 22:28:01 +00:00
|
|
|
xattrs: Attribute::list(&target_path).unwrap_or(Vec::new()),
|
2015-02-23 14:52:07 +00:00
|
|
|
name: filename.to_string(),
|
|
|
|
this: None,
|
2015-01-24 17:26:26 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Err(filename.to_string())
|
2014-06-21 18:39:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-24 12:38:05 +00:00
|
|
|
/// This file's number of hard links as a coloured string.
|
|
|
|
///
|
|
|
|
/// 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.
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn links(&self) -> Links {
|
|
|
|
let count = self.stat.as_raw().nlink();
|
|
|
|
|
|
|
|
Links {
|
|
|
|
count: count,
|
|
|
|
multiple: self.is_file() && count > 1,
|
|
|
|
}
|
2015-01-24 12:38:05 +00:00
|
|
|
}
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn inode(&self) -> Inode {
|
|
|
|
Inode(self.stat.as_raw().ino())
|
2015-01-24 12:38:05 +00:00
|
|
|
}
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn blocks(&self) -> Blocks {
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
if self.is_file() || self.is_link() {
|
2015-05-11 22:28:01 +00:00
|
|
|
Blocks::Some(self.stat.as_raw().blocks())
|
2015-01-24 12:38:05 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-05-11 22:28:01 +00:00
|
|
|
Blocks::None
|
2015-01-24 12:38:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn user(&self) -> User {
|
|
|
|
User(self.stat.as_raw().uid())
|
2015-01-24 12:38:05 +00:00
|
|
|
}
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn group(&self) -> Group {
|
|
|
|
Group(self.stat.as_raw().gid())
|
2015-01-24 12:38:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This file's size, formatted using the given way, as a coloured string.
|
|
|
|
///
|
|
|
|
/// For directories, no size is given. Although they do have a size on
|
|
|
|
/// 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.
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn size(&self) -> Size {
|
2015-02-26 14:05:26 +00:00
|
|
|
if self.is_directory() {
|
2015-05-11 22:28:01 +00:00
|
|
|
Size::None
|
2014-11-25 20:50:23 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-05-11 22:28:01 +00:00
|
|
|
Size::Some(self.stat.len())
|
2014-05-25 14:52:36 +00:00
|
|
|
}
|
2014-05-04 20:33:14 +00:00
|
|
|
}
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn timestamp(&self, time_type: TimeType) -> Time {
|
2015-02-09 16:33:27 +00:00
|
|
|
let time_in_seconds = match time_type {
|
2015-05-03 15:25:53 +00:00
|
|
|
TimeType::FileAccessed => self.stat.as_raw().atime(),
|
|
|
|
TimeType::FileModified => self.stat.as_raw().mtime(),
|
|
|
|
TimeType::FileCreated => self.stat.as_raw().ctime(),
|
2015-05-11 22:28:01 +00:00
|
|
|
};
|
2015-02-09 18:14:05 +00:00
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
Time(time_in_seconds)
|
2015-02-09 16:33:27 +00:00
|
|
|
}
|
|
|
|
|
2015-01-24 12:38:05 +00:00
|
|
|
/// 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.
|
2015-05-11 22:28:01 +00:00
|
|
|
fn type_char(&self) -> Type {
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
if self.is_file() {
|
2015-05-11 22:28:01 +00:00
|
|
|
Type::File
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
}
|
|
|
|
else if self.is_directory() {
|
2015-05-11 22:28:01 +00:00
|
|
|
Type::Directory
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
}
|
|
|
|
else if self.is_pipe() {
|
2015-05-11 22:28:01 +00:00
|
|
|
Type::Pipe
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
}
|
|
|
|
else if self.is_link() {
|
2015-05-11 22:28:01 +00:00
|
|
|
Type::Link
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-05-11 22:28:01 +00:00
|
|
|
Type::Special
|
2014-05-04 20:33:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn permissions(&self) -> Permissions {
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
let bits = self.stat.permissions().mode();
|
2015-05-11 22:28:01 +00:00
|
|
|
let has_bit = |bit| { bits & bit == bit };
|
|
|
|
|
|
|
|
Permissions {
|
|
|
|
file_type: self.type_char(),
|
|
|
|
user_read: has_bit(unix::fs::USER_READ),
|
|
|
|
user_write: has_bit(unix::fs::USER_WRITE),
|
|
|
|
user_execute: has_bit(unix::fs::USER_EXECUTE),
|
|
|
|
group_read: has_bit(unix::fs::GROUP_READ),
|
|
|
|
group_write: has_bit(unix::fs::GROUP_WRITE),
|
|
|
|
group_execute: has_bit(unix::fs::GROUP_EXECUTE),
|
|
|
|
other_read: has_bit(unix::fs::OTHER_READ),
|
|
|
|
other_write: has_bit(unix::fs::OTHER_WRITE),
|
|
|
|
other_execute: has_bit(unix::fs::OTHER_EXECUTE),
|
|
|
|
attribute: !self.xattrs.is_empty()
|
2014-05-26 10:50:46 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-24 12:38:05 +00:00
|
|
|
|
|
|
|
/// For this file, return a vector of alternate file paths that, if any of
|
|
|
|
/// them exist, mean that *this* file should be coloured as `Compiled`.
|
|
|
|
///
|
|
|
|
/// The point of this is to highlight compiled files such as `foo.o` when
|
|
|
|
/// their source file `foo.c` exists in the same directory. It's too
|
|
|
|
/// dangerous to highlight *all* compiled, so the paths in this vector
|
|
|
|
/// are checked for existence first: for example, `foo.js` is perfectly
|
|
|
|
/// valid without `foo.coffee`.
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
pub fn get_source_files(&self) -> Vec<PathBuf> {
|
2015-01-24 12:38:05 +00:00
|
|
|
if let Some(ref ext) = self.ext {
|
2015-02-22 17:11:33 +00:00
|
|
|
match &ext[..] {
|
2015-01-24 12:38:05 +00:00
|
|
|
"class" => vec![self.path.with_extension("java")], // Java
|
|
|
|
"css" => vec![self.path.with_extension("sass"), self.path.with_extension("less")], // SASS, Less
|
|
|
|
"elc" => vec![self.path.with_extension("el")], // Emacs Lisp
|
|
|
|
"hi" => vec![self.path.with_extension("hs")], // Haskell
|
|
|
|
"js" => vec![self.path.with_extension("coffee"), self.path.with_extension("ts")], // CoffeeScript, TypeScript
|
|
|
|
"o" => vec![self.path.with_extension("c"), self.path.with_extension("cpp")], // C, C++
|
|
|
|
"pyc" => vec![self.path.with_extension("py")], // Python
|
|
|
|
|
|
|
|
"aux" => vec![self.path.with_extension("tex")], // TeX: auxiliary file
|
|
|
|
"bbl" => vec![self.path.with_extension("tex")], // BibTeX bibliography file
|
|
|
|
"blg" => vec![self.path.with_extension("tex")], // BibTeX log file
|
|
|
|
"lof" => vec![self.path.with_extension("tex")], // TeX list of figures
|
|
|
|
"log" => vec![self.path.with_extension("tex")], // TeX log file
|
|
|
|
"lot" => vec![self.path.with_extension("tex")], // TeX list of tables
|
|
|
|
"toc" => vec![self.path.with_extension("tex")], // TeX table of contents
|
|
|
|
|
|
|
|
_ => vec![], // No source files if none of the above
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
vec![] // No source files if there's no extension, either!
|
|
|
|
}
|
|
|
|
}
|
2015-01-27 15:01:17 +00:00
|
|
|
|
2015-05-09 15:10:26 +00:00
|
|
|
pub fn extension_is_one_of(&self, choices: &[&str]) -> bool {
|
|
|
|
match self.ext {
|
|
|
|
Some(ref ext) => choices.contains(&&ext[..]),
|
|
|
|
None => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn name_is_one_of(&self, choices: &[&str]) -> bool {
|
|
|
|
choices.contains(&&self.name[..])
|
|
|
|
}
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
pub fn git_status(&self) -> Git {
|
|
|
|
match self.dir {
|
|
|
|
None => Git { staged: GitStatus::NotModified, unstaged: GitStatus::NotModified },
|
2015-04-03 22:14:49 +00:00
|
|
|
Some(d) => {
|
|
|
|
let cwd = match current_dir() {
|
|
|
|
Err(_) => Path::new(".").join(&self.path),
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
Ok(dir) => dir.join(&self.path),
|
2015-04-03 22:14:49 +00:00
|
|
|
};
|
|
|
|
|
2015-05-11 22:28:01 +00:00
|
|
|
d.git_status(&cwd, self.is_directory())
|
2015-04-03 22:14:49 +00:00
|
|
|
},
|
2015-05-11 22:28:01 +00:00
|
|
|
}
|
2015-01-27 15:01:17 +00:00
|
|
|
}
|
2015-01-24 12:38:05 +00:00
|
|
|
}
|
|
|
|
|
2015-02-23 11:32:35 +00:00
|
|
|
/// Extract the filename to display from a path, converting it from UTF-8
|
|
|
|
/// lossily, into a String.
|
|
|
|
///
|
|
|
|
/// The filename to display is the last component of the path. However,
|
|
|
|
/// the path has no components for `.`, `..`, and `/`, so in these
|
|
|
|
/// cases, the entire path is used.
|
|
|
|
fn path_filename(path: &Path) -> String {
|
Use new io + path + fs libraries (LOTS OF CHANGES)
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.
Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.
As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.
Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
2015-04-23 12:00:34 +00:00
|
|
|
match path.iter().last() {
|
|
|
|
Some(os_str) => os_str.to_string_lossy().to_string(),
|
|
|
|
None => ".".to_string(), // can this even be reached?
|
|
|
|
}
|
2015-02-23 11:32:35 +00:00
|
|
|
}
|
|
|
|
|
2015-01-26 01:16:19 +00:00
|
|
|
/// Extract an extension from a string, if one is present, in lowercase.
|
2015-01-24 12:38:05 +00:00
|
|
|
///
|
|
|
|
/// The extension is the series of characters after the last dot. This
|
|
|
|
/// deliberately counts dotfiles, so the ".git" folder has the extension "git".
|
2015-01-26 01:16:19 +00:00
|
|
|
///
|
|
|
|
/// ASCII lowercasing is used because these extensions are only compared
|
|
|
|
/// against a pre-compiled list of extensions which are known to only exist
|
|
|
|
/// within ASCII, so it's alright.
|
2015-01-24 12:38:05 +00:00
|
|
|
fn ext<'a>(name: &'a str) -> Option<String> {
|
2015-01-26 01:16:19 +00:00
|
|
|
name.rfind('.').map(|p| name[p+1..].to_ascii_lowercase())
|
2014-05-04 20:33:14 +00:00
|
|
|
}
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-04-23 12:47:46 +00:00
|
|
|
#[cfg(broken_test)]
|
2015-01-26 01:16:19 +00:00
|
|
|
pub mod test {
|
2015-01-25 13:43:44 +00:00
|
|
|
pub use super::*;
|
2015-02-23 11:32:35 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
pub use column::{Cell, Column};
|
2015-02-23 11:32:35 +00:00
|
|
|
pub use output::details::UserLocale;
|
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
pub use users::{User, Group};
|
|
|
|
pub use users::mock::MockUsers;
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
pub use ansi_term::Style::Plain;
|
|
|
|
pub use ansi_term::Colour::Yellow;
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:47:07 +00:00
|
|
|
#[test]
|
|
|
|
fn extension() {
|
|
|
|
assert_eq!(Some("dat".to_string()), super::ext("fester.dat"))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dotfile() {
|
|
|
|
assert_eq!(Some("vimrc".to_string()), super::ext(".vimrc"))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn no_extension() {
|
|
|
|
assert_eq!(None, super::ext("jarlsberg"))
|
|
|
|
}
|
|
|
|
|
2015-02-04 01:12:08 +00:00
|
|
|
pub fn new_file(stat: io::FileStat, path: &'static str) -> File {
|
|
|
|
File::with_stat(stat, &Path::new(path), None, false)
|
|
|
|
}
|
|
|
|
|
2015-02-13 21:24:29 +00:00
|
|
|
pub fn dummy_stat() -> io::FileStat {
|
|
|
|
io::FileStat {
|
2015-01-25 13:04:15 +00:00
|
|
|
size: 0,
|
|
|
|
kind: io::FileType::RegularFile,
|
|
|
|
created: 0,
|
|
|
|
modified: 0,
|
|
|
|
accessed: 0,
|
|
|
|
perm: io::USER_READ,
|
|
|
|
unstable: io::UnstableFileStat {
|
|
|
|
inode: 0,
|
|
|
|
device: 0,
|
|
|
|
rdev: 0,
|
|
|
|
nlink: 0,
|
|
|
|
uid: 0,
|
|
|
|
gid: 0,
|
|
|
|
blksize: 0,
|
|
|
|
blocks: 0,
|
|
|
|
flags: 0,
|
|
|
|
gen: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-10 18:14:56 +00:00
|
|
|
pub fn dummy_locale() -> UserLocale {
|
|
|
|
UserLocale::default()
|
2015-02-10 16:42:25 +00:00
|
|
|
}
|
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
mod users {
|
|
|
|
use super::*;
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
#[test]
|
|
|
|
fn named() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.uid = 1000;
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-02-04 01:12:08 +00:00
|
|
|
let file = new_file(stat, "/hi");
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
let mut users = MockUsers::with_current_uid(1000);
|
|
|
|
users.add_user(User { uid: 1000, name: "enoch".to_string(), primary_group: 100 });
|
|
|
|
|
|
|
|
let cell = Cell::paint(Yellow.bold(), "enoch");
|
2015-02-10 16:42:25 +00:00
|
|
|
assert_eq!(cell, file.display(&Column::User, &mut users, &dummy_locale()))
|
2015-01-25 13:43:44 +00:00
|
|
|
}
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
#[test]
|
|
|
|
fn unnamed() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.uid = 1000;
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-02-04 01:12:08 +00:00
|
|
|
let file = new_file(stat, "/hi");
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
let mut users = MockUsers::with_current_uid(1000);
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
let cell = Cell::paint(Yellow.bold(), "1000");
|
2015-02-10 16:42:25 +00:00
|
|
|
assert_eq!(cell, file.display(&Column::User, &mut users, &dummy_locale()))
|
2015-01-25 13:43:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn different_named() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.uid = 1000;
|
|
|
|
|
2015-02-04 01:12:08 +00:00
|
|
|
let file = new_file(stat, "/hi");
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
let mut users = MockUsers::with_current_uid(3);
|
|
|
|
users.add_user(User { uid: 1000, name: "enoch".to_string(), primary_group: 100 });
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
let cell = Cell::paint(Plain, "enoch");
|
2015-02-10 16:42:25 +00:00
|
|
|
assert_eq!(cell, file.display(&Column::User, &mut users, &dummy_locale()))
|
2015-01-25 13:43:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn different_unnamed() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.uid = 1000;
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-02-04 01:12:08 +00:00
|
|
|
let file = new_file(stat, "/hi");
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
let mut users = MockUsers::with_current_uid(3);
|
|
|
|
|
|
|
|
let cell = Cell::paint(Plain, "1000");
|
2015-02-10 16:42:25 +00:00
|
|
|
assert_eq!(cell, file.display(&Column::User, &mut users, &dummy_locale()))
|
2015-01-25 13:43:44 +00:00
|
|
|
}
|
2015-02-23 13:37:59 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn overflow() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.uid = 2_147_483_648;
|
|
|
|
|
|
|
|
let file = new_file(stat, "/hi");
|
|
|
|
|
|
|
|
let mut users = MockUsers::with_current_uid(3);
|
|
|
|
|
|
|
|
let cell = Cell::paint(Plain, "2147483648");
|
|
|
|
assert_eq!(cell, file.display(&Column::User, &mut users, &dummy_locale()))
|
|
|
|
}
|
2015-01-25 13:04:15 +00:00
|
|
|
}
|
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
mod groups {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn named() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.gid = 100;
|
|
|
|
|
2015-02-04 01:12:08 +00:00
|
|
|
let file = new_file(stat, "/hi");
|
2015-01-25 13:43:44 +00:00
|
|
|
|
|
|
|
let mut users = MockUsers::with_current_uid(3);
|
|
|
|
users.add_group(Group { gid: 100, name: "folk".to_string(), members: vec![] });
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
let cell = Cell::paint(Plain, "folk");
|
2015-02-10 16:42:25 +00:00
|
|
|
assert_eq!(cell, file.display(&Column::Group, &mut users, &dummy_locale()))
|
2015-01-25 13:43:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn unnamed() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.gid = 100;
|
|
|
|
|
2015-02-04 01:12:08 +00:00
|
|
|
let file = new_file(stat, "/hi");
|
2015-01-25 13:43:44 +00:00
|
|
|
|
|
|
|
let mut users = MockUsers::with_current_uid(3);
|
|
|
|
|
|
|
|
let cell = Cell::paint(Plain, "100");
|
2015-02-10 16:42:25 +00:00
|
|
|
assert_eq!(cell, file.display(&Column::Group, &mut users, &dummy_locale()))
|
2015-01-25 13:43:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn primary() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.gid = 100;
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-02-04 01:12:08 +00:00
|
|
|
let file = new_file(stat, "/hi");
|
2015-01-25 13:04:15 +00:00
|
|
|
|
2015-01-25 13:43:44 +00:00
|
|
|
let mut users = MockUsers::with_current_uid(3);
|
|
|
|
users.add_user(User { uid: 3, name: "eve".to_string(), primary_group: 100 });
|
|
|
|
users.add_group(Group { gid: 100, name: "folk".to_string(), members: vec![] });
|
|
|
|
|
|
|
|
let cell = Cell::paint(Yellow.bold(), "folk");
|
2015-02-10 16:42:25 +00:00
|
|
|
assert_eq!(cell, file.display(&Column::Group, &mut users, &dummy_locale()))
|
2015-01-25 13:43:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn secondary() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.gid = 100;
|
|
|
|
|
2015-02-04 01:12:08 +00:00
|
|
|
let file = new_file(stat, "/hi");
|
2015-01-25 13:43:44 +00:00
|
|
|
|
|
|
|
let mut users = MockUsers::with_current_uid(3);
|
|
|
|
users.add_user(User { uid: 3, name: "eve".to_string(), primary_group: 12 });
|
|
|
|
users.add_group(Group { gid: 100, name: "folk".to_string(), members: vec![ "eve".to_string() ] });
|
|
|
|
|
|
|
|
let cell = Cell::paint(Yellow.bold(), "folk");
|
2015-02-10 16:42:25 +00:00
|
|
|
assert_eq!(cell, file.display(&Column::Group, &mut users, &dummy_locale()))
|
2015-01-25 13:43:44 +00:00
|
|
|
}
|
2015-02-23 13:37:59 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn overflow() {
|
|
|
|
let mut stat = dummy_stat();
|
|
|
|
stat.unstable.gid = 2_147_483_648;
|
|
|
|
|
|
|
|
let file = new_file(stat, "/hi");
|
|
|
|
|
|
|
|
let mut users = MockUsers::with_current_uid(3);
|
|
|
|
|
|
|
|
let cell = Cell::paint(Plain, "2147483648");
|
|
|
|
assert_eq!(cell, file.display(&Column::Group, &mut users, &dummy_locale()))
|
|
|
|
}
|
2015-01-25 13:04:15 +00:00
|
|
|
}
|
|
|
|
}
|