mirror of https://github.com/astral-sh/uv
Show a dedicated error for missing subdirectories (#9761)
## Summary
On `main`, if you ask for a source but name a missing subdirectory, you
just get:
```
{source} does not appear to be a Python project, as neither `pyproject.toml` nor `setup.py` are present in the directory
```
But, in reality, the directory doesn't exist at all.
This commit is contained in:
parent
8a2e3a8339
commit
341126cf72
|
|
@ -92,6 +92,8 @@ pub enum Error {
|
|||
MissingEggInfo,
|
||||
#[error("The source distribution is missing a `requires.txt` file")]
|
||||
MissingRequiresTxt,
|
||||
#[error("The source distribution `{}` has no subdirectory `{}`", _0, _1.display())]
|
||||
MissingSubdirectory(Url, PathBuf),
|
||||
#[error("Failed to extract static metadata from `PKG-INFO`")]
|
||||
PkgInfo(#[source] uv_pypi_types::MetadataError),
|
||||
#[error("Failed to extract metadata from `requires.txt`")]
|
||||
|
|
|
|||
|
|
@ -393,6 +393,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
let cache_shard = cache_shard.shard(revision.id());
|
||||
let source_dist_entry = cache_shard.entry(SOURCE);
|
||||
|
||||
// Validate that the subdirectory exists.
|
||||
if let Some(subdirectory) = subdirectory {
|
||||
if !source_dist_entry.path().join(subdirectory).is_dir() {
|
||||
return Err(Error::MissingSubdirectory(
|
||||
url.clone(),
|
||||
subdirectory.to_path_buf(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// If there are build settings, we need to scope to a cache shard.
|
||||
let config_settings = self.build_context.config_settings();
|
||||
let cache_shard = if config_settings.is_empty() {
|
||||
|
|
@ -496,6 +506,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
let cache_shard = cache_shard.shard(revision.id());
|
||||
let source_dist_entry = cache_shard.entry(SOURCE);
|
||||
|
||||
// Validate that the subdirectory exists.
|
||||
if let Some(subdirectory) = subdirectory {
|
||||
if !source_dist_entry.path().join(subdirectory).is_dir() {
|
||||
return Err(Error::MissingSubdirectory(
|
||||
url.clone(),
|
||||
subdirectory.to_path_buf(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// If the metadata is static, return it.
|
||||
if let Some(metadata) =
|
||||
Self::read_static_metadata(source, source_dist_entry.path(), subdirectory).await?
|
||||
|
|
@ -1303,6 +1323,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
)
|
||||
.await?;
|
||||
|
||||
// Validate that the subdirectory exists.
|
||||
if let Some(subdirectory) = resource.subdirectory {
|
||||
if !fetch.path().join(subdirectory).is_dir() {
|
||||
return Err(Error::MissingSubdirectory(
|
||||
resource.url.to_url(),
|
||||
subdirectory.to_path_buf(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let git_sha = fetch.git().precise().expect("Exact commit after checkout");
|
||||
let cache_shard = self.build_context.cache().shard(
|
||||
CacheBucket::SourceDistributions,
|
||||
|
|
@ -1390,6 +1420,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
)
|
||||
.await?;
|
||||
|
||||
// Validate that the subdirectory exists.
|
||||
if let Some(subdirectory) = resource.subdirectory {
|
||||
if !fetch.path().join(subdirectory).is_dir() {
|
||||
return Err(Error::MissingSubdirectory(
|
||||
resource.url.to_url(),
|
||||
subdirectory.to_path_buf(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let git_sha = fetch.git().precise().expect("Exact commit after checkout");
|
||||
let cache_shard = self.build_context.cache().shard(
|
||||
CacheBucket::SourceDistributions,
|
||||
|
|
@ -1438,12 +1478,6 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
.await?
|
||||
.filter(|metadata| metadata.matches(source.name(), source.version()))
|
||||
{
|
||||
let path = if let Some(subdirectory) = resource.subdirectory {
|
||||
Cow::Owned(fetch.path().join(subdirectory))
|
||||
} else {
|
||||
Cow::Borrowed(fetch.path())
|
||||
};
|
||||
|
||||
let git_member = GitWorkspaceMember {
|
||||
fetch_root: fetch.path(),
|
||||
git_source: resource,
|
||||
|
|
|
|||
|
|
@ -7589,3 +7589,45 @@ fn build_tag() {
|
|||
----- stderr -----
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_subdirectory_git() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
let requirements_txt = context.temp_dir.child("requirements.txt");
|
||||
requirements_txt.touch()?;
|
||||
|
||||
uv_snapshot!(context.pip_install()
|
||||
.arg("source-distribution @ git+https://github.com/astral-sh/workspace-in-root-test#subdirectory=missing"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× Failed to download and build `source-distribution @ git+https://github.com/astral-sh/workspace-in-root-test#subdirectory=missing`
|
||||
╰─▶ The source distribution `git+https://github.com/astral-sh/workspace-in-root-test#subdirectory=missing` has no subdirectory `missing`
|
||||
"###
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_subdirectory_url() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
let requirements_txt = context.temp_dir.child("requirements.txt");
|
||||
requirements_txt.touch()?;
|
||||
|
||||
uv_snapshot!(context.pip_install()
|
||||
.arg("source-distribution @ https://files.pythonhosted.org/packages/1f/e5/5b016c945d745f8b108e759d428341488a6aee8f51f07c6c4e33498bb91f/source_distribution-0.0.3.tar.gz#subdirectory=missing"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× Failed to download and build `source-distribution @ https://files.pythonhosted.org/packages/1f/e5/5b016c945d745f8b108e759d428341488a6aee8f51f07c6c4e33498bb91f/source_distribution-0.0.3.tar.gz#subdirectory=missing`
|
||||
╰─▶ The source distribution `https://files.pythonhosted.org/packages/1f/e5/5b016c945d745f8b108e759d428341488a6aee8f51f07c6c4e33498bb91f/source_distribution-0.0.3.tar.gz#subdirectory=missing` has no subdirectory `missing`
|
||||
"###
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue