feat(link_to): rename feature link to link_to

This commit is contained in:
Scott Haug 2023-02-27 13:41:13 -08:00
parent 7fb373ce5b
commit 292e5d0cdc
7 changed files with 148 additions and 137 deletions

View File

@ -53,5 +53,5 @@ harness = false
[features] [features]
default = ["async-std", "async-attributes"] default = ["async-std", "async-attributes"]
link = [] link_to = []
tokio-runtime = ["tokio", "tokio-stream"] tokio-runtime = ["tokio", "tokio-stream"]

View File

@ -63,8 +63,8 @@ Minimum supported Rust version is `1.43.0`.
cacache = { version = "*", default-features = false, features = ["tokio-runtime"] } cacache = { version = "*", default-features = false, features = ["tokio-runtime"] }
``` ```
Experimental support for tracking existing files through symlinks is provided Experimental support for symlinking to existing files is provided via the
via the "link" feature. "link_to" feature.
## Contributing ## Contributing

View File

@ -208,6 +208,7 @@ fn write_hash_async(c: &mut Criterion) {
}); });
} }
#[cfg(feature = "link_to")]
fn create_tmpfile(tmp: &tempfile::TempDir, buf: &[u8]) -> PathBuf { fn create_tmpfile(tmp: &tempfile::TempDir, buf: &[u8]) -> PathBuf {
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
let target = dir.join("target-file"); let target = dir.join("target-file");
@ -218,8 +219,8 @@ fn create_tmpfile(tmp: &tempfile::TempDir, buf: &[u8]) -> PathBuf {
target target
} }
#[cfg(feature = "link")] #[cfg(feature = "link_to")]
fn link_async(c: &mut Criterion) { fn link_to_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let target = create_tmpfile(&tmp, b"hello world"); let target = create_tmpfile(&tmp, b"hello world");
@ -229,27 +230,32 @@ fn link_async(c: &mut Criterion) {
b.iter_custom(|iters| { b.iter_custom(|iters| {
let start = std::time::Instant::now(); let start = std::time::Instant::now();
for i in 0..iters { for i in 0..iters {
block_on(cacache::link(&cache, format!("key{}", i), target.clone())).unwrap(); block_on(cacache::link_to(
&cache,
format!("key{}", i),
target.clone(),
))
.unwrap();
} }
start.elapsed() start.elapsed()
}) })
}); });
} }
#[cfg(feature = "link")] #[cfg(feature = "link_to")]
fn link_hash_async(c: &mut Criterion) { fn link_to_hash_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let target = create_tmpfile(&tmp, b"hello world"); let target = create_tmpfile(&tmp, b"hello world");
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let cache = tmp.path().to_owned(); let cache = tmp.path().to_owned();
c.bench_function("link::file_hash", move |b| { c.bench_function("link::file_hash", move |b| {
b.iter(|| block_on(cacache::link_hash(&cache, target.clone())).unwrap()) b.iter(|| block_on(cacache::link_to_hash(&cache, target.clone())).unwrap())
}); });
} }
#[cfg(feature = "link")] #[cfg(feature = "link_to")]
fn link_sync(c: &mut Criterion) { fn link_to_sync(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let target = create_tmpfile(&tmp, b"hello world"); let target = create_tmpfile(&tmp, b"hello world");
@ -259,22 +265,22 @@ fn link_sync(c: &mut Criterion) {
b.iter_custom(|iters| { b.iter_custom(|iters| {
let start = std::time::Instant::now(); let start = std::time::Instant::now();
for i in 0..iters { for i in 0..iters {
cacache::link_sync(&cache, format!("key{}", i), target.clone()).unwrap(); cacache::link_to_sync(&cache, format!("key{}", i), target.clone()).unwrap();
} }
start.elapsed() start.elapsed()
}) })
}); });
} }
#[cfg(feature = "link")] #[cfg(feature = "link_to")]
fn link_hash_sync(c: &mut Criterion) { fn link_to_hash_sync(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let target = create_tmpfile(&tmp, b"hello world"); let target = create_tmpfile(&tmp, b"hello world");
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let cache = tmp.path().to_owned(); let cache = tmp.path().to_owned();
c.bench_function("link::file_hash_sync", move |b| { c.bench_function("link::file_hash_sync", move |b| {
b.iter(|| cacache::link_hash_sync(&cache, target.clone()).unwrap()) b.iter(|| cacache::link_to_hash_sync(&cache, target.clone()).unwrap())
}); });
} }
@ -295,16 +301,16 @@ criterion_group!(
read_hash_sync_big_data read_hash_sync_big_data
); );
#[cfg(feature = "link")] #[cfg(feature = "link_to")]
criterion_group!( criterion_group!(
link_benches, link_to_benches,
link_async, link_to_async,
link_hash_async, link_to_hash_async,
link_sync, link_to_sync,
link_hash_sync link_to_hash_sync
); );
#[cfg(feature = "link")] #[cfg(feature = "link_to")]
criterion_main!(benches, link_benches); criterion_main!(benches, link_to_benches);
#[cfg(not(feature = "link"))] #[cfg(not(feature = "link_to"))]
criterion_main!(benches); criterion_main!(benches);

View File

@ -59,9 +59,9 @@ fn create_symlink(sri: Integrity, cache: &PathBuf, target: &PathBuf) -> Result<I
} }
/// A `Read`-like type that calculates the integrity of a file as it is read. /// A `Read`-like type that calculates the integrity of a file as it is read.
/// When the linker is committed, the file is symlinked into the cache using the /// When the linker is committed, a symlink is created from the cache to the
/// integrity computed from the target file's contents. /// target file using the integrity computed from the file's contents.
pub struct Linker { pub struct ToLinker {
/// The path to the target file that will be symlinked from the cache. /// The path to the target file that will be symlinked from the cache.
target: PathBuf, target: PathBuf,
/// The path to the root of the cache directory. /// The path to the root of the cache directory.
@ -72,7 +72,7 @@ pub struct Linker {
builder: IntegrityOpts, builder: IntegrityOpts,
} }
impl Linker { impl ToLinker {
pub fn new(cache: &Path, algo: Algorithm, target: &Path) -> Result<Self> { pub fn new(cache: &Path, algo: Algorithm, target: &Path) -> Result<Self> {
let file = File::open(target) let file = File::open(target)
.with_context(|| format!("Failed to open reader to {}", target.display()))?; .with_context(|| format!("Failed to open reader to {}", target.display()))?;
@ -84,13 +84,13 @@ impl Linker {
}) })
} }
/// Consume the Linker and commit the symlink to the cache. /// Add the symlink to the target file from the cache.
pub fn commit(self) -> Result<Integrity> { pub fn commit(self) -> Result<Integrity> {
create_symlink(self.builder.result(), &self.cache, &self.target) create_symlink(self.builder.result(), &self.cache, &self.target)
} }
} }
impl std::io::Read for Linker { impl std::io::Read for ToLinker {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let amt = self.fd.read(buf)?; let amt = self.fd.read(buf)?;
if amt > 0 { if amt > 0 {
@ -101,9 +101,9 @@ impl std::io::Read for Linker {
} }
/// An `AsyncRead`-like type that calculates the integrity of a file as it is /// An `AsyncRead`-like type that calculates the integrity of a file as it is
/// read. When the linker is committed, the file is symlinked into the cache /// read. When the linker is committed, a symlink is created from the cache to
/// using the integrity computed from the target file's contents. /// the target file using the integrity computed from the file's contents.
pub struct AsyncLinker { pub struct AsyncToLinker {
/// The path to the target file that will be symlinked from the cache. /// The path to the target file that will be symlinked from the cache.
target: PathBuf, target: PathBuf,
/// The path to the root of the cache directory. /// The path to the root of the cache directory.
@ -114,7 +114,7 @@ pub struct AsyncLinker {
builder: IntegrityOpts, builder: IntegrityOpts,
} }
impl AsyncRead for AsyncLinker { impl AsyncRead for AsyncToLinker {
#[cfg(feature = "async-std")] #[cfg(feature = "async-std")]
fn poll_read( fn poll_read(
mut self: Pin<&mut Self>, mut self: Pin<&mut Self>,
@ -143,7 +143,7 @@ impl AsyncRead for AsyncLinker {
} }
} }
impl AsyncLinker { impl AsyncToLinker {
pub async fn new(cache: &Path, algo: Algorithm, target: &Path) -> Result<Self> { pub async fn new(cache: &Path, algo: Algorithm, target: &Path) -> Result<Self> {
let file = crate::async_lib::File::open(target) let file = crate::async_lib::File::open(target)
.await .await
@ -156,7 +156,7 @@ impl AsyncLinker {
}) })
} }
/// Consume the Linker and commit the symlink to the cache. /// Add the symlink to the target file from the cache.
pub async fn commit(self) -> Result<Integrity> { pub async fn commit(self) -> Result<Integrity> {
create_symlink(self.builder.result(), &self.cache, &self.target) create_symlink(self.builder.result(), &self.cache, &self.target)
} }
@ -195,7 +195,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
let mut linker = Linker::new(&dir, Algorithm::Sha256, &target).unwrap(); let mut linker = ToLinker::new(&dir, Algorithm::Sha256, &target).unwrap();
// read all of the data from the linker, which will calculate the integrity // read all of the data from the linker, which will calculate the integrity
// hash. // hash.
@ -223,7 +223,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
let mut linker = AsyncLinker::new(&dir, Algorithm::Sha256, &target) let mut linker = AsyncToLinker::new(&dir, Algorithm::Sha256, &target)
.await .await
.unwrap(); .unwrap();

View File

@ -3,5 +3,5 @@ pub mod read;
pub mod rm; pub mod rm;
pub mod write; pub mod write;
#[cfg(feature = "link")] #[cfg(feature = "link_to")]
pub mod symlink; pub mod linkto;

View File

@ -122,21 +122,21 @@
//! } //! }
//! ``` //! ```
//! //!
//! ### Linking exsiting files //! ### Linking to existing files
//! //!
//! The `link` feature enables an additional set of APIs for adding existing //! The `link_to` feature enables an additional set of APIs for adding existing
//! files into the cache via symlinks, without having to duplicate the data. //! files into the cache via symlinks, without having to duplicate their data.
//! Once linked into the cache, these files can be accessed by key just like //! Once the cache links to them, these files can be accessed by key just like
//! other cached data, with the same integrity checking. //! other cached data, with the same integrity checking.
//! //!
//! The `link` methods are available in both async and sync variants, using the //! The `link_to` methods are available in both async and sync variants, using
//! same suffixes as the other APIs. //! the same suffixes as the other APIs.
//! //!
//! ```no_run //! ```no_run
//! #[async_attributes::main] //! #[async_attributes::main]
//! async fn main() -> cacache::Result<()> { //! async fn main() -> cacache::Result<()> {
//! #[cfg(feature = "link")] //! #[cfg(feature = "link_to")]
//! cacache::link("./my-cache", "key", "/path/to/my-other-file.txt").await?; //! cacache::link_to("./my-cache", "key", "/path/to/my-other-file.txt").await?;
//! let data = cacache::read("./my-cache", "key").await?; //! let data = cacache::read("./my-cache", "key").await?;
//! assert_eq!(data, b"my-data"); //! assert_eq!(data, b"my-data");
//! Ok(()) //! Ok(())
@ -160,8 +160,8 @@ mod errors;
pub mod index; pub mod index;
mod get; mod get;
#[cfg(feature = "link")] #[cfg(feature = "link_to")]
mod link; mod linkto;
mod ls; mod ls;
mod put; mod put;
mod rm; mod rm;
@ -170,8 +170,8 @@ pub use errors::{Error, Result};
pub use index::Metadata; pub use index::Metadata;
pub use get::*; pub use get::*;
#[cfg(feature = "link")] #[cfg(feature = "link_to")]
pub use link::*; pub use linkto::*;
pub use ls::*; pub use ls::*;
pub use put::*; pub use put::*;
pub use rm::*; pub use rm::*;

View File

@ -1,5 +1,5 @@
use crate::async_lib::AsyncRead; use crate::async_lib::AsyncRead;
use crate::content::symlink; use crate::content::linkto;
use crate::errors::{Error, IoErrorExt, Result}; use crate::errors::{Error, IoErrorExt, Result};
use crate::{index, WriteOpts}; use crate::{index, WriteOpts};
use ssri::{Algorithm, Integrity}; use ssri::{Algorithm, Integrity};
@ -26,17 +26,17 @@ const PROBE_SIZE: usize = 8;
/// ///
/// #[async_attributes::main] /// #[async_attributes::main]
/// async fn main() -> cacache::Result<()> { /// async fn main() -> cacache::Result<()> {
/// cacache::link("./my-cache", "my-key", "../my-other-files/my-file.tgz").await?; /// cacache::link_to("./my-cache", "my-key", "../my-other-files/my-file.tgz").await?;
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
pub async fn link<P, K, T>(cache: P, key: K, target: T) -> Result<Integrity> pub async fn link_to<P, K, T>(cache: P, key: K, target: T) -> Result<Integrity>
where where
P: AsRef<Path>, P: AsRef<Path>,
K: AsRef<str>, K: AsRef<str>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
Linker::open(cache, key, target).await?.commit().await ToLinker::open(cache, key, target).await?.commit().await
} }
/// Asynchrounously adds `target` to the `cache` with a symlink, skipping /// Asynchrounously adds `target` to the `cache` with a symlink, skipping
@ -49,20 +49,20 @@ where
/// ///
/// #[async_attributes::main] /// #[async_attributes::main]
/// async fn main() -> cacache::Result<()> { /// async fn main() -> cacache::Result<()> {
/// cacache::link_hash("./my-cache", "../my-other-files/my-file.tgz").await?; /// cacache::link_to_hash("./my-cache", "../my-other-files/my-file.tgz").await?;
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
pub async fn link_hash<P, T>(cache: P, target: T) -> Result<Integrity> pub async fn link_to_hash<P, T>(cache: P, target: T) -> Result<Integrity>
where where
P: AsRef<Path>, P: AsRef<Path>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
Linker::open_hash(cache, target).await?.commit().await ToLinker::open_hash(cache, target).await?.commit().await
} }
/// Synchronously adds `target` to the `cache` with a symlink, indexing it under /// Synchronously creates a symlink in the `cache` to the `target`, indexing it
/// `key`. /// under `key`.
/// ///
/// ## Example /// ## Example
/// ```no_run /// ```no_run
@ -70,20 +70,20 @@ where
/// use std::path::Path; /// use std::path::Path;
/// ///
/// fn main() -> cacache::Result<()> { /// fn main() -> cacache::Result<()> {
/// cacache::link_sync("./my-cache", "my-key", "../my-other-files/my-file.tgz")?; /// cacache::link_to_sync("./my-cache", "my-key", "../my-other-files/my-file.tgz")?;
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
pub fn link_sync<P, K, T>(cache: P, key: K, target: T) -> Result<Integrity> pub fn link_to_sync<P, K, T>(cache: P, key: K, target: T) -> Result<Integrity>
where where
P: AsRef<Path>, P: AsRef<Path>,
K: AsRef<str>, K: AsRef<str>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
SyncLinker::open(cache, key, target)?.commit() SyncToLinker::open(cache, key, target)?.commit()
} }
/// Synchronously adds `target` to the `cache` with a symlink, skipping /// Synchronously creates a symlink in the `cache` to the `target`, skipping
/// associating an index key with it. /// associating an index key with it.
/// ///
/// ## Example /// ## Example
@ -92,34 +92,39 @@ where
/// use std::path::Path; /// use std::path::Path;
/// ///
/// fn main() -> cacache::Result<()> { /// fn main() -> cacache::Result<()> {
/// cacache::link_hash_sync("./my-cache", "../foo/bar.tgz")?; /// cacache::link_to_hash_sync("./my-cache", "../foo/bar.tgz")?;
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
pub fn link_hash_sync<P, T>(cache: P, target: T) -> Result<Integrity> pub fn link_to_hash_sync<P, T>(cache: P, target: T) -> Result<Integrity>
where where
P: AsRef<Path>, P: AsRef<Path>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
SyncLinker::open_hash(cache, target)?.commit() SyncToLinker::open_hash(cache, target)?.commit()
} }
/// Extend the `WriteOpts` struct with factories for creating `Linker` and /// Extend the `WriteOpts` struct with factories for creating `ToLinker` and
/// `SyncLinker` instances. /// `SyncToLinker` instances.
impl WriteOpts { impl WriteOpts {
/// Opens the target file handle for reading, returning a Linker instance. /// Opens the target file handle for reading, returning a ToLinker instance.
pub async fn link<P, K, T>(self, cache: P, key: K, target: T) -> Result<Linker> pub async fn link_to<P, K, T>(self, cache: P, key: K, target: T) -> Result<ToLinker>
where where
P: AsRef<Path>, P: AsRef<Path>,
K: AsRef<str>, K: AsRef<str>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
async fn inner(opts: WriteOpts, cache: &Path, key: &str, target: &Path) -> Result<Linker> { async fn inner(
Ok(Linker { opts: WriteOpts,
cache: &Path,
key: &str,
target: &Path,
) -> Result<ToLinker> {
Ok(ToLinker {
cache: cache.to_path_buf(), cache: cache.to_path_buf(),
key: Some(String::from(key)), key: Some(String::from(key)),
read: 0, read: 0,
linker: symlink::AsyncLinker::new( linker: linkto::AsyncToLinker::new(
cache, cache,
opts.algorithm.unwrap_or(Algorithm::Sha256), opts.algorithm.unwrap_or(Algorithm::Sha256),
target, target,
@ -132,18 +137,18 @@ impl WriteOpts {
} }
/// Opens the target file handle for reading, without a key, returning a /// Opens the target file handle for reading, without a key, returning a
/// Linker instance. /// ToLinker instance.
pub async fn link_hash<P, T>(self, cache: P, target: T) -> Result<Linker> pub async fn link_to_hash<P, T>(self, cache: P, target: T) -> Result<ToLinker>
where where
P: AsRef<Path>, P: AsRef<Path>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
async fn inner(opts: WriteOpts, cache: &Path, target: &Path) -> Result<Linker> { async fn inner(opts: WriteOpts, cache: &Path, target: &Path) -> Result<ToLinker> {
Ok(Linker { Ok(ToLinker {
cache: cache.to_path_buf(), cache: cache.to_path_buf(),
key: None, key: None,
read: 0, read: 0,
linker: symlink::AsyncLinker::new( linker: linkto::AsyncToLinker::new(
cache, cache,
opts.algorithm.unwrap_or(Algorithm::Sha256), opts.algorithm.unwrap_or(Algorithm::Sha256),
target, target,
@ -156,19 +161,19 @@ impl WriteOpts {
} }
/// Opens the target file handle for reading synchronously, returning a /// Opens the target file handle for reading synchronously, returning a
/// SyncLinker instance. /// SyncToLinker instance.
pub fn link_sync<P, K, T>(self, cache: P, key: K, target: T) -> Result<SyncLinker> pub fn link_to_sync<P, K, T>(self, cache: P, key: K, target: T) -> Result<SyncToLinker>
where where
P: AsRef<Path>, P: AsRef<Path>,
K: AsRef<str>, K: AsRef<str>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
fn inner(opts: WriteOpts, cache: &Path, key: &str, target: &Path) -> Result<SyncLinker> { fn inner(opts: WriteOpts, cache: &Path, key: &str, target: &Path) -> Result<SyncToLinker> {
Ok(SyncLinker { Ok(SyncToLinker {
cache: cache.to_path_buf(), cache: cache.to_path_buf(),
key: Some(String::from(key)), key: Some(String::from(key)),
read: 0, read: 0,
linker: symlink::Linker::new( linker: linkto::ToLinker::new(
cache, cache,
opts.algorithm.unwrap_or(Algorithm::Sha256), opts.algorithm.unwrap_or(Algorithm::Sha256),
target, target,
@ -180,18 +185,18 @@ impl WriteOpts {
} }
/// Opens the target file handle for reading synchronously, without a key, /// Opens the target file handle for reading synchronously, without a key,
/// returning a SyncLinker instance. /// returning a SyncToLinker instance.
pub fn link_hash_sync<P, T>(self, cache: P, target: T) -> Result<SyncLinker> pub fn link_to_hash_sync<P, T>(self, cache: P, target: T) -> Result<SyncToLinker>
where where
P: AsRef<Path>, P: AsRef<Path>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
fn inner(opts: WriteOpts, cache: &Path, target: &Path) -> Result<SyncLinker> { fn inner(opts: WriteOpts, cache: &Path, target: &Path) -> Result<SyncToLinker> {
Ok(SyncLinker { Ok(SyncToLinker {
cache: cache.to_path_buf(), cache: cache.to_path_buf(),
key: None, key: None,
read: 0, read: 0,
linker: symlink::Linker::new( linker: linkto::ToLinker::new(
cache, cache,
opts.algorithm.unwrap_or(Algorithm::Sha256), opts.algorithm.unwrap_or(Algorithm::Sha256),
target, target,
@ -203,20 +208,20 @@ impl WriteOpts {
} }
} }
/// A file handle for asynchronously reading data from a file to be added to the /// A file handle for asynchronously reading in data from a file to be added to
/// cache via a symlink. /// the cache via a symlink to the target file.
/// ///
/// Make sure to call `.commit()` when done reading to actually add the file to /// Make sure to call `.commit()` when done reading to actually add the file to
/// the cache. /// the cache.
pub struct Linker { pub struct ToLinker {
cache: PathBuf, cache: PathBuf,
key: Option<String>, key: Option<String>,
read: usize, read: usize,
pub(crate) linker: symlink::AsyncLinker, pub(crate) linker: linkto::AsyncToLinker,
opts: WriteOpts, opts: WriteOpts,
} }
impl AsyncRead for Linker { impl AsyncRead for ToLinker {
#[cfg(feature = "async-std")] #[cfg(feature = "async-std")]
fn poll_read( fn poll_read(
mut self: Pin<&mut Self>, mut self: Pin<&mut Self>,
@ -248,7 +253,7 @@ fn filesize(target: &Path) -> Result<usize> {
.len() as usize) .len() as usize)
} }
impl Linker { impl ToLinker {
/// Creates a new asynchronous readable file handle into the cache. /// Creates a new asynchronous readable file handle into the cache.
pub async fn open<P, K, T>(cache: P, key: K, target: T) -> Result<Self> pub async fn open<P, K, T>(cache: P, key: K, target: T) -> Result<Self>
where where
@ -256,12 +261,12 @@ impl Linker {
K: AsRef<str>, K: AsRef<str>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
async fn inner(cache: &Path, key: &str, target: &Path) -> Result<Linker> { async fn inner(cache: &Path, key: &str, target: &Path) -> Result<ToLinker> {
let size = filesize(&target)?; let size = filesize(target)?;
WriteOpts::new() WriteOpts::new()
.algorithm(Algorithm::Sha256) .algorithm(Algorithm::Sha256)
.size(size) .size(size)
.link(cache, key, target) .link_to(cache, key, target)
.await .await
} }
inner(cache.as_ref(), key.as_ref(), target.as_ref()).await inner(cache.as_ref(), key.as_ref(), target.as_ref()).await
@ -273,20 +278,20 @@ impl Linker {
P: AsRef<Path>, P: AsRef<Path>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
async fn inner(cache: &Path, target: &Path) -> Result<Linker> { async fn inner(cache: &Path, target: &Path) -> Result<ToLinker> {
let size = filesize(&target)?; let size = filesize(target)?;
WriteOpts::new() WriteOpts::new()
.algorithm(Algorithm::Sha256) .algorithm(Algorithm::Sha256)
.size(size) .size(size)
.link_hash(cache, target) .link_to_hash(cache, target)
.await .await
} }
inner(cache.as_ref(), target.as_ref()).await inner(cache.as_ref(), target.as_ref()).await
} }
/// Consumes the rest of the file handle, creates a symlink into the cache, /// Consumes the rest of the file handle, creates an symlink into
/// and creates index entries for the linked file. Also verifies data /// the cache, and creates index entries for the linked file. Also verifies
/// against `size` and `integrity` options, if provided. Must be called /// data against `size` and `integrity` options, if provided. Must be called
/// manually in order to complete the writing process, otherwise everything /// manually in order to complete the writing process, otherwise everything
/// will be thrown out. /// will be thrown out.
pub async fn commit(mut self) -> Result<Integrity> { pub async fn commit(mut self) -> Result<Integrity> {
@ -338,15 +343,15 @@ impl Linker {
/// ///
/// Make sure to call `.commit()` when done reading to actually add the file /// Make sure to call `.commit()` when done reading to actually add the file
/// to the cache. /// to the cache.
pub struct SyncLinker { pub struct SyncToLinker {
cache: PathBuf, cache: PathBuf,
key: Option<String>, key: Option<String>,
read: usize, read: usize,
pub(crate) linker: symlink::Linker, pub(crate) linker: linkto::ToLinker,
opts: WriteOpts, opts: WriteOpts,
} }
impl std::io::Read for SyncLinker { impl std::io::Read for SyncToLinker {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let amt = self.linker.read(buf)?; let amt = self.linker.read(buf)?;
self.read += amt; self.read += amt;
@ -354,9 +359,9 @@ impl std::io::Read for SyncLinker {
} }
} }
impl SyncLinker { impl SyncToLinker {
/// Creates a new readable file handle to a file that will be linked into /// Creates a new readable file handle to a file the cache will link to,
/// the cache, indexed at the provided key, on commit. /// indexed at the provided key, on commit.
/// ///
/// It is not necessary to read any of the file before calling `.commit()`. /// It is not necessary to read any of the file before calling `.commit()`.
/// ///
@ -366,7 +371,7 @@ impl SyncLinker {
/// ///
/// fn main() -> cacache::Result<()> { /// fn main() -> cacache::Result<()> {
/// let path = "../my-other-files/my-file.tgz"; /// let path = "../my-other-files/my-file.tgz";
/// let mut fd = cacache::SyncLinker::open("./my-cache", "my-key", path)?; /// let mut fd = cacache::SyncToLinker::open("./my-cache", "my-key", path)?;
/// let mut str = String::new(); /// let mut str = String::new();
/// fd.read_to_string(&mut str).expect("Failed to read to string"); /// fd.read_to_string(&mut str).expect("Failed to read to string");
/// // The file is not linked into the cache until you commit it. /// // The file is not linked into the cache until you commit it.
@ -380,18 +385,18 @@ impl SyncLinker {
K: AsRef<str>, K: AsRef<str>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
fn inner(cache: &Path, key: &str, target: &Path) -> Result<SyncLinker> { fn inner(cache: &Path, key: &str, target: &Path) -> Result<SyncToLinker> {
let size = filesize(&target)?; let size = filesize(target)?;
WriteOpts::new() WriteOpts::new()
.algorithm(Algorithm::Sha256) .algorithm(Algorithm::Sha256)
.size(size) .size(size)
.link_sync(cache, key, target) .link_to_sync(cache, key, target)
} }
inner(cache.as_ref(), key.as_ref(), target.as_ref()) inner(cache.as_ref(), key.as_ref(), target.as_ref())
} }
/// Creates a new readable file handle to a file that will be linked into /// Creates a new readable file handle to a file that the cache will link
/// the cache, without an indexe key, on commit. /// to, without an indexe key, on commit.
/// ///
/// It is not necessary to read any of the file before calling `.commit()`. /// It is not necessary to read any of the file before calling `.commit()`.
/// ///
@ -401,7 +406,7 @@ impl SyncLinker {
/// ///
/// fn main() -> cacache::Result<()> { /// fn main() -> cacache::Result<()> {
/// let path = "../my-other-files/my-file.tgz"; /// let path = "../my-other-files/my-file.tgz";
/// let mut fd = cacache::SyncLinker::open_hash("./my-cache", path)?; /// let mut fd = cacache::SyncToLinker::open_hash("./my-cache", path)?;
/// let mut str = String::new(); /// let mut str = String::new();
/// fd.read_to_string(&mut str).expect("Failed to read to string"); /// fd.read_to_string(&mut str).expect("Failed to read to string");
/// // The file is not linked into the cache until you commit it. /// // The file is not linked into the cache until you commit it.
@ -414,21 +419,21 @@ impl SyncLinker {
P: AsRef<Path>, P: AsRef<Path>,
T: AsRef<Path>, T: AsRef<Path>,
{ {
fn inner(cache: &Path, target: &Path) -> Result<SyncLinker> { fn inner(cache: &Path, target: &Path) -> Result<SyncToLinker> {
let size = filesize(&target)?; let size = filesize(target)?;
WriteOpts::new() WriteOpts::new()
.algorithm(Algorithm::Sha256) .algorithm(Algorithm::Sha256)
.size(size) .size(size)
.link_hash_sync(cache, target) .link_to_hash_sync(cache, target)
} }
inner(cache.as_ref(), target.as_ref()) inner(cache.as_ref(), target.as_ref())
} }
/// Consumes the rest of the file handle, creates a symlink into the cache, /// Consumes the rest of the file handle, creates a symlink to the file, and
/// and creates index entries for the linked file. Also verifies data /// creates index entries for the linked file. Also verifies data against
/// against `size` and `integrity` options, if provided. Must be called /// `size` and `integrity` options, if provided. Must be called manually in
/// manually in order to complete the writing process, otherwise everything /// order to complete the writing process, otherwise everything will be
/// will be thrown out. /// thrown out.
pub fn commit(mut self) -> Result<Integrity> { pub fn commit(mut self) -> Result<Integrity> {
self.consume()?; self.consume()?;
let cache = self.cache; let cache = self.cache;
@ -501,46 +506,46 @@ mod tests {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
crate::link(&dir, "my-key", target).await.unwrap(); crate::link_to(&dir, "my-key", target).await.unwrap();
let buf = crate::read(&dir, "my-key").await.unwrap(); let buf = crate::read(&dir, "my-key").await.unwrap();
assert_eq!(buf, b"hello world"); assert_eq!(buf, b"hello world");
} }
#[async_test] #[async_test]
async fn test_link_hash() { async fn test_link_to_hash() {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let target = create_tmpfile(&tmp, b"hello world"); let target = create_tmpfile(&tmp, b"hello world");
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
let sri = crate::link_hash(&dir, target).await.unwrap(); let sri = crate::link_to_hash(&dir, target).await.unwrap();
let buf = crate::read_hash(&dir, &sri).await.unwrap(); let buf = crate::read_hash(&dir, &sri).await.unwrap();
assert_eq!(buf, b"hello world"); assert_eq!(buf, b"hello world");
} }
#[test] #[test]
fn test_link_sync() { fn test_link_to_sync() {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let target = create_tmpfile(&tmp, b"hello world"); let target = create_tmpfile(&tmp, b"hello world");
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
crate::link_sync(&dir, "my-key", target).unwrap(); crate::link_to_sync(&dir, "my-key", target).unwrap();
let buf = crate::read_sync(&dir, "my-key").unwrap(); let buf = crate::read_sync(&dir, "my-key").unwrap();
assert_eq!(buf, b"hello world"); assert_eq!(buf, b"hello world");
} }
#[test] #[test]
fn test_link_hash_sync() { fn test_link_to_hash_sync() {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let target = create_tmpfile(&tmp, b"hello world"); let target = create_tmpfile(&tmp, b"hello world");
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
let sri = crate::link_hash_sync(&dir, target).unwrap(); let sri = crate::link_to_hash_sync(&dir, target).unwrap();
let buf = crate::read_hash_sync(&dir, &sri).unwrap(); let buf = crate::read_hash_sync(&dir, &sri).unwrap();
assert_eq!(buf, b"hello world"); assert_eq!(buf, b"hello world");
@ -553,7 +558,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
let mut handle = crate::Linker::open(&dir, "my-key", target).await.unwrap(); let mut handle = crate::ToLinker::open(&dir, "my-key", target).await.unwrap();
let mut buf = Vec::new(); let mut buf = Vec::new();
handle.read_to_end(&mut buf).await.unwrap(); handle.read_to_end(&mut buf).await.unwrap();
@ -571,7 +576,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
let mut handle = crate::Linker::open_hash(&dir, target).await.unwrap(); let mut handle = crate::ToLinker::open_hash(&dir, target).await.unwrap();
let mut buf = Vec::new(); let mut buf = Vec::new();
handle.read_to_end(&mut buf).await.unwrap(); handle.read_to_end(&mut buf).await.unwrap();
@ -589,7 +594,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
let mut handle = crate::SyncLinker::open(&dir, "my-key", target).unwrap(); let mut handle = crate::SyncToLinker::open(&dir, "my-key", target).unwrap();
let mut buf = Vec::new(); let mut buf = Vec::new();
handle.read_to_end(&mut buf).unwrap(); handle.read_to_end(&mut buf).unwrap();
@ -607,7 +612,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned(); let dir = tmp.path().to_owned();
let mut handle = crate::SyncLinker::open_hash(&dir, target).unwrap(); let mut handle = crate::SyncToLinker::open_hash(&dir, target).unwrap();
let mut buf = Vec::new(); let mut buf = Vec::new();
handle.read_to_end(&mut buf).unwrap(); handle.read_to_end(&mut buf).unwrap();