Skip to content

Commit

Permalink
Add --package to uv sync
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Jul 31, 2024
1 parent f268b7c commit 955a1cd
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 4 deletions.
4 changes: 4 additions & 0 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2008,6 +2008,10 @@ pub struct SyncArgs {
#[command(flatten)]
pub refresh: RefreshArgs,

/// Sync a specific package in the workspace.
#[arg(long)]
pub package: Option<PackageName>,

/// The Python interpreter to use to build the run environment.
///
/// By default, uv uses the virtual environment in the current working directory or any parent
Expand Down
19 changes: 15 additions & 4 deletions crates/uv/src/commands/project/sync.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyhow::Result;
use anyhow::{Context, Result};

use uv_auth::store_credentials_from_url;
use uv_cache::Cache;
Expand All @@ -10,11 +10,12 @@ use uv_dispatch::BuildDispatch;
use uv_distribution::DEV_DEPENDENCIES;
use uv_fs::CWD;
use uv_installer::SitePackages;
use uv_normalize::PackageName;
use uv_python::{PythonEnvironment, PythonFetch, PythonPreference, PythonRequest};
use uv_resolver::{FlatIndex, Lock};
use uv_types::{BuildIsolation, HashStrategy};
use uv_warnings::warn_user_once;
use uv_workspace::{DiscoveryOptions, VirtualProject};
use uv_workspace::{DiscoveryOptions, VirtualProject, Workspace};

use crate::commands::pip::operations::Modifications;
use crate::commands::project::lock::do_safe_lock;
Expand All @@ -28,6 +29,7 @@ use crate::settings::{InstallerSettingsRef, ResolverInstallerSettings};
pub(crate) async fn sync(
locked: bool,
frozen: bool,
package: Option<PackageName>,
extras: ExtrasSpecification,
dev: bool,
modifications: Modifications,
Expand All @@ -46,8 +48,17 @@ pub(crate) async fn sync(
warn_user_once!("`uv sync` is experimental and may change without warning");
}

// Identify the project
let project = VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await?;
// Identify the project.
let project = if let Some(package) = package {
VirtualProject::Project(
Workspace::discover(&CWD, &DiscoveryOptions::default())
.await?
.with_current_project(package.clone())
.with_context(|| format!("Package `{package}` not found in workspace"))?,
)
} else {
VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await?
};

// Discover or create the virtual environment.
let venv = project::get_or_init_environment(
Expand Down
1 change: 1 addition & 0 deletions crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,7 @@ async fn run_project(
commands::sync(
args.locked,
args.frozen,
args.package,
args.extras,
args.dev,
args.modifications,
Expand Down
3 changes: 3 additions & 0 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ pub(crate) struct SyncSettings {
pub(crate) extras: ExtrasSpecification,
pub(crate) dev: bool,
pub(crate) modifications: Modifications,
pub(crate) package: Option<PackageName>,
pub(crate) python: Option<String>,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings,
Expand All @@ -564,6 +565,7 @@ impl SyncSettings {
installer,
build,
refresh,
package,
python,
} = args;

Expand All @@ -582,6 +584,7 @@ impl SyncSettings {
),
dev: flag(dev, no_dev).unwrap_or(true),
modifications,
package,
python,
refresh: Refresh::from(refresh),
settings: ResolverInstallerSettings::combine(
Expand Down
66 changes: 66 additions & 0 deletions crates/uv/tests/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,69 @@ fn empty() -> Result<()> {

Ok(())
}

/// Sync an individual package within a workspace.
#[test]
fn package() -> Result<()> {
let context = TestContext::new("3.12");

let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "root"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["child", "anyio>3"]
[tool.uv.sources]
child = { workspace = true }
[tool.uv.workspace]
members = ["child"]
"#,
)?;

let src = context.temp_dir.child("src").child("albatross");
src.create_dir_all()?;

let init = src.child("__init__.py");
init.touch()?;

let child = context.temp_dir.child("child");
fs_err::create_dir_all(&child)?;

let pyproject_toml = child.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "child"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["iniconfig>1"]
"#,
)?;

let src = child.child("src").child("albatross");
src.create_dir_all()?;

let init = src.child("__init__.py");
init.touch()?;

uv_snapshot!(context.filters(), context.sync().arg("--package").arg("child"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv sync` is experimental and may change without warning
warning: `uv.sources` is experimental and may change without warning
Resolved 6 packages in [TIME]
Prepared 2 packages in [TIME]
Installed 2 packages in [TIME]
+ child==0.1.0 (from file://[TEMP_DIR]/child)
+ iniconfig==2.0.0
"###);

Ok(())
}

0 comments on commit 955a1cd

Please sign in to comment.