diff --git a/src/output/details.rs b/src/output/details.rs index aa59fbc..d96b618 100644 --- a/src/output/details.rs +++ b/src/output/details.rs @@ -81,7 +81,7 @@ use std::io::{Write, Error as IOError, Result as IOResult}; use std::ops::Add; use std::path::PathBuf; use std::string::ToString; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, MutexGuard}; use ansi_term::Style; @@ -150,7 +150,7 @@ pub struct Details { /// running instances of exa, depending on the user's computer's configuration. /// /// Any environment field should be able to be mocked up for test runs. -pub struct Environment { +pub struct Environment { // where U: Users+Groups /// The year of the current time. This gets used to determine which date /// format to use. @@ -176,6 +176,12 @@ pub struct Environment { users: Mutex, } +impl Environment { + pub fn users(&self) -> MutexGuard { + self.users.lock().unwrap() + } +} + impl Default for Environment { fn default() -> Self { let tz = determine_time_zone(); @@ -414,7 +420,7 @@ impl Row { /// A **Table** object gets built up by the view as it lists files and /// directories. -pub struct Table<'a, U: Users+Groups+'a> { +pub struct Table<'a, U: 'a> { // where U: Users+Groups pub rows: Vec, pub columns: &'a [Column], @@ -680,42 +686,6 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> { } } - fn render_user(&self, user: f::User) -> TextCell { - let users = self.env.users.lock().unwrap(); - - - let user_name = match users.get_user_by_uid(user.0) { - Some(user) => user.name().to_owned(), - None => user.0.to_string(), - }; - - let style = if users.get_current_uid() == user.0 { self.opts.colours.users.user_you } - else { self.opts.colours.users.user_someone_else }; - TextCell::paint(style, user_name) - } - - fn render_group(&self, group: f::Group) -> TextCell { - use users::os::unix::GroupExt; - - let mut style = self.opts.colours.users.group_not_yours; - - let users = self.env.users.lock().unwrap(); - let group = match users.get_group_by_gid(group.0) { - Some(g) => (*g).clone(), - None => return TextCell::paint(style, group.0.to_string()), - }; - - let current_uid = users.get_current_uid(); - if let Some(current_user) = users.get_user_by_uid(current_uid) { - if current_user.primary_group_id() == group.gid() - || group.members().contains(¤t_user.name().to_owned()) { - style = self.opts.colours.users.group_yours; - } - } - - TextCell::paint(style, group.name().to_owned()) - } - /// Render the table as a vector of Cells, to be displayed on standard output. pub fn print_table(self) -> Vec { let mut tree_trunk = TreeTrunk::default(); @@ -775,19 +745,13 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> { #[cfg(test)] pub mod test { - pub use super::{Table, Environment, Details}; - pub use std::sync::Mutex; + use super::{Table, Environment, Details}; + use std::sync::Mutex; - pub use fs::{File, fields as f}; - pub use output::column::{Column, Columns}; - pub use output::cell::TextCell; + use output::column::Column; - pub use users::{User, Group, uid_t, gid_t}; - pub use users::mock::MockUsers; - pub use users::os::unix::{UserExt, GroupExt}; - pub use datetime::fmt::DateFormat; - pub use ansi_term::Style; - pub use ansi_term::Colour::*; + use users::mock::MockUsers; + use datetime::fmt::DateFormat; impl Default for Environment { fn default() -> Self { @@ -817,163 +781,4 @@ pub mod test { rows: Vec::new(), } } - - mod users { - #![allow(unused_results)] - use super::*; - - #[test] - fn named() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.user_you = Red.bold(); - - let mut users = MockUsers::with_current_uid(1000); - users.add_user(User::new(1000, "enoch", 100)); - - let table = new_table(&columns, &details, users); - - let user = f::User(1000); - let expected = TextCell::paint_str(Red.bold(), "enoch"); - assert_eq!(expected, table.render_user(user)) - } - - #[test] - fn unnamed() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.user_you = Cyan.bold(); - - let users = MockUsers::with_current_uid(1000); - - let table = new_table(&columns, &details, users); - - let user = f::User(1000); - let expected = TextCell::paint_str(Cyan.bold(), "1000"); - assert_eq!(expected, table.render_user(user)); - } - - #[test] - fn different_named() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.user_someone_else = Green.bold(); - - let table = new_table(&columns, &details, MockUsers::with_current_uid(0)); - table.env.users.lock().unwrap().add_user(User::new(1000, "enoch", 100)); - - let user = f::User(1000); - let expected = TextCell::paint_str(Green.bold(), "enoch"); - assert_eq!(expected, table.render_user(user)); - } - - #[test] - fn different_unnamed() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.user_someone_else = Red.normal(); - - let table = new_table(&columns, &details, MockUsers::with_current_uid(0)); - - let user = f::User(1000); - let expected = TextCell::paint_str(Red.normal(), "1000"); - assert_eq!(expected, table.render_user(user)); - } - - #[test] - fn overflow() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.user_someone_else = Blue.underline(); - - let table = new_table(&columns, &details, MockUsers::with_current_uid(0)); - - let user = f::User(2_147_483_648); - let expected = TextCell::paint_str(Blue.underline(), "2147483648"); - assert_eq!(expected, table.render_user(user)); - } - } - - mod groups { - #![allow(unused_results)] - use super::*; - - #[test] - fn named() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.group_not_yours = Fixed(101).normal(); - - let mut users = MockUsers::with_current_uid(1000); - users.add_group(Group::new(100, "folk")); - let table = new_table(&columns, &details, users); - - let group = f::Group(100); - let expected = TextCell::paint_str(Fixed(101).normal(), "folk"); - assert_eq!(expected, table.render_group(group)) - } - - #[test] - fn unnamed() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.group_not_yours = Fixed(87).normal(); - - let users = MockUsers::with_current_uid(1000); - let table = new_table(&columns, &details, users); - - let group = f::Group(100); - let expected = TextCell::paint_str(Fixed(87).normal(), "100"); - assert_eq!(expected, table.render_group(group)); - } - - #[test] - fn primary() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.group_yours = Fixed(64).normal(); - - let mut users = MockUsers::with_current_uid(2); - users.add_user(User::new(2, "eve", 100)); - users.add_group(Group::new(100, "folk")); - - let table = new_table(&columns, &details, users); - - let group = f::Group(100); - let expected = TextCell::paint_str(Fixed(64).normal(), "folk"); - assert_eq!(expected, table.render_group(group)) - } - - #[test] - fn secondary() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.group_yours = Fixed(31).normal(); - - let mut users = MockUsers::with_current_uid(2); - users.add_user(User::new(2, "eve", 666)); - - let test_group = Group::new(100, "folk").add_member("eve"); - users.add_group(test_group); - - let table = new_table(&columns, &details, users); - - let group = f::Group(100); - let expected = TextCell::paint_str(Fixed(31).normal(), "folk"); - assert_eq!(expected, table.render_group(group)) - } - - #[test] - fn overflow() { - let columns = Columns::default().for_dir(None); - let mut details = Details::default(); - details.colours.users.group_not_yours = Blue.underline(); - - let table = new_table(&columns, &details, MockUsers::with_current_uid(0)); - - let group = f::Group(2_147_483_648); - let expected = TextCell::paint_str(Blue.underline(), "2147483648"); - assert_eq!(expected, table.render_group(group)); - } - } } diff --git a/src/output/mod.rs b/src/output/mod.rs index 48b886e..29d117a 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -16,3 +16,4 @@ mod colours; mod tree; pub mod file_name; mod escape; +mod users; diff --git a/src/output/users.rs b/src/output/users.rs new file mode 100644 index 0000000..58ddcf7 --- /dev/null +++ b/src/output/users.rs @@ -0,0 +1,222 @@ +use users::{Users, Groups}; + +use fs::fields as f; +use output::cell::TextCell; +use output::details::Table; + + +impl<'a, U: Users+Groups+'a> Table<'a, U> { + + pub fn render_user(&self, user: f::User) -> TextCell { + let users = self.env.users(); + + let user_name = match users.get_user_by_uid(user.0) { + Some(user) => user.name().to_owned(), + None => user.0.to_string(), + }; + + let style = if users.get_current_uid() == user.0 { self.opts.colours.users.user_you } + else { self.opts.colours.users.user_someone_else }; + TextCell::paint(style, user_name) + } + + pub fn render_group(&self, group: f::Group) -> TextCell { + use users::os::unix::GroupExt; + + let mut style = self.opts.colours.users.group_not_yours; + + let users = self.env.users(); + let group = match users.get_group_by_gid(group.0) { + Some(g) => (*g).clone(), + None => return TextCell::paint(style, group.0.to_string()), + }; + + let current_uid = users.get_current_uid(); + if let Some(current_user) = users.get_user_by_uid(current_uid) { + if current_user.primary_group_id() == group.gid() + || group.members().contains(¤t_user.name().to_owned()) { + style = self.opts.colours.users.group_yours; + } + } + + TextCell::paint(style, group.name().to_owned()) + } +} + + +#[cfg(test)] +pub mod test { + pub use output::details::{Table, Environment, Details}; + pub use output::details::test::new_table; + pub use std::sync::Mutex; + + pub use fs::{File, fields as f}; + pub use output::column::{Column, Columns}; + pub use output::cell::TextCell; + + pub use users::{User, Group, uid_t, gid_t}; + pub use users::mock::MockUsers; + pub use users::os::unix::{UserExt, GroupExt}; + pub use datetime::fmt::DateFormat; + pub use ansi_term::Style; + pub use ansi_term::Colour::*; + + mod users { + #![allow(unused_results)] + use super::*; + + #[test] + fn named() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.user_you = Red.bold(); + + let mut users = MockUsers::with_current_uid(1000); + users.add_user(User::new(1000, "enoch", 100)); + + let table = new_table(&columns, &details, users); + + let user = f::User(1000); + let expected = TextCell::paint_str(Red.bold(), "enoch"); + assert_eq!(expected, table.render_user(user)) + } + + #[test] + fn unnamed() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.user_you = Cyan.bold(); + + let users = MockUsers::with_current_uid(1000); + + let table = new_table(&columns, &details, users); + + let user = f::User(1000); + let expected = TextCell::paint_str(Cyan.bold(), "1000"); + assert_eq!(expected, table.render_user(user)); + } + + #[test] + fn different_named() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.user_someone_else = Green.bold(); + + let table = new_table(&columns, &details, MockUsers::with_current_uid(0)); + table.env.users().add_user(User::new(1000, "enoch", 100)); + + let user = f::User(1000); + let expected = TextCell::paint_str(Green.bold(), "enoch"); + assert_eq!(expected, table.render_user(user)); + } + + #[test] + fn different_unnamed() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.user_someone_else = Red.normal(); + + let table = new_table(&columns, &details, MockUsers::with_current_uid(0)); + + let user = f::User(1000); + let expected = TextCell::paint_str(Red.normal(), "1000"); + assert_eq!(expected, table.render_user(user)); + } + + #[test] + fn overflow() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.user_someone_else = Blue.underline(); + + let table = new_table(&columns, &details, MockUsers::with_current_uid(0)); + + let user = f::User(2_147_483_648); + let expected = TextCell::paint_str(Blue.underline(), "2147483648"); + assert_eq!(expected, table.render_user(user)); + } + } + + mod groups { + #![allow(unused_results)] + use super::*; + + #[test] + fn named() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.group_not_yours = Fixed(101).normal(); + + let mut users = MockUsers::with_current_uid(1000); + users.add_group(Group::new(100, "folk")); + let table = new_table(&columns, &details, users); + + let group = f::Group(100); + let expected = TextCell::paint_str(Fixed(101).normal(), "folk"); + assert_eq!(expected, table.render_group(group)) + } + + #[test] + fn unnamed() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.group_not_yours = Fixed(87).normal(); + + let users = MockUsers::with_current_uid(1000); + let table = new_table(&columns, &details, users); + + let group = f::Group(100); + let expected = TextCell::paint_str(Fixed(87).normal(), "100"); + assert_eq!(expected, table.render_group(group)); + } + + #[test] + fn primary() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.group_yours = Fixed(64).normal(); + + let mut users = MockUsers::with_current_uid(2); + users.add_user(User::new(2, "eve", 100)); + users.add_group(Group::new(100, "folk")); + + let table = new_table(&columns, &details, users); + + let group = f::Group(100); + let expected = TextCell::paint_str(Fixed(64).normal(), "folk"); + assert_eq!(expected, table.render_group(group)) + } + + #[test] + fn secondary() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.group_yours = Fixed(31).normal(); + + let mut users = MockUsers::with_current_uid(2); + users.add_user(User::new(2, "eve", 666)); + + let test_group = Group::new(100, "folk").add_member("eve"); + users.add_group(test_group); + + let table = new_table(&columns, &details, users); + + let group = f::Group(100); + let expected = TextCell::paint_str(Fixed(31).normal(), "folk"); + assert_eq!(expected, table.render_group(group)) + } + + #[test] + fn overflow() { + let columns = Columns::default().for_dir(None); + let mut details = Details::default(); + details.colours.users.group_not_yours = Blue.underline(); + + let table = new_table(&columns, &details, MockUsers::with_current_uid(0)); + + let group = f::Group(2_147_483_648); + let expected = TextCell::paint_str(Blue.underline(), "2147483648"); + assert_eq!(expected, table.render_group(group)); + } + } +}