فهرست منبع

Replare Unix module with users crate

Feels good turning all that code into a dependency!
Ben S 11 سال پیش
والد
کامیت
6770ac5475
5فایلهای تغییر یافته به همراه57 افزوده شده و 174 حذف شده
  1. 6 0
      Cargo.lock
  2. 3 3
      Cargo.toml
  3. 15 14
      src/exa.rs
  4. 33 16
      src/file.rs
  5. 0 141
      src/unix.rs

+ 6 - 0
Cargo.lock

@@ -3,6 +3,7 @@ name = "exa"
 version = "0.1.0"
 dependencies = [
  "ansi_term 0.3.0 (git+https://github.com/ogham/rust-ansi-term.git)",
+ "users 0.1.0 (git+https://github.com/ogham/rust-users)",
 ]
 
 [[package]]
@@ -10,3 +11,8 @@ name = "ansi_term"
 version = "0.3.0"
 source = "git+https://github.com/ogham/rust-ansi-term.git#4b9ea6cf266053e1a771e75b935b4e54c586c139"
 
+[[package]]
+name = "users"
+version = "0.1.0"
+source = "git+https://github.com/ogham/rust-users#221a1463d3e25acac41615186a1c7fdcf0ad36d7"
+

+ 3 - 3
Cargo.toml

@@ -1,13 +1,13 @@
 [package]
-
 name = "exa"
 version = "0.1.0"
 authors = [ "ogham@bsago.me" ]
 
 [[bin]]
-
 name = "exa"
 
 [dependencies.ansi_term]
+git = "https://github.com/ogham/rust-ansi-term.git"
 
-git = "https://github.com/ogham/rust-ansi-term.git"
+[dependencies.users]
+git = "https://github.com/ogham/rust-users.git"

+ 15 - 14
src/exa.rs

@@ -2,30 +2,31 @@
 extern crate regex;
 #[phase(plugin)] extern crate regex_macros;
 extern crate ansi_term;
+extern crate users;
 extern crate unicode;
 
-use std::os;
-use std::io::fs;
 use std::io::FileType;
+use std::io::fs;
 use std::iter::AdditiveIterator;
+use std::os;
 use std::str::StrVector;
 
-use file::File;
-use dir::Dir;
-use column::Column;
 use column::Alignment::Left;
+use column::Column;
+use dir::Dir;
+use file::File;
 use options::{Options, View};
-use unix::Unix;
 
 use ansi_term::Style::Plain;
 use ansi_term::strip_formatting;
 
+use users::OSUsers;
+
 pub mod column;
 pub mod dir;
 pub mod format;
 pub mod file;
 pub mod filetype;
-pub mod unix;
 pub mod options;
 pub mod sort;
 pub mod term;
@@ -42,7 +43,7 @@ fn main() {
 fn exa(opts: &Options) {
     let mut dirs: Vec<String> = vec![];
     let mut files: Vec<File> = vec![];
-    
+
     // Separate the user-supplied paths into directories and files.
     // Files are shown first, and then each directory is expanded
     // and listed second.
@@ -71,7 +72,7 @@ fn exa(opts: &Options) {
     if !files.is_empty() {
         view(opts, files);
     }
-    
+
     for dir_name in dirs.into_iter() {
         if first {
             first = false;
@@ -121,7 +122,7 @@ fn grid_view(across: bool, console_width: uint, files: Vec<File>) {
     let width = files.iter()
                      .map(|f| f.name.len() + 2)
                      .sum() - 2;
-    
+
     if width <= console_width {
         let names: Vec<String> = files.iter()
                                       .map(|f| f.file_name().to_string())
@@ -140,7 +141,7 @@ fn grid_view(across: bool, console_width: uint, files: Vec<File>) {
     if count % num_columns != 0 {
         num_rows += 1;
     }
-    
+
     for y in range(0, num_rows) {
         for x in range(0, num_columns) {
             let num = if across {
@@ -149,11 +150,11 @@ fn grid_view(across: bool, console_width: uint, files: Vec<File>) {
             else {
                 y + num_rows * x
             };
-            
+
             if num >= count {
                 continue;
             }
-            
+
             let ref file = files[num];
             let file_name = file.name.clone();
             let styled_name = file.file_colour().paint(file_name.as_slice()).to_string();
@@ -175,7 +176,7 @@ fn details_view(options: &Options, columns: &Vec<Column>, files: Vec<File>) {
     // width of each column based on the length of the results and
     // padding the fields during output.
 
-    let mut cache = Unix::empty_cache();
+    let mut cache = OSUsers::empty_cache();
 
     let mut table: Vec<Vec<String>> = files.iter()
         .map(|f| columns.iter().map(|c| f.display(c, &mut cache)).collect())

+ 33 - 16
src/file.rs

@@ -5,10 +5,11 @@ use ansi_term::{ANSIString, Colour, Style};
 use ansi_term::Style::Plain;
 use ansi_term::Colour::{Red, Green, Yellow, Blue, Purple, Cyan, Fixed};
 
+use users::{Users, OSUsers};
+
 use column::Column;
 use column::Column::*;
 use format::{format_metric_bytes, format_IEC_bytes};
-use unix::Unix;
 use sort::SortPart;
 use dir::Dir;
 use filetype::HasType;
@@ -40,17 +41,17 @@ impl<'a> File<'a> {
     }
 
     pub fn with_stat(stat: io::FileStat, path: Path, parent: Option<&'a Dir>) -> File<'a> {
-		let v = path.filename().unwrap();  // fails if / or . or ..
+        let v = path.filename().unwrap();  // fails if / or . or ..
         let filename = String::from_utf8(v.to_vec()).unwrap_or_else(|_| panic!("Name was not valid UTF-8"));
 
-    	File {
+        File {
             path:  path.clone(),
             dir:   parent,
             stat:  stat,
             name:  filename.clone(),
             ext:   File::ext(filename.clone()),
             parts: SortPart::split_into_parts(filename.clone()),
-    	}
+        }
     }
 
     fn ext(name: String) -> Option<String> {
@@ -103,7 +104,7 @@ impl<'a> File<'a> {
         }
     }
 
-    pub fn display(&self, column: &Column, unix: &mut Unix) -> String {
+    pub fn display(&self, column: &Column, users_cache: &mut OSUsers) -> String {
         match *column {
             Permissions => {
                 self.permissions_string()
@@ -141,18 +142,34 @@ impl<'a> File<'a> {
             // Display the ID if the user/group doesn't exist, which
             // usually means it was deleted but its files weren't.
             User => {
-                let uid = self.stat.unstable.uid as u32;
-                unix.load_user(uid);
-                let user_name = unix.get_user_name(uid).unwrap_or(uid.to_string());
-                let style = if unix.uid == uid { Yellow.bold() } else { Plain };
+                let uid = self.stat.unstable.uid as i32;
+
+                let user_name = match users_cache.get_user_by_uid(uid) {
+                    Some(user) => user.name,
+                    None => uid.to_string(),
+                };
+
+                let style = if users_cache.get_current_uid() == uid { Yellow.bold() } else { Plain };
                 style.paint(user_name.as_slice()).to_string()
             },
 
             Group => {
                 let gid = self.stat.unstable.gid as u32;
-                unix.load_group(gid);
-                let group_name = unix.get_group_name(gid).unwrap_or(gid.to_string());
-                let style = if unix.is_group_member(gid) { Yellow.normal() } else { Plain };
+                let mut style = Plain;
+
+                let group_name = match users_cache.get_group_by_gid(gid) {
+                    Some(group) => {
+                        let current_uid = users_cache.get_current_uid();
+                        if let Some(current_user) = users_cache.get_user_by_uid(current_uid) {
+                            if current_user.primary_group == group.gid || group.members.contains(&current_user.name) {
+                                style = Yellow.bold();
+                            }
+                        }
+                        group.name
+                    },
+                    None => gid.to_string(),
+                };
+
                 style.paint(group_name.as_slice()).to_string()
             },
         }
@@ -164,10 +181,10 @@ impl<'a> File<'a> {
         if self.stat.kind == io::FileType::Symlink {
             match fs::readlink(&self.path) {
                 Ok(path) => {
-                	let target_path = match self.dir {
-                		Some(dir) => dir.path.join(path),
-                		None => path,
-                	};
+                    let target_path = match self.dir {
+                        Some(dir) => dir.path.join(path),
+                        None => path,
+                    };
                     format!("{} {}", displayed_name, self.target_file_name_and_arrow(target_path))
                 }
                 Err(_) => displayed_name.to_string(),

+ 0 - 141
src/unix.rs

@@ -1,141 +0,0 @@
-use std::ptr::read;
-use std::ptr;
-use std::collections::HashMap;
-
-mod c {
-    #![allow(non_camel_case_types)]
-    extern crate libc;
-    pub use self::libc::{
-        c_char,
-        c_int,
-        uid_t,
-        gid_t,
-        time_t
-    };
-
-    #[repr(C)]
-    pub struct c_passwd {
-        pub pw_name:    *const c_char,  // login name
-        pub pw_passwd:  *const c_char,
-        pub pw_uid:     c_int,          // user ID
-        pub pw_gid:     c_int,          // group ID
-        pub pw_change:  time_t,
-        pub pw_class:   *const c_char,
-        pub pw_gecos:   *const c_char,  // full name
-        pub pw_dir:     *const c_char,  // login dir
-        pub pw_shell:   *const c_char,  // login shell
-        pub pw_expire:  time_t,         // password expiry time
-    }
-
-    #[repr(C)]
-    pub struct c_group {
-        pub gr_name:   *const c_char,         // group name
-        pub gr_passwd: *const c_char,         // password
-        pub gr_gid:    gid_t,                 // group id
-        pub gr_mem:    *const *const c_char,  // names of users in the group
-    }
-
-    extern {
-        pub fn getpwuid(uid: c_int) -> *const c_passwd;
-        pub fn getgrgid(gid: uid_t) -> *const c_group;
-        pub fn getuid() -> libc::c_int;
-    }
-}
-
-pub struct Unix {
-    user_names:    HashMap<u32, Option<String>>,  // mapping of user IDs to user names
-    group_names:   HashMap<u32, Option<String>>,  // mapping of groups IDs to group names
-    groups:        HashMap<u32, bool>,            // mapping of group IDs to whether the current user is a member
-    pub uid:       u32,                           // current user's ID
-    pub username:  String,                        // current user's name
-}
-
-impl Unix {
-    pub fn empty_cache() -> Unix {
-        let uid = unsafe { c::getuid() };
-        let infoptr = unsafe { c::getpwuid(uid as i32) };
-        let info = unsafe { infoptr.as_ref().unwrap() };  // the user has to have a name
-
-        let username = unsafe { String::from_raw_buf(info.pw_name as *const u8) };
-
-        let mut user_names = HashMap::new();
-        user_names.insert(uid as u32, Some(username.clone()));
-
-        // Unix groups work like this: every group has a list of
-        // users, referred to by their names. But, every user also has
-        // a primary group, which isn't in this list. So handle this
-        // case immediately after we look up the user's details.
-        let mut groups = HashMap::new();
-        groups.insert(info.pw_gid as u32, true);
-
-        Unix {
-            user_names:  user_names,
-            group_names: HashMap::new(),
-            uid:         uid as u32,
-            username:    username,
-            groups:      groups,
-        }
-    }
-
-    pub fn get_user_name(&self, uid: u32) -> Option<String> {
-        self.user_names[uid].clone()
-    }
-
-    pub fn get_group_name(&self, gid: u32) -> Option<String> {
-        self.group_names[gid].clone()
-    }
-
-    pub fn is_group_member(&self, gid: u32) -> bool {
-        self.groups[gid]
-    }
-
-    pub fn load_user(&mut self, uid: u32) {
-        let pw = unsafe { c::getpwuid(uid as i32) };
-        if pw.is_not_null() {
-            let username = unsafe { Some(String::from_raw_buf(read(pw).pw_name as *const u8)) };
-            self.user_names.insert(uid, username);
-        }
-        else {
-            self.user_names.insert(uid, None);
-        }
-    }
-
-    fn group_membership(group: *const *const c::c_char, uname: &String) -> bool {
-        let mut i = 0;
-
-        // The list of members is a pointer to a pointer of
-        // characters, terminated by a null pointer.
-        loop {
-            match unsafe { group.offset(i).as_ref() } {
-                Some(&username) => {
-                    if username == ptr::null() {
-                        return false;  // username was null, weird
-                    }
-                    else if unsafe { String::from_raw_buf(username as *const u8) } == *uname {
-                        return true;   // group found!
-                    }
-                    else {
-                        i += 1;        // try again with the next group
-                    }
-                },
-                None => return false,  // no more groups to check, and none found
-            }
-        }
-    }
-
-    pub fn load_group(&mut self, gid: u32) {
-        match unsafe { c::getgrgid(gid).as_ref() } {
-            None => {
-                self.group_names.insert(gid, None);
-                self.groups.insert(gid, false);
-            },
-            Some(r) => {
-                let group_name = unsafe { Some(String::from_raw_buf(r.gr_name as *const u8)) };
-                if !self.groups.contains_key(&gid) {
-                    self.groups.insert(gid, Unix::group_membership(r.gr_mem, &self.username));
-                }
-                self.group_names.insert(gid, group_name);
-            }
-        }
-    }
-}