Skip to content

Commit

Permalink
Store a typed Apath in Index Entry
Browse files Browse the repository at this point in the history
Apath is now serializable by Serde, which turns out to be pretty straightforward.

Moves further towards unifying entries.
  • Loading branch information
sourcefrog committed Nov 29, 2019
1 parent eebfa60 commit 8e6a456
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 27 deletions.
6 changes: 4 additions & 2 deletions src/apath.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Conserve backup system.
// Copyright 2015, 2016, 2017, 2018 Martin Pool.
// Copyright 2015, 2016, 2017, 2018, 2019 Martin Pool.

//! "Apaths" (for archive paths) are platform-independent relative file paths used
//! inside archive snapshots.
Expand All @@ -13,14 +13,16 @@ use std::fmt;
use std::fmt::{Display, Formatter};
use std::ops::Deref;

use serde::{Deserialize, Serialize};

/// An ordered archive path.
///
/// The ordering groups all the direct parents of a directory together, followed
/// by all the subdirectories.
///
/// Equal strings are equivalent to equal apaths, but the ordering is not the same as
/// string ordering.
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Apath(String);

impl Apath {
Expand Down
10 changes: 5 additions & 5 deletions src/backup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl tree::WriteTree for BackupWriter {
fn write_dir(&mut self, source_entry: &dyn Entry) -> Result<()> {
self.report.increment("dir", 1);
self.push_entry(IndexEntry {
apath: String::from(source_entry.apath()),
apath: source_entry.apath(),
mtime: source_entry.unix_mtime(),
kind: Kind::Dir,
addrs: vec![],
Expand All @@ -74,7 +74,7 @@ impl tree::WriteTree for BackupWriter {
);
// TODO: Perhaps return a future for an index, so that storage of the files can overlap.
self.push_entry(IndexEntry {
apath: String::from(source_entry.apath()),
apath: source_entry.apath(),
mtime: source_entry.unix_mtime(),
kind: Kind::File,
addrs,
Expand All @@ -87,7 +87,7 @@ impl tree::WriteTree for BackupWriter {
let target = source_entry.symlink_target().clone();
assert!(target.is_some());
self.push_entry(IndexEntry {
apath: String::from(source_entry.apath()),
apath: source_entry.apath(),
mtime: source_entry.unix_mtime(),
kind: Kind::Symlink,
addrs: vec![],
Expand Down Expand Up @@ -139,7 +139,7 @@ mod tests {

let e2 = &index_entries[1];
assert_eq!(e2.kind(), Kind::Symlink);
assert_eq!(e2.apath, "/symlink");
assert_eq!(&e2.apath, "/symlink");
assert_eq!(e2.target.as_ref().unwrap(), "/a/broken/destination");
}

Expand Down Expand Up @@ -196,7 +196,7 @@ mod tests {
.iter_entries(&af.report())
.unwrap()
.map(|i| i.unwrap())
.find(|ref i| i.apath == "/empty")
.find(|ref i| &i.apath == "/empty")
.expect("found one entry");
let mut sf = st.file_contents(&empty_entry).unwrap();
let mut s = String::new();
Expand Down
29 changes: 14 additions & 15 deletions src/index.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Conserve backup system.
// Copyright 2015, 2016, 2017, 2018 Martin Pool.
// Copyright 2015, 2016, 2017, 2018, 2019 Martin Pool.

//! Index lists the files in a band in the archive.
Expand All @@ -25,8 +25,7 @@ pub const MAX_ENTRIES_PER_HUNK: usize = 1000;
#[derive(Debug, Serialize, Deserialize)]
pub struct IndexEntry {
/// Path of this entry relative to the base of the backup, in `apath` form.
// TODO: Make it an actual Apath, once that's encodable.
pub apath: String,
pub apath: Apath,

/// File modification time, in whole seconds past the Unix epoch.
pub mtime: Option<u64>,
Expand All @@ -43,7 +42,7 @@ pub struct IndexEntry {

impl entry::Entry for IndexEntry {
fn apath(&self) -> Apath {
Apath::from(self.apath.as_str())
self.apath.clone()
}

fn kind(&self) -> Kind {
Expand Down Expand Up @@ -103,7 +102,7 @@ impl IndexBuilder {
pub fn push(&mut self, entry: IndexEntry) {
// We do this check here rather than the Index constructor so that we
// can still read invalid apaths...
self.check_order.check(&Apath::from(entry.apath.as_str()));
self.check_order.check(&entry.apath);
self.entries.push(entry);
}

Expand Down Expand Up @@ -288,7 +287,7 @@ impl Iter {
self.buffered_entries = entries
.into_iter()
.filter(|entry| {
if self.excludes.is_match(&entry.apath) {
if self.excludes.is_match(Path::new(&entry.apath.to_string())) {
match entry.kind() {
Kind::Dir => self.report.increment("skipped.excluded.directories", 1),
Kind::Symlink => self.report.increment("skipped.excluded.symlinks", 1),
Expand Down Expand Up @@ -324,7 +323,7 @@ mod tests {

pub fn add_an_entry(ib: &mut IndexBuilder, apath: &str) {
ib.push(IndexEntry {
apath: apath.to_string(),
apath: apath.into(),
mtime: None,
kind: Kind::File,
addrs: vec![],
Expand All @@ -335,7 +334,7 @@ mod tests {
#[test]
fn serialize_index() {
let entries = [IndexEntry {
apath: "/a/b".to_string(),
apath: "/a/b".into(),
mtime: Some(1461736377),
kind: Kind::File,
addrs: vec![],
Expand All @@ -358,14 +357,14 @@ mod tests {
fn index_builder_checks_order() {
let (_testdir, mut ib, _report) = scratch_indexbuilder();
ib.push(IndexEntry {
apath: "/zzz".to_string(),
apath: "/zzz".into(),
mtime: None,
kind: Kind::File,
addrs: vec![],
target: None,
});
ib.push(IndexEntry {
apath: "aaa".to_string(),
apath: "aaa".into(),
mtime: None,
kind: Kind::File,
addrs: vec![],
Expand All @@ -378,7 +377,7 @@ mod tests {
fn index_builder_checks_names() {
let (_testdir, mut ib, _report) = scratch_indexbuilder();
ib.push(IndexEntry {
apath: "../escapecat".to_string(),
apath: "../escapecat".into(),
mtime: None,
kind: Kind::File,
addrs: vec![],
Expand Down Expand Up @@ -440,12 +439,12 @@ mod tests {
.next()
.expect("Get first entry")
.expect("First entry isn't an error");
assert_eq!(entry.apath, "/apple");
assert_eq!(&entry.apath, "/apple");
let entry = it
.next()
.expect("Get second entry")
.expect("IndexEntry isn't an error");
assert_eq!(entry.apath, "/banana");
assert_eq!(&entry.apath, "/banana");
let opt_entry = it.next();
if !opt_entry.is_none() {
panic!("Expected no more entries but got {:?}", opt_entry);
Expand All @@ -469,7 +468,7 @@ mod tests {
format!("index::Iter {{ dir: {:?}, next_hunk_number: 0 }}", ib.dir)
);

let names: Vec<String> = it.map(|x| x.unwrap().apath).collect();
let names: Vec<String> = it.map(|x| x.unwrap().apath.into()).collect();
assert_eq!(names, &["/1.1", "/1.2", "/2.1", "/2.2"]);
}

Expand Down Expand Up @@ -508,7 +507,7 @@ mod tests {
format!("index::Iter {{ dir: {:?}, next_hunk_number: 0 }}", ib.dir)
);

let names: Vec<String> = it.map(|x| x.unwrap().apath).collect();
let names: Vec<String> = it.map(|x| x.unwrap().apath.into()).collect();
assert_eq!(names, &["/bar"]);
}
}
2 changes: 1 addition & 1 deletion src/stored_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl StoredFile {
}

/// Validate the stored file hash is as expected.
pub(crate) fn validate(&self, _apath: &Apath) -> Result<()> {
pub(crate) fn validate(&self) -> Result<()> {
// TODO: Perhaps the file should know its apath and hold its entry.
// TODO: Give a more specific message including the band and apath, if
// the content can't be loaded.
Expand Down
4 changes: 2 additions & 2 deletions src/stored_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ impl StoredTree {

fn validate_one_entry(&self, e: &IndexEntry) -> Result<()> {
self.report().start_entry(e);
self.open_stored_file(&e)?.validate(&e.apath.clone().into())
self.open_stored_file(&e)?.validate()
}

/// Open a file stored within this tree.
Expand Down Expand Up @@ -156,7 +156,7 @@ mod test {
let names: Vec<String> = st
.iter_entries(&af.report())
.unwrap()
.map(|e| e.unwrap().apath)
.map(|e| e.unwrap().apath.into())
.collect();
let expected = if SYMLINKS_SUPPORTED {
vec![
Expand Down
4 changes: 2 additions & 2 deletions tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ fn check_backup(af: &ScratchArchive, report: &Report) {
assert_eq!(2, index_entries.len());

let root_entry = &index_entries[0];
assert_eq!("/", root_entry.apath);
assert_eq!("/", root_entry.apath.to_string());
assert_eq!(Kind::Dir, root_entry.kind);
assert!(root_entry.mtime.unwrap() > 0);

let file_entry = &index_entries[1];
assert_eq!("/hello", file_entry.apath);
assert_eq!("/hello", file_entry.apath.to_string());
assert_eq!(Kind::File, file_entry.kind);
assert!(file_entry.mtime.unwrap() > 0);

Expand Down

0 comments on commit 8e6a456

Please sign in to comment.