Make Python and PyPy install mirrors configurable in uv.toml (#8695)

<!--
Thank you for contributing to uv! To help us out with reviewing, please
consider the following:

- Does this pull request include a summary of the change? (See below.)
-->

## Summary

Adds python-install-mirror and pypy-install-mirror as keys for uv.toml,
and cli args for `uv python install`.

Could leave the cli args out if we think the env vars and configs are
sufficient.

Fixes #8186 

<!-- What's the purpose of the change? What does it do, and why? -->

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
This commit is contained in:
Owen Brooks 2024-11-14 03:08:55 +11:00 committed by GitHub
parent 2966471db2
commit 2ea81b3b55
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 573 additions and 27 deletions

View file

@ -466,9 +466,11 @@ impl ManagedPythonDownload {
installation_dir: &Path,
cache_dir: &Path,
reinstall: bool,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
reporter: Option<&dyn Reporter>,
) -> Result<DownloadResult, Error> {
let url = self.download_url()?;
let url = self.download_url(python_install_mirror, pypy_install_mirror)?;
let path = installation_dir.join(self.key().to_string());
// If it is not a reinstall and the dir already exists, return it.
@ -585,10 +587,14 @@ impl ManagedPythonDownload {
/// Return the [`Url`] to use when downloading the distribution. If a mirror is set via the
/// appropriate environment variable, use it instead.
fn download_url(&self) -> Result<Url, Error> {
fn download_url(
&self,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
) -> Result<Url, Error> {
match self.key.implementation {
LenientImplementationName::Known(ImplementationName::CPython) => {
if let Ok(mirror) = std::env::var(EnvVars::UV_PYTHON_INSTALL_MIRROR) {
if let Some(mirror) = python_install_mirror {
let Some(suffix) = self.url.strip_prefix(
"https://github.com/indygreg/python-build-standalone/releases/download/",
) else {
@ -601,7 +607,7 @@ impl ManagedPythonDownload {
}
LenientImplementationName::Known(ImplementationName::PyPy) => {
if let Ok(mirror) = std::env::var(EnvVars::UV_PYPY_INSTALL_MIRROR) {
if let Some(mirror) = pypy_install_mirror {
let Some(suffix) = self.url.strip_prefix("https://downloads.python.org/pypy/")
else {
return Err(Error::Mirror(EnvVars::UV_PYPY_INSTALL_MIRROR, self.url));

View file

@ -86,6 +86,8 @@ impl PythonInstallation {
client_builder: &BaseClientBuilder<'a>,
cache: &Cache,
reporter: Option<&dyn Reporter>,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
) -> Result<Self, Error> {
let request = request.unwrap_or_else(|| &PythonRequest::Default);
@ -100,7 +102,16 @@ impl PythonInstallation {
{
if let Some(request) = PythonDownloadRequest::from_request(request) {
debug!("Requested Python not found, checking for available download...");
match Self::fetch(request.fill()?, client_builder, cache, reporter).await {
match Self::fetch(
request.fill()?,
client_builder,
cache,
reporter,
python_install_mirror,
pypy_install_mirror,
)
.await
{
Ok(installation) => Ok(installation),
Err(Error::Download(downloads::Error::NoDownloadFound(_))) => {
Err(Error::MissingPython(err))
@ -121,6 +132,8 @@ impl PythonInstallation {
client_builder: &BaseClientBuilder<'a>,
cache: &Cache,
reporter: Option<&dyn Reporter>,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
) -> Result<Self, Error> {
let installations = ManagedPythonInstallations::from_settings()?.init()?;
let installations_dir = installations.root();
@ -132,7 +145,15 @@ impl PythonInstallation {
info!("Fetching requested Python...");
let result = download
.fetch(&client, installations_dir, &cache_dir, false, reporter)
.fetch(
&client,
installations_dir,
&cache_dir,
false,
python_install_mirror,
pypy_install_mirror,
reporter,
)
.await?;
let path = match result {