Skip to content

Commit 039a67b

Browse files
committed
feat!: More rewrite features
1 parent 9975ab9 commit 039a67b

File tree

10 files changed

+425
-248
lines changed

10 files changed

+425
-248
lines changed

crates/core/src/backend/ignore/mapper.rs

Lines changed: 77 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -6,65 +6,21 @@ use std::{ffi::OsStr, path::Path};
66
use derive_setters::Setters;
77
use ignore::DirEntry;
88
use jiff::Timestamp;
9+
use log::warn;
910
use serde::{Deserialize, Serialize};
1011
use serde_with::serde_as;
1112

1213
use super::{IgnoreErrorKind, IgnoreResult, OpenFile};
1314
use crate::backend::{
1415
ReadSourceEntry,
15-
node::{ExtendedAttribute, Metadata, Node, NodeType},
16+
node::{
17+
ExtendedAttribute, Metadata, Node, NodeType,
18+
modification::{DevIdOption, TimeOption, XattrOption},
19+
},
1620
};
1721

1822
#[cfg(not(windows))]
19-
use {
20-
log::warn,
21-
std::os::unix::fs::{FileTypeExt, MetadataExt},
22-
};
23-
24-
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
25-
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
26-
#[serde(rename_all = "kebab-case")]
27-
pub enum TimeOption {
28-
Yes,
29-
Mtime,
30-
No,
31-
}
32-
33-
impl TimeOption {
34-
fn map(self, default: Option<Timestamp>, mtime: Option<Timestamp>) -> Option<Timestamp> {
35-
match self {
36-
Self::Yes => default,
37-
Self::Mtime => mtime,
38-
Self::No => None,
39-
}
40-
}
41-
}
42-
43-
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
44-
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
45-
#[serde(rename_all = "kebab-case")]
46-
pub enum DevIdOption {
47-
Yes,
48-
#[default]
49-
Hardlink,
50-
No,
51-
}
52-
53-
impl DevIdOption {
54-
#[cfg(windows)]
55-
fn map(self, _m: &std::fs::Metadata) -> u64 {
56-
0
57-
}
58-
59-
#[cfg(not(windows))]
60-
fn map(self, m: &std::fs::Metadata) -> u64 {
61-
match self {
62-
Self::Yes => m.dev(),
63-
Self::Hardlink if m.nlink() > 1 && !m.is_dir() => m.dev(),
64-
_ => 0,
65-
}
66-
}
67-
}
23+
use std::os::unix::fs::{FileTypeExt, MetadataExt};
6824

6925
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
7026
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
@@ -75,63 +31,6 @@ pub enum BlockdevOption {
7531
File,
7632
}
7733

78-
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
79-
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
80-
#[serde(rename_all = "kebab-case")]
81-
pub enum XattrOption {
82-
#[default]
83-
Yes,
84-
No,
85-
}
86-
87-
impl XattrOption {
88-
#[cfg(any(windows, target_os = "openbsd"))]
89-
fn map(&self, _path: &Path) -> Vec<ExtendedAttribute> {
90-
Vec::new()
91-
}
92-
93-
/// List [`ExtendedAttribute`] for a [`Node`] located at `path`
94-
///
95-
/// # Argument
96-
///
97-
/// * `path` to the [`Node`] for which to list attributes
98-
///
99-
/// # Errors
100-
///
101-
/// * If Xattr couldn't be listed or couldn't be read
102-
#[cfg(not(any(windows, target_os = "openbsd")))]
103-
fn map(self, path: &Path) -> Vec<ExtendedAttribute> {
104-
let list = |path: &Path| {
105-
xattr::list(path)
106-
.map_err(|err| IgnoreErrorKind::ErrorXattr {
107-
path: path.to_path_buf(),
108-
source: err,
109-
})?
110-
.map(|name| {
111-
Ok(ExtendedAttribute {
112-
name: name.to_string_lossy().to_string(),
113-
value: xattr::get(path, name).map_err(|err| {
114-
IgnoreErrorKind::ErrorXattr {
115-
path: path.to_path_buf(),
116-
source: err,
117-
}
118-
})?,
119-
})
120-
})
121-
.collect::<IgnoreResult<Vec<ExtendedAttribute>>>()
122-
};
123-
124-
match self {
125-
Self::Yes => list(path)
126-
.inspect_err(|err| {
127-
warn!("ignoring error: {err}");
128-
})
129-
.unwrap_or_default(),
130-
Self::No => Vec::new(),
131-
}
132-
}
133-
}
134-
13534
#[serde_as]
13635
#[cfg_attr(feature = "clap", derive(clap::Parser))]
13736
#[cfg_attr(feature = "merge", derive(conflate::Merge))]
@@ -141,7 +40,7 @@ impl XattrOption {
14140
#[non_exhaustive]
14241
/// [`LocalSourceSaveOptions`] describes how entries from a local source will be saved in the repository.
14342
pub struct LocalSourceSaveOptions {
144-
/// Set access time [default: yes]
43+
/// Set access time [default: mtime]
14544
#[cfg_attr(feature = "clap", clap(long))]
14645
#[cfg_attr(feature = "merge", merge(strategy = conflate::option::overwrite_none))]
14746
pub set_atime: Option<TimeOption>,
@@ -189,18 +88,29 @@ impl LocalSourceSaveOptions {
18988
})?;
19089

19190
let mtime = m.modified().ok().and_then(|t| Timestamp::try_from(t).ok());
192-
let atime = m.accessed().ok().and_then(|t| Timestamp::try_from(t).ok());
91+
let atime = || m.accessed().ok().and_then(|t| Timestamp::try_from(t).ok());
19392
let atime = self
19493
.set_atime
19594
.unwrap_or(TimeOption::Mtime)
196-
.map(atime, mtime);
197-
let ctime = Self::default_ctime(&m);
198-
let ctime = self.set_ctime.unwrap_or(TimeOption::Yes).map(ctime, mtime);
95+
.map_or_else(atime, mtime);
96+
let ctime = || Self::ctime(&m);
97+
let ctime = self
98+
.set_ctime
99+
.unwrap_or(TimeOption::Yes)
100+
.map_or_else(ctime, mtime);
199101

200102
let (uid, user, gid, group) = Self::user_group(&m);
201103
let size = if m.is_dir() { 0 } else { m.len() };
202-
let device_id = self.set_devid.unwrap_or_default().map(&m);
203-
let extended_attributes = self.set_xattrs.unwrap_or_default().map(entry.path());
104+
let device_id = self
105+
.set_devid
106+
.unwrap_or_default()
107+
.map_or_else(|| Self::device_id(&m), Self::hardlink(&m));
108+
let xattr = || {
109+
Self::xattrs(entry.path())
110+
.inspect_err(|err| warn!("ignoring error obtaining xargs: {err}"))
111+
.unwrap_or_default()
112+
};
113+
let extended_attributes = self.set_xattrs.unwrap_or_default().map_or_else(xattr);
204114
let (mode, inode, links) = Self::nix_infos(&m);
205115

206116
let meta = Metadata {
@@ -251,11 +161,19 @@ impl LocalSourceSaveOptions {
251161

252162
#[cfg(not(windows))]
253163
impl LocalSourceSaveOptions {
254-
fn default_ctime(m: &std::fs::Metadata) -> Option<Timestamp> {
164+
fn ctime(m: &std::fs::Metadata) -> Option<Timestamp> {
255165
#[allow(clippy::cast_possible_truncation)]
256166
Timestamp::new(m.ctime(), m.ctime_nsec() as i32).ok()
257167
}
258168

169+
fn device_id(m: &std::fs::Metadata) -> u64 {
170+
m.dev()
171+
}
172+
173+
fn hardlink(m: &std::fs::Metadata) -> bool {
174+
m.nlink() > 1 && !m.is_dir()
175+
}
176+
259177
fn user_group(
260178
m: &std::fs::Metadata,
261179
) -> (Option<u32>, Option<String>, Option<u32>, Option<String>) {
@@ -273,6 +191,39 @@ impl LocalSourceSaveOptions {
273191
(Some(mode), inode, links)
274192
}
275193

194+
/// List [`ExtendedAttribute`] for a [`Node`] located at `path`
195+
///
196+
/// # Argument
197+
///
198+
/// * `path` to the [`Node`] for which to list attributes
199+
///
200+
/// # Errors
201+
///
202+
/// * If Xattr couldn't be listed or couldn't be read
203+
#[cfg(not(target_os = "openbsd"))]
204+
fn xattrs(path: &Path) -> IgnoreResult<Vec<ExtendedAttribute>> {
205+
xattr::list(path)
206+
.map_err(|err| IgnoreErrorKind::ErrorXattr {
207+
path: path.to_path_buf(),
208+
source: err,
209+
})?
210+
.map(|name| {
211+
Ok(ExtendedAttribute {
212+
name: name.to_string_lossy().to_string(),
213+
value: xattr::get(path, name).map_err(|err| IgnoreErrorKind::ErrorXattr {
214+
path: path.to_path_buf(),
215+
source: err,
216+
})?,
217+
})
218+
})
219+
.collect::<IgnoreResult<Vec<ExtendedAttribute>>>()
220+
}
221+
222+
#[cfg(target_os = "openbsd")]
223+
fn xattrs(_path: &Path) -> IgnoreResult<Vec<ExtendedAttribute>> {
224+
Ok(Vec::new())
225+
}
226+
276227
fn to_node_other(self, name: &OsStr, m: &std::fs::Metadata, meta: Metadata) -> Node {
277228
let filetype = m.file_type();
278229
if filetype.is_block_device() {
@@ -297,9 +248,15 @@ impl LocalSourceSaveOptions {
297248

298249
#[cfg(windows)]
299250
impl LocalSourceSaveOptions {
300-
fn default_ctime(m: &std::fs::Metadata) -> Option<Timestamp> {
251+
fn ctime(m: &std::fs::Metadata) -> Option<Timestamp> {
301252
m.created().ok().and_then(|t| Timestamp::try_from(t).ok())
302253
}
254+
fn device_id(_m: &std::fs::Metadata) -> u64 {
255+
0
256+
}
257+
fn hardlink(m: &std::fs::Metadata) -> bool {
258+
false
259+
}
303260
fn user_group(
304261
_m: &std::fs::Metadata,
305262
) -> (Option<u32>, Option<String>, Option<u32>, Option<String>) {
@@ -310,6 +267,10 @@ impl LocalSourceSaveOptions {
310267
(None, 0, 0)
311268
}
312269

270+
fn xattrs(_path: &Path) -> IgnoreResult<Vec<ExtendedAttribute>> {
271+
Ok(Vec::new())
272+
}
273+
313274
fn to_node_other(self, name: &OsStr, _m: &std::fs::Metadata, meta: Metadata) -> Node {
314275
Node::new_node(name, NodeType::File, meta)
315276
}

crates/core/src/backend/node.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pub mod modification;
2+
13
use std::{
24
cmp::Ordering,
35
ffi::{OsStr, OsString},

0 commit comments

Comments
 (0)