From 91c3ebc6f7bf07c4a5b9c9bd22f9d65e31c38c75 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Thu, 21 Nov 2024 06:35:02 -0500 Subject: [PATCH] Fix Python interpreter discovery on non-glibc hosts (#9005) ## Summary On Termux, uv currently fails to find any interpreter because it can't find a glibc version, because there isn't one. But the Python interpreter is still functional nonetheless. So, when glibc cannot be found, simply return 0 for the version numbers and mark the interpreter as being incompatible with manylinux I really don't know if this is the right way to address this, but I can attest that manual testing shows uv appears to be fully functional, at least for pip and virtualenvs. Fixes #7373 ## Test Plan I tried running the test suite, and after some tweaks, a good portion of the test suite passes as well. A significant number of tests fail, but this appears to be due to minor differences in output, like warnings about hard links not working (hard links are completely disallowed on Android), differences in the number of files removed, etc. The test suite seems to be very sensitive to minor variations in output. --- crates/uv-platform-tags/src/platform.rs | 2 ++ crates/uv-platform-tags/src/tags.rs | 8 +++++ .../uv-python/python/get_interpreter_info.py | 32 +++++++++++++------ .../uv-python/python/packaging/_manylinux.py | 2 +- crates/uv-python/src/platform.rs | 6 ++-- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/crates/uv-platform-tags/src/platform.rs b/crates/uv-platform-tags/src/platform.rs index 9ad464a6e..12876bb08 100644 --- a/crates/uv-platform-tags/src/platform.rs +++ b/crates/uv-platform-tags/src/platform.rs @@ -50,6 +50,7 @@ pub enum Os { Dragonfly { release: String }, Illumos { release: String, arch: String }, Haiku { release: String }, + Android { api_level: u16 }, } impl fmt::Display for Os { @@ -65,6 +66,7 @@ impl fmt::Display for Os { Self::Dragonfly { .. } => write!(f, "DragonFly"), Self::Illumos { .. } => write!(f, "Illumos"), Self::Haiku { .. } => write!(f, "Haiku"), + Self::Android { .. } => write!(f, "Android"), } } } diff --git a/crates/uv-platform-tags/src/tags.rs b/crates/uv-platform-tags/src/tags.rs index b3b31f43f..6cfe3709d 100644 --- a/crates/uv-platform-tags/src/tags.rs +++ b/crates/uv-platform-tags/src/tags.rs @@ -543,6 +543,14 @@ fn compatible_tags(platform: &Platform) -> Result, PlatformError> { let os = os.to_string().to_lowercase(); vec![format!("{}_{}_{}", os, release, arch)] } + (Os::Android { api_level }, _) => { + vec![format!( + "{}_{}_{}", + os.to_string().to_lowercase(), + api_level, + arch + )] + } _ => { return Err(PlatformError::OsVersionDetectionError(format!( "Unsupported operating system and architecture combination: {os} {arch}" diff --git a/crates/uv-python/python/get_interpreter_info.py b/crates/uv-python/python/get_interpreter_info.py index f39506bfe..d89d86e68 100644 --- a/crates/uv-python/python/get_interpreter_info.py +++ b/crates/uv-python/python/get_interpreter_info.py @@ -462,22 +462,30 @@ def get_operating_system_and_architecture(): from .packaging._musllinux import _get_musl_version musl_version = _get_musl_version(sys.executable) - glibc_version = _get_glibc_version() + if musl_version: operating_system = { "name": "musllinux", "major": musl_version[0], "minor": musl_version[1], } - elif glibc_version != (-1, -1): - operating_system = { - "name": "manylinux", - "major": glibc_version[0], - "minor": glibc_version[1], - } else: - print(json.dumps({"result": "error", "kind": "libc_not_found"})) - sys.exit(0) + glibc_version = _get_glibc_version() + + if glibc_version != (0, 0): + operating_system = { + "name": "manylinux", + "major": glibc_version[0], + "minor": glibc_version[1], + } + elif hasattr(sys, "getandroidapilevel"): + operating_system = { + "name": "android", + "api_level": sys.getandroidapilevel(), + } + else: + print(json.dumps({"result": "error", "kind": "libc_not_found"})) + sys.exit(0) elif operating_system == "win": operating_system = { "name": "windows", @@ -542,9 +550,11 @@ def main() -> None: "python_version": ".".join(platform.python_version_tuple()[:2]), "sys_platform": sys.platform, } + os_and_arch = get_operating_system_and_architecture() - manylinux_compatible = True + manylinux_compatible = False + if os_and_arch["os"]["name"] == "manylinux": # noinspection PyProtectedMember from .packaging._manylinux import _get_glibc_version, _is_compatible @@ -552,6 +562,8 @@ def main() -> None: manylinux_compatible = _is_compatible( arch=os_and_arch["arch"], version=_get_glibc_version() ) + elif os_and_arch["os"]["name"] == "musllinux": + manylinux_compatible = True interpreter_info = { "result": "success", diff --git a/crates/uv-python/python/packaging/_manylinux.py b/crates/uv-python/python/packaging/_manylinux.py index baa9fac4f..884bc86b3 100644 --- a/crates/uv-python/python/packaging/_manylinux.py +++ b/crates/uv-python/python/packaging/_manylinux.py @@ -173,7 +173,7 @@ def _parse_glibc_version(version_str: str) -> tuple[int, int]: def _get_glibc_version() -> tuple[int, int]: version_str = _glibc_version_string() if version_str is None: - return (-1, -1) + return (0, 0) return _parse_glibc_version(version_str) diff --git a/crates/uv-python/src/platform.rs b/crates/uv-python/src/platform.rs index 6b54477c0..88598fa64 100644 --- a/crates/uv-python/src/platform.rs +++ b/crates/uv-python/src/platform.rs @@ -203,9 +203,9 @@ impl From<&uv_platform_tags::Os> for Os { uv_platform_tags::Os::Haiku { .. } => Self(target_lexicon::OperatingSystem::Haiku), uv_platform_tags::Os::Illumos { .. } => Self(target_lexicon::OperatingSystem::Illumos), uv_platform_tags::Os::Macos { .. } => Self(target_lexicon::OperatingSystem::Darwin), - uv_platform_tags::Os::Manylinux { .. } | uv_platform_tags::Os::Musllinux { .. } => { - Self(target_lexicon::OperatingSystem::Linux) - } + uv_platform_tags::Os::Manylinux { .. } + | uv_platform_tags::Os::Musllinux { .. } + | uv_platform_tags::Os::Android { .. } => Self(target_lexicon::OperatingSystem::Linux), uv_platform_tags::Os::NetBsd { .. } => Self(target_lexicon::OperatingSystem::Netbsd), uv_platform_tags::Os::OpenBsd { .. } => Self(target_lexicon::OperatingSystem::Openbsd), uv_platform_tags::Os::Windows => Self(target_lexicon::OperatingSystem::Windows),