Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sync-only): add support for removing async runtime dependency al… #56

Merged
merged 1 commit into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ tokio = { version = "1.12.0", features = [
"fs",
"io-util",
"macros",
"rt"
"rt",
], optional = true }
tokio-stream = { version = "0.1.7", features = ["io-util"], optional = true }
walkdir = "2.3.2"
Expand All @@ -49,7 +49,7 @@ tokio = { version = "1.12.0", features = [
"macros",
"rt",
"rt-multi-thread",
]}
] }

[[bench]]
name = "benchmarks"
Expand Down
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ Minimum supported Rust version is `1.43.0`.

## Features

- First-class async support, using either [`async-std`](https://crates.io/crates/async-std) or [`tokio`](https://crates.io/crates/tokio) as its runtime. Sync APIs are available but secondary
- First-class async support, using either
[`async-std`](https://crates.io/crates/async-std) or
[`tokio`](https://crates.io/crates/tokio) as its runtime. Sync APIs are
available but secondary. You can also use sync APIs only and remove the
async runtime dependency.
- `std::fs`-style API
- Extraction by key or by content address (shasum, etc)
- [Subresource Integrity](#integrity) web standard support
Expand All @@ -56,21 +60,37 @@ Minimum supported Rust version is `1.43.0`.
- [`miette`](https://crates.io/crates/miette) integration for detailed, helpful error reporting.
- Punches nazis

`async-std` is the default async runtime. To use `tokio` instead, turn off default features and enable the `tokio-runtime` feature, like this:
`async-std` is the default async runtime. To use `tokio` instead, turn off
default features and enable the `tokio-runtime` feature, like this:

```toml
[dependencies]
cacache = { version = "*", default-features = false, features = ["tokio-runtime"] }
cacache = { version = "*", default-features = false, features = ["tokio-runtime", "mmap"] }
```

You can also remove async APIs altogether, including removing async runtime
dependency:

```toml
[dependencies]
cacache = { version = "*", default-features = false, features = ["mmap"] }
```

Experimental support for symlinking to existing files is provided via the
"link_to" feature.

## Contributing

The cacache team enthusiastically welcomes contributions and project participation! There's a bunch of things you can do if you want to contribute! The [Contributor Guide](CONTRIBUTING.md) has all the information you need for everything from reporting bugs to contributing entire new features. Please don't hesitate to jump in if you'd like to, or even ask us questions if something isn't clear.
The cacache team enthusiastically welcomes contributions and project
participation! There's a bunch of things you can do if you want to contribute!
The [Contributor Guide](CONTRIBUTING.md) has all the information you need for
everything from reporting bugs to contributing entire new features. Please
don't hesitate to jump in if you'd like to, or even ask us questions if
something isn't clear.

All participants and maintainers in this project are expected to follow [Code of Conduct](CODE_OF_CONDUCT.md), and just generally be excellent to each other.
All participants and maintainers in this project are expected to follow [Code
of Conduct](CODE_OF_CONDUCT.md), and just generally be excellent to each
other.

Happy hacking!

Expand Down
62 changes: 46 additions & 16 deletions benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ fn baseline_read_many_sync(c: &mut Criterion) {
});
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
fn baseline_read_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join("test_file");
Expand All @@ -74,6 +75,7 @@ fn baseline_read_async(c: &mut Criterion) {
});
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
fn baseline_read_many_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let paths: Vec<_> = (0..)
Expand Down Expand Up @@ -188,6 +190,7 @@ fn read_hash_sync_big_data_xxh3(c: &mut Criterion) {
});
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
fn read_hash_many_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let cache = tmp.path().to_owned();
Expand All @@ -209,6 +212,7 @@ fn read_hash_many_async(c: &mut Criterion) {
});
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
fn read_hash_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let cache = tmp.path().to_owned();
Expand All @@ -219,6 +223,7 @@ fn read_hash_async(c: &mut Criterion) {
});
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
fn read_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let cache = tmp.path().to_owned();
Expand All @@ -229,6 +234,7 @@ fn read_async(c: &mut Criterion) {
});
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
fn read_hash_async_big_data(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let cache = tmp.path().to_owned();
Expand Down Expand Up @@ -271,6 +277,8 @@ fn write_hash_xxh3(c: &mut Criterion) {
})
});
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
fn write_hash_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let cache = tmp.path().to_owned();
Expand All @@ -285,6 +293,7 @@ fn write_hash_async(c: &mut Criterion) {
});
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
fn write_hash_async_xxh3(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let cache = tmp.path().to_owned();
Expand Down Expand Up @@ -316,6 +325,7 @@ fn create_tmpfile(tmp: &tempfile::TempDir, buf: &[u8]) -> PathBuf {
}

#[cfg(feature = "link_to")]
#[cfg(any(feature = "async-std", feature = "tokio"))]
fn link_to_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let target = create_tmpfile(&tmp, b"hello world");
Expand All @@ -338,7 +348,7 @@ fn link_to_async(c: &mut Criterion) {
});
}

#[cfg(feature = "link_to")]
#[cfg(all(feature = "link_to", any(feature = "async-std", feature = "tokio")))]
fn link_to_hash_async(c: &mut Criterion) {
let tmp = tempfile::tempdir().unwrap();
let target = create_tmpfile(&tmp, b"hello world");
Expand Down Expand Up @@ -384,35 +394,55 @@ criterion_group!(
benches,
baseline_read_sync,
baseline_read_many_sync,
baseline_read_async,
baseline_read_many_async,
read_hash_async,
read_hash_many_async,
read_async,
write_hash,
write_hash_xxh3,
write_hash_async,
write_hash_async_xxh3,
read_hash_sync,
read_hash_sync_xxh3,
read_hash_many_sync,
read_hash_many_sync_xxh3,
read_sync,
read_hash_async_big_data,
read_hash_sync_big_data,
read_hash_sync_big_data_xxh3,
);

#[cfg(feature = "link_to")]
#[cfg(any(feature = "async-std", feature = "tokio"))]
criterion_group!(
link_to_benches,
link_to_async,
link_to_hash_async,
link_to_sync,
link_to_hash_sync
benches_async,
baseline_read_async,
baseline_read_many_async,
read_hash_async,
read_hash_many_async,
read_async,
write_hash_async,
write_hash_async_xxh3,
read_hash_async_big_data,
);

#[cfg(all(feature = "link_to", any(feature = "async-std", feature = "tokio")))]
criterion_group!(link_to_benches_async, link_to_async, link_to_hash_async,);

#[cfg(feature = "link_to")]
criterion_group!(link_to_benches, link_to_sync, link_to_hash_sync);

#[cfg(all(
feature = "link_to",
not(any(feature = "async-std", feature = "tokio"))
))]
criterion_main!(benches, link_to_benches);
#[cfg(not(feature = "link_to"))]
#[cfg(all(
not(feature = "link_to"),
any(feature = "async-std", feature = "tokio")
))]
criterion_main!(benches, benches_async);
#[cfg(all(feature = "link_to", any(feature = "async-std", feature = "tokio")))]
criterion_main!(
benches,
benches_async,
link_to_benches,
link_to_benches_async
);
#[cfg(all(
not(feature = "link_to"),
not(any(feature = "async-std", feature = "tokio"))
))]
criterion_main!(benches);
4 changes: 2 additions & 2 deletions src/async_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ pub async fn create_named_tempfile(tmp_path: std::path::PathBuf) -> crate::Resul
#[inline]
pub async fn create_named_tempfile(tmp_path: std::path::PathBuf) -> crate::Result<NamedTempFile> {
let cloned = tmp_path.clone();
Ok(spawn_blocking(|| NamedTempFile::new_in(tmp_path))
spawn_blocking(|| NamedTempFile::new_in(tmp_path))
.await
.unwrap()
.with_context(|| format!("Failed to create a temp file at {}", cloned.display()))?)
.with_context(|| format!("Failed to create a temp file at {}", cloned.display()))
}
7 changes: 7 additions & 0 deletions src/content/linkto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ use ssri::{Algorithm, Integrity, IntegrityOpts};
use std::fs::DirBuilder;
use std::fs::File;
use std::path::{Path, PathBuf};
#[cfg(any(feature = "async-std", feature = "tokio"))]
use std::pin::Pin;
#[cfg(any(feature = "async-std", feature = "tokio"))]
use std::task::{Context, Poll};

#[cfg(any(feature = "async-std", feature = "tokio"))]
use crate::async_lib::AsyncRead;
use crate::content::path;
use crate::errors::{IoErrorExt, Result};
Expand Down Expand Up @@ -103,6 +106,7 @@ impl std::io::Read for ToLinker {
/// An `AsyncRead`-like type that calculates the integrity of a file as it is
/// read. When the linker is committed, a symlink is created from the cache to
/// the target file using the integrity computed from the file's contents.
#[cfg(any(feature = "async-std", feature = "tokio"))]
pub struct AsyncToLinker {
/// The path to the target file that will be symlinked from the cache.
target: PathBuf,
Expand All @@ -114,6 +118,7 @@ pub struct AsyncToLinker {
builder: IntegrityOpts,
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
impl AsyncRead for AsyncToLinker {
#[cfg(feature = "async-std")]
fn poll_read(
Expand Down Expand Up @@ -143,6 +148,7 @@ impl AsyncRead for AsyncToLinker {
}
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
impl AsyncToLinker {
pub async fn new(cache: &Path, algo: Algorithm, target: &Path) -> Result<Self> {
let file = crate::async_lib::File::open(target)
Expand Down Expand Up @@ -216,6 +222,7 @@ mod tests {
assert_eq!(std::fs::read(cpath).unwrap(), b"hello world");
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
#[async_test]
async fn basic_async_link() {
let tmp = tempfile::tempdir().unwrap();
Expand Down
12 changes: 12 additions & 0 deletions src/content/read.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::fs::{self, File};
use std::io::Read;
use std::path::Path;
#[cfg(any(feature = "async-std", feature = "tokio"))]
use std::pin::Pin;
#[cfg(any(feature = "async-std", feature = "tokio"))]
use std::task::{Context, Poll};

#[cfg(feature = "async-std")]
Expand All @@ -11,6 +13,7 @@ use tokio::io::AsyncReadExt;

use ssri::{Algorithm, Integrity, IntegrityChecker};

#[cfg(any(feature = "async-std", feature = "tokio"))]
use crate::async_lib::AsyncRead;
use crate::content::path;
use crate::errors::{IoErrorExt, Result};
Expand All @@ -34,11 +37,13 @@ impl Reader {
}
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
pub struct AsyncReader {
fd: crate::async_lib::File,
checker: IntegrityChecker,
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
impl AsyncRead for AsyncReader {
#[cfg(feature = "async-std")]
fn poll_read(
Expand Down Expand Up @@ -68,6 +73,7 @@ impl AsyncRead for AsyncReader {
}
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
impl AsyncReader {
pub fn check(self) -> Result<Algorithm> {
Ok(self.checker.result()?)
Expand All @@ -87,6 +93,7 @@ pub fn open(cache: &Path, sri: Integrity) -> Result<Reader> {
})
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
pub async fn open_async(cache: &Path, sri: Integrity) -> Result<AsyncReader> {
let cpath = path::content_path(cache, &sri);
Ok(AsyncReader {
Expand All @@ -112,6 +119,7 @@ pub fn read(cache: &Path, sri: &Integrity) -> Result<Vec<u8>> {
Ok(ret)
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
pub async fn read_async<'a>(cache: &'a Path, sri: &'a Integrity) -> Result<Vec<u8>> {
let cpath = path::content_path(cache, sri);
let ret = crate::async_lib::read(&cpath).await.with_context(|| {
Expand Down Expand Up @@ -158,6 +166,7 @@ pub fn copy(cache: &Path, sri: &Integrity, to: &Path) -> Result<u64> {
Ok(size as u64)
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
pub async fn copy_unchecked_async<'a>(
cache: &'a Path,
sri: &'a Integrity,
Expand All @@ -176,6 +185,7 @@ pub async fn copy_unchecked_async<'a>(
Ok(())
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
pub async fn copy_async<'a>(cache: &'a Path, sri: &'a Integrity, to: &'a Path) -> Result<u64> {
copy_unchecked_async(cache, sri, to).await?;
let mut reader = open_async(cache, sri.clone()).await?;
Expand Down Expand Up @@ -230,6 +240,7 @@ pub fn hard_link(cache: &Path, sri: &Integrity, to: &Path) -> Result<()> {
Ok(())
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
pub async fn hard_link_async(cache: &Path, sri: &Integrity, to: &Path) -> Result<()> {
hard_link_unchecked(cache, sri, to)?;
let mut reader = open_async(cache, sri.clone()).await?;
Expand Down Expand Up @@ -259,6 +270,7 @@ pub fn has_content(cache: &Path, sri: &Integrity) -> Option<Integrity> {
}
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
pub async fn has_content_async(cache: &Path, sri: &Integrity) -> Option<Integrity> {
if crate::async_lib::metadata(path::content_path(cache, sri))
.await
Expand Down
1 change: 1 addition & 0 deletions src/content/rm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub fn rm(cache: &Path, sri: &Integrity) -> Result<()> {
Ok(())
}

#[cfg(any(feature = "async-std", feature = "tokio"))]
pub async fn rm_async(cache: &Path, sri: &Integrity) -> Result<()> {
crate::async_lib::remove_file(path::content_path(cache, sri))
.await
Expand Down
Loading
Loading