mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Add an HTTP cache (and --no-cache
argument) (#14)
Closes https://github.com/astral-sh/puffin/issues/3.
This commit is contained in:
parent
1063d8c150
commit
2d6266b167
6 changed files with 31 additions and 23 deletions
|
@ -10,5 +10,3 @@ documentation = "https://astral.sh"
|
||||||
repository = "https://github.com/astral-sh/puffin"
|
repository = "https://github.com/astral-sh/puffin"
|
||||||
authors = ["Astral Software Inc. <hey@astral.sh>"]
|
authors = ["Astral Software Inc. <hey@astral.sh>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
|
||||||
|
|
|
@ -23,3 +23,4 @@ pep440_rs = { version = "0.3.12" }
|
||||||
tracing = { version = "0.1.37" }
|
tracing = { version = "0.1.37" }
|
||||||
tracing-tree = { version = "0.2.5" }
|
tracing-tree = { version = "0.2.5" }
|
||||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||||
|
directories = "5.0.1"
|
||||||
|
|
|
@ -29,7 +29,7 @@ enum Response {
|
||||||
Version(Metadata21, Requirement),
|
Version(Metadata21, Requirement),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn install(src: &Path) -> Result<ExitStatus> {
|
pub(crate) async fn install(src: &Path, cache: Option<&Path>) -> Result<ExitStatus> {
|
||||||
// Read the `requirements.txt` from disk.
|
// Read the `requirements.txt` from disk.
|
||||||
let requirements_txt = std::fs::read_to_string(src)?;
|
let requirements_txt = std::fs::read_to_string(src)?;
|
||||||
|
|
||||||
|
@ -44,8 +44,13 @@ pub(crate) async fn install(src: &Path) -> Result<ExitStatus> {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Instantiate a client.
|
// Instantiate a client.
|
||||||
let pypi_client = PypiClientBuilder::default().build();
|
let pypi_client = {
|
||||||
let proxy_client = PypiClientBuilder::default().build();
|
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
|
// 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).
|
// 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<ExitStatus> {
|
||||||
.map_ok(move |metadata| Response::Package(metadata, requirement)),
|
.map_ok(move |metadata| Response::Package(metadata, requirement)),
|
||||||
),
|
),
|
||||||
Request::Version(requirement, file) => Either::Right(
|
Request::Version(requirement, file) => Either::Right(
|
||||||
proxy_client
|
pypi_client
|
||||||
.file(file)
|
.file(file)
|
||||||
.map_ok(move |metadata| Response::Version(metadata, requirement)),
|
.map_ok(move |metadata| Response::Version(metadata, requirement)),
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::process::ExitCode;
|
||||||
|
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
use directories::ProjectDirs;
|
||||||
|
|
||||||
use crate::commands::ExitStatus;
|
use crate::commands::ExitStatus;
|
||||||
|
|
||||||
|
@ -27,6 +28,10 @@ enum Commands {
|
||||||
struct InstallArgs {
|
struct InstallArgs {
|
||||||
/// Path to the `requirements.text` file to install.
|
/// Path to the `requirements.text` file to install.
|
||||||
src: PathBuf,
|
src: PathBuf,
|
||||||
|
|
||||||
|
/// Avoid reading from or writing to the cache.
|
||||||
|
#[arg(long)]
|
||||||
|
no_cache: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::main]
|
#[async_std::main]
|
||||||
|
@ -35,8 +40,18 @@ async fn main() -> ExitCode {
|
||||||
|
|
||||||
let _ = logging::setup_logging();
|
let _ = logging::setup_logging();
|
||||||
|
|
||||||
|
let dirs = ProjectDirs::from("", "", "puffin");
|
||||||
|
|
||||||
let result = match &cli.command {
|
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 {
|
match result {
|
||||||
|
|
|
@ -16,8 +16,6 @@ impl PypiClient {
|
||||||
&self,
|
&self,
|
||||||
package_name: impl AsRef<str>,
|
package_name: impl AsRef<str>,
|
||||||
) -> Result<SimpleJson, PypiClientError> {
|
) -> Result<SimpleJson, PypiClientError> {
|
||||||
let start = std::time::Instant::now();
|
|
||||||
|
|
||||||
// Format the URL for PyPI.
|
// Format the URL for PyPI.
|
||||||
let mut url = self.registry.join("simple")?;
|
let mut url = self.registry.join("simple")?;
|
||||||
url.path_segments_mut()
|
url.path_segments_mut()
|
||||||
|
@ -34,12 +32,8 @@ impl PypiClient {
|
||||||
|
|
||||||
// Fetch from the registry.
|
// Fetch from the registry.
|
||||||
let text = self.simple_impl(&package_name, &url).await?;
|
let text = self.simple_impl(&package_name, &url).await?;
|
||||||
let payload = serde_json::from_str(&text)
|
serde_json::from_str(&text)
|
||||||
.map_err(move |e| PypiClientError::from_json_err(e, String::new()));
|
.map_err(move |e| PypiClientError::from_json_err(e, String::new()))
|
||||||
|
|
||||||
trace!("fetched metadata for {} in {:?}", url, start.elapsed());
|
|
||||||
|
|
||||||
payload
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn simple_impl(
|
async fn simple_impl(
|
||||||
|
@ -69,8 +63,6 @@ impl PypiClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn file(&self, file: File) -> Result<Metadata21, PypiClientError> {
|
pub async fn file(&self, file: File) -> Result<Metadata21, PypiClientError> {
|
||||||
let start = std::time::Instant::now();
|
|
||||||
|
|
||||||
// Send to the proxy.
|
// Send to the proxy.
|
||||||
let url = self.proxy.join(
|
let url = self.proxy.join(
|
||||||
file.url
|
file.url
|
||||||
|
@ -82,11 +74,7 @@ impl PypiClient {
|
||||||
|
|
||||||
// Fetch from the registry.
|
// Fetch from the registry.
|
||||||
let text = self.file_impl(&file.filename, &url).await?;
|
let text = self.file_impl(&file.filename, &url).await?;
|
||||||
let payload = Metadata21::parse(text.as_bytes()).map_err(std::convert::Into::into);
|
Metadata21::parse(text.as_bytes()).map_err(std::convert::Into::into)
|
||||||
|
|
||||||
trace!("fetched file {} in {:?}", url, start.elapsed());
|
|
||||||
|
|
||||||
payload
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn file_impl(
|
async fn file_impl(
|
||||||
|
|
|
@ -16,7 +16,8 @@ serde = { version = "1.0.188" }
|
||||||
thiserror = { version = "1.0.49" }
|
thiserror = { version = "1.0.49" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.5.1"
|
criterion = { version = "0.5.1" }
|
||||||
|
insta = { version = "1.33.0" }
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "parser"
|
name = "parser"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue