mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-31 20:09:09 +00:00
Add uv sync --no-install-workspace to skip installation of all workspace members (#6539)
Extends #6538 See #4028 Another version of https://github.com/astral-sh/uv/pull/6398
This commit is contained in:
parent
4e82db093a
commit
ca50243174
10 changed files with 117 additions and 1 deletions
|
|
@ -2282,6 +2282,16 @@ pub struct SyncArgs {
|
|||
#[arg(long)]
|
||||
pub no_install_project: bool,
|
||||
|
||||
/// Do not install any workspace members, including the root project.
|
||||
///
|
||||
/// By default, all of the workspace members and their dependencies are installed into the
|
||||
/// environment. The `--no-install-workspace` option allows exclusion of all the workspace
|
||||
/// members while retaining their dependencies. This is particularly useful in situations like
|
||||
/// building Docker images where installing the workspace separately from its dependencies
|
||||
/// allows optimal layer caching.
|
||||
#[arg(long)]
|
||||
pub no_install_workspace: bool,
|
||||
|
||||
/// Assert that the `uv.lock` will remain unchanged.
|
||||
///
|
||||
/// Requires that the lockfile is up-to-date. If the lockfile is missing or
|
||||
|
|
|
|||
|
|
@ -604,6 +604,7 @@ pub(crate) async fn add(
|
|||
&extras,
|
||||
dev,
|
||||
false,
|
||||
false,
|
||||
Modifications::Sufficient,
|
||||
settings.as_ref().into(),
|
||||
&state,
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ pub(crate) async fn remove(
|
|||
let extras = ExtrasSpecification::All;
|
||||
let dev = true;
|
||||
let no_install_project = false;
|
||||
let no_install_workspace = false;
|
||||
|
||||
// Initialize any shared state.
|
||||
let state = SharedState::default();
|
||||
|
|
@ -202,6 +203,7 @@ pub(crate) async fn remove(
|
|||
&extras,
|
||||
dev,
|
||||
no_install_project,
|
||||
no_install_workspace,
|
||||
Modifications::Exact,
|
||||
settings.as_ref().into(),
|
||||
&state,
|
||||
|
|
|
|||
|
|
@ -418,6 +418,7 @@ pub(crate) async fn run(
|
|||
&extras,
|
||||
dev,
|
||||
false,
|
||||
false,
|
||||
Modifications::Sufficient,
|
||||
settings.as_ref().into(),
|
||||
&state,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ pub(crate) async fn sync(
|
|||
extras: ExtrasSpecification,
|
||||
dev: bool,
|
||||
no_install_project: bool,
|
||||
no_install_workspace: bool,
|
||||
modifications: Modifications,
|
||||
python: Option<String>,
|
||||
python_preference: PythonPreference,
|
||||
|
|
@ -106,6 +107,7 @@ pub(crate) async fn sync(
|
|||
&extras,
|
||||
dev,
|
||||
no_install_project,
|
||||
no_install_workspace,
|
||||
modifications,
|
||||
settings.as_ref().into(),
|
||||
&state,
|
||||
|
|
@ -122,6 +124,7 @@ pub(crate) async fn sync(
|
|||
}
|
||||
|
||||
/// Sync a lockfile with an environment.
|
||||
#[allow(clippy::fn_params_excessive_bools)]
|
||||
pub(super) async fn do_sync(
|
||||
project: &VirtualProject,
|
||||
venv: &PythonEnvironment,
|
||||
|
|
@ -129,6 +132,7 @@ pub(super) async fn do_sync(
|
|||
extras: &ExtrasSpecification,
|
||||
dev: bool,
|
||||
no_install_project: bool,
|
||||
no_install_workspace: bool,
|
||||
modifications: Modifications,
|
||||
settings: InstallerSettingsRef<'_>,
|
||||
state: &SharedState,
|
||||
|
|
@ -195,6 +199,9 @@ pub(super) async fn do_sync(
|
|||
// If `--no-install-project` is set, remove the project itself.
|
||||
let resolution = apply_no_install_project(no_install_project, resolution, project);
|
||||
|
||||
// If `--no-install-workspace` is set, remove the project and any workspace members.
|
||||
let resolution = apply_no_install_workspace(no_install_workspace, resolution, project);
|
||||
|
||||
// Add all authenticated sources to the cache.
|
||||
for url in index_locations.urls() {
|
||||
store_credentials_from_url(url);
|
||||
|
|
@ -299,3 +306,18 @@ fn apply_no_install_project(
|
|||
|
||||
resolution.filter(|dist| dist.name() != project_name)
|
||||
}
|
||||
|
||||
fn apply_no_install_workspace(
|
||||
no_install_workspace: bool,
|
||||
resolution: distribution_types::Resolution,
|
||||
project: &VirtualProject,
|
||||
) -> distribution_types::Resolution {
|
||||
if !no_install_workspace {
|
||||
return resolution;
|
||||
}
|
||||
|
||||
let workspace_packages = project.workspace().packages();
|
||||
resolution.filter(|dist| {
|
||||
!workspace_packages.contains_key(dist.name()) && Some(dist.name()) != project.project_name()
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1103,6 +1103,7 @@ async fn run_project(
|
|||
args.extras,
|
||||
args.dev,
|
||||
args.no_install_project,
|
||||
args.no_install_workspace,
|
||||
args.modifications,
|
||||
args.python,
|
||||
globals.python_preference,
|
||||
|
|
|
|||
|
|
@ -618,6 +618,7 @@ pub(crate) struct SyncSettings {
|
|||
pub(crate) extras: ExtrasSpecification,
|
||||
pub(crate) dev: bool,
|
||||
pub(crate) no_install_project: bool,
|
||||
pub(crate) no_install_workspace: bool,
|
||||
pub(crate) modifications: Modifications,
|
||||
pub(crate) package: Option<PackageName>,
|
||||
pub(crate) python: Option<String>,
|
||||
|
|
@ -638,6 +639,7 @@ impl SyncSettings {
|
|||
inexact,
|
||||
exact,
|
||||
no_install_project,
|
||||
no_install_workspace,
|
||||
locked,
|
||||
frozen,
|
||||
installer,
|
||||
|
|
@ -671,6 +673,7 @@ impl SyncSettings {
|
|||
),
|
||||
dev: flag(dev, no_dev).unwrap_or(true),
|
||||
no_install_project,
|
||||
no_install_workspace,
|
||||
modifications,
|
||||
package,
|
||||
python,
|
||||
|
|
|
|||
|
|
@ -863,3 +863,70 @@ fn no_install_project() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Avoid syncing local dependencies for workspace dependencies when `--no-install-project` is provided, but
|
||||
/// include the workspace dependency's dependencies.
|
||||
#[test]
|
||||
fn no_install_workspace() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["anyio==3.7.0", "child"]
|
||||
|
||||
[tool.uv.workspace]
|
||||
members = ["child"]
|
||||
|
||||
[tool.uv.sources]
|
||||
child = { workspace = true }
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Add a workspace member.
|
||||
let child = context.temp_dir.child("child");
|
||||
child.child("pyproject.toml").write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "child"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["iniconfig>1"]
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
"#,
|
||||
)?;
|
||||
child
|
||||
.child("src")
|
||||
.child("child")
|
||||
.child("__init__.py")
|
||||
.touch()?;
|
||||
|
||||
// Generate a lockfile.
|
||||
context.lock().assert().success();
|
||||
|
||||
// Running with `--no-install-workspace` should install `anyio` and `iniconfig`, but not
|
||||
// `project` or `child`.
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--no-install-workspace"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 6 packages in [TIME]
|
||||
Prepared 4 packages in [TIME]
|
||||
Installed 4 packages in [TIME]
|
||||
+ anyio==3.7.0
|
||||
+ idna==3.6
|
||||
+ iniconfig==2.0.0
|
||||
+ sniffio==1.3.1
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue