Sfoglia il codice sorgente

Move all optional features into features module

This module provides feature-specific implementations, and also dummy implementations for when they aren't supported by the system or OS.

Doing it this way limits all the #[cfg(feature)] annotations, as we can now just include the module or not.
Ben S 11 anni fa
parent
commit
2ffa64cff6
11 ha cambiato i file con 195 aggiunte e 192 eliminazioni
  1. 6 105
      src/dir.rs
  2. 85 0
      src/feature/git.rs
  3. 62 0
      src/feature/mod.rs
  4. 15 14
      src/feature/xattr_darwin.rs
  5. 15 15
      src/feature/xattr_linux.rs
  6. 4 5
      src/file.rs
  7. 1 1
      src/main.rs
  8. 6 6
      src/options.rs
  9. 1 1
      src/output/details.rs
  10. 0 13
      src/xattr/mod.rs
  11. 0 32
      src/xattr/xattr_other.rs

+ 6 - 105
src/dir.rs

@@ -1,11 +1,9 @@
 use std::old_io::{fs, IoResult};
 use std::old_path::GenericPath;
 use std::old_path::posix::Path;
-use file::{File, GREY};
 
-#[cfg(feature="git")] use ansi_term::{ANSIString, ANSIStrings};
-#[cfg(feature="git")] use ansi_term::Colour::*;
-#[cfg(feature="git")] use git2;
+use feature::Git;
+use file::{File, GREY};
 
 /// A **Dir** provides a cached list of the file paths in a directory that's
 /// being listed.
@@ -20,6 +18,7 @@ pub struct Dir {
 }
 
 impl Dir {
+
     /// 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.
@@ -67,107 +66,9 @@ impl Dir {
     /// Get a string describing the Git status of the given file.
     pub fn git_status(&self, path: &Path, prefix_lookup: bool) -> String {
         match (&self.git, prefix_lookup) {
-            (&Some(ref git), false) => git.status(path),
-            (&Some(ref git), true)  => git.dir_status(path),
-            (&None, _)              => GREY.paint("--").to_string(),
-        }
-    }
-}
-
-/// Container of Git statuses for all the files in this folder's Git repository.
-#[cfg(feature="git")]
-struct Git {
-    statuses: Vec<(Path, git2::Status)>,
-}
-
-#[cfg(feature="git")]
-impl Git {
-
-    /// Discover a Git repository on or above this directory, scanning it for
-    /// the files' statuses if one is found.
-    fn scan(path: &Path) -> Result<Git, git2::Error> {
-        use std::os::unix::ffi::OsStrExt;
-        use std::ffi::AsOsStr;
-
-        // TODO: libgit2-rs uses the new Path module, but exa still uses the
-        // old_path one, and will have to continue to do so until the new IO
-        // module gets a bit more developed. So we have to turn Paths into
-        // old_path::Paths. Yes, this is hacky, but hopefully temporary.
-        let repo = try!(git2::Repository::discover(path));
-        let workdir = match repo.workdir() {
-            Some(w) => Path::new(w.as_os_str().as_bytes()),
-            None => return Ok(Git { statuses: vec![] }),  // bare repo
-        };
-
-        let statuses = try!(repo.statuses(None)).iter()
-                                                .map(|e| (workdir.join(e.path_bytes()), e.status()))
-                                                .collect();
-        Ok(Git { statuses: statuses })
-    }
-
-    /// Get the status for the file at the given path, if present.
-    fn status(&self, path: &Path) -> String {
-        let status = self.statuses.iter()
-                                  .find(|p| &p.0 == path);
-        match status {
-            Some(&(_, s)) => ANSIStrings( &[Git::index_status(s), Git::working_tree_status(s) ]).to_string(),
-            None => GREY.paint("--").to_string(),
+            (&Some(ref git), false)  => git.status(path),
+            (&Some(ref git), true)   => git.dir_status(path),
+            (&None, _)               => GREY.paint("--").to_string(),
         }
     }
-
-    /// 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.
-    fn dir_status(&self, dir: &Path) -> String {
-        let s = self.statuses.iter()
-                             .filter(|p| dir.is_ancestor_of(&p.0))
-                             .fold(git2::Status::empty(), |a, b| a | b.1);
-
-        ANSIStrings( &[Git::index_status(s), Git::working_tree_status(s)] ).to_string()
-    }
-
-    /// The character to display if the file has been modified, but not staged.
-    fn working_tree_status(status: git2::Status) -> ANSIString<'static> {
-        match status {
-            s if s.contains(git2::STATUS_WT_NEW) => Green.paint("A"),
-            s if s.contains(git2::STATUS_WT_MODIFIED) => Blue.paint("M"),
-            s if s.contains(git2::STATUS_WT_DELETED) => Red.paint("D"),
-            s if s.contains(git2::STATUS_WT_RENAMED) => Yellow.paint("R"),
-            s if s.contains(git2::STATUS_WT_TYPECHANGE) => Purple.paint("T"),
-            _ => GREY.paint("-"),
-        }
-    }
-
-    /// The character to display if the file has been modified, and the change
-    /// has been staged.
-    fn index_status(status: git2::Status) -> ANSIString<'static> {
-        match status {
-            s if s.contains(git2::STATUS_INDEX_NEW) => Green.paint("A"),
-            s if s.contains(git2::STATUS_INDEX_MODIFIED) => Blue.paint("M"),
-            s if s.contains(git2::STATUS_INDEX_DELETED) => Red.paint("D"),
-            s if s.contains(git2::STATUS_INDEX_RENAMED) => Yellow.paint("R"),
-            s if s.contains(git2::STATUS_INDEX_TYPECHANGE) => Purple.paint("T"),
-            _ => GREY.paint("-"),
-        }
-    }
-}
-
-#[cfg(not(feature="git"))]
-struct Git;
-
-#[cfg(not(feature="git"))]
-impl Git {
-    fn scan(_: &Path) -> Result<Git, ()> {
-        // Don't do anything without Git support
-        Err(())
-    }
-
-    fn status(&self, _: &Path) -> String {
-        // The Err above means that this should never happen
-        panic!("Tried to access a Git repo without Git support!");
-    }
-
-    fn dir_status(&self, path: &Path) -> String {
-        self.status(path)
-    }
 }

+ 85 - 0
src/feature/git.rs

@@ -0,0 +1,85 @@
+use std::old_path::GenericPath;
+use std::old_path::posix::Path;
+
+use ansi_term::{ANSIString, ANSIStrings};
+use ansi_term::Colour::*;
+use git2;
+
+use file::GREY;
+
+/// Container of Git statuses for all the files in this folder's Git repository.
+pub struct Git {
+    statuses: Vec<(Path, git2::Status)>,
+}
+
+impl Git {
+
+    /// Discover a Git repository on or above this directory, scanning it for
+    /// the files' statuses if one is found.
+    pub fn scan(path: &Path) -> Result<Git, git2::Error> {
+        use std::os::unix::ffi::OsStrExt;
+        use std::ffi::AsOsStr;
+
+        // TODO: libgit2-rs uses the new Path module, but exa still uses the
+        // old_path one, and will have to continue to do so until the new IO
+        // module gets a bit more developed. So we have to turn Paths into
+        // old_path::Paths. Yes, this is hacky, but hopefully temporary.
+        let new_path = path.as_os_str();
+        let repo = try!(git2::Repository::discover(new_path));
+        let workdir = match repo.workdir() {
+            Some(w) => Path::new(w.as_os_str().as_bytes()),
+            None => return Ok(Git { statuses: vec![] }),  // bare repo
+        };
+
+        let statuses = try!(repo.statuses(None)).iter()
+                                                .map(|e| (workdir.join(e.path_bytes()), e.status()))
+                                                .collect();
+        Ok(Git { statuses: statuses })
+    }
+
+    /// Get the status for the file at the given path, if present.
+    pub fn status(&self, path: &Path) -> String {
+        let status = self.statuses.iter()
+                                  .find(|p| &p.0 == path);
+        match status {
+            Some(&(_, s)) => ANSIStrings( &[Git::index_status(s), Git::working_tree_status(s) ]).to_string(),
+            None => GREY.paint("--").to_string(),
+        }
+    }
+
+    /// 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) -> String {
+        let s = self.statuses.iter()
+                             .filter(|p| dir.is_ancestor_of(&p.0))
+                             .fold(git2::Status::empty(), |a, b| a | b.1);
+
+        ANSIStrings( &[Git::index_status(s), Git::working_tree_status(s)] ).to_string()
+    }
+
+    /// The character to display if the file has been modified, but not staged.
+    fn working_tree_status(status: git2::Status) -> ANSIString<'static> {
+        match status {
+            s if s.contains(git2::STATUS_WT_NEW) => Green.paint("A"),
+            s if s.contains(git2::STATUS_WT_MODIFIED) => Blue.paint("M"),
+            s if s.contains(git2::STATUS_WT_DELETED) => Red.paint("D"),
+            s if s.contains(git2::STATUS_WT_RENAMED) => Yellow.paint("R"),
+            s if s.contains(git2::STATUS_WT_TYPECHANGE) => Purple.paint("T"),
+            _ => GREY.paint("-"),
+        }
+    }
+
+    /// The character to display if the file has been modified, and the change
+    /// has been staged.
+    fn index_status(status: git2::Status) -> ANSIString<'static> {
+        match status {
+            s if s.contains(git2::STATUS_INDEX_NEW) => Green.paint("A"),
+            s if s.contains(git2::STATUS_INDEX_MODIFIED) => Blue.paint("M"),
+            s if s.contains(git2::STATUS_INDEX_DELETED) => Red.paint("D"),
+            s if s.contains(git2::STATUS_INDEX_RENAMED) => Yellow.paint("R"),
+            s if s.contains(git2::STATUS_INDEX_TYPECHANGE) => Purple.paint("T"),
+            _ => GREY.paint("-"),
+        }
+    }
+}

+ 62 - 0
src/feature/mod.rs

@@ -0,0 +1,62 @@
+// Extended attribute support
+
+#[cfg(target_os = "macos")] mod xattr_darwin;
+#[cfg(target_os = "macos")] pub use self::xattr_darwin::Attribute;
+
+#[cfg(target_os = "linux")] mod xattr_linux;
+#[cfg(target_os = "linux")] pub use self::xattr_linux::Attribute;
+
+#[cfg(not(any(target_os = "macos", target_os = "linux")))] use std::old_io as io;
+#[cfg(not(any(target_os = "macos", target_os = "linux")))]
+#[derive(Clone)]
+pub struct Attribute;
+
+#[cfg(not(any(target_os = "macos", target_os = "linux")))]
+impl Attribute {
+
+    /// Getter for name
+    pub fn name(&self) -> &str {
+        unimplemented!()
+    }
+
+    /// Getter for size
+    pub fn size(&self) -> usize {
+        unimplemented!()
+    }
+
+    /// Lists the extended attributes. Follows symlinks like `stat`
+    pub fn list(_: &Path) -> io::IoResult<Vec<Attribute>> {
+        Ok(Vec::new())
+    }
+
+    /// Lists the extended attributes. Does not follow symlinks like `lstat`
+    pub fn llist(_: &Path) -> io::IoResult<Vec<Attribute>> {
+        Ok(Vec::new())
+    }
+
+    pub fn feature_implemented() -> bool { false }
+}
+
+
+
+// Git support
+
+#[cfg(feature="git")] mod git;
+#[cfg(feature="git")] pub use self::git::Git;
+
+#[cfg(not(feature="git"))] pub struct Git;
+#[cfg(not(feature="git"))] use std::old_path::posix::Path;
+#[cfg(not(feature="git"))]
+impl Git {
+    pub fn scan(_: &Path) -> Result<Git, ()> {
+        Err(())
+    }
+
+    pub fn status(&self, _: &Path) -> String {
+        panic!("Tried to access a Git repo without Git support!");
+    }
+
+    pub fn dir_status(&self, path: &Path) -> String {
+        self.status(path)
+    }
+}

+ 15 - 14
src/xattr/xattr_darwin.rs → src/feature/xattr_darwin.rs

@@ -41,7 +41,7 @@ pub struct Attribute {
 impl Attribute {
     /// Lists the extended attribute of `path`.
     /// Does follow symlinks by default.
-    pub fn list(path: &Path, flags: &[ListFlags]) -> io::IoResult<Vec<Attribute>> {
+    pub fn list_attrs(path: &Path, flags: &[ListFlags]) -> io::IoResult<Vec<Attribute>> {
         let mut c_flags: c_int = 0;
         for &flag in flags.iter() {
             c_flags |= flag as c_int
@@ -112,19 +112,20 @@ impl Attribute {
     pub fn size(&self) -> usize {
         self.size
     }
-}
 
-/// Lists the extended attributes.
-/// Follows symlinks like `stat`
-pub fn list(path: &Path) -> io::IoResult<Vec<Attribute>> {
-    Attribute::list(path, &[])
-}
-/// Lists the extended attributes.
-/// Does not follow symlinks like `lstat`
-pub fn llist(path: &Path) -> io::IoResult<Vec<Attribute>> {
-    Attribute::list(path, &[ListFlags::NoFollow])
+    /// Lists the extended attributes.
+    /// Follows symlinks like `stat`
+    pub fn list(path: &Path) -> io::IoResult<Vec<Attribute>> {
+        Attribute::list_attrs(path, &[])
+    }
+    /// Lists the extended attributes.
+    /// Does not follow symlinks like `lstat`
+    pub fn llist(path: &Path) -> io::IoResult<Vec<Attribute>> {
+        Attribute::list_attrs(path, &[ListFlags::NoFollow])
+    }
+
+    /// Returns true if the extended attribute feature is implemented on this platform.
+    #[inline(always)]
+    pub fn feature_implemented() -> bool { true }
 }
 
-/// Returns true if the extended attribute feature is implemented on this platform.
-#[inline(always)]
-pub fn feature_implemented() -> bool { true }

+ 15 - 15
src/xattr/xattr_linux.rs → src/feature/xattr_linux.rs

@@ -36,7 +36,7 @@ pub struct Attribute {
 impl Attribute {
     /// Lists the extended attribute of `path`.
     /// Does follow symlinks by default.
-    pub fn list(path: &Path, do_follow: FollowSymlinks) -> io::IoResult<Vec<Attribute>> {
+    pub fn list_attrs(path: &Path, do_follow: FollowSymlinks) -> io::IoResult<Vec<Attribute>> {
         let (listxattr, getxattr) = match do_follow {
             FollowSymlinks::Yes => (listxattr, getxattr),
             FollowSymlinks::No => (llistxattr, lgetxattr),
@@ -103,19 +103,19 @@ impl Attribute {
     pub fn size(&self) -> usize {
         self.size
     }
-}
 
-/// Lists the extended attributes.
-/// Follows symlinks like `stat`
-pub fn list(path: &Path) -> io::IoResult<Vec<Attribute>> {
-    Attribute::list(path, FollowSymlinks::Yes)
-}
-/// Lists the extended attributes.
-/// Does not follow symlinks like `lstat`
-pub fn llist(path: &Path) -> io::IoResult<Vec<Attribute>> {
-    Attribute::list(path, FollowSymlinks::No)
-}
+    /// Lists the extended attributes.
+    /// Follows symlinks like `stat`
+    pub fn list(path: &Path) -> io::IoResult<Vec<Attribute>> {
+        Attribute::list_attrs(path, FollowSymlinks::Yes)
+    }
+    /// Lists the extended attributes.
+    /// Does not follow symlinks like `lstat`
+    pub fn llist(path: &Path) -> io::IoResult<Vec<Attribute>> {
+        Attribute::list_attrs(path, FollowSymlinks::No)
+    }
 
-/// Returns true if the extended attribute feature is implemented on this platform.
-#[inline(always)]
-pub fn feature_implemented() -> bool { true }
+    /// Returns true if the extended attribute feature is implemented on this platform.
+    #[inline(always)]
+    pub fn feature_implemented() -> bool { true }
+}

+ 4 - 5
src/file.rs

@@ -31,11 +31,10 @@ use column::Column::*;
 use dir::Dir;
 use filetype::HasType;
 use options::{SizeFormat, TimeType};
-use xattr;
-use xattr::Attribute;
+use feature::Attribute;
 
 /// This grey value is directly in between white and black, so it's guaranteed
-/// to show up on either backgrounded terminal.
+/// to show up on either backg"#160909"rounded terminal.
 pub static GREY: Colour = Fixed(244);
 
 /// A **File** is a wrapper around one of Rust's Path objects, along with
@@ -83,7 +82,7 @@ impl<'a> File<'a> {
             dir:    parent,
             stat:   stat,
             ext:    ext(&filename),
-            xattrs: xattr::llist(path).unwrap_or(Vec::new()),
+            xattrs: Attribute::llist(path).unwrap_or(Vec::new()),
             name:   filename.to_string(),
             this:   this,
         }
@@ -227,7 +226,7 @@ impl<'a> File<'a> {
                 dir:    self.dir,
                 stat:   stat,
                 ext:    ext(&filename),
-                xattrs: xattr::list(target_path).unwrap_or(Vec::new()),
+                xattrs: Attribute::list(target_path).unwrap_or(Vec::new()),
                 name:   filename.to_string(),
                 this:   None,
             })

+ 1 - 1
src/main.rs

@@ -33,12 +33,12 @@ use output::lines_view;
 
 pub mod column;
 pub mod dir;
+pub mod feature;
 pub mod file;
 pub mod filetype;
 pub mod options;
 pub mod output;
 pub mod term;
-pub mod xattr;
 
 #[cfg(not(test))]
 struct Exa<'a> {

+ 6 - 6
src/options.rs

@@ -2,9 +2,9 @@ use dir::Dir;
 use file::File;
 use column::Column;
 use column::Column::*;
+use feature::Attribute;
 use output::{Grid, Details};
 use term::dimensions;
-use xattr;
 
 use std::cmp::Ordering;
 use std::fmt;
@@ -76,7 +76,7 @@ impl Options {
             opts.optflag("", "git", "show git status");
         }
 
-        if xattr::feature_implemented() {
+        if Attribute::feature_implemented() {
             opts.optflag("@", "extended", "display extended attribute keys and sizes in long (-l) output");
         }
 
@@ -255,7 +255,7 @@ impl View {
                         columns: try!(Columns::deduce(matches)),
                         header: matches.opt_present("header"),
                         recurse: dir_action.recurse_options().map(|o| (o, filter)),
-                        xattr: xattr::feature_implemented() && matches.opt_present("extended"),
+                        xattr: Attribute::feature_implemented() && matches.opt_present("extended"),
                 };
 
                 Ok(View::Details(details))
@@ -294,7 +294,7 @@ impl View {
         else if matches.opt_present("level") && !matches.opt_present("recurse") {
             Err(Misfire::Useless2("level", "recurse", "tree"))
         }
-        else if xattr::feature_implemented() && matches.opt_present("extended") {
+        else if Attribute::feature_implemented() && matches.opt_present("extended") {
             Err(Misfire::Useless("extended", false, "long"))
         }
         else if matches.opt_present("oneline") {
@@ -572,7 +572,7 @@ mod test {
     use super::Options;
     use super::Misfire;
     use super::Misfire::*;
-    use xattr;
+    use feature::Attribute;
 
     fn is_helpful<T>(misfire: Result<T, Misfire>) -> bool {
         match misfire {
@@ -674,7 +674,7 @@ mod test {
 
     #[test]
     fn extended_without_long() {
-        if xattr::feature_implemented() {
+        if Attribute::feature_implemented() {
             let opts = Options::getopts(&[ "--extended".to_string() ]);
             assert_eq!(opts.unwrap_err(), Misfire::Useless("extended", false, "long"))
         }

+ 1 - 1
src/output/details.rs

@@ -1,5 +1,5 @@
 use column::{Alignment, Column, Cell};
-use xattr::Attribute;
+use feature::Attribute;
 use dir::Dir;
 use file::{File, GREY};
 use options::{Columns, FileFilter, RecurseOptions};

+ 0 - 13
src/xattr/mod.rs

@@ -1,13 +0,0 @@
-//! Extended attribute support
-#[cfg(target_os = "macos")]
-mod xattr_darwin;
-#[cfg(target_os = "macos")]
-pub use self::xattr_darwin::*;
-#[cfg(target_os = "linux")]
-mod xattr_linux;
-#[cfg(target_os = "linux")]
-pub use self::xattr_linux::*;
-#[cfg(not(any(target_os = "macos", target_os = "linux")))]
-mod xattr_other;
-#[cfg(not(any(target_os = "macos", target_os = "linux")))]
-pub use self::xattr_other::*;

+ 0 - 32
src/xattr/xattr_other.rs

@@ -1,32 +0,0 @@
-//! Extended attribute support for other os
-use std::old_io as io;
-
-/// Extended attribute
-#[derive(Clone)]
-pub struct Attribute;
-
-impl Attribute {
-    
-    /// Getter for name
-    pub fn name(&self) -> &str {
-        unimplemented!()
-    }
-
-    /// Getter for size
-    pub fn size(&self) -> usize {
-        unimplemented!()
-    }
-}
-
-/// Lists the extended attributes. Follows symlinks like `stat`
-pub fn list(_: &Path) -> io::IoResult<Vec<Attribute>> {
-    Ok(Vec::new())
-}
-/// Lists the extended attributes. Does not follow symlinks like `lstat`
-pub fn llist(_: &Path) -> io::IoResult<Vec<Attribute>> {
-    Ok(Vec::new())
-}
-
-/// Returns true if the extended attribute feature is implemented on this platform.
-#[inline(always)]
-pub fn feature_implemented() -> bool { false }