Skip to content

Commit

Permalink
cp: gnu test case preserve-mode fix
Browse files Browse the repository at this point in the history
  • Loading branch information
matrixhead committed May 25, 2024
1 parent 6adf07e commit b49fac3
Showing 1 changed file with 97 additions and 41 deletions.
138 changes: 97 additions & 41 deletions src/uu/cp/src/cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,11 +556,6 @@ pub fn uu_app() -> Command {
.num_args(0..)
.require_equals(true)
.value_name("ATTR_LIST")
.overrides_with_all([
options::ARCHIVE,
options::PRESERVE_DEFAULT_ATTRIBUTES,
options::NO_PRESERVE,
])
// -d sets this option
// --archive sets this option
.help(
Expand All @@ -572,19 +567,18 @@ pub fn uu_app() -> Command {
Arg::new(options::PRESERVE_DEFAULT_ATTRIBUTES)
.short('p')
.long(options::PRESERVE_DEFAULT_ATTRIBUTES)
.overrides_with_all([options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE])
.help("same as --preserve=mode,ownership(unix only),timestamps")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::NO_PRESERVE)
.long(options::NO_PRESERVE)
.action(ArgAction::Append)
.use_value_delimiter(true)
.value_parser(ShortcutValueParser::new(PRESERVABLE_ATTRIBUTES))
.num_args(0..)
.require_equals(true)
.value_name("ATTR_LIST")
.overrides_with_all([
options::PRESERVE_DEFAULT_ATTRIBUTES,
options::PRESERVE,
options::ARCHIVE,
])
.help("don't preserve the specified attributes"),
)
.arg(
Expand Down Expand Up @@ -621,11 +615,6 @@ pub fn uu_app() -> Command {
Arg::new(options::ARCHIVE)
.short('a')
.long(options::ARCHIVE)
.overrides_with_all([
options::PRESERVE_DEFAULT_ATTRIBUTES,
options::PRESERVE,
options::NO_PRESERVE,
])
.help("Same as -dR --preserve=all")
.action(ArgAction::SetTrue),
)
Expand Down Expand Up @@ -839,6 +828,42 @@ impl Attributes {
}
}

pub fn diff(self, other: &Self) -> Self {
Self {
#[cfg(unix)]
ownership: if matches!(other.ownership, Preserve::Yes { .. }) {
Preserve::No { explicit: true }

Check warning on line 835 in src/uu/cp/src/cp.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/cp/src/cp.rs#L835

Added line #L835 was not covered by tests
} else {
self.ownership
},
mode: if matches!(other.mode, Preserve::Yes { .. }) {
Preserve::No { explicit: true }
} else {
self.mode
},
timestamps: if matches!(other.timestamps, Preserve::Yes { .. }) {
Preserve::No { explicit: true }

Check warning on line 845 in src/uu/cp/src/cp.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/cp/src/cp.rs#L845

Added line #L845 was not covered by tests
} else {
self.timestamps
},
context: if matches!(other.context, Preserve::Yes { .. }) {
Preserve::No { explicit: true }

Check warning on line 850 in src/uu/cp/src/cp.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/cp/src/cp.rs#L850

Added line #L850 was not covered by tests
} else {
self.context
},
links: if matches!(other.links, Preserve::Yes { .. }) {
Preserve::No { explicit: true }
} else {
self.links
},
xattr: if matches!(other.xattr, Preserve::Yes { .. }) {
Preserve::No { explicit: true }

Check warning on line 860 in src/uu/cp/src/cp.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/cp/src/cp.rs#L860

Added line #L860 was not covered by tests
} else {
self.xattr
},
}
}

pub fn parse_iter<T>(values: impl Iterator<Item = T>) -> Result<Self, Error>
where
T: AsRef<str>,
Expand Down Expand Up @@ -926,34 +951,65 @@ impl Options {
}
};

// Parse attributes to preserve
let mut attributes =
if let Some(attribute_strs) = matches.get_many::<String>(options::PRESERVE) {
if attribute_strs.len() == 0 {
Attributes::DEFAULT
} else {
Attributes::parse_iter(attribute_strs)?
let mut overiding_priority = [
options::ARCHIVE,
options::PRESERVE,
options::NO_PRESERVE,
options::PRESERVE_DEFAULT_ATTRIBUTES,
options::NO_DEREFERENCE_PRESERVE_LINKS,
];
overiding_priority.sort_by(|a, b| {
let a_index = matches.indices_of(a).and_then(|v| v.last());
let b_index = matches.indices_of(b).and_then(|v| v.last());
match (a_index, b_index) {
(None, None) => Ordering::Equal,
(None, Some(_)) => Ordering::Greater,
(Some(_), None) => Ordering::Less,
(Some(a), Some(b)) => {
if a < b {
Ordering::Less
} else {
Ordering::Greater
}
}
} else if matches.get_flag(options::ARCHIVE) {
// --archive is used. Same as --preserve=all
Attributes::ALL
} else if matches.get_flag(options::NO_DEREFERENCE_PRESERVE_LINKS) {
Attributes::LINKS
} else if matches.get_flag(options::PRESERVE_DEFAULT_ATTRIBUTES) {
Attributes::DEFAULT
} else {
Attributes::NONE
};
}
});

// handling no-preserve options and adjusting the attributes
if let Some(attribute_strs) = matches.get_many::<String>(options::NO_PRESERVE) {
if attribute_strs.len() > 0 {
let no_preserve_attributes = Attributes::parse_iter(attribute_strs)?;
if matches!(no_preserve_attributes.links, Preserve::Yes { .. }) {
attributes.links = Preserve::No { explicit: true };
} else if matches!(no_preserve_attributes.mode, Preserve::Yes { .. }) {
attributes.mode = Preserve::No { explicit: true };
let mut attributes = Attributes::NONE;

for option in overiding_priority {
match option {
options::ARCHIVE => {
if matches.get_flag(options::ARCHIVE) {
attributes = Attributes::ALL;
}
}
options::PRESERVE_DEFAULT_ATTRIBUTES => {
if matches.get_flag(options::PRESERVE_DEFAULT_ATTRIBUTES) {
attributes = attributes.union(&Attributes::DEFAULT);
}
}
options::NO_DEREFERENCE_PRESERVE_LINKS => {
if matches.get_flag(options::NO_DEREFERENCE_PRESERVE_LINKS) {
attributes = attributes.union(&Attributes::LINKS);
}
}
options::PRESERVE => {
if let Some(attribute_strs) = matches.get_many::<String>(options::PRESERVE) {
if attribute_strs.len() == 0 {
attributes = attributes.union(&Attributes::DEFAULT);
}
attributes = attributes.union(&Attributes::parse_iter(attribute_strs)?);
}
}
options::NO_PRESERVE => {
if let Some(attribute_strs) = matches.get_many::<String>(options::NO_PRESERVE) {
if attribute_strs.len() > 0 {
attributes = attributes.diff(&Attributes::parse_iter(attribute_strs)?);
}
}
}
_ => (),
}
}

Expand Down

0 comments on commit b49fac3

Please sign in to comment.