Skip to content

Commit

Permalink
Pass --mmap to memory-map files for hashing (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
casey authored Sep 3, 2024
1 parent f2b1615 commit 36b5063
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 16 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license = "CC0-1.0"
repository = "https://github.com/casey/filepack"

[dependencies]
blake3 = { version = "1.5.4", features = ["serde"] }
blake3 = { version = "1.5.4", features = ["mmap", "serde"] }
camino = { version = "1.1.9", features = ["serde1"] }
clap = { version = "4.5.16", features = ["derive"] }
serde = { version = "1.0.209", features = ["derive"] }
Expand Down
29 changes: 29 additions & 0 deletions src/arguments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use {
super::*,
clap::builder::{
styling::{AnsiColor, Effects},
Styles,
},
};

#[derive(Parser)]
#[command(
version,
styles = Styles::styled()
.header(AnsiColor::Green.on_default() | Effects::BOLD)
.usage(AnsiColor::Green.on_default() | Effects::BOLD)
.literal(AnsiColor::Blue.on_default() | Effects::BOLD)
.placeholder(AnsiColor::Cyan.on_default()))
]
pub(crate) struct Arguments {
#[command(flatten)]
options: Options,
#[command(subcommand)]
subcommand: Subcommand,
}

impl Arguments {
pub(crate) fn run(self) -> Result {
self.subcommand.run(self.options)
}
}
10 changes: 6 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use {
self::{
error::Error, hash::Hash, lint::Lint, list::List, manifest::Manifest,
relative_path::RelativePath, subcommand::Subcommand,
arguments::Arguments, error::Error, hash::Hash, lint::Lint, list::List, manifest::Manifest,
options::Options, relative_path::RelativePath, subcommand::Subcommand,
},
blake3::Hasher,
camino::{Utf8Component, Utf8Path, Utf8PathBuf},
Expand All @@ -14,25 +14,27 @@ use {
fmt::{self, Display, Formatter},
fs::{self, File},
io,
path::PathBuf,
path::{Path, PathBuf},
process,
str::FromStr,
},
walkdir::WalkDir,
};

mod arguments;
mod error;
mod hash;
mod lint;
mod list;
mod manifest;
mod options;
mod relative_path;
mod subcommand;

type Result<T = (), E = Error> = std::result::Result<T, E>;

fn main() {
if let Err(err) = Subcommand::parse().run() {
if let Err(err) = Arguments::parse().run() {
eprintln!("error: {err}");

for (i, err) in err.iter_chain().skip(1).enumerate() {
Expand Down
7 changes: 7 additions & 0 deletions src/options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use super::*;

#[derive(Parser)]
pub(crate) struct Options {
#[arg(long, help = "Memory-map files for hashing")]
pub(crate) mmap: bool,
}
6 changes: 6 additions & 0 deletions src/relative_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ impl AsRef<Utf8Path> for RelativePath {
}
}

impl AsRef<Path> for RelativePath {
fn as_ref(&self) -> &Path {
self.0.as_ref()
}
}

impl<'de> Deserialize<'de> for RelativePath {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand Down
6 changes: 3 additions & 3 deletions src/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ pub(crate) enum Subcommand {
}

impl Subcommand {
pub(crate) fn run(self) -> Result {
pub(crate) fn run(self, options: Options) -> Result {
match self {
Self::Create { root } => create::run(&root),
Self::Verify { root } => verify::run(&root),
Self::Create { root } => create::run(options, &root),
Self::Verify { root } => verify::run(options, &root),
}
}
}
11 changes: 7 additions & 4 deletions src/subcommand/create.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;

pub(crate) fn run(root: &Utf8Path) -> Result {
pub(crate) fn run(options: Options, root: &Utf8Path) -> Result {
let mut files = HashMap::new();

let mut dirs = Vec::new();
Expand Down Expand Up @@ -31,11 +31,14 @@ pub(crate) fn run(root: &Utf8Path) -> Result {
return Err(error::Symlink { path }.build());
}

let file = File::open(path).context(error::Io { path })?;

let mut hasher = Hasher::new();

hasher.update_reader(file).context(error::Io { path })?;
if options.mmap {
hasher.update_mmap(path).context(error::Io { path })?;
} else {
let file = File::open(root.join(path)).context(error::Io { path })?;
hasher.update_reader(file).context(error::Io { path })?;
}

let relative = path.strip_prefix(root).unwrap();

Expand Down
11 changes: 7 additions & 4 deletions src/subcommand/verify.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;

pub(crate) fn run(root: &Utf8Path) -> Result {
pub(crate) fn run(options: Options, root: &Utf8Path) -> Result {
let source = root.join(Manifest::FILENAME);

let json = fs::read_to_string(&source).context(error::Io {
Expand All @@ -12,11 +12,14 @@ pub(crate) fn run(root: &Utf8Path) -> Result {
})?;

for (path, &expected) in &manifest.files {
let file = File::open(root.join(path)).context(error::Io { path })?;

let mut hasher = Hasher::new();

hasher.update_reader(file).context(error::Io { path })?;
if options.mmap {
hasher.update_mmap(path).context(error::Io { path })?;
} else {
let file = File::open(root.join(path)).context(error::Io { path })?;
hasher.update_reader(file).context(error::Io { path })?;
}

let actual = Hash::from(hasher.finalize());

Expand Down
25 changes: 25 additions & 0 deletions tests/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,31 @@ fn single_file() {
.success();
}

#[test]
fn single_file_with_mmap() {
let dir = TempDir::new().unwrap();

dir.child("foo").touch().unwrap();

Command::cargo_bin("filepack")
.unwrap()
.args(["--mmap", "create", "."])
.current_dir(&dir)
.assert()
.success();

dir.child("filepack.json").assert(
r#"{"files":{"foo":"af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262"}}"#,
);

Command::cargo_bin("filepack")
.unwrap()
.args(["--mmap", "verify", "."])
.current_dir(&dir)
.assert()
.success();
}

#[test]
fn file_in_subdirectory() {
let dir = TempDir::new().unwrap();
Expand Down
42 changes: 42 additions & 0 deletions tests/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,48 @@ fn no_files() {
.success();
}

#[test]
fn single_file() {
let dir = TempDir::new().unwrap();

dir.child("foo").touch().unwrap();

dir
.child("filepack.json")
.write_str(
r#"{"files":{"foo":"af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262"}}"#,
)
.unwrap();

Command::cargo_bin("filepack")
.unwrap()
.args(["verify", "."])
.current_dir(&dir)
.assert()
.success();
}

#[test]
fn single_file_with_mmap() {
let dir = TempDir::new().unwrap();

dir.child("foo").touch().unwrap();

dir
.child("filepack.json")
.write_str(
r#"{"files":{"foo":"af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262"}}"#,
)
.unwrap();

Command::cargo_bin("filepack")
.unwrap()
.args(["--mmap", "verify", "."])
.current_dir(&dir)
.assert()
.success();
}

#[test]
fn extra_fields_are_not_allowed() {
let dir = TempDir::new().unwrap();
Expand Down

0 comments on commit 36b5063

Please sign in to comment.