Skip to content

Commit

Permalink
Detect musl and error for musl pbs builds (#6643)
Browse files Browse the repository at this point in the history
As described in #4242, we're currently incorrectly downloading glibc
python-build-standalone on musl target, but we also can't fix this by
using musl python-build-standalone on musl targets since the musl builds
are effectively broken.

We reintroduce the libc detection previously removed in #2381, using it
to detect which libc is the current one before we have a python
interpreter. I changed the strategy a big to support an empty `PATH`
which we use in the tests.

For simplicity, i've decided to just filter out the musl
python-build-standalone archives from the list of available archive,
given this is temporary. This means we show the same error message as if
we don't have a build for the platform. We could also add a dedicated
error message for musl.

Fixes #4242

## Test Plan

Tested manually.

On my ubuntu host, python downloads continue to pass:
```
target/x86_64-unknown-linux-musl/debug/uv python install
```

On alpine, we fail:
```
$ docker run -it --rm -v .:/io alpine /io/target/x86_64-unknown-linux-musl/debug/uv python install
  Searching for Python installations
  error: No download found for request: cpython-any-linux-x86_64-musl
```
  • Loading branch information
konstin authored Aug 27, 2024
1 parent 1ae2c3f commit ae57d85
Show file tree
Hide file tree
Showing 11 changed files with 363 additions and 30 deletions.
44 changes: 41 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ fs-err = { version = "2.11.0" }
fs2 = { version = "0.4.3" }
futures = { version = "0.3.30" }
glob = { version = "0.3.1" }
goblin = { version = "0.8.2", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] }
hex = { version = "0.4.3" }
home = { version = "0.5.9" }
html-escape = { version = "0.2.13" }
Expand Down
1 change: 1 addition & 0 deletions crates/uv-python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ clap = { workspace = true, optional = true }
configparser = { workspace = true }
fs-err = { workspace = true, features = ["tokio"] }
futures = { workspace = true }
goblin = { workspace = true }
itertools = { workspace = true }
owo-colors = { workspace = true }
regex = { workspace = true }
Expand Down
18 changes: 12 additions & 6 deletions crates/uv-python/src/downloads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::implementation::{
Error as ImplementationError, ImplementationName, LenientImplementationName,
};
use crate::installation::PythonInstallationKey;
use crate::libc::LibcDetectionError;
use crate::platform::{self, Arch, Libc, Os};
use crate::{Interpreter, PythonRequest, PythonVersion, VersionRequest};

Expand Down Expand Up @@ -75,6 +76,8 @@ pub enum Error {
"A mirror was provided via `{0}`, but the URL does not match the expected format: {0}"
)]
Mirror(&'static str, &'static str),
#[error(transparent)]
LibcDetection(#[from] LibcDetectionError),
}

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -167,8 +170,7 @@ impl PythonDownloadRequest {
/// Fill empty entries with default values.
///
/// Platform information is pulled from the environment.
#[must_use]
pub fn fill(mut self) -> Self {
pub fn fill(mut self) -> Result<Self, Error> {
if self.implementation.is_none() {
self.implementation = Some(ImplementationName::CPython);
}
Expand All @@ -179,9 +181,9 @@ impl PythonDownloadRequest {
self.os = Some(Os::from_env());
}
if self.libc.is_none() {
self.libc = Some(Libc::from_env());
self.libc = Some(Libc::from_env()?);
}
self
Ok(self)
}

/// Construct a new [`PythonDownloadRequest`] with platform information from the environment.
Expand All @@ -191,7 +193,7 @@ impl PythonDownloadRequest {
None,
Some(Arch::from_env()),
Some(Os::from_env()),
Some(Libc::from_env()),
Some(Libc::from_env()?),
))
}

Expand Down Expand Up @@ -387,7 +389,11 @@ impl ManagedPythonDownload {

/// Iterate over all [`PythonDownload`]'s.
pub fn iter_all() -> impl Iterator<Item = &'static ManagedPythonDownload> {
PYTHON_DOWNLOADS.iter()
PYTHON_DOWNLOADS
.iter()
// TODO(konsti): musl python-build-standalone builds are currently broken (statically
// linked), so we pretend they don't exist. https://github.com/astral-sh/uv/issues/4242
.filter(|download| download.key.libc != Libc::Some(target_lexicon::Environment::Musl))
}

pub fn url(&self) -> &str {
Expand Down
2 changes: 1 addition & 1 deletion crates/uv-python/src/installation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ 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).await {
Ok(installation) => Ok(installation),
Err(Error::Download(downloads::Error::NoDownloadFound(_))) => {
Err(Error::MissingPython(err))
Expand Down
1 change: 1 addition & 0 deletions crates/uv-python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod environment;
mod implementation;
mod installation;
mod interpreter;
mod libc;
pub mod managed;
pub mod platform;
mod pointer_size;
Expand Down
Loading

0 comments on commit ae57d85

Please sign in to comment.