use std::collections::HashSet;
use std::sync::LazyLock;
use nu_ansi_term::Style;
use uzers::{Groups, Users};
use crate::fs::fields as f;
use crate::output::cell::TextCell;
use crate::theme::Theme;
static MY_GROUPS: LazyLock<HashSet<u32>> = LazyLock::new(|| {
let mut groups = HashSet::new();
groups.insert(uzers::get_effective_gid());
if let Some(list) = uzers::get_user_groups(
&uzers::get_current_username().unwrap_or_default(),
uzers::get_effective_gid(),
) {
for g in &list {
groups.insert(g.gid());
}
}
groups
});
impl f::Group {
pub fn render<U: Users + Groups>(self, theme: &Theme, users: &U) -> TextCell {
let style = self.style(theme, false);
match self.lookup_name(users) {
Some(name) => TextCell::paint(style, name),
None => TextCell::paint(style, self.0.to_string()),
}
}
pub fn render_gid<U: Users + Groups>(self, theme: &Theme, _users: &U) -> TextCell {
TextCell::paint(
self.style(theme, true),
self.0.to_string(),
)
}
fn lookup_name<U: Users + Groups>(self, users: &U) -> Option<String> {
users
.get_group_by_gid(self.0)
.map(|g| g.name().to_string_lossy().into())
}
fn style(self, theme: &Theme, gid_column: bool) -> Style {
let users = &theme.ui.users;
let tier = if self.0 == uzers::get_effective_gid() {
GroupTier::Primary
} else if MY_GROUPS.contains(&self.0) {
GroupTier::Member
} else {
GroupTier::Other
};
match (gid_column, tier) {
(false, GroupTier::Primary) => users.group_yours,
(false, GroupTier::Member) => users.group_member,
(false, GroupTier::Other) => users.group_not_yours,
(true, GroupTier::Primary) => users.gid_yours,
(true, GroupTier::Member) => users.gid_member,
(true, GroupTier::Other) => users.gid_not_yours,
}
}
}
enum GroupTier {
Primary,
Member,
Other,
}
#[cfg(test)]
#[allow(unused_results)]
pub mod test {
use crate::fs::fields as f;
use crate::output::cell::TextCell;
use crate::theme::Theme;
use nu_ansi_term::Color::*;
use uzers::Group;
use uzers::mock::MockUsers;
fn theme() -> Theme {
let mut t = Theme::test_default();
t.ui.users.group_yours = Fixed(80).normal();
t.ui.users.group_member = Fixed(84).normal();
t.ui.users.group_not_yours = Fixed(81).normal();
t.ui.users.gid_yours = Fixed(82).normal();
t.ui.users.gid_member = Fixed(85).normal();
t.ui.users.gid_not_yours = Fixed(83).normal();
t
}
const FOREIGN_GID: u32 = 99999;
#[test]
fn named_other_group() {
let mut users = MockUsers::with_current_uid(1000);
users.add_group(Group::new(FOREIGN_GID, "folk"));
let group = f::Group(FOREIGN_GID);
let expected = TextCell::paint_str(Fixed(81).normal(), "folk");
assert_eq!(expected, group.render(&theme(), &users));
let expected = TextCell::paint(Fixed(83).normal(), FOREIGN_GID.to_string());
assert_eq!(expected, group.render_gid(&theme(), &users));
}
#[test]
fn unnamed_falls_back_to_gid() {
let users = MockUsers::with_current_uid(1000);
let group = f::Group(FOREIGN_GID);
let expected_name = TextCell::paint(Fixed(81).normal(), FOREIGN_GID.to_string());
assert_eq!(expected_name, group.render(&theme(), &users));
let expected_gid = TextCell::paint(Fixed(83).normal(), FOREIGN_GID.to_string());
assert_eq!(expected_gid, group.render_gid(&theme(), &users));
}
#[test]
fn primary_group() {
let egid = uzers::get_effective_gid();
let mut users = MockUsers::with_current_uid(uzers::get_current_uid());
users.add_group(Group::new(egid, "primary"));
let group = f::Group(egid);
let expected = TextCell::paint_str(Fixed(80).normal(), "primary");
assert_eq!(expected, group.render(&theme(), &users));
}
#[test]
fn member_group() {
let egid = uzers::get_effective_gid();
let member_gid = super::MY_GROUPS.iter().find(|&&g| g != egid).copied();
if let Some(gid) = member_gid {
let mut users = MockUsers::with_current_uid(uzers::get_current_uid());
users.add_group(Group::new(gid, "supplementary"));
let group = f::Group(gid);
let expected = TextCell::paint_str(Fixed(84).normal(), "supplementary");
assert_eq!(expected, group.render(&theme(), &users));
}
}
#[test]
fn overflow() {
let group = f::Group(2_147_483_648);
let expected = TextCell::paint_str(Fixed(83).normal(), "2147483648");
assert_eq!(
expected,
group.render_gid(&theme(), &MockUsers::with_current_uid(0))
);
}
}