mirror of https://github.com/astral-sh/uv
Add initial work
This commit is contained in:
parent
9f51dca37c
commit
fc5d5e871c
|
|
@ -34,6 +34,7 @@ use uv_platform_tags::Tags;
|
|||
use uv_preview::Preview;
|
||||
use uv_pypi_types::{Conflicts, ResolverMarkerEnvironment};
|
||||
use uv_python::{PythonEnvironment, PythonInstallation};
|
||||
use uv_redacted::DisplaySafeUrl;
|
||||
use uv_requirements::{
|
||||
GroupsSpecification, LookaheadResolver, NamedRequirementsResolver, RequirementsSource,
|
||||
RequirementsSpecification, SourceTree, SourceTreeResolver,
|
||||
|
|
@ -454,6 +455,20 @@ impl ChangedDist {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn version(&self) -> Option<&Version> {
|
||||
match self {
|
||||
Self::Local(dist) => Some(dist.installed_version().version()),
|
||||
Self::Remote(dist) => dist.version(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn url(&self) -> Option<&DisplaySafeUrl> {
|
||||
match self {
|
||||
Self::Local(dist) => dist.installed_version().url(),
|
||||
Self::Remote(dist) => dist.version_or_url().url().map(|url| &**url),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A summary of the changes made to the environment during an installation.
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ pub(crate) async fn remove(
|
|||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {}
|
||||
Ok(_) => {}
|
||||
Err(ProjectError::Operation(err)) => {
|
||||
return diagnostics::OperationDiagnostic::native_tls(client_builder.is_native_tls())
|
||||
.report(err)
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {}
|
||||
Ok(_) => {}
|
||||
Err(ProjectError::Operation(err)) => {
|
||||
return diagnostics::OperationDiagnostic::native_tls(
|
||||
client_builder.is_native_tls(),
|
||||
|
|
@ -867,7 +867,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {}
|
||||
Ok(_) => {}
|
||||
Err(ProjectError::Operation(err)) => {
|
||||
return diagnostics::OperationDiagnostic::native_tls(
|
||||
client_builder.is_native_tls(),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use uv_configuration::{
|
|||
use uv_dispatch::BuildDispatch;
|
||||
use uv_distribution::LoweredExtraBuildDependencies;
|
||||
use uv_distribution_types::{
|
||||
DirectorySourceDist, Dist, Index, Requirement, Resolution, ResolvedDist, SourceDist,
|
||||
DirectorySourceDist, Dist, Index, Name, Requirement, Resolution, ResolvedDist, SourceDist,
|
||||
};
|
||||
use uv_fs::{PortablePathBuf, Simplified};
|
||||
use uv_installer::{InstallationStrategy, SitePackages};
|
||||
|
|
@ -37,16 +37,16 @@ use uv_workspace::pyproject::Source;
|
|||
use uv_workspace::{DiscoveryOptions, MemberDiscovery, VirtualProject, Workspace, WorkspaceCache};
|
||||
|
||||
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger, InstallLogger};
|
||||
use crate::commands::pip::operations::Modifications;
|
||||
use crate::commands::pip::operations::{ChangedDist, Changelog, Modifications};
|
||||
use crate::commands::pip::resolution_markers;
|
||||
use crate::commands::pip::{operations, resolution_tags};
|
||||
use crate::commands::project::install_target::InstallTarget;
|
||||
use crate::commands::project::lock::{LockMode, LockOperation, LockResult};
|
||||
use crate::commands::project::lock_target::LockTarget;
|
||||
use crate::commands::project::{
|
||||
PlatformState, ProjectEnvironment, ProjectError, ScriptEnvironment, UniversalState,
|
||||
default_dependency_groups, detect_conflicts, script_extra_build_requires, script_specification,
|
||||
update_environment,
|
||||
EnvironmentUpdate, PlatformState, ProjectEnvironment, ProjectError, ScriptEnvironment,
|
||||
UniversalState, default_dependency_groups, detect_conflicts, script_extra_build_requires,
|
||||
script_specification, update_environment,
|
||||
};
|
||||
use crate::commands::{ExitStatus, diagnostics};
|
||||
use crate::printer::Printer;
|
||||
|
|
@ -207,11 +207,12 @@ pub(crate) async fn sync(
|
|||
})
|
||||
.ok();
|
||||
|
||||
let sync_report = SyncReport {
|
||||
let mut sync_report = SyncReport {
|
||||
dry_run: dry_run.enabled(),
|
||||
environment: EnvironmentReport::from(&environment),
|
||||
action: SyncAction::from(&environment),
|
||||
target: TargetName::from(&target),
|
||||
packages: Vec::new(),
|
||||
};
|
||||
|
||||
// Show the intermediate results if relevant
|
||||
|
|
@ -292,7 +293,8 @@ pub(crate) async fn sync(
|
|||
)
|
||||
.await
|
||||
{
|
||||
Ok(..) => {
|
||||
Ok(EnvironmentUpdate { changelog, .. }) => {
|
||||
sync_report.packages = PackageChangeReport::from_changelog(&changelog);
|
||||
// Generate a report for the script without a lockfile
|
||||
let report = Report {
|
||||
schema: SchemaReport::default(),
|
||||
|
|
@ -387,27 +389,13 @@ pub(crate) async fn sync(
|
|||
writeln!(printer.stderr(), "{message}")?;
|
||||
}
|
||||
|
||||
let report = Report {
|
||||
schema: SchemaReport::default(),
|
||||
target: TargetName::from(&target),
|
||||
project: target.project().map(ProjectReport::from),
|
||||
script: target.script().map(ScriptReport::from),
|
||||
sync: sync_report,
|
||||
lock: Some(lock_report),
|
||||
dry_run: dry_run.enabled(),
|
||||
};
|
||||
|
||||
if let Some(output) = report.format(output_format) {
|
||||
writeln!(printer.stdout_important(), "{output}")?;
|
||||
}
|
||||
|
||||
// Identify the installation target.
|
||||
let sync_target = identify_installation_target(&target, outcome.lock(), all_packages, &package);
|
||||
|
||||
let state = state.fork();
|
||||
|
||||
// Perform the sync operation.
|
||||
match do_sync(
|
||||
let changelog = match do_sync(
|
||||
sync_target,
|
||||
&environment,
|
||||
&extras,
|
||||
|
|
@ -430,13 +418,29 @@ pub(crate) async fn sync(
|
|||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {}
|
||||
Ok(changelog) => changelog,
|
||||
Err(ProjectError::Operation(err)) => {
|
||||
return diagnostics::OperationDiagnostic::native_tls(client_builder.is_native_tls())
|
||||
.report(err)
|
||||
.map_or(Ok(ExitStatus::Failure), |err| Err(err.into()));
|
||||
}
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
|
||||
sync_report.packages = PackageChangeReport::from_changelog(&changelog);
|
||||
|
||||
let report = Report {
|
||||
schema: SchemaReport::default(),
|
||||
target: TargetName::from(&target),
|
||||
project: target.project().map(ProjectReport::from),
|
||||
script: target.script().map(ScriptReport::from),
|
||||
sync: sync_report,
|
||||
lock: Some(lock_report),
|
||||
dry_run: dry_run.enabled(),
|
||||
};
|
||||
|
||||
if let Some(output) = report.format(output_format) {
|
||||
writeln!(printer.stdout_important(), "{output}")?;
|
||||
}
|
||||
|
||||
match outcome {
|
||||
|
|
@ -614,7 +618,7 @@ pub(super) async fn do_sync(
|
|||
dry_run: DryRun,
|
||||
printer: Printer,
|
||||
preview: Preview,
|
||||
) -> Result<(), ProjectError> {
|
||||
) -> Result<Changelog, ProjectError> {
|
||||
// Extract the project settings.
|
||||
let InstallerSettingsRef {
|
||||
index_locations,
|
||||
|
|
@ -825,7 +829,7 @@ pub(super) async fn do_sync(
|
|||
let site_packages = SitePackages::from_environment(venv)?;
|
||||
|
||||
// Sync the environment.
|
||||
operations::install(
|
||||
let changelog = operations::install(
|
||||
&resolution,
|
||||
site_packages,
|
||||
InstallationStrategy::Strict,
|
||||
|
|
@ -850,7 +854,7 @@ pub(super) async fn do_sync(
|
|||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
Ok(changelog)
|
||||
}
|
||||
|
||||
/// Filter out any virtual workspace members.
|
||||
|
|
@ -1254,6 +1258,9 @@ struct SyncReport {
|
|||
environment: EnvironmentReport,
|
||||
/// The action performed during the sync, e.g., what was done to the environment.
|
||||
action: SyncAction,
|
||||
/// The packages that changed during the sync.
|
||||
#[serde(default)]
|
||||
packages: Vec<PackageChangeReport>,
|
||||
|
||||
// We store these fields so the report can format itself self-contained, but the outer
|
||||
// [`Report`] is intended to include these in user-facing output
|
||||
|
|
@ -1276,6 +1283,7 @@ impl SyncReport {
|
|||
let Self {
|
||||
environment,
|
||||
action,
|
||||
packages: _,
|
||||
dry_run,
|
||||
target,
|
||||
} = self;
|
||||
|
|
@ -1294,6 +1302,77 @@ impl SyncReport {
|
|||
}
|
||||
}
|
||||
|
||||
/// A summary of a single package change performed during sync.
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
struct PackageChangeReport {
|
||||
/// The normalized package name.
|
||||
name: String,
|
||||
/// The resolved version of the package.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
version: Option<uv_pep440::Version>,
|
||||
/// The source for URL-based requirements.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
source: Option<PackageChangeSourceReport>,
|
||||
/// The action that was taken for the package.
|
||||
action: PackageChangeAction,
|
||||
}
|
||||
|
||||
impl PackageChangeReport {
|
||||
fn from_changelog(changelog: &Changelog) -> Vec<Self> {
|
||||
let mut changes: Vec<_> = changelog
|
||||
.uninstalled
|
||||
.iter()
|
||||
.map(|dist| Self::from_dist(dist, PackageChangeAction::Removed))
|
||||
.chain(
|
||||
changelog
|
||||
.installed
|
||||
.iter()
|
||||
.map(|dist| Self::from_dist(dist, PackageChangeAction::Added)),
|
||||
)
|
||||
.chain(
|
||||
changelog
|
||||
.reinstalled
|
||||
.iter()
|
||||
.map(|dist| Self::from_dist(dist, PackageChangeAction::Reinstalled)),
|
||||
)
|
||||
.collect();
|
||||
|
||||
changes.sort_by(|a, b| {
|
||||
a.name
|
||||
.cmp(&b.name)
|
||||
.then_with(|| a.action.cmp(&b.action))
|
||||
.then_with(|| a.version.cmp(&b.version))
|
||||
});
|
||||
changes
|
||||
}
|
||||
|
||||
fn from_dist(dist: &ChangedDist, action: PackageChangeAction) -> Self {
|
||||
Self {
|
||||
name: dist.name().to_string(),
|
||||
version: dist.version().cloned(),
|
||||
source: dist.url().map(|url| PackageChangeSourceReport {
|
||||
url: url.to_string(),
|
||||
}),
|
||||
action,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The action taken on an individual package during sync.
|
||||
#[derive(Serialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
enum PackageChangeAction {
|
||||
Removed,
|
||||
Added,
|
||||
Reinstalled,
|
||||
}
|
||||
|
||||
/// The source for a package change, when it originated from a URL requirement.
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
struct PackageChangeSourceReport {
|
||||
url: String,
|
||||
}
|
||||
|
||||
/// The report for a lock operation.
|
||||
#[derive(Debug, Serialize)]
|
||||
struct LockReport {
|
||||
|
|
|
|||
|
|
@ -680,7 +680,7 @@ async fn lock_and_sync(
|
|||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {}
|
||||
Ok(_) => {}
|
||||
Err(ProjectError::Operation(err)) => {
|
||||
return diagnostics::OperationDiagnostic::native_tls(client_builder.is_native_tls())
|
||||
.report(err)
|
||||
|
|
|
|||
|
|
@ -420,7 +420,14 @@ fn sync_json() -> Result<()> {
|
|||
"implementation": "cpython"
|
||||
}
|
||||
},
|
||||
"action": "check"
|
||||
"action": "check",
|
||||
"packages": [
|
||||
{
|
||||
"name": "iniconfig",
|
||||
"version": "2.0.0",
|
||||
"action": "added"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lock": {
|
||||
"path": "[TEMP_DIR]/uv.lock",
|
||||
|
|
@ -464,7 +471,8 @@ fn sync_json() -> Result<()> {
|
|||
"implementation": "cpython"
|
||||
}
|
||||
},
|
||||
"action": "check"
|
||||
"action": "check",
|
||||
"packages": []
|
||||
},
|
||||
"lock": {
|
||||
"path": "[TEMP_DIR]/uv.lock",
|
||||
|
|
@ -503,7 +511,8 @@ fn sync_json() -> Result<()> {
|
|||
"implementation": "cpython"
|
||||
}
|
||||
},
|
||||
"action": "check"
|
||||
"action": "check",
|
||||
"packages": []
|
||||
},
|
||||
"lock": {
|
||||
"path": "[TEMP_DIR]/uv.lock",
|
||||
|
|
@ -569,7 +578,8 @@ fn sync_json() -> Result<()> {
|
|||
"implementation": "cpython"
|
||||
}
|
||||
},
|
||||
"action": "check"
|
||||
"action": "check",
|
||||
"packages": []
|
||||
},
|
||||
"lock": {
|
||||
"path": "[TEMP_DIR]/uv.lock",
|
||||
|
|
@ -629,7 +639,14 @@ fn sync_dry_json() -> Result<()> {
|
|||
"implementation": "cpython"
|
||||
}
|
||||
},
|
||||
"action": "create"
|
||||
"action": "create",
|
||||
"packages": [
|
||||
{
|
||||
"name": "iniconfig",
|
||||
"version": "2.0.0",
|
||||
"action": "added"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lock": {
|
||||
"path": "[TEMP_DIR]/uv.lock",
|
||||
|
|
@ -6856,7 +6873,24 @@ fn sync_active_script_environment_json() -> Result<()> {
|
|||
"implementation": "cpython"
|
||||
}
|
||||
},
|
||||
"action": "create"
|
||||
"action": "create",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anyio",
|
||||
"version": "4.3.0",
|
||||
"action": "added"
|
||||
},
|
||||
{
|
||||
"name": "idna",
|
||||
"version": "3.6",
|
||||
"action": "added"
|
||||
},
|
||||
{
|
||||
"name": "sniffio",
|
||||
"version": "1.3.1",
|
||||
"action": "added"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lock": null,
|
||||
"dry_run": false
|
||||
|
|
@ -6902,7 +6936,24 @@ fn sync_active_script_environment_json() -> Result<()> {
|
|||
"implementation": "cpython"
|
||||
}
|
||||
},
|
||||
"action": "create"
|
||||
"action": "create",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anyio",
|
||||
"version": "4.3.0",
|
||||
"action": "added"
|
||||
},
|
||||
{
|
||||
"name": "idna",
|
||||
"version": "3.6",
|
||||
"action": "added"
|
||||
},
|
||||
{
|
||||
"name": "sniffio",
|
||||
"version": "1.3.1",
|
||||
"action": "added"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lock": null,
|
||||
"dry_run": false
|
||||
|
|
@ -6961,7 +7012,24 @@ fn sync_active_script_environment_json() -> Result<()> {
|
|||
"implementation": "cpython"
|
||||
}
|
||||
},
|
||||
"action": "update"
|
||||
"action": "update",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anyio",
|
||||
"version": "4.3.0",
|
||||
"action": "added"
|
||||
},
|
||||
{
|
||||
"name": "idna",
|
||||
"version": "3.6",
|
||||
"action": "added"
|
||||
},
|
||||
{
|
||||
"name": "sniffio",
|
||||
"version": "1.3.1",
|
||||
"action": "added"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lock": null,
|
||||
"dry_run": false
|
||||
|
|
|
|||
Loading…
Reference in New Issue