mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-14 20:39:37 +00:00
Use stable environments for remote and stdin scripts (#11364)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux libc (push) Blocked by required conditions
CI / build binary | linux musl (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux libc (push) Blocked by required conditions
CI / build binary | linux musl (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
## Summary This is a follow-on to #11347 to use a stable directory for remote and stdin scripts. The annoying piece here was figuring out what to use as the cache key. For remote scripts, I'm using the URL; for stdin scripts, there isn't any identifying information, so I'm just using a hash of the metadata.
This commit is contained in:
parent
79ad7a1ab9
commit
1cd9c37151
8 changed files with 161 additions and 199 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -5604,6 +5604,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.11",
|
"thiserror 2.0.11",
|
||||||
"toml",
|
"toml",
|
||||||
|
"url",
|
||||||
"uv-pep440",
|
"uv-pep440",
|
||||||
"uv-pep508",
|
"uv-pep508",
|
||||||
"uv-pypi-types",
|
"uv-pypi-types",
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use owo_colors::OwoColorize;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use owo_colors::OwoColorize;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use uv_cache::Cache;
|
use uv_cache::Cache;
|
||||||
use uv_cache_key::cache_digest;
|
use uv_cache_key::cache_digest;
|
||||||
use uv_fs::{LockedFile, Simplified};
|
use uv_fs::{LockedFile, Simplified};
|
||||||
|
|
|
@ -23,3 +23,4 @@ memchr = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
toml = { workspace = true }
|
toml = { workspace = true }
|
||||||
|
url = { workspace = true }
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::sync::LazyLock;
|
||||||
use memchr::memmem::Finder;
|
use memchr::memmem::Finder;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use uv_pep440::VersionSpecifiers;
|
use uv_pep440::VersionSpecifiers;
|
||||||
use uv_pep508::PackageName;
|
use uv_pep508::PackageName;
|
||||||
|
@ -24,7 +25,7 @@ pub enum Pep723Item {
|
||||||
/// A PEP 723 script provided via `stdin`.
|
/// A PEP 723 script provided via `stdin`.
|
||||||
Stdin(Pep723Metadata),
|
Stdin(Pep723Metadata),
|
||||||
/// A PEP 723 script provided via a remote URL.
|
/// A PEP 723 script provided via a remote URL.
|
||||||
Remote(Pep723Metadata),
|
Remote(Pep723Metadata, Url),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pep723Item {
|
impl Pep723Item {
|
||||||
|
@ -33,7 +34,7 @@ impl Pep723Item {
|
||||||
match self {
|
match self {
|
||||||
Self::Script(script) => &script.metadata,
|
Self::Script(script) => &script.metadata,
|
||||||
Self::Stdin(metadata) => metadata,
|
Self::Stdin(metadata) => metadata,
|
||||||
Self::Remote(metadata) => metadata,
|
Self::Remote(metadata, ..) => metadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ impl Pep723Item {
|
||||||
match self {
|
match self {
|
||||||
Self::Script(script) => script.metadata,
|
Self::Script(script) => script.metadata,
|
||||||
Self::Stdin(metadata) => metadata,
|
Self::Stdin(metadata) => metadata,
|
||||||
Self::Remote(metadata) => metadata,
|
Self::Remote(metadata, ..) => metadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,8 +51,8 @@ impl Pep723Item {
|
||||||
pub fn path(&self) -> Option<&Path> {
|
pub fn path(&self) -> Option<&Path> {
|
||||||
match self {
|
match self {
|
||||||
Self::Script(script) => Some(&script.path),
|
Self::Script(script) => Some(&script.path),
|
||||||
Self::Stdin(_) => None,
|
Self::Stdin(..) => None,
|
||||||
Self::Remote(_) => None,
|
Self::Remote(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ pub enum Pep723ItemRef<'item> {
|
||||||
/// A PEP 723 script provided via `stdin`.
|
/// A PEP 723 script provided via `stdin`.
|
||||||
Stdin(&'item Pep723Metadata),
|
Stdin(&'item Pep723Metadata),
|
||||||
/// A PEP 723 script provided via a remote URL.
|
/// A PEP 723 script provided via a remote URL.
|
||||||
Remote(&'item Pep723Metadata),
|
Remote(&'item Pep723Metadata, &'item Url),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pep723ItemRef<'_> {
|
impl Pep723ItemRef<'_> {
|
||||||
|
@ -81,7 +82,7 @@ impl Pep723ItemRef<'_> {
|
||||||
match self {
|
match self {
|
||||||
Self::Script(script) => &script.metadata,
|
Self::Script(script) => &script.metadata,
|
||||||
Self::Stdin(metadata) => metadata,
|
Self::Stdin(metadata) => metadata,
|
||||||
Self::Remote(metadata) => metadata,
|
Self::Remote(metadata, ..) => metadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +90,8 @@ impl Pep723ItemRef<'_> {
|
||||||
pub fn path(&self) -> Option<&Path> {
|
pub fn path(&self) -> Option<&Path> {
|
||||||
match self {
|
match self {
|
||||||
Self::Script(script) => Some(&script.path),
|
Self::Script(script) => Some(&script.path),
|
||||||
Self::Stdin(_) => None,
|
Self::Stdin(..) => None,
|
||||||
Self::Remote(_) => None,
|
Self::Remote(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ impl<'item> From<&'item Pep723Item> for Pep723ItemRef<'item> {
|
||||||
match item {
|
match item {
|
||||||
Pep723Item::Script(script) => Self::Script(script),
|
Pep723Item::Script(script) => Self::Script(script),
|
||||||
Pep723Item::Stdin(metadata) => Self::Stdin(metadata),
|
Pep723Item::Stdin(metadata) => Self::Stdin(metadata),
|
||||||
Pep723Item::Remote(metadata) => Self::Remote(metadata),
|
Pep723Item::Remote(metadata, url) => Self::Remote(metadata, url),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,11 +157,6 @@ impl CachedEnvironment {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the [`CachedEnvironment`] into an [`Interpreter`].
|
|
||||||
pub(crate) fn into_interpreter(self) -> Interpreter {
|
|
||||||
self.0.into_interpreter()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the [`Interpreter`] to use for the cached environment, based on a given
|
/// Return the [`Interpreter`] to use for the cached environment, based on a given
|
||||||
/// [`Interpreter`].
|
/// [`Interpreter`].
|
||||||
///
|
///
|
||||||
|
|
|
@ -39,7 +39,7 @@ use uv_resolver::{
|
||||||
FlatIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython, ResolverEnvironment,
|
FlatIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython, ResolverEnvironment,
|
||||||
ResolverOutput,
|
ResolverOutput,
|
||||||
};
|
};
|
||||||
use uv_scripts::{Pep723ItemRef, Pep723Script};
|
use uv_scripts::Pep723ItemRef;
|
||||||
use uv_settings::PythonInstallMirrors;
|
use uv_settings::PythonInstallMirrors;
|
||||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
||||||
use uv_warnings::{warn_user, warn_user_once};
|
use uv_warnings::{warn_user, warn_user_once};
|
||||||
|
@ -530,17 +530,26 @@ pub(crate) enum ScriptInterpreter {
|
||||||
|
|
||||||
impl ScriptInterpreter {
|
impl ScriptInterpreter {
|
||||||
/// Return the expected virtual environment path for the [`Pep723Script`].
|
/// Return the expected virtual environment path for the [`Pep723Script`].
|
||||||
pub(crate) fn root(script: &Pep723Script, cache: &Cache) -> PathBuf {
|
pub(crate) fn root(script: Pep723ItemRef<'_>, cache: &Cache) -> PathBuf {
|
||||||
let digest = cache_digest(&script.path);
|
let entry = match script {
|
||||||
let entry = if let Some(name) = script
|
// For local scripts, use a hash of the path to the script.
|
||||||
.path
|
Pep723ItemRef::Script(script) => {
|
||||||
.file_stem()
|
let digest = cache_digest(&script.path);
|
||||||
.and_then(|name| name.to_str())
|
if let Some(file_name) = script
|
||||||
.and_then(cache_name)
|
.path
|
||||||
{
|
.file_stem()
|
||||||
format!("{name}-{digest}")
|
.and_then(|name| name.to_str())
|
||||||
} else {
|
.and_then(cache_name)
|
||||||
digest
|
{
|
||||||
|
format!("{file_name}-{digest}")
|
||||||
|
} else {
|
||||||
|
digest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For remote scripts, use a hash of the URL.
|
||||||
|
Pep723ItemRef::Remote(.., url) => cache_digest(url),
|
||||||
|
// Otherwise, use a hash of the metadata.
|
||||||
|
Pep723ItemRef::Stdin(metadata) => cache_digest(&metadata.raw),
|
||||||
};
|
};
|
||||||
cache
|
cache
|
||||||
.shard(CacheBucket::Environments, entry)
|
.shard(CacheBucket::Environments, entry)
|
||||||
|
@ -570,42 +579,39 @@ impl ScriptInterpreter {
|
||||||
requires_python,
|
requires_python,
|
||||||
} = ScriptPython::from_request(python_request, workspace, script, no_config).await?;
|
} = ScriptPython::from_request(python_request, workspace, script, no_config).await?;
|
||||||
|
|
||||||
// If this is a local script, use a stable virtual environment.
|
let root = Self::root(script, cache);
|
||||||
if let Pep723ItemRef::Script(script) = script {
|
match PythonEnvironment::from_root(&root, cache) {
|
||||||
let root = Self::root(script, cache);
|
Ok(venv) => {
|
||||||
match PythonEnvironment::from_root(&root, cache) {
|
if python_request.as_ref().map_or(true, |request| {
|
||||||
Ok(venv) => {
|
if request.satisfied(venv.interpreter(), cache) {
|
||||||
if python_request.as_ref().map_or(true, |request| {
|
debug!(
|
||||||
if request.satisfied(venv.interpreter(), cache) {
|
"The script environment's Python version satisfies `{}`",
|
||||||
debug!(
|
request.to_canonical_string()
|
||||||
"The script environment's Python version satisfies `{}`",
|
);
|
||||||
request.to_canonical_string()
|
true
|
||||||
);
|
} else {
|
||||||
true
|
debug!(
|
||||||
} else {
|
"The script environment's Python version does not satisfy `{}`",
|
||||||
debug!(
|
request.to_canonical_string()
|
||||||
"The script environment's Python version does not satisfy `{}`",
|
);
|
||||||
request.to_canonical_string()
|
false
|
||||||
);
|
}
|
||||||
false
|
}) {
|
||||||
}
|
if let Some((requires_python, ..)) = requires_python.as_ref() {
|
||||||
}) {
|
if requires_python.contains(venv.interpreter().python_version()) {
|
||||||
if let Some((requires_python, ..)) = requires_python.as_ref() {
|
|
||||||
if requires_python.contains(venv.interpreter().python_version()) {
|
|
||||||
return Ok(Self::Environment(venv));
|
|
||||||
}
|
|
||||||
debug!(
|
|
||||||
"The script environment's Python version does not meet the script's Python requirement: `{requires_python}`"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Ok(Self::Environment(venv));
|
return Ok(Self::Environment(venv));
|
||||||
}
|
}
|
||||||
|
debug!(
|
||||||
|
"The script environment's Python version does not meet the script's Python requirement: `{requires_python}`"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Ok(Self::Environment(venv));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(uv_python::Error::MissingEnvironment(_)) => {}
|
}
|
||||||
Err(err) => warn!("Ignoring existing script environment: {err}"),
|
Err(uv_python::Error::MissingEnvironment(_)) => {}
|
||||||
};
|
Err(err) => warn!("Ignoring existing script environment: {err}"),
|
||||||
}
|
};
|
||||||
|
|
||||||
let client_builder = BaseClientBuilder::new()
|
let client_builder = BaseClientBuilder::new()
|
||||||
.connectivity(connectivity)
|
.connectivity(connectivity)
|
||||||
|
@ -652,12 +658,30 @@ impl ScriptInterpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grab a file lock for the script to prevent concurrent writes across processes.
|
/// Grab a file lock for the script to prevent concurrent writes across processes.
|
||||||
pub(crate) async fn lock(script: &Pep723Script) -> Result<LockedFile, std::io::Error> {
|
pub(crate) async fn lock(script: Pep723ItemRef<'_>) -> Result<LockedFile, std::io::Error> {
|
||||||
LockedFile::acquire(
|
match script {
|
||||||
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(&script.path))),
|
Pep723ItemRef::Script(script) => {
|
||||||
script.path.simplified_display(),
|
LockedFile::acquire(
|
||||||
)
|
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(&script.path))),
|
||||||
.await
|
script.path.simplified_display(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Pep723ItemRef::Remote(.., url) => {
|
||||||
|
LockedFile::acquire(
|
||||||
|
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(url))),
|
||||||
|
url.to_string(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Pep723ItemRef::Stdin(metadata) => {
|
||||||
|
LockedFile::acquire(
|
||||||
|
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(&metadata.raw))),
|
||||||
|
"stdin".to_string(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,7 +1245,7 @@ struct ScriptEnvironment(PythonEnvironment);
|
||||||
impl ScriptEnvironment {
|
impl ScriptEnvironment {
|
||||||
/// Initialize a virtual environment for a PEP 723 script.
|
/// Initialize a virtual environment for a PEP 723 script.
|
||||||
pub(crate) async fn get_or_init(
|
pub(crate) async fn get_or_init(
|
||||||
script: &Pep723Script,
|
script: Pep723ItemRef<'_>,
|
||||||
python_request: Option<PythonRequest>,
|
python_request: Option<PythonRequest>,
|
||||||
python_preference: PythonPreference,
|
python_preference: PythonPreference,
|
||||||
python_downloads: PythonDownloads,
|
python_downloads: PythonDownloads,
|
||||||
|
@ -1237,7 +1261,7 @@ impl ScriptEnvironment {
|
||||||
let _lock = ScriptInterpreter::lock(script).await?;
|
let _lock = ScriptInterpreter::lock(script).await?;
|
||||||
|
|
||||||
match ScriptInterpreter::discover(
|
match ScriptInterpreter::discover(
|
||||||
Pep723ItemRef::Script(script),
|
script,
|
||||||
python_request,
|
python_request,
|
||||||
python_preference,
|
python_preference,
|
||||||
python_downloads,
|
python_downloads,
|
||||||
|
@ -1280,8 +1304,8 @@ impl ScriptEnvironment {
|
||||||
// 1) The name of the script
|
// 1) The name of the script
|
||||||
// 2) No prompt
|
// 2) No prompt
|
||||||
let prompt = script
|
let prompt = script
|
||||||
.path
|
.path()
|
||||||
.file_name()
|
.and_then(|path| path.file_name())
|
||||||
.map(|f| f.to_string_lossy().to_string())
|
.map(|f| f.to_string_lossy().to_string())
|
||||||
.map(uv_virtualenv::Prompt::Static)
|
.map(uv_virtualenv::Prompt::Static)
|
||||||
.unwrap_or(uv_virtualenv::Prompt::None);
|
.unwrap_or(uv_virtualenv::Prompt::None);
|
||||||
|
|
|
@ -180,14 +180,14 @@ pub(crate) async fn run(
|
||||||
script.path.user_display()
|
script.path.user_display()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Pep723Item::Stdin(_) => {
|
Pep723Item::Stdin(..) => {
|
||||||
if requirements_from_stdin {
|
if requirements_from_stdin {
|
||||||
bail!("Cannot read both requirements file and script from stdin");
|
bail!("Cannot read both requirements file and script from stdin");
|
||||||
}
|
}
|
||||||
debug!("Reading inline script metadata from `{}`", "stdin");
|
debug!("Reading inline script metadata from stdin");
|
||||||
}
|
}
|
||||||
Pep723Item::Remote(_) => {
|
Pep723Item::Remote(..) => {
|
||||||
debug!("Reading inline script metadata from `{}`", "remote URL");
|
debug!("Reading inline script metadata from remote URL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ pub(crate) async fn run(
|
||||||
|
|
||||||
// Discover the interpreter for the script.
|
// Discover the interpreter for the script.
|
||||||
let environment = ScriptEnvironment::get_or_init(
|
let environment = ScriptEnvironment::get_or_init(
|
||||||
script.as_script().unwrap(),
|
(&script).into(),
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python.as_deref().map(PythonRequest::parse),
|
||||||
python_preference,
|
python_preference,
|
||||||
python_downloads,
|
python_downloads,
|
||||||
|
@ -409,119 +409,57 @@ pub(crate) async fn run(
|
||||||
let spec =
|
let spec =
|
||||||
RequirementsSpecification::from_overrides(requirements, constraints, overrides);
|
RequirementsSpecification::from_overrides(requirements, constraints, overrides);
|
||||||
|
|
||||||
if let Some(script) = script.as_script() {
|
let environment = ScriptEnvironment::get_or_init(
|
||||||
// If the script is a local file, use a persistent environment.
|
(&script).into(),
|
||||||
let environment = ScriptEnvironment::get_or_init(
|
python.as_deref().map(PythonRequest::parse),
|
||||||
script,
|
python_preference,
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python_downloads,
|
||||||
python_preference,
|
connectivity,
|
||||||
python_downloads,
|
native_tls,
|
||||||
connectivity,
|
allow_insecure_host,
|
||||||
native_tls,
|
&install_mirrors,
|
||||||
allow_insecure_host,
|
no_config,
|
||||||
&install_mirrors,
|
cache,
|
||||||
no_config,
|
printer,
|
||||||
cache,
|
)
|
||||||
printer,
|
.await?
|
||||||
)
|
.into_environment();
|
||||||
.await?
|
|
||||||
.into_environment();
|
|
||||||
|
|
||||||
match update_environment(
|
match update_environment(
|
||||||
environment,
|
environment,
|
||||||
spec,
|
spec,
|
||||||
modifications,
|
modifications,
|
||||||
&settings,
|
&settings,
|
||||||
&sync_state,
|
&sync_state,
|
||||||
if show_resolution {
|
if show_resolution {
|
||||||
Box::new(DefaultResolveLogger)
|
Box::new(DefaultResolveLogger)
|
||||||
} else {
|
} else {
|
||||||
Box::new(SummaryResolveLogger)
|
Box::new(SummaryResolveLogger)
|
||||||
},
|
},
|
||||||
if show_resolution {
|
if show_resolution {
|
||||||
Box::new(DefaultInstallLogger)
|
Box::new(DefaultInstallLogger)
|
||||||
} else {
|
} else {
|
||||||
Box::new(SummaryInstallLogger)
|
Box::new(SummaryInstallLogger)
|
||||||
},
|
},
|
||||||
installer_metadata,
|
installer_metadata,
|
||||||
connectivity,
|
connectivity,
|
||||||
concurrency,
|
concurrency,
|
||||||
native_tls,
|
native_tls,
|
||||||
allow_insecure_host,
|
allow_insecure_host,
|
||||||
cache,
|
cache,
|
||||||
printer,
|
printer,
|
||||||
preview,
|
preview,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(update) => Some(update.into_environment().into_interpreter()),
|
Ok(update) => Some(update.into_environment().into_interpreter()),
|
||||||
Err(ProjectError::Operation(err)) => {
|
Err(ProjectError::Operation(err)) => {
|
||||||
return diagnostics::OperationDiagnostic::native_tls(native_tls)
|
return diagnostics::OperationDiagnostic::native_tls(native_tls)
|
||||||
.with_context("script")
|
.with_context("script")
|
||||||
.report(err)
|
.report(err)
|
||||||
.map_or(Ok(ExitStatus::Failure), |err| Err(err.into()))
|
.map_or(Ok(ExitStatus::Failure), |err| Err(err.into()))
|
||||||
}
|
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
}
|
}
|
||||||
} else {
|
Err(err) => return Err(err.into()),
|
||||||
// Otherwise, use an ephemeral environment.
|
|
||||||
let interpreter = ScriptInterpreter::discover(
|
|
||||||
(&script).into(),
|
|
||||||
python.as_deref().map(PythonRequest::parse),
|
|
||||||
python_preference,
|
|
||||||
python_downloads,
|
|
||||||
connectivity,
|
|
||||||
native_tls,
|
|
||||||
allow_insecure_host,
|
|
||||||
&install_mirrors,
|
|
||||||
no_config,
|
|
||||||
cache,
|
|
||||||
printer,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
.into_interpreter();
|
|
||||||
|
|
||||||
let result = CachedEnvironment::from_spec(
|
|
||||||
EnvironmentSpecification::from(spec),
|
|
||||||
&interpreter,
|
|
||||||
&settings,
|
|
||||||
&sync_state,
|
|
||||||
if show_resolution {
|
|
||||||
Box::new(DefaultResolveLogger)
|
|
||||||
} else {
|
|
||||||
Box::new(SummaryResolveLogger)
|
|
||||||
},
|
|
||||||
if show_resolution {
|
|
||||||
Box::new(DefaultInstallLogger)
|
|
||||||
} else {
|
|
||||||
Box::new(SummaryInstallLogger)
|
|
||||||
},
|
|
||||||
installer_metadata,
|
|
||||||
connectivity,
|
|
||||||
concurrency,
|
|
||||||
native_tls,
|
|
||||||
allow_insecure_host,
|
|
||||||
cache,
|
|
||||||
printer,
|
|
||||||
preview,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let environment = match result {
|
|
||||||
Ok(resolution) => resolution,
|
|
||||||
Err(ProjectError::Operation(err)) => {
|
|
||||||
return diagnostics::OperationDiagnostic::native_tls(native_tls)
|
|
||||||
.with_context("script")
|
|
||||||
.report(err)
|
|
||||||
.map_or(Ok(ExitStatus::Failure), |err| Err(err.into()))
|
|
||||||
}
|
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear any existing overlay.
|
|
||||||
environment.clear_overlay()?;
|
|
||||||
|
|
||||||
Some(environment.into_interpreter())
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create a virtual environment.
|
// Create a virtual environment.
|
||||||
|
@ -1266,7 +1204,7 @@ pub(crate) enum RunCommand {
|
||||||
/// Execute a `pythonw` script provided via `stdin`.
|
/// Execute a `pythonw` script provided via `stdin`.
|
||||||
PythonGuiStdin(Vec<u8>, Vec<OsString>),
|
PythonGuiStdin(Vec<u8>, Vec<OsString>),
|
||||||
/// Execute a Python script provided via a remote URL.
|
/// Execute a Python script provided via a remote URL.
|
||||||
PythonRemote(tempfile::NamedTempFile, Vec<OsString>),
|
PythonRemote(Url, tempfile::NamedTempFile, Vec<OsString>),
|
||||||
/// Execute an external command.
|
/// Execute an external command.
|
||||||
External(OsString, Vec<OsString>),
|
External(OsString, Vec<OsString>),
|
||||||
/// Execute an empty command (in practice, `python` with no arguments).
|
/// Execute an empty command (in practice, `python` with no arguments).
|
||||||
|
@ -1319,7 +1257,7 @@ impl RunCommand {
|
||||||
process.args(args);
|
process.args(args);
|
||||||
process
|
process
|
||||||
}
|
}
|
||||||
Self::PythonRemote(target, args) => {
|
Self::PythonRemote(.., target, args) => {
|
||||||
let mut process = Command::new(interpreter.sys_executable());
|
let mut process = Command::new(interpreter.sys_executable());
|
||||||
process.arg(target.path());
|
process.arg(target.path());
|
||||||
process.args(args);
|
process.args(args);
|
||||||
|
@ -1535,7 +1473,7 @@ impl RunCommand {
|
||||||
writer.write_all(&chunk?)?;
|
writer.write_all(&chunk?)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(Self::PythonRemote(file, args.to_vec()));
|
return Ok(Self::PythonRemote(url, file, args.to_vec()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,9 +178,9 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => None,
|
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => None,
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err.into()),
|
||||||
},
|
},
|
||||||
Some(RunCommand::PythonRemote(script, _)) => {
|
Some(RunCommand::PythonRemote(url, script, _)) => {
|
||||||
match Pep723Metadata::read(&script).await {
|
match Pep723Metadata::read(&script).await {
|
||||||
Ok(Some(metadata)) => Some(Pep723Item::Remote(metadata)),
|
Ok(Some(metadata)) => Some(Pep723Item::Remote(metadata, url.clone())),
|
||||||
Ok(None) => None,
|
Ok(None) => None,
|
||||||
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
|
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||||
None
|
None
|
||||||
|
@ -1571,8 +1571,8 @@ async fn run_project(
|
||||||
// Unwrap the script.
|
// Unwrap the script.
|
||||||
let script = script.map(|script| match script {
|
let script = script.map(|script| match script {
|
||||||
Pep723Item::Script(script) => script,
|
Pep723Item::Script(script) => script,
|
||||||
Pep723Item::Stdin(_) => unreachable!("`uv lock` does not support stdin"),
|
Pep723Item::Stdin(..) => unreachable!("`uv lock` does not support stdin"),
|
||||||
Pep723Item::Remote(_) => unreachable!("`uv lock` does not support remote files"),
|
Pep723Item::Remote(..) => unreachable!("`uv lock` does not support remote files"),
|
||||||
});
|
});
|
||||||
|
|
||||||
Box::pin(commands::lock(
|
Box::pin(commands::lock(
|
||||||
|
@ -1669,8 +1669,8 @@ async fn run_project(
|
||||||
// Unwrap the script.
|
// Unwrap the script.
|
||||||
let script = script.map(|script| match script {
|
let script = script.map(|script| match script {
|
||||||
Pep723Item::Script(script) => script,
|
Pep723Item::Script(script) => script,
|
||||||
Pep723Item::Stdin(_) => unreachable!("`uv remove` does not support stdin"),
|
Pep723Item::Stdin(..) => unreachable!("`uv remove` does not support stdin"),
|
||||||
Pep723Item::Remote(_) => unreachable!("`uv remove` does not support remote files"),
|
Pep723Item::Remote(..) => unreachable!("`uv remove` does not support remote files"),
|
||||||
});
|
});
|
||||||
|
|
||||||
Box::pin(commands::remove(
|
Box::pin(commands::remove(
|
||||||
|
@ -1711,8 +1711,8 @@ async fn run_project(
|
||||||
// Unwrap the script.
|
// Unwrap the script.
|
||||||
let script = script.map(|script| match script {
|
let script = script.map(|script| match script {
|
||||||
Pep723Item::Script(script) => script,
|
Pep723Item::Script(script) => script,
|
||||||
Pep723Item::Stdin(_) => unreachable!("`uv tree` does not support stdin"),
|
Pep723Item::Stdin(..) => unreachable!("`uv tree` does not support stdin"),
|
||||||
Pep723Item::Remote(_) => unreachable!("`uv tree` does not support remote files"),
|
Pep723Item::Remote(..) => unreachable!("`uv tree` does not support remote files"),
|
||||||
});
|
});
|
||||||
|
|
||||||
Box::pin(commands::tree(
|
Box::pin(commands::tree(
|
||||||
|
@ -1757,8 +1757,8 @@ async fn run_project(
|
||||||
// Unwrap the script.
|
// Unwrap the script.
|
||||||
let script = script.map(|script| match script {
|
let script = script.map(|script| match script {
|
||||||
Pep723Item::Script(script) => script,
|
Pep723Item::Script(script) => script,
|
||||||
Pep723Item::Stdin(_) => unreachable!("`uv export` does not support stdin"),
|
Pep723Item::Stdin(..) => unreachable!("`uv export` does not support stdin"),
|
||||||
Pep723Item::Remote(_) => unreachable!("`uv export` does not support remote files"),
|
Pep723Item::Remote(..) => unreachable!("`uv export` does not support remote files"),
|
||||||
});
|
});
|
||||||
|
|
||||||
commands::export(
|
commands::export(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue