mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +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",
|
||||
"thiserror 2.0.11",
|
||||
"toml",
|
||||
"url",
|
||||
"uv-pep440",
|
||||
"uv-pep508",
|
||||
"uv-pypi-types",
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use owo_colors::OwoColorize;
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use owo_colors::OwoColorize;
|
||||
use tracing::debug;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_cache_key::cache_digest;
|
||||
use uv_fs::{LockedFile, Simplified};
|
||||
|
|
|
@ -23,3 +23,4 @@ memchr = { workspace = true }
|
|||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::sync::LazyLock;
|
|||
use memchr::memmem::Finder;
|
||||
use serde::Deserialize;
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
use uv_pep440::VersionSpecifiers;
|
||||
use uv_pep508::PackageName;
|
||||
|
@ -24,7 +25,7 @@ pub enum Pep723Item {
|
|||
/// A PEP 723 script provided via `stdin`.
|
||||
Stdin(Pep723Metadata),
|
||||
/// A PEP 723 script provided via a remote URL.
|
||||
Remote(Pep723Metadata),
|
||||
Remote(Pep723Metadata, Url),
|
||||
}
|
||||
|
||||
impl Pep723Item {
|
||||
|
@ -33,7 +34,7 @@ impl Pep723Item {
|
|||
match self {
|
||||
Self::Script(script) => &script.metadata,
|
||||
Self::Stdin(metadata) => metadata,
|
||||
Self::Remote(metadata) => metadata,
|
||||
Self::Remote(metadata, ..) => metadata,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +43,7 @@ impl Pep723Item {
|
|||
match self {
|
||||
Self::Script(script) => script.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> {
|
||||
match self {
|
||||
Self::Script(script) => Some(&script.path),
|
||||
Self::Stdin(_) => None,
|
||||
Self::Remote(_) => None,
|
||||
Self::Stdin(..) => None,
|
||||
Self::Remote(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +73,7 @@ pub enum Pep723ItemRef<'item> {
|
|||
/// A PEP 723 script provided via `stdin`.
|
||||
Stdin(&'item Pep723Metadata),
|
||||
/// A PEP 723 script provided via a remote URL.
|
||||
Remote(&'item Pep723Metadata),
|
||||
Remote(&'item Pep723Metadata, &'item Url),
|
||||
}
|
||||
|
||||
impl Pep723ItemRef<'_> {
|
||||
|
@ -81,7 +82,7 @@ impl Pep723ItemRef<'_> {
|
|||
match self {
|
||||
Self::Script(script) => &script.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> {
|
||||
match self {
|
||||
Self::Script(script) => Some(&script.path),
|
||||
Self::Stdin(_) => None,
|
||||
Self::Remote(_) => None,
|
||||
Self::Stdin(..) => None,
|
||||
Self::Remote(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +101,7 @@ impl<'item> From<&'item Pep723Item> for Pep723ItemRef<'item> {
|
|||
match item {
|
||||
Pep723Item::Script(script) => Self::Script(script),
|
||||
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(())
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// [`Interpreter`].
|
||||
///
|
||||
|
|
|
@ -39,7 +39,7 @@ use uv_resolver::{
|
|||
FlatIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython, ResolverEnvironment,
|
||||
ResolverOutput,
|
||||
};
|
||||
use uv_scripts::{Pep723ItemRef, Pep723Script};
|
||||
use uv_scripts::Pep723ItemRef;
|
||||
use uv_settings::PythonInstallMirrors;
|
||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
|
@ -530,17 +530,26 @@ pub(crate) enum ScriptInterpreter {
|
|||
|
||||
impl ScriptInterpreter {
|
||||
/// Return the expected virtual environment path for the [`Pep723Script`].
|
||||
pub(crate) fn root(script: &Pep723Script, cache: &Cache) -> PathBuf {
|
||||
let digest = cache_digest(&script.path);
|
||||
let entry = if let Some(name) = script
|
||||
.path
|
||||
.file_stem()
|
||||
.and_then(|name| name.to_str())
|
||||
.and_then(cache_name)
|
||||
{
|
||||
format!("{name}-{digest}")
|
||||
} else {
|
||||
digest
|
||||
pub(crate) fn root(script: Pep723ItemRef<'_>, cache: &Cache) -> PathBuf {
|
||||
let entry = match script {
|
||||
// For local scripts, use a hash of the path to the script.
|
||||
Pep723ItemRef::Script(script) => {
|
||||
let digest = cache_digest(&script.path);
|
||||
if let Some(file_name) = script
|
||||
.path
|
||||
.file_stem()
|
||||
.and_then(|name| name.to_str())
|
||||
.and_then(cache_name)
|
||||
{
|
||||
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
|
||||
.shard(CacheBucket::Environments, entry)
|
||||
|
@ -570,42 +579,39 @@ impl ScriptInterpreter {
|
|||
requires_python,
|
||||
} = ScriptPython::from_request(python_request, workspace, script, no_config).await?;
|
||||
|
||||
// If this is a local script, use a stable virtual environment.
|
||||
if let Pep723ItemRef::Script(script) = script {
|
||||
let root = Self::root(script, cache);
|
||||
match PythonEnvironment::from_root(&root, cache) {
|
||||
Ok(venv) => {
|
||||
if python_request.as_ref().map_or(true, |request| {
|
||||
if request.satisfied(venv.interpreter(), cache) {
|
||||
debug!(
|
||||
"The script environment's Python version satisfies `{}`",
|
||||
request.to_canonical_string()
|
||||
);
|
||||
true
|
||||
} else {
|
||||
debug!(
|
||||
"The script environment's Python version does not satisfy `{}`",
|
||||
request.to_canonical_string()
|
||||
);
|
||||
false
|
||||
}
|
||||
}) {
|
||||
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 {
|
||||
let root = Self::root(script, cache);
|
||||
match PythonEnvironment::from_root(&root, cache) {
|
||||
Ok(venv) => {
|
||||
if python_request.as_ref().map_or(true, |request| {
|
||||
if request.satisfied(venv.interpreter(), cache) {
|
||||
debug!(
|
||||
"The script environment's Python version satisfies `{}`",
|
||||
request.to_canonical_string()
|
||||
);
|
||||
true
|
||||
} else {
|
||||
debug!(
|
||||
"The script environment's Python version does not satisfy `{}`",
|
||||
request.to_canonical_string()
|
||||
);
|
||||
false
|
||||
}
|
||||
}) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
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()
|
||||
.connectivity(connectivity)
|
||||
|
@ -652,12 +658,30 @@ impl ScriptInterpreter {
|
|||
}
|
||||
|
||||
/// 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> {
|
||||
LockedFile::acquire(
|
||||
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(&script.path))),
|
||||
script.path.simplified_display(),
|
||||
)
|
||||
.await
|
||||
pub(crate) async fn lock(script: Pep723ItemRef<'_>) -> Result<LockedFile, std::io::Error> {
|
||||
match script {
|
||||
Pep723ItemRef::Script(script) => {
|
||||
LockedFile::acquire(
|
||||
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(&script.path))),
|
||||
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 {
|
||||
/// Initialize a virtual environment for a PEP 723 script.
|
||||
pub(crate) async fn get_or_init(
|
||||
script: &Pep723Script,
|
||||
script: Pep723ItemRef<'_>,
|
||||
python_request: Option<PythonRequest>,
|
||||
python_preference: PythonPreference,
|
||||
python_downloads: PythonDownloads,
|
||||
|
@ -1237,7 +1261,7 @@ impl ScriptEnvironment {
|
|||
let _lock = ScriptInterpreter::lock(script).await?;
|
||||
|
||||
match ScriptInterpreter::discover(
|
||||
Pep723ItemRef::Script(script),
|
||||
script,
|
||||
python_request,
|
||||
python_preference,
|
||||
python_downloads,
|
||||
|
@ -1280,8 +1304,8 @@ impl ScriptEnvironment {
|
|||
// 1) The name of the script
|
||||
// 2) No prompt
|
||||
let prompt = script
|
||||
.path
|
||||
.file_name()
|
||||
.path()
|
||||
.and_then(|path| path.file_name())
|
||||
.map(|f| f.to_string_lossy().to_string())
|
||||
.map(uv_virtualenv::Prompt::Static)
|
||||
.unwrap_or(uv_virtualenv::Prompt::None);
|
||||
|
|
|
@ -180,14 +180,14 @@ pub(crate) async fn run(
|
|||
script.path.user_display()
|
||||
);
|
||||
}
|
||||
Pep723Item::Stdin(_) => {
|
||||
Pep723Item::Stdin(..) => {
|
||||
if requirements_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(_) => {
|
||||
debug!("Reading inline script metadata from `{}`", "remote URL");
|
||||
Pep723Item::Remote(..) => {
|
||||
debug!("Reading inline script metadata from remote URL");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ pub(crate) async fn run(
|
|||
|
||||
// Discover the interpreter for the script.
|
||||
let environment = ScriptEnvironment::get_or_init(
|
||||
script.as_script().unwrap(),
|
||||
(&script).into(),
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
python_preference,
|
||||
python_downloads,
|
||||
|
@ -409,119 +409,57 @@ pub(crate) async fn run(
|
|||
let spec =
|
||||
RequirementsSpecification::from_overrides(requirements, constraints, overrides);
|
||||
|
||||
if let Some(script) = script.as_script() {
|
||||
// If the script is a local file, use a persistent environment.
|
||||
let environment = ScriptEnvironment::get_or_init(
|
||||
script,
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
python_preference,
|
||||
python_downloads,
|
||||
connectivity,
|
||||
native_tls,
|
||||
allow_insecure_host,
|
||||
&install_mirrors,
|
||||
no_config,
|
||||
cache,
|
||||
printer,
|
||||
)
|
||||
.await?
|
||||
.into_environment();
|
||||
let environment = ScriptEnvironment::get_or_init(
|
||||
(&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_environment();
|
||||
|
||||
match update_environment(
|
||||
environment,
|
||||
spec,
|
||||
modifications,
|
||||
&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
|
||||
{
|
||||
Ok(update) => Some(update.into_environment().into_interpreter()),
|
||||
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()),
|
||||
match update_environment(
|
||||
environment,
|
||||
spec,
|
||||
modifications,
|
||||
&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
|
||||
{
|
||||
Ok(update) => Some(update.into_environment().into_interpreter()),
|
||||
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()))
|
||||
}
|
||||
} else {
|
||||
// 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())
|
||||
Err(err) => return Err(err.into()),
|
||||
}
|
||||
} else {
|
||||
// Create a virtual environment.
|
||||
|
@ -1266,7 +1204,7 @@ pub(crate) enum RunCommand {
|
|||
/// Execute a `pythonw` script provided via `stdin`.
|
||||
PythonGuiStdin(Vec<u8>, Vec<OsString>),
|
||||
/// Execute a Python script provided via a remote URL.
|
||||
PythonRemote(tempfile::NamedTempFile, Vec<OsString>),
|
||||
PythonRemote(Url, tempfile::NamedTempFile, Vec<OsString>),
|
||||
/// Execute an external command.
|
||||
External(OsString, Vec<OsString>),
|
||||
/// Execute an empty command (in practice, `python` with no arguments).
|
||||
|
@ -1319,7 +1257,7 @@ impl RunCommand {
|
|||
process.args(args);
|
||||
process
|
||||
}
|
||||
Self::PythonRemote(target, args) => {
|
||||
Self::PythonRemote(.., target, args) => {
|
||||
let mut process = Command::new(interpreter.sys_executable());
|
||||
process.arg(target.path());
|
||||
process.args(args);
|
||||
|
@ -1535,7 +1473,7 @@ impl RunCommand {
|
|||
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(err) => return Err(err.into()),
|
||||
},
|
||||
Some(RunCommand::PythonRemote(script, _)) => {
|
||||
Some(RunCommand::PythonRemote(url, script, _)) => {
|
||||
match Pep723Metadata::read(&script).await {
|
||||
Ok(Some(metadata)) => Some(Pep723Item::Remote(metadata)),
|
||||
Ok(Some(metadata)) => Some(Pep723Item::Remote(metadata, url.clone())),
|
||||
Ok(None) => None,
|
||||
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||
None
|
||||
|
@ -1571,8 +1571,8 @@ async fn run_project(
|
|||
// Unwrap the script.
|
||||
let script = script.map(|script| match script {
|
||||
Pep723Item::Script(script) => script,
|
||||
Pep723Item::Stdin(_) => unreachable!("`uv lock` does not support stdin"),
|
||||
Pep723Item::Remote(_) => unreachable!("`uv lock` does not support remote files"),
|
||||
Pep723Item::Stdin(..) => unreachable!("`uv lock` does not support stdin"),
|
||||
Pep723Item::Remote(..) => unreachable!("`uv lock` does not support remote files"),
|
||||
});
|
||||
|
||||
Box::pin(commands::lock(
|
||||
|
@ -1669,8 +1669,8 @@ async fn run_project(
|
|||
// Unwrap the script.
|
||||
let script = script.map(|script| match script {
|
||||
Pep723Item::Script(script) => script,
|
||||
Pep723Item::Stdin(_) => unreachable!("`uv remove` does not support stdin"),
|
||||
Pep723Item::Remote(_) => unreachable!("`uv remove` does not support remote files"),
|
||||
Pep723Item::Stdin(..) => unreachable!("`uv remove` does not support stdin"),
|
||||
Pep723Item::Remote(..) => unreachable!("`uv remove` does not support remote files"),
|
||||
});
|
||||
|
||||
Box::pin(commands::remove(
|
||||
|
@ -1711,8 +1711,8 @@ async fn run_project(
|
|||
// Unwrap the script.
|
||||
let script = script.map(|script| match script {
|
||||
Pep723Item::Script(script) => script,
|
||||
Pep723Item::Stdin(_) => unreachable!("`uv tree` does not support stdin"),
|
||||
Pep723Item::Remote(_) => unreachable!("`uv tree` does not support remote files"),
|
||||
Pep723Item::Stdin(..) => unreachable!("`uv tree` does not support stdin"),
|
||||
Pep723Item::Remote(..) => unreachable!("`uv tree` does not support remote files"),
|
||||
});
|
||||
|
||||
Box::pin(commands::tree(
|
||||
|
@ -1757,8 +1757,8 @@ async fn run_project(
|
|||
// Unwrap the script.
|
||||
let script = script.map(|script| match script {
|
||||
Pep723Item::Script(script) => script,
|
||||
Pep723Item::Stdin(_) => unreachable!("`uv export` does not support stdin"),
|
||||
Pep723Item::Remote(_) => unreachable!("`uv export` does not support remote files"),
|
||||
Pep723Item::Stdin(..) => unreachable!("`uv export` does not support stdin"),
|
||||
Pep723Item::Remote(..) => unreachable!("`uv export` does not support remote files"),
|
||||
});
|
||||
|
||||
commands::export(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue