Always use base interpreter for cached environments (#4805)

Closes #4801.
This commit is contained in:
Charlie Marsh 2024-07-04 13:38:53 -04:00 committed by GitHub
parent 6a27135a65
commit 445d45b82c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 41 additions and 4 deletions

View file

@ -140,6 +140,25 @@ impl Interpreter {
}
}
/// Return the [`Interpreter`] for the base executable, if it's available.
///
/// If no such base executable is available, or if the base executable is the same as the
/// current executable, this method returns `None`.
pub fn to_base_interpreter(&self, cache: &Cache) -> Result<Option<Self>, Error> {
if let Some(base_executable) = self
.sys_base_executable()
.filter(|base_executable| *base_executable != self.sys_executable())
{
match Self::query(base_executable, cache) {
Ok(base_interpreter) => Ok(Some(base_interpreter)),
Err(Error::NotFound(_)) => Ok(None),
Err(err) => Err(err),
}
} else {
Ok(None)
}
}
/// Returns the path to the Python virtual environment.
#[inline]
pub fn platform(&self) -> &Platform {

View file

@ -42,6 +42,22 @@ impl CachedEnvironment {
) -> anyhow::Result<Self> {
let spec = RequirementsSpecification::from_requirements(requirements);
// When caching, always use the base interpreter, rather than that of the virtual
// environment.
let interpreter = if let Some(interpreter) = interpreter.to_base_interpreter(cache)? {
debug!(
"Caching via base interpreter: `{}`",
interpreter.sys_executable().display()
);
interpreter
} else {
debug!(
"Caching via interpreter: `{}`",
interpreter.sys_executable().display()
);
interpreter
};
// Resolve the requirements with the interpreter.
let resolution = resolve_environment(
&interpreter,
@ -60,11 +76,13 @@ impl CachedEnvironment {
// Hash the resolution by hashing the generated lockfile.
// TODO(charlie): If the resolution contains any mutable metadata (like a path or URL
// dependency), skip this step.
let lock = Lock::from_resolution_graph(&resolution)?;
let toml = lock.to_toml()?;
let resolution_hash = digest(&toml);
let resolution_hash = digest(
&Lock::from_resolution_graph(&resolution)?
.to_toml()?
.as_bytes(),
);
// Hash the interpreter by hashing the sysconfig data.
// Hash the interpreter based on its path.
// TODO(charlie): Come up with a robust hash for the interpreter.
let interpreter_hash = digest(&interpreter.sys_executable());