mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
chgrp: add option --from
This commit is contained in:
parent
0ba4dad0a6
commit
c45bbe3d1c
2 changed files with 153 additions and 1 deletions
|
@ -49,11 +49,27 @@ fn parse_gid_and_uid(matches: &ArgMatches) -> UResult<GidUidOwnerFilter> {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Handle --from option
|
||||
let filter = if let Some(from_group) = matches.get_one::<String>(options::FROM) {
|
||||
match entries::grp2gid(from_group) {
|
||||
Ok(g) => IfFrom::Group(g),
|
||||
_ => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid group: {}", from_group.quote()),
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IfFrom::All
|
||||
};
|
||||
|
||||
Ok(GidUidOwnerFilter {
|
||||
dest_gid,
|
||||
dest_uid: None,
|
||||
raw_owner: raw_group,
|
||||
filter: IfFrom::All,
|
||||
filter,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -120,6 +136,12 @@ pub fn uu_app() -> Command {
|
|||
.value_hint(clap::ValueHint::FilePath)
|
||||
.help("use RFILE's group rather than specifying GROUP values"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FROM)
|
||||
.long(options::FROM)
|
||||
.value_name("GROUP")
|
||||
.help("change the group only if its current group matches GROUP"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::RECURSIVE)
|
||||
.short('R')
|
||||
|
|
|
@ -417,3 +417,133 @@ fn test_traverse_symlinks() {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
fn test_from_option() {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
let groups = nix::unistd::getgroups().unwrap();
|
||||
// Skip test if we don't have at least two different groups to work with
|
||||
if groups.len() < 2 {
|
||||
return;
|
||||
}
|
||||
let (first_group, second_group) = (groups[0], groups[1]);
|
||||
|
||||
at.touch("test_file");
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(first_group.to_string())
|
||||
.arg("test_file")
|
||||
.succeeds();
|
||||
|
||||
// Test successful group change with --from
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--from")
|
||||
.arg(first_group.to_string())
|
||||
.arg(second_group.to_string())
|
||||
.arg("test_file")
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
// Verify the group was changed
|
||||
let new_gid = at.plus("test_file").metadata().unwrap().gid();
|
||||
assert_eq!(new_gid, second_group.as_raw());
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--from")
|
||||
.arg(first_group.to_string())
|
||||
.arg(first_group.to_string())
|
||||
.arg("test_file")
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
let unchanged_gid = at.plus("test_file").metadata().unwrap().gid();
|
||||
assert_eq!(unchanged_gid, second_group.as_raw());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||
fn test_from_with_invalid_group() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.touch("test_file");
|
||||
#[cfg(not(target_os = "android"))]
|
||||
let err_msg = "chgrp: invalid user: 'nonexistent_group'\n";
|
||||
#[cfg(target_os = "android")]
|
||||
let err_msg = "chgrp: invalid user: 'staff'\n";
|
||||
|
||||
ucmd.arg("--from")
|
||||
.arg("nonexistent_group")
|
||||
.arg("staff")
|
||||
.arg("test_file")
|
||||
.fails()
|
||||
.stderr_is(err_msg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
fn test_verbosity_messages() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
let groups = nix::unistd::getgroups().unwrap();
|
||||
// Skip test if we don't have at least one group to work with
|
||||
if groups.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
at.touch("ref_file");
|
||||
at.touch("target_file");
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-v")
|
||||
.arg("--reference=ref_file")
|
||||
.arg("target_file")
|
||||
.succeeds()
|
||||
.stderr_contains("group of 'target_file' retained as ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
fn test_from_with_reference() {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
let groups = nix::unistd::getgroups().unwrap();
|
||||
if groups.len() < 2 {
|
||||
return;
|
||||
}
|
||||
let (first_group, second_group) = (groups[0], groups[1]);
|
||||
|
||||
at.touch("ref_file");
|
||||
at.touch("test_file");
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(first_group.to_string())
|
||||
.arg("test_file")
|
||||
.succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(second_group.to_string())
|
||||
.arg("ref_file")
|
||||
.succeeds();
|
||||
|
||||
// Test --from with --reference
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--from")
|
||||
.arg(first_group.to_string())
|
||||
.arg("--reference=ref_file")
|
||||
.arg("test_file")
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
let new_gid = at.plus("test_file").metadata().unwrap().gid();
|
||||
let ref_gid = at.plus("ref_file").metadata().unwrap().gid();
|
||||
assert_eq!(new_gid, ref_gid);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue