Add preview mode and use for warning in uv run (#3192)

Adds hidden `--preview` / `--no-preview` flags with `UV_PREVIEW`
environment variable support. Copies the `PreviewMode` type from Ruff.

Does a little bit of extra work to port `uv run` to the new settings
model.

Note we allow `uv run` invocations without preview and only use its
presence to toggle an experimental warning.

## Test plan

```
❯ cargo run -q -- run --no-workspace -- python --version
warning: `uv run` is experimental and may change without warning.
Python 3.12.2
❯ cargo run -q -- run --no-workspace --preview -- python --version
Python 3.12.2
❯ UV_PREVIEW=1 cargo run -q -- run --no-workspace -- python --version
Python 3.12.2
```
This commit is contained in:
Zanie Blue 2024-04-22 15:41:15 -05:00 committed by GitHub
parent 11c6a07bb5
commit b9419e67aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 109 additions and 3 deletions

View file

@ -5,6 +5,7 @@ pub use constraints::*;
pub use name_specifiers::*;
pub use overrides::*;
pub use package_options::*;
pub use preview::*;
pub use target_triple::*;
mod authentication;
@ -14,4 +15,5 @@ mod constraints;
mod name_specifiers;
mod overrides;
mod package_options;
mod preview;
mod target_triple;

View file

@ -0,0 +1,37 @@
use std::fmt::{Display, Formatter};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum PreviewMode {
#[default]
Disabled,
Enabled,
}
impl PreviewMode {
pub fn is_enabled(&self) -> bool {
matches!(self, Self::Enabled)
}
pub fn is_disabled(&self) -> bool {
matches!(self, Self::Disabled)
}
}
impl From<bool> for PreviewMode {
fn from(version: bool) -> Self {
if version {
PreviewMode::Enabled
} else {
PreviewMode::Disabled
}
}
}
impl Display for PreviewMode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Disabled => write!(f, "disabled"),
Self::Enabled => write!(f, "enabled"),
}
}
}

View file

@ -33,6 +33,7 @@ pub(crate) struct Tools {
pub struct Options {
pub native_tls: Option<bool>,
pub no_cache: Option<bool>,
pub preview: Option<bool>,
pub cache_dir: Option<PathBuf>,
pub pip: Option<PipOptions>,
}

View file

@ -79,6 +79,13 @@ pub(crate) struct GlobalArgs {
#[arg(global = true, long, overrides_with("native_tls"), hide = true)]
pub(crate) no_native_tls: bool,
/// Whether to enable experimental, preview features.
#[arg(global = true, long, hide = true, env = "UV_PREVIEW", value_parser = clap::builder::BoolishValueParser::new(), overrides_with("no_preview"))]
pub(crate) preview: bool,
#[arg(global = true, long, overrides_with("preview"), hide = true)]
pub(crate) no_preview: bool,
}
#[derive(Debug, Clone, clap::ValueEnum)]

View file

@ -17,11 +17,13 @@ use std::{env, iter};
use tempfile::{tempdir_in, TempDir};
use tokio::process::Command;
use tracing::debug;
use uv_warnings::warn_user;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, RegistryClient, RegistryClientBuilder};
use uv_configuration::{
ConfigSettings, Constraints, NoBinary, NoBuild, Overrides, Reinstall, SetupPyStrategy,
ConfigSettings, Constraints, NoBinary, NoBuild, Overrides, PreviewMode, Reinstall,
SetupPyStrategy,
};
use uv_dispatch::BuildDispatch;
use uv_fs::Simplified;
@ -45,9 +47,14 @@ pub(crate) async fn run(
mut requirements: Vec<RequirementsSource>,
isolated: bool,
no_workspace: bool,
preview: PreviewMode,
cache: &Cache,
printer: Printer,
) -> Result<ExitStatus> {
if preview.is_disabled() {
warn_user!("`uv run` is experimental and may change without warning.");
}
let command = if let Some(target) = target {
let target_path = PathBuf::from(&target);
if target_path

View file

@ -476,6 +476,9 @@ async fn run() -> Result<ExitStatus> {
.await
}
Commands::Run(args) => {
// Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::RunSettings::resolve(args, workspace);
let requirements = args
.with
.into_iter()
@ -502,6 +505,7 @@ async fn run() -> Result<ExitStatus> {
requirements,
args.isolated,
args.no_workspace,
globals.preview,
&cache,
printer,
)

View file

@ -1,3 +1,4 @@
use std::ffi::OsString;
use std::path::PathBuf;
use distribution_types::IndexLocations;
@ -5,7 +6,7 @@ use install_wheel_rs::linker::LinkMode;
use uv_cache::{CacheArgs, Refresh};
use uv_client::Connectivity;
use uv_configuration::{
ConfigSettings, IndexStrategy, KeyringProviderType, NoBinary, NoBuild, Reinstall,
ConfigSettings, IndexStrategy, KeyringProviderType, NoBinary, NoBuild, PreviewMode, Reinstall,
SetupPyStrategy, TargetTriple, Upgrade,
};
use uv_normalize::PackageName;
@ -16,7 +17,7 @@ use uv_workspace::{PipOptions, Workspace};
use crate::cli::{
ColorChoice, GlobalArgs, Maybe, PipCheckArgs, PipCompileArgs, PipFreezeArgs, PipInstallArgs,
PipListArgs, PipShowArgs, PipSyncArgs, PipUninstallArgs, VenvArgs,
PipListArgs, PipShowArgs, PipSyncArgs, PipUninstallArgs, RunArgs, VenvArgs,
};
use crate::commands::ListFormat;
@ -28,6 +29,7 @@ pub(crate) struct GlobalSettings {
pub(crate) verbose: u8,
pub(crate) color: ColorChoice,
pub(crate) native_tls: bool,
pub(crate) preview: PreviewMode,
}
impl GlobalSettings {
@ -44,6 +46,11 @@ impl GlobalSettings {
native_tls: flag(args.native_tls, args.no_native_tls)
.or(workspace.and_then(|workspace| workspace.options.native_tls))
.unwrap_or(false),
preview: PreviewMode::from(
flag(args.preview, args.no_preview)
.or(workspace.and_then(|workspace| workspace.options.preview))
.unwrap_or(false),
),
}
}
}
@ -71,6 +78,41 @@ impl CacheSettings {
}
}
/// The resolved settings to use for a `run` invocation.
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone)]
pub(crate) struct RunSettings {
// CLI-only settings.
pub(crate) target: Option<String>,
pub(crate) args: Vec<OsString>,
pub(crate) isolated: bool,
pub(crate) with: Vec<String>,
pub(crate) no_workspace: bool,
}
impl RunSettings {
/// Resolve the [`RunSettings`] from the CLI and workspace configuration.
#[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: RunArgs, _workspace: Option<Workspace>) -> Self {
let RunArgs {
target,
args,
isolated,
with,
no_workspace,
} = args;
Self {
// CLI-only settings.
target,
args,
isolated,
with,
no_workspace,
}
}
}
/// The resolved settings to use for a `pip compile` invocation.
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone)]

6
uv.schema.json generated
View file

@ -31,6 +31,12 @@
"type": "null"
}
]
},
"preview": {
"type": [
"boolean",
"null"
]
}
},
"additionalProperties": false,