Shared Git and in-memory index across operations (#4715)

## Summary

I ended up needing this for https://github.com/astral-sh/uv/issues/4664
but I think it's a good change more broadly. We should be able to share
this cached information across operations within a given invocation.
This commit is contained in:
Charlie Marsh 2024-07-01 20:27:01 -04:00 committed by GitHub
parent 13077406f8
commit 368276d7d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 57 additions and 27 deletions

View file

@ -18,6 +18,7 @@ use uv_warnings::warn_user_once;
use crate::commands::pip::operations::Modifications; use crate::commands::pip::operations::Modifications;
use crate::commands::pip::resolution_environment; use crate::commands::pip::resolution_environment;
use crate::commands::project::SharedState;
use crate::commands::reporters::ResolverReporter; use crate::commands::reporters::ResolverReporter;
use crate::commands::{project, ExitStatus}; use crate::commands::{project, ExitStatus};
use crate::printer::Printer; use crate::printer::Printer;
@ -205,11 +206,15 @@ pub(crate) async fn add(
pyproject.to_string(), pyproject.to_string(),
)?; )?;
// Initialize any shared state.
let state = SharedState::default();
// Lock and sync the environment. // Lock and sync the environment.
let lock = project::lock::do_lock( let lock = project::lock::do_lock(
project.workspace(), project.workspace(),
venv.interpreter(), venv.interpreter(),
settings.as_ref().into(), settings.as_ref().into(),
&state,
preview, preview,
connectivity, connectivity,
concurrency, concurrency,
@ -232,6 +237,7 @@ pub(crate) async fn add(
dev, dev,
Modifications::Sufficient, Modifications::Sufficient,
settings.as_ref().into(), settings.as_ref().into(),
&state,
preview, preview,
connectivity, connectivity,
concurrency, concurrency,

View file

@ -8,16 +8,14 @@ use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode, Reinstall, SetupPyStrategy}; use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode, Reinstall, SetupPyStrategy};
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_distribution::{Workspace, DEV_DEPENDENCIES}; use uv_distribution::{Workspace, DEV_DEPENDENCIES};
use uv_git::GitResolver; use uv_git::ResolvedRepositoryReference;
use uv_requirements::upgrade::{read_lockfile, LockedRequirements}; use uv_requirements::upgrade::{read_lockfile, LockedRequirements};
use uv_resolver::{ use uv_resolver::{FlatIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython};
FlatIndex, InMemoryIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython,
};
use uv_toolchain::{Interpreter, ToolchainPreference, ToolchainRequest}; use uv_toolchain::{Interpreter, ToolchainPreference, ToolchainRequest};
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight}; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
use uv_warnings::{warn_user, warn_user_once}; use uv_warnings::{warn_user, warn_user_once};
use crate::commands::project::{find_requires_python, FoundInterpreter, ProjectError}; use crate::commands::project::{find_requires_python, FoundInterpreter, ProjectError, SharedState};
use crate::commands::{pip, ExitStatus}; use crate::commands::{pip, ExitStatus};
use crate::printer::Printer; use crate::printer::Printer;
use crate::settings::{ResolverSettings, ResolverSettingsRef}; use crate::settings::{ResolverSettings, ResolverSettingsRef};
@ -59,6 +57,7 @@ pub(crate) async fn lock(
&workspace, &workspace,
&interpreter, &interpreter,
settings.as_ref(), settings.as_ref(),
&SharedState::default(),
preview, preview,
connectivity, connectivity,
concurrency, concurrency,
@ -86,6 +85,7 @@ pub(super) async fn do_lock(
workspace: &Workspace, workspace: &Workspace,
interpreter: &Interpreter, interpreter: &Interpreter,
settings: ResolverSettingsRef<'_>, settings: ResolverSettingsRef<'_>,
state: &SharedState,
preview: PreviewMode, preview: PreviewMode,
connectivity: Connectivity, connectivity: Connectivity,
concurrency: Concurrency, concurrency: Concurrency,
@ -163,7 +163,6 @@ pub(super) async fn do_lock(
// Initialize any shared state. // Initialize any shared state.
let in_flight = InFlight::default(); let in_flight = InFlight::default();
let index = InMemoryIndex::default();
// TODO(charlie): These are all default values. We should consider whether we want to make them // TODO(charlie): These are all default values. We should consider whether we want to make them
// optional on the downstream APIs. // optional on the downstream APIs.
@ -181,8 +180,10 @@ pub(super) async fn do_lock(
// If an existing lockfile exists, build up a set of preferences. // If an existing lockfile exists, build up a set of preferences.
let LockedRequirements { preferences, git } = read_lockfile(workspace, upgrade).await?; let LockedRequirements { preferences, git } = read_lockfile(workspace, upgrade).await?;
// Create the Git resolver. // Populate the Git resolver.
let git = GitResolver::from_refs(git); for ResolvedRepositoryReference { reference, sha } in git {
state.git.insert(reference, sha);
}
// Create a build dispatch. // Create a build dispatch.
let build_dispatch = BuildDispatch::new( let build_dispatch = BuildDispatch::new(
@ -191,8 +192,8 @@ pub(super) async fn do_lock(
interpreter, interpreter,
index_locations, index_locations,
&flat_index, &flat_index,
&index, &state.index,
&git, &state.git,
&in_flight, &in_flight,
index_strategy, index_strategy,
setup_py, setup_py,
@ -224,7 +225,7 @@ pub(super) async fn do_lock(
python_requirement, python_requirement,
&client, &client,
&flat_index, &flat_index,
&index, &state.index,
&build_dispatch, &build_dispatch,
concurrency, concurrency,
options, options,

View file

@ -273,11 +273,21 @@ pub(crate) async fn get_or_init_environment(
} }
} }
/// Shared state used during resolution and installation.
#[derive(Default)]
pub(crate) struct SharedState {
/// The resolved Git references.
git: GitResolver,
/// The fetched package versions and metadata.
index: InMemoryIndex,
}
/// Update a [`PythonEnvironment`] to satisfy a set of [`RequirementsSource`]s. /// Update a [`PythonEnvironment`] to satisfy a set of [`RequirementsSource`]s.
pub(crate) async fn update_environment( pub(crate) async fn update_environment(
venv: PythonEnvironment, venv: PythonEnvironment,
spec: RequirementsSpecification, spec: RequirementsSpecification,
settings: &ResolverInstallerSettings, settings: &ResolverInstallerSettings,
state: &SharedState,
preview: PreviewMode, preview: PreviewMode,
connectivity: Connectivity, connectivity: Connectivity,
concurrency: Concurrency, concurrency: Concurrency,
@ -350,9 +360,7 @@ pub(crate) async fn update_environment(
.build(); .build();
// Initialize any shared state. // Initialize any shared state.
let git = GitResolver::default();
let in_flight = InFlight::default(); let in_flight = InFlight::default();
let index = InMemoryIndex::default();
// TODO(charlie): These are all default values. We should consider whether we want to make them // TODO(charlie): These are all default values. We should consider whether we want to make them
// optional on the downstream APIs. // optional on the downstream APIs.
@ -378,8 +386,8 @@ pub(crate) async fn update_environment(
interpreter, interpreter,
index_locations, index_locations,
&flat_index, &flat_index,
&index, &state.index,
&git, &state.git,
&in_flight, &in_flight,
*index_strategy, *index_strategy,
setup_py, setup_py,
@ -411,7 +419,7 @@ pub(crate) async fn update_environment(
python_requirement, python_requirement,
&client, &client,
&flat_index, &flat_index,
&index, &state.index,
&resolve_dispatch, &resolve_dispatch,
concurrency, concurrency,
options, options,
@ -438,8 +446,8 @@ pub(crate) async fn update_environment(
interpreter, interpreter,
index_locations, index_locations,
&flat_index, &flat_index,
&index, &state.index,
&git, &state.git,
&in_flight, &in_flight,
*index_strategy, *index_strategy,
setup_py, setup_py,

View file

@ -11,6 +11,7 @@ use uv_toolchain::{ToolchainPreference, ToolchainRequest};
use uv_warnings::{warn_user, warn_user_once}; use uv_warnings::{warn_user, warn_user_once};
use crate::commands::pip::operations::Modifications; use crate::commands::pip::operations::Modifications;
use crate::commands::project::SharedState;
use crate::commands::{project, ExitStatus}; use crate::commands::{project, ExitStatus};
use crate::printer::Printer; use crate::printer::Printer;
use crate::settings::{InstallerSettings, ResolverSettings}; use crate::settings::{InstallerSettings, ResolverSettings};
@ -95,11 +96,15 @@ pub(crate) async fn remove(
// Use the default settings. // Use the default settings.
let settings = ResolverSettings::default(); let settings = ResolverSettings::default();
// Initialize any shared state.
let state = SharedState::default();
// Lock and sync the environment. // Lock and sync the environment.
let lock = project::lock::do_lock( let lock = project::lock::do_lock(
project.workspace(), project.workspace(),
venv.interpreter(), venv.interpreter(),
settings.as_ref(), settings.as_ref(),
&state,
preview, preview,
connectivity, connectivity,
concurrency, concurrency,
@ -123,6 +128,7 @@ pub(crate) async fn remove(
dev, dev,
Modifications::Exact, Modifications::Exact,
settings.as_ref(), settings.as_ref(),
&state,
preview, preview,
connectivity, connectivity,
concurrency, concurrency,

View file

@ -21,6 +21,7 @@ use uv_toolchain::{
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
use crate::commands::pip::operations::Modifications; use crate::commands::pip::operations::Modifications;
use crate::commands::project::SharedState;
use crate::commands::{project, ExitStatus}; use crate::commands::{project, ExitStatus};
use crate::printer::Printer; use crate::printer::Printer;
use crate::settings::ResolverInstallerSettings; use crate::settings::ResolverInstallerSettings;
@ -50,6 +51,9 @@ pub(crate) async fn run(
// Parse the input command. // Parse the input command.
let command = RunCommand::from(command); let command = RunCommand::from(command);
// Initialize any shared state.
let state = SharedState::default();
// Determine whether the command to execute is a PEP 723 script. // Determine whether the command to execute is a PEP 723 script.
let temp_dir; let temp_dir;
let script_interpreter = if let RunCommand::Python(target, _) = &command { let script_interpreter = if let RunCommand::Python(target, _) = &command {
@ -106,6 +110,7 @@ pub(crate) async fn run(
venv, venv,
spec, spec,
&settings, &settings,
&state,
preview, preview,
connectivity, connectivity,
concurrency, concurrency,
@ -177,6 +182,7 @@ pub(crate) async fn run(
project.workspace(), project.workspace(),
venv.interpreter(), venv.interpreter(),
settings.as_ref().into(), settings.as_ref().into(),
&state,
preview, preview,
connectivity, connectivity,
concurrency, concurrency,
@ -193,6 +199,7 @@ pub(crate) async fn run(
dev, dev,
Modifications::Sufficient, Modifications::Sufficient,
settings.as_ref().into(), settings.as_ref().into(),
&state,
preview, preview,
connectivity, connectivity,
concurrency, concurrency,
@ -289,6 +296,7 @@ pub(crate) async fn run(
venv, venv,
spec, spec,
&settings, &settings,
&state,
preview, preview,
connectivity, connectivity,
concurrency, concurrency,

View file

@ -5,15 +5,14 @@ use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode, SetupPyStrategy}; use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode, SetupPyStrategy};
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_distribution::{VirtualProject, DEV_DEPENDENCIES}; use uv_distribution::{VirtualProject, DEV_DEPENDENCIES};
use uv_git::GitResolver;
use uv_installer::SitePackages; use uv_installer::SitePackages;
use uv_resolver::{FlatIndex, InMemoryIndex, Lock}; use uv_resolver::{FlatIndex, Lock};
use uv_toolchain::{PythonEnvironment, ToolchainPreference, ToolchainRequest}; use uv_toolchain::{PythonEnvironment, ToolchainPreference, ToolchainRequest};
use uv_types::{BuildIsolation, HashStrategy, InFlight}; use uv_types::{BuildIsolation, HashStrategy, InFlight};
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
use crate::commands::pip::operations::Modifications; use crate::commands::pip::operations::Modifications;
use crate::commands::project::ProjectError; use crate::commands::project::{ProjectError, SharedState};
use crate::commands::{pip, project, ExitStatus}; use crate::commands::{pip, project, ExitStatus};
use crate::printer::Printer; use crate::printer::Printer;
use crate::settings::{InstallerSettings, InstallerSettingsRef}; use crate::settings::{InstallerSettings, InstallerSettingsRef};
@ -68,6 +67,7 @@ pub(crate) async fn sync(
dev, dev,
modifications, modifications,
settings.as_ref(), settings.as_ref(),
&SharedState::default(),
preview, preview,
connectivity, connectivity,
concurrency, concurrency,
@ -89,6 +89,7 @@ pub(super) async fn do_sync(
dev: bool, dev: bool,
modifications: Modifications, modifications: Modifications,
settings: InstallerSettingsRef<'_>, settings: InstallerSettingsRef<'_>,
state: &SharedState,
preview: PreviewMode, preview: PreviewMode,
connectivity: Connectivity, connectivity: Connectivity,
concurrency: Concurrency, concurrency: Concurrency,
@ -143,9 +144,7 @@ pub(super) async fn do_sync(
.build(); .build();
// Initialize any shared state. // Initialize any shared state.
let git = GitResolver::default();
let in_flight = InFlight::default(); let in_flight = InFlight::default();
let index = InMemoryIndex::default();
// TODO(charlie): These are all default values. We should consider whether we want to make them // TODO(charlie): These are all default values. We should consider whether we want to make them
// optional on the downstream APIs. // optional on the downstream APIs.
@ -169,8 +168,8 @@ pub(super) async fn do_sync(
venv.interpreter(), venv.interpreter(),
index_locations, index_locations,
&flat_index, &flat_index,
&index, &state.index,
&git, &state.git,
&in_flight, &in_flight,
index_strategy, index_strategy,
setup_py, setup_py,

View file

@ -21,7 +21,7 @@ use uv_tool::{entrypoint_paths, find_executable_directory, InstalledTools, Tool,
use uv_toolchain::{EnvironmentPreference, Toolchain, ToolchainPreference, ToolchainRequest}; use uv_toolchain::{EnvironmentPreference, Toolchain, ToolchainPreference, ToolchainRequest};
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
use crate::commands::project::update_environment; use crate::commands::project::{update_environment, SharedState};
use crate::commands::ExitStatus; use crate::commands::ExitStatus;
use crate::printer::Printer; use crate::printer::Printer;
use crate::settings::ResolverInstallerSettings; use crate::settings::ResolverInstallerSettings;
@ -146,6 +146,7 @@ pub(crate) async fn install(
environment, environment,
spec, spec,
&settings, &settings,
&SharedState::default(),
preview, preview,
connectivity, connectivity,
concurrency, concurrency,

View file

@ -19,7 +19,7 @@ use uv_toolchain::{
}; };
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
use crate::commands::project::update_environment; use crate::commands::project::{update_environment, SharedState};
use crate::commands::ExitStatus; use crate::commands::ExitStatus;
use crate::printer::Printer; use crate::printer::Printer;
use crate::settings::ResolverInstallerSettings; use crate::settings::ResolverInstallerSettings;
@ -102,6 +102,7 @@ pub(crate) async fn run(
venv, venv,
spec, spec,
&settings, &settings,
&SharedState::default(),
preview, preview,
connectivity, connectivity,
concurrency, concurrency,