diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 3ef7711df995..c3e6588b62ef 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -1749,10 +1749,6 @@ pub struct AddArgs { #[arg(long)] pub dev: bool, - /// Add the requirements as workspace dependencies. - #[arg(long)] - pub workspace: bool, - /// Add the requirements as editables. #[arg(long, default_missing_value = "true", num_args(0..=1))] pub editable: Option, diff --git a/crates/uv-distribution/src/pyproject.rs b/crates/uv-distribution/src/pyproject.rs index fb2589285066..9e77e41a0160 100644 --- a/crates/uv-distribution/src/pyproject.rs +++ b/crates/uv-distribution/src/pyproject.rs @@ -194,14 +194,19 @@ pub enum Source { #[derive(Error, Debug)] pub enum SourceError { - #[error("Cannot resolve git reference `{0}`.")] + #[error("Cannot resolve git reference `{0}`")] UnresolvedReference(String), - #[error("Workspace dependency must be a local path.")] - InvalidWorkspaceRequirement, + #[error("Workspace dependency `{0}` must refer to local directory, not a Git repository")] + WorkspacePackageGit(String), + #[error("Workspace dependency `{0}` must refer to local directory, not a URL")] + WorkspacePackageUrl(String), + #[error("Workspace dependency `{0}` must refer to local directory, not a file")] + WorkspacePackageFile(String), } impl Source { pub fn from_requirement( + name: &PackageName, source: RequirementSource, workspace: bool, editable: Option, @@ -210,15 +215,23 @@ impl Source { branch: Option, ) -> Result, SourceError> { if workspace { - match source { - RequirementSource::Registry { .. } | RequirementSource::Directory { .. } => {} - _ => return Err(SourceError::InvalidWorkspaceRequirement), - } - - return Ok(Some(Source::Workspace { - editable, - workspace: true, - })); + return match source { + RequirementSource::Registry { .. } | RequirementSource::Directory { .. } => { + Ok(Some(Source::Workspace { + editable, + workspace: true, + })) + } + RequirementSource::Url { .. } => { + Err(SourceError::WorkspacePackageUrl(name.to_string())) + } + RequirementSource::Git { .. } => { + Err(SourceError::WorkspacePackageGit(name.to_string())) + } + RequirementSource::Path { .. } => { + Err(SourceError::WorkspacePackageFile(name.to_string())) + } + }; } let source = match source { diff --git a/crates/uv/src/commands/project/add.rs b/crates/uv/src/commands/project/add.rs index 243862cb9701..7eebc95dc841 100644 --- a/crates/uv/src/commands/project/add.rs +++ b/crates/uv/src/commands/project/add.rs @@ -26,7 +26,6 @@ use crate::settings::ResolverInstallerSettings; #[allow(clippy::too_many_arguments, clippy::fn_params_excessive_bools)] pub(crate) async fn add( requirements: Vec, - workspace: bool, dev: bool, editable: Option, raw: bool, @@ -154,7 +153,9 @@ pub(crate) async fn add( (pep508_rs::Requirement::from(req), None) } else { // Otherwise, try to construct the source. + let workspace = project.workspace().packages().contains_key(&req.name); let result = Source::from_requirement( + &req.name, req.source.clone(), workspace, editable, diff --git a/crates/uv/src/main.rs b/crates/uv/src/main.rs index 53026baf5e7e..260487e7395c 100644 --- a/crates/uv/src/main.rs +++ b/crates/uv/src/main.rs @@ -719,7 +719,6 @@ async fn run() -> Result { commands::add( args.requirements, - args.workspace, args.dev, args.editable, args.raw, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index dff5e674e34c..b5d91814a33e 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -432,7 +432,6 @@ impl LockSettings { pub(crate) struct AddSettings { pub(crate) requirements: Vec, pub(crate) dev: bool, - pub(crate) workspace: bool, pub(crate) editable: Option, pub(crate) raw: bool, pub(crate) rev: Option, @@ -451,7 +450,6 @@ impl AddSettings { let AddArgs { requirements, dev, - workspace, editable, raw, rev, @@ -471,7 +469,6 @@ impl AddSettings { Self { requirements, - workspace, dev, editable, raw, diff --git a/crates/uv/tests/edit.rs b/crates/uv/tests/edit.rs index a2da486fbadb..46279a236228 100644 --- a/crates/uv/tests/edit.rs +++ b/crates/uv/tests/edit.rs @@ -735,11 +735,29 @@ fn add_remove_workspace() -> Result<()> { dependencies = [] "#})?; + // Adding a workspace package with a mismatched source should error. + let mut add_cmd = + context.add(&["child2 @ git+https://github.com/astral-test/uv-public-pypackage"]); + add_cmd + .arg("--preview") + .arg("--package") + .arg("child1") + .current_dir(&context.temp_dir); + + uv_snapshot!(context.filters(), add_cmd, @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: Workspace dependency `child2` must refer to local directory, not a Git repository + "###); + + // Workspace packages should be detected automatically. let child1 = context.temp_dir.join("child1"); let mut add_cmd = context.add(&["child2"]); add_cmd .arg("--preview") - .arg("--workspace") .arg("--package") .arg("child1") .current_dir(&context.temp_dir); @@ -921,7 +939,6 @@ fn add_workspace_editable() -> Result<()> { let mut add_cmd = context.add(&["child2"]); add_cmd .arg("--editable") - .arg("--workspace") .arg("--preview") .current_dir(&child1);