mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Automatically detect workspace packages in uv add
(#4557)
## Summary If the package _isn't_ marked as `workspace = true`, locking will fail given: ```rust let workspace_package_declared = // We require that when you use a package that's part of the workspace, ... !workspace.packages().contains_key(&requirement.name) // ... it must be declared as a workspace dependency (`workspace = true`), ... || matches!( source, Some(Source::Workspace { // By using toml, we technically support `workspace = false`. workspace: true, .. }) ) // ... except for recursive self-inclusion (extras that activate other extras), e.g. // `framework[machine_learning]` depends on `framework[cuda]`. || &requirement.name == project_name; if !workspace_package_declared { return Err(LoweringError::UndeclaredWorkspacePackage); } ``` Closes https://github.com/astral-sh/uv/issues/4552.
This commit is contained in:
parent
a328c7b995
commit
45c271d15d
6 changed files with 46 additions and 23 deletions
|
@ -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<bool>,
|
||||
|
|
|
@ -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<bool>,
|
||||
|
@ -210,15 +215,23 @@ impl Source {
|
|||
branch: Option<String>,
|
||||
) -> Result<Option<Source>, 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 {
|
||||
|
|
|
@ -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<RequirementsSource>,
|
||||
workspace: bool,
|
||||
dev: bool,
|
||||
editable: Option<bool>,
|
||||
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,
|
||||
|
|
|
@ -719,7 +719,6 @@ async fn run() -> Result<ExitStatus> {
|
|||
|
||||
commands::add(
|
||||
args.requirements,
|
||||
args.workspace,
|
||||
args.dev,
|
||||
args.editable,
|
||||
args.raw,
|
||||
|
|
|
@ -432,7 +432,6 @@ impl LockSettings {
|
|||
pub(crate) struct AddSettings {
|
||||
pub(crate) requirements: Vec<RequirementsSource>,
|
||||
pub(crate) dev: bool,
|
||||
pub(crate) workspace: bool,
|
||||
pub(crate) editable: Option<bool>,
|
||||
pub(crate) raw: bool,
|
||||
pub(crate) rev: Option<String>,
|
||||
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue