mirror of https://github.com/astral-sh/uv
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
|
|
@ -2282,6 +2282,16 @@ pub struct SyncArgs {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub no_install_project: bool,
|
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.
|
/// Assert that the `uv.lock` will remain unchanged.
|
||||||
///
|
///
|
||||||
/// Requires that the lockfile is up-to-date. If the lockfile is missing or
|
/// Requires that the lockfile is up-to-date. If the lockfile is missing or
|
||||||
|
|
|
||||||
|
|
@ -604,6 +604,7 @@ pub(crate) async fn add(
|
||||||
&extras,
|
&extras,
|
||||||
dev,
|
dev,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
Modifications::Sufficient,
|
Modifications::Sufficient,
|
||||||
settings.as_ref().into(),
|
settings.as_ref().into(),
|
||||||
&state,
|
&state,
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,7 @@ pub(crate) async fn remove(
|
||||||
let extras = ExtrasSpecification::All;
|
let extras = ExtrasSpecification::All;
|
||||||
let dev = true;
|
let dev = true;
|
||||||
let no_install_project = false;
|
let no_install_project = false;
|
||||||
|
let no_install_workspace = false;
|
||||||
|
|
||||||
// Initialize any shared state.
|
// Initialize any shared state.
|
||||||
let state = SharedState::default();
|
let state = SharedState::default();
|
||||||
|
|
@ -202,6 +203,7 @@ pub(crate) async fn remove(
|
||||||
&extras,
|
&extras,
|
||||||
dev,
|
dev,
|
||||||
no_install_project,
|
no_install_project,
|
||||||
|
no_install_workspace,
|
||||||
Modifications::Exact,
|
Modifications::Exact,
|
||||||
settings.as_ref().into(),
|
settings.as_ref().into(),
|
||||||
&state,
|
&state,
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,7 @@ pub(crate) async fn run(
|
||||||
&extras,
|
&extras,
|
||||||
dev,
|
dev,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
Modifications::Sufficient,
|
Modifications::Sufficient,
|
||||||
settings.as_ref().into(),
|
settings.as_ref().into(),
|
||||||
&state,
|
&state,
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ pub(crate) async fn sync(
|
||||||
extras: ExtrasSpecification,
|
extras: ExtrasSpecification,
|
||||||
dev: bool,
|
dev: bool,
|
||||||
no_install_project: bool,
|
no_install_project: bool,
|
||||||
|
no_install_workspace: bool,
|
||||||
modifications: Modifications,
|
modifications: Modifications,
|
||||||
python: Option<String>,
|
python: Option<String>,
|
||||||
python_preference: PythonPreference,
|
python_preference: PythonPreference,
|
||||||
|
|
@ -106,6 +107,7 @@ pub(crate) async fn sync(
|
||||||
&extras,
|
&extras,
|
||||||
dev,
|
dev,
|
||||||
no_install_project,
|
no_install_project,
|
||||||
|
no_install_workspace,
|
||||||
modifications,
|
modifications,
|
||||||
settings.as_ref().into(),
|
settings.as_ref().into(),
|
||||||
&state,
|
&state,
|
||||||
|
|
@ -122,6 +124,7 @@ pub(crate) async fn sync(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sync a lockfile with an environment.
|
/// Sync a lockfile with an environment.
|
||||||
|
#[allow(clippy::fn_params_excessive_bools)]
|
||||||
pub(super) async fn do_sync(
|
pub(super) async fn do_sync(
|
||||||
project: &VirtualProject,
|
project: &VirtualProject,
|
||||||
venv: &PythonEnvironment,
|
venv: &PythonEnvironment,
|
||||||
|
|
@ -129,6 +132,7 @@ pub(super) async fn do_sync(
|
||||||
extras: &ExtrasSpecification,
|
extras: &ExtrasSpecification,
|
||||||
dev: bool,
|
dev: bool,
|
||||||
no_install_project: bool,
|
no_install_project: bool,
|
||||||
|
no_install_workspace: bool,
|
||||||
modifications: Modifications,
|
modifications: Modifications,
|
||||||
settings: InstallerSettingsRef<'_>,
|
settings: InstallerSettingsRef<'_>,
|
||||||
state: &SharedState,
|
state: &SharedState,
|
||||||
|
|
@ -195,6 +199,9 @@ pub(super) async fn do_sync(
|
||||||
// If `--no-install-project` is set, remove the project itself.
|
// If `--no-install-project` is set, remove the project itself.
|
||||||
let resolution = apply_no_install_project(no_install_project, resolution, project);
|
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.
|
// Add all authenticated sources to the cache.
|
||||||
for url in index_locations.urls() {
|
for url in index_locations.urls() {
|
||||||
store_credentials_from_url(url);
|
store_credentials_from_url(url);
|
||||||
|
|
@ -299,3 +306,18 @@ fn apply_no_install_project(
|
||||||
|
|
||||||
resolution.filter(|dist| dist.name() != project_name)
|
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.extras,
|
||||||
args.dev,
|
args.dev,
|
||||||
args.no_install_project,
|
args.no_install_project,
|
||||||
|
args.no_install_workspace,
|
||||||
args.modifications,
|
args.modifications,
|
||||||
args.python,
|
args.python,
|
||||||
globals.python_preference,
|
globals.python_preference,
|
||||||
|
|
|
||||||
|
|
@ -618,6 +618,7 @@ pub(crate) struct SyncSettings {
|
||||||
pub(crate) extras: ExtrasSpecification,
|
pub(crate) extras: ExtrasSpecification,
|
||||||
pub(crate) dev: bool,
|
pub(crate) dev: bool,
|
||||||
pub(crate) no_install_project: bool,
|
pub(crate) no_install_project: bool,
|
||||||
|
pub(crate) no_install_workspace: bool,
|
||||||
pub(crate) modifications: Modifications,
|
pub(crate) modifications: Modifications,
|
||||||
pub(crate) package: Option<PackageName>,
|
pub(crate) package: Option<PackageName>,
|
||||||
pub(crate) python: Option<String>,
|
pub(crate) python: Option<String>,
|
||||||
|
|
@ -638,6 +639,7 @@ impl SyncSettings {
|
||||||
inexact,
|
inexact,
|
||||||
exact,
|
exact,
|
||||||
no_install_project,
|
no_install_project,
|
||||||
|
no_install_workspace,
|
||||||
locked,
|
locked,
|
||||||
frozen,
|
frozen,
|
||||||
installer,
|
installer,
|
||||||
|
|
@ -671,6 +673,7 @@ impl SyncSettings {
|
||||||
),
|
),
|
||||||
dev: flag(dev, no_dev).unwrap_or(true),
|
dev: flag(dev, no_dev).unwrap_or(true),
|
||||||
no_install_project,
|
no_install_project,
|
||||||
|
no_install_workspace,
|
||||||
modifications,
|
modifications,
|
||||||
package,
|
package,
|
||||||
python,
|
python,
|
||||||
|
|
|
||||||
|
|
@ -863,3 +863,70 @@ fn no_install_project() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ If not mounting the cache, image size can be reduced with `--no-cache` flag.
|
||||||
### Intermediate layers
|
### Intermediate layers
|
||||||
|
|
||||||
If you're using uv to manage your project, you can improve build times by moving your transitive
|
If you're using uv to manage your project, you can improve build times by moving your transitive
|
||||||
dependency installation into its own layer via `uv sync --no-install-project`.
|
dependency installation into its own layer via the `--no-install` options.
|
||||||
|
|
||||||
`uv sync --no-install-project` will install the dependencies of the project but not the project
|
`uv sync --no-install-project` will install the dependencies of the project but not the project
|
||||||
itself. Since the project changes frequently, but its dependencies are generally static, this can be
|
itself. Since the project changes frequently, but its dependencies are generally static, this can be
|
||||||
|
|
@ -216,3 +216,8 @@ WORKDIR /app
|
||||||
# Sync the project
|
# Sync the project
|
||||||
RUN uv sync --frozen
|
RUN uv sync --frozen
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
|
||||||
|
If you're using a [workspace](../../concepts/workspaces.md), then consider the
|
||||||
|
`--no-install-workspace` flag which excludes the project _and_ any workspace members.
|
||||||
|
|
|
||||||
|
|
@ -1174,6 +1174,10 @@ uv sync [OPTIONS]
|
||||||
|
|
||||||
<p>By default, the current project is installed into the environment with all of its dependencies. The <code>--no-install-project</code> option allows the project to be excluded, but all of its dependencies are still installed. This is particularly useful in situations like building Docker images where installing the project separately from its dependencies allows optimal layer caching.</p>
|
<p>By default, the current project is installed into the environment with all of its dependencies. The <code>--no-install-project</code> option allows the project to be excluded, but all of its dependencies are still installed. This is particularly useful in situations like building Docker images where installing the project separately from its dependencies allows optimal layer caching.</p>
|
||||||
|
|
||||||
|
</dd><dt><code>--no-install-workspace</code></dt><dd><p>Do not install any workspace members, including the root project.</p>
|
||||||
|
|
||||||
|
<p>By default, all of the workspace members and their dependencies are installed into the environment. The <code>--no-install-workspace</code> 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.</p>
|
||||||
|
|
||||||
</dd><dt><code>--no-progress</code></dt><dd><p>Hide all progress outputs.</p>
|
</dd><dt><code>--no-progress</code></dt><dd><p>Hide all progress outputs.</p>
|
||||||
|
|
||||||
<p>For example, spinners or progress bars.</p>
|
<p>For example, spinners or progress bars.</p>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue