From 2d6266b167f487155c7f3711784b925e164c6981 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 5 Oct 2023 19:14:05 -0400 Subject: [PATCH] Add an HTTP cache (and `--no-cache` argument) (#14) Closes https://github.com/astral-sh/puffin/issues/3. --- Cargo.toml | 2 -- crates/puffin-cli/Cargo.toml | 1 + crates/puffin-cli/src/commands/install.rs | 13 +++++++++---- crates/puffin-cli/src/main.rs | 17 ++++++++++++++++- crates/puffin-client/src/api.rs | 18 +++--------------- crates/puffin-requirements/Cargo.toml | 3 ++- 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b78fce4a3..2066d672e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,3 @@ documentation = "https://astral.sh" repository = "https://github.com/astral-sh/puffin" authors = ["Astral Software Inc. "] license = "MIT OR Apache-2.0" - -[workspace.dependencies] diff --git a/crates/puffin-cli/Cargo.toml b/crates/puffin-cli/Cargo.toml index 5d3bc6326..f9d68d54e 100644 --- a/crates/puffin-cli/Cargo.toml +++ b/crates/puffin-cli/Cargo.toml @@ -23,3 +23,4 @@ pep440_rs = { version = "0.3.12" } tracing = { version = "0.1.37" } tracing-tree = { version = "0.2.5" } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +directories = "5.0.1" diff --git a/crates/puffin-cli/src/commands/install.rs b/crates/puffin-cli/src/commands/install.rs index 9becb374a..91f921ac7 100644 --- a/crates/puffin-cli/src/commands/install.rs +++ b/crates/puffin-cli/src/commands/install.rs @@ -29,7 +29,7 @@ enum Response { Version(Metadata21, Requirement), } -pub(crate) async fn install(src: &Path) -> Result { +pub(crate) async fn install(src: &Path, cache: Option<&Path>) -> Result { // Read the `requirements.txt` from disk. let requirements_txt = std::fs::read_to_string(src)?; @@ -44,8 +44,13 @@ pub(crate) async fn install(src: &Path) -> Result { ); // Instantiate a client. - let pypi_client = PypiClientBuilder::default().build(); - let proxy_client = PypiClientBuilder::default().build(); + let pypi_client = { + let mut pypi_client = PypiClientBuilder::default(); + if let Some(cache) = cache { + pypi_client = pypi_client.cache(cache); + } + pypi_client.build() + }; // A channel to fetch package metadata (e.g., given `flask`, fetch all versions) and version // metadata (e.g., given `flask==1.0.0`, fetch the metadata for that version). @@ -60,7 +65,7 @@ pub(crate) async fn install(src: &Path) -> Result { .map_ok(move |metadata| Response::Package(metadata, requirement)), ), Request::Version(requirement, file) => Either::Right( - proxy_client + pypi_client .file(file) .map_ok(move |metadata| Response::Version(metadata, requirement)), ), diff --git a/crates/puffin-cli/src/main.rs b/crates/puffin-cli/src/main.rs index 1615d3011..71c24abb4 100644 --- a/crates/puffin-cli/src/main.rs +++ b/crates/puffin-cli/src/main.rs @@ -3,6 +3,7 @@ use std::process::ExitCode; use clap::{Args, Parser, Subcommand}; use colored::Colorize; +use directories::ProjectDirs; use crate::commands::ExitStatus; @@ -27,6 +28,10 @@ enum Commands { struct InstallArgs { /// Path to the `requirements.text` file to install. src: PathBuf, + + /// Avoid reading from or writing to the cache. + #[arg(long)] + no_cache: bool, } #[async_std::main] @@ -35,8 +40,18 @@ async fn main() -> ExitCode { let _ = logging::setup_logging(); + let dirs = ProjectDirs::from("", "", "puffin"); + let result = match &cli.command { - Commands::Install(install) => commands::install(&install.src).await, + Commands::Install(install) => { + commands::install( + &install.src, + dirs.as_ref() + .map(directories::ProjectDirs::cache_dir) + .filter(|_| !install.no_cache), + ) + .await + } }; match result { diff --git a/crates/puffin-client/src/api.rs b/crates/puffin-client/src/api.rs index 24a440460..ec1bfc298 100644 --- a/crates/puffin-client/src/api.rs +++ b/crates/puffin-client/src/api.rs @@ -16,8 +16,6 @@ impl PypiClient { &self, package_name: impl AsRef, ) -> Result { - let start = std::time::Instant::now(); - // Format the URL for PyPI. let mut url = self.registry.join("simple")?; url.path_segments_mut() @@ -34,12 +32,8 @@ impl PypiClient { // Fetch from the registry. let text = self.simple_impl(&package_name, &url).await?; - let payload = serde_json::from_str(&text) - .map_err(move |e| PypiClientError::from_json_err(e, String::new())); - - trace!("fetched metadata for {} in {:?}", url, start.elapsed()); - - payload + serde_json::from_str(&text) + .map_err(move |e| PypiClientError::from_json_err(e, String::new())) } async fn simple_impl( @@ -69,8 +63,6 @@ impl PypiClient { } pub async fn file(&self, file: File) -> Result { - let start = std::time::Instant::now(); - // Send to the proxy. let url = self.proxy.join( file.url @@ -82,11 +74,7 @@ impl PypiClient { // Fetch from the registry. let text = self.file_impl(&file.filename, &url).await?; - let payload = Metadata21::parse(text.as_bytes()).map_err(std::convert::Into::into); - - trace!("fetched file {} in {:?}", url, start.elapsed()); - - payload + Metadata21::parse(text.as_bytes()).map_err(std::convert::Into::into) } async fn file_impl( diff --git a/crates/puffin-requirements/Cargo.toml b/crates/puffin-requirements/Cargo.toml index a0f6971d3..ae49673c0 100644 --- a/crates/puffin-requirements/Cargo.toml +++ b/crates/puffin-requirements/Cargo.toml @@ -16,7 +16,8 @@ serde = { version = "1.0.188" } thiserror = { version = "1.0.49" } [dev-dependencies] -criterion = "0.5.1" +criterion = { version = "0.5.1" } +insta = { version = "1.33.0" } [[bench]] name = "parser"