Explorar o código

Merge pull request #85 from skade/move-to-stable

Move to stable
Benjamin Sago %!s(int64=10) %!d(string=hai) anos
pai
achega
caf5fce1e8
Modificáronse 6 ficheiros con 90 adicións e 29 borrados
  1. 4 1
      .travis.yml
  2. 2 3
      README.md
  3. 2 2
      src/feature/xattr.rs
  4. 71 18
      src/file.rs
  5. 0 3
      src/main.rs
  6. 11 2
      src/output/details.rs

+ 4 - 1
.travis.yml

@@ -4,5 +4,8 @@ before_install:
   - sudo apt-get install cmake
 sudo: true
 language: rust
-rust: nightly
+rust:
+  - nightly
+  - beta
+  - stable
 

+ 2 - 3
README.md

@@ -2,8 +2,7 @@
 
 [exa](http://bsago.me/exa) is a replacement for `ls` written in Rust.
 
-**You'll have to use the Rust 1.6.0 nightly, rather than stable (1.4) or beta (1.5). Sorry about that.**
-
+Works on all recent Rust versions >= 1.4.0.
 
 ## Screenshot
 
@@ -52,6 +51,6 @@ You can sort by **name**, **size**, **ext**, **inode**, **modified**, **created*
 
 ## Installation
 
-exa is written in [Rust](http://www.rust-lang.org). You'll have to use the nightly -- I try to keep it up to date with the latest version when possible.  Once you have it set up, a simple `make install` will compile exa and install it into `/usr/local/bin`.
+exa is written in [Rust](http://www.rust-lang.org). Once you have it set up, a simple `make install` will compile exa and install it into `/usr/local/bin`.
 
 exa depends on [libgit2](https://github.com/alexcrichton/git2-rs) for certain features. If you're unable to compile libgit2, you can opt out of Git support by passing `--no-default-features` to Cargo.

+ 2 - 2
src/feature/xattr.rs

@@ -3,7 +3,7 @@ extern crate libc;
 
 use std::io;
 use std::path::Path;
-
+use std::ffi::CString;
 
 pub const ENABLED: bool = cfg!(feature="git") && cfg!(any(target_os="macos", target_os="linux"));
 
@@ -51,7 +51,7 @@ pub struct Attribute {
 
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 pub fn list_attrs(lister: lister::Lister, path: &Path) -> io::Result<Vec<Attribute>> {
-    let c_path = match path.as_os_str().to_cstring() {
+    let c_path = match path.to_str().and_then(|s| { CString::new(s).ok() }) {
         Some(cstring) => cstring,
         None => return Err(io::Error::new(io::ErrorKind::Other, "Error: path somehow contained a NUL?")),
     };

+ 71 - 18
src/file.rs

@@ -4,7 +4,6 @@ use std::ascii::AsciiExt;
 use std::env::current_dir;
 use std::fs;
 use std::io;
-use std::os::unix;
 use std::os::unix::fs::{MetadataExt, PermissionsExt};
 use std::path::{Component, Path, PathBuf};
 
@@ -15,6 +14,35 @@ use options::TimeType;
 
 use self::fields as f;
 
+// Constant table copied from https://doc.rust-lang.org/src/std/sys/unix/ext/fs.rs.html#11-259
+// which is currently unstable and lacks vision for stabilization,
+// see https://github.com/rust-lang/rust/issues/27712
+
+#[allow(dead_code)]
+mod modes {
+    use std::os::unix::raw;
+
+    pub const USER_READ: raw::mode_t = 0o400;
+    pub const USER_WRITE: raw::mode_t = 0o200;
+    pub const USER_EXECUTE: raw::mode_t = 0o100;
+    pub const USER_RWX: raw::mode_t = 0o700;
+    pub const GROUP_READ: raw::mode_t = 0o040;
+    pub const GROUP_WRITE: raw::mode_t = 0o020;
+    pub const GROUP_EXECUTE: raw::mode_t = 0o010;
+    pub const GROUP_RWX: raw::mode_t = 0o070;
+    pub const OTHER_READ: raw::mode_t = 0o004;
+    pub const OTHER_WRITE: raw::mode_t = 0o002;
+    pub const OTHER_EXECUTE: raw::mode_t = 0o001;
+    pub const OTHER_RWX: raw::mode_t = 0o007;
+    pub const ALL_READ: raw::mode_t = 0o444;
+    pub const ALL_WRITE: raw::mode_t = 0o222;
+    pub const ALL_EXECUTE: raw::mode_t = 0o111;
+    pub const ALL_RWX: raw::mode_t = 0o777;
+    pub const SETUID: raw::mode_t = 0o4000;
+    pub const SETGID: raw::mode_t = 0o2000;
+    pub const STICKY_BIT: raw::mode_t = 0o1000;
+}
+
 
 /// A **File** is a wrapper around one of Rust's Path objects, along with
 /// associated data about the file.
@@ -104,7 +132,7 @@ impl<'dir> File<'dir> {
     /// current user. Executable files have different semantics than
     /// executable directories, and so should be highlighted differently.
     pub fn is_executable_file(&self) -> bool {
-        let bit = unix::fs::USER_EXECUTE;
+        let bit = modes::USER_EXECUTE;
         self.is_file() && (self.metadata.permissions().mode() & bit) == bit
     }
 
@@ -141,16 +169,15 @@ impl<'dir> File<'dir> {
         let components: Vec<Component> = self.path.components().collect();
         let mut path_prefix = String::new();
 
-        if let Some((_, components_init)) = components.split_last() {
-            for component in components_init.iter() {
-                path_prefix.push_str(&*component.as_os_str().to_string_lossy());
+        // This slicing is safe as components always has the RootComponent
+        // as the first element.
+        for component in components[..(components.len() - 1)].iter() {
+            path_prefix.push_str(&*component.as_os_str().to_string_lossy());
 
-                if component != &Component::RootDir {
-                    path_prefix.push_str("/");
-                }
+            if component != &Component::RootDir {
+                path_prefix.push_str("/");
             }
         }
-
         path_prefix
     }
 
@@ -299,15 +326,15 @@ impl<'dir> File<'dir> {
 
         f::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),
+            user_read:      has_bit(modes::USER_READ),
+            user_write:     has_bit(modes::USER_WRITE),
+            user_execute:   has_bit(modes::USER_EXECUTE),
+            group_read:     has_bit(modes::GROUP_READ),
+            group_write:    has_bit(modes::GROUP_WRITE),
+            group_execute:  has_bit(modes::GROUP_EXECUTE),
+            other_read:     has_bit(modes::OTHER_READ),
+            other_write:    has_bit(modes::OTHER_WRITE),
+            other_execute:  has_bit(modes::OTHER_EXECUTE),
         }
     }
 
@@ -483,6 +510,8 @@ pub mod fields {
 #[cfg(test)]
 mod test {
     use super::ext;
+    use super::File;
+    use std::path::Path;
 
     #[test]
     fn extension() {
@@ -498,4 +527,28 @@ mod test {
     fn no_extension() {
         assert_eq!(None, ext("jarlsberg"))
     }
+
+    #[test]
+    fn test_prefix_empty() {
+        let f = File::from_path(Path::new("Cargo.toml"), None).unwrap();
+        assert_eq!("", f.path_prefix());
+    }
+
+    #[test]
+    fn test_prefix_file() {
+        let f = File::from_path(Path::new("src/main.rs"), None).unwrap();
+        assert_eq!("src/", f.path_prefix());
+    }
+
+    #[test]
+    fn test_prefix_path() {
+        let f = File::from_path(Path::new("src"), None).unwrap();
+        assert_eq!("", f.path_prefix());
+    }
+
+    #[test]
+    fn test_prefix_root() {
+        let f = File::from_path(Path::new("/"), None).unwrap();
+        assert_eq!("", f.path_prefix());
+    }
 }

+ 0 - 3
src/main.rs

@@ -1,6 +1,3 @@
-#![feature(iter_arith)]
-#![feature(convert, fs_mode)]
-
 #![warn(trivial_casts, trivial_numeric_casts)]
 #![warn(unused_extern_crates, unused_qualifications)]
 #![warn(unused_results)]

+ 11 - 2
src/output/details.rs

@@ -115,6 +115,8 @@ use std::error::Error;
 use std::io;
 use std::path::PathBuf;
 use std::string::ToString;
+use std::ops::Add;
+use std::iter::repeat;
 
 use colours::Colours;
 use column::{Alignment, Column, Cell};
@@ -656,7 +658,7 @@ impl<U> Table<U> where U: Users {
             .map(|n| self.rows.iter().map(|row| row.column_width(n)).max().unwrap_or(0))
             .collect();
 
-        let total_width: usize = self.columns.len() + column_widths.iter().sum::<usize>();
+        let total_width: usize = self.columns.len() + column_widths.iter().fold(0,Add::add);
 
         for row in self.rows.iter() {
             let mut cell = Cell::empty();
@@ -682,7 +684,14 @@ impl<U> Table<U> where U: Users {
             // necessary to maintain information about the previously-printed
             // lines, as the output will change based on whether the
             // *previous* entry was the last in its directory.
-            stack.resize(row.depth + 1, TreePart::Edge);
+            // TODO: Replace this by Vec::resize() when it becomes stable (1.5.0)
+            let stack_len = stack.len();
+            if row.depth + 1 > stack_len {
+                stack.extend(repeat(TreePart::Edge).take(row.depth + 1 - stack_len));
+            } else {
+                stack = stack[..(row.depth + 1)].into();
+            }
+
             stack[row.depth] = if row.last { TreePart::Corner } else { TreePart::Edge };
 
             for i in 1 .. row.depth + 1 {