mirror of https://github.com/astral-sh/uv
Respect relative paths in `uv build` sources (#8237)
## Summary Right now, `uv build` will fail if a package depends on a local source in `build-system.requires`.
This commit is contained in:
parent
b4dca669b4
commit
999b3f06a4
|
|
@ -245,6 +245,7 @@ impl SourceBuild {
|
|||
pub async fn setup(
|
||||
source: &Path,
|
||||
subdirectory: Option<&Path>,
|
||||
install_path: &Path,
|
||||
fallback_package_name: Option<&PackageName>,
|
||||
fallback_package_version: Option<&Version>,
|
||||
interpreter: &Interpreter,
|
||||
|
|
@ -273,6 +274,7 @@ impl SourceBuild {
|
|||
// Check if we have a PEP 517 build backend.
|
||||
let (pep517_backend, project) = Self::extract_pep517_backend(
|
||||
&source_tree,
|
||||
install_path,
|
||||
fallback_package_name,
|
||||
locations,
|
||||
source_strategy,
|
||||
|
|
@ -368,6 +370,7 @@ impl SourceBuild {
|
|||
create_pep517_build_environment(
|
||||
&runner,
|
||||
&source_tree,
|
||||
install_path,
|
||||
&venv,
|
||||
&pep517_backend,
|
||||
build_context,
|
||||
|
|
@ -436,6 +439,7 @@ impl SourceBuild {
|
|||
/// Extract the PEP 517 backend from the `pyproject.toml` or `setup.py` file.
|
||||
async fn extract_pep517_backend(
|
||||
source_tree: &Path,
|
||||
install_path: &Path,
|
||||
package_name: Option<&PackageName>,
|
||||
locations: &IndexLocations,
|
||||
source_strategy: SourceStrategy,
|
||||
|
|
@ -469,7 +473,7 @@ impl SourceBuild {
|
|||
};
|
||||
let requires_dist = RequiresDist::from_project_maybe_workspace(
|
||||
requires_dist,
|
||||
source_tree,
|
||||
install_path,
|
||||
locations,
|
||||
source_strategy,
|
||||
LowerBound::Allow,
|
||||
|
|
@ -803,6 +807,7 @@ fn escape_path_for_python(path: &Path) -> String {
|
|||
async fn create_pep517_build_environment(
|
||||
runner: &PythonRunner,
|
||||
source_tree: &Path,
|
||||
install_path: &Path,
|
||||
venv: &PythonEnvironment,
|
||||
pep517_backend: &Pep517Backend,
|
||||
build_context: &impl BuildContext,
|
||||
|
|
@ -921,7 +926,7 @@ async fn create_pep517_build_environment(
|
|||
};
|
||||
let requires_dist = RequiresDist::from_project_maybe_workspace(
|
||||
requires_dist,
|
||||
source_tree,
|
||||
install_path,
|
||||
locations,
|
||||
source_strategy,
|
||||
LowerBound::Allow,
|
||||
|
|
|
|||
|
|
@ -318,6 +318,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
|
|||
&'data self,
|
||||
source: &'data Path,
|
||||
subdirectory: Option<&'data Path>,
|
||||
install_path: &'data Path,
|
||||
version_id: Option<String>,
|
||||
dist: Option<&'data SourceDist>,
|
||||
sources: SourceStrategy,
|
||||
|
|
@ -352,6 +353,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
|
|||
let builder = SourceBuild::setup(
|
||||
source,
|
||||
subdirectory,
|
||||
install_path,
|
||||
dist_name,
|
||||
dist_version,
|
||||
self.interpreter,
|
||||
|
|
|
|||
|
|
@ -1712,6 +1712,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
.setup_build(
|
||||
source_root,
|
||||
subdirectory,
|
||||
source_root,
|
||||
Some(source.to_string()),
|
||||
source.as_dist(),
|
||||
source_strategy,
|
||||
|
|
@ -1756,6 +1757,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
.setup_build(
|
||||
source_root,
|
||||
subdirectory,
|
||||
source_root,
|
||||
Some(source.to_string()),
|
||||
source.as_dist(),
|
||||
source_strategy,
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ pub trait BuildContext {
|
|||
&'a self,
|
||||
source: &'a Path,
|
||||
subdirectory: Option<&'a Path>,
|
||||
install_path: &'a Path,
|
||||
version_id: Option<String>,
|
||||
dist: Option<&'a SourceDist>,
|
||||
sources: SourceStrategy,
|
||||
|
|
|
|||
|
|
@ -535,9 +535,9 @@ async fn build_package(
|
|||
};
|
||||
|
||||
// Prepare some common arguments for the build.
|
||||
let dist = None;
|
||||
let subdirectory = None;
|
||||
let version_id = source.path().file_name().and_then(|name| name.to_str());
|
||||
let dist = None;
|
||||
|
||||
let build_output = match printer {
|
||||
Printer::Default | Printer::NoProgress | Printer::Verbose => {
|
||||
|
|
@ -563,6 +563,7 @@ async fn build_package(
|
|||
.setup_build(
|
||||
source.path(),
|
||||
subdirectory,
|
||||
source.path(),
|
||||
version_id.map(ToString::to_string),
|
||||
dist,
|
||||
sources,
|
||||
|
|
@ -601,6 +602,7 @@ async fn build_package(
|
|||
.setup_build(
|
||||
&extracted,
|
||||
subdirectory,
|
||||
source.path(),
|
||||
version_id.map(ToString::to_string),
|
||||
dist,
|
||||
sources,
|
||||
|
|
@ -623,6 +625,7 @@ async fn build_package(
|
|||
.setup_build(
|
||||
source.path(),
|
||||
subdirectory,
|
||||
source.path(),
|
||||
version_id.map(ToString::to_string),
|
||||
dist,
|
||||
sources,
|
||||
|
|
@ -645,6 +648,7 @@ async fn build_package(
|
|||
.setup_build(
|
||||
source.path(),
|
||||
subdirectory,
|
||||
source.path(),
|
||||
version_id.map(ToString::to_string),
|
||||
dist,
|
||||
sources,
|
||||
|
|
@ -666,6 +670,7 @@ async fn build_package(
|
|||
.setup_build(
|
||||
source.path(),
|
||||
subdirectory,
|
||||
source.path(),
|
||||
version_id.map(ToString::to_string),
|
||||
dist,
|
||||
sources,
|
||||
|
|
@ -684,6 +689,7 @@ async fn build_package(
|
|||
.setup_build(
|
||||
source.path(),
|
||||
subdirectory,
|
||||
source.path(),
|
||||
version_id.map(ToString::to_string),
|
||||
dist,
|
||||
sources,
|
||||
|
|
@ -724,6 +730,7 @@ async fn build_package(
|
|||
.setup_build(
|
||||
&extracted,
|
||||
subdirectory,
|
||||
source.path(),
|
||||
version_id.map(ToString::to_string),
|
||||
dist,
|
||||
sources,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::common::{uv_snapshot, TestContext};
|
|||
use anyhow::Result;
|
||||
use assert_fs::prelude::*;
|
||||
use fs_err::File;
|
||||
use indoc::indoc;
|
||||
use insta::assert_snapshot;
|
||||
use predicates::prelude::predicate;
|
||||
use zip::ZipArchive;
|
||||
|
|
@ -1766,6 +1767,159 @@ fn build_no_build_logs() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tool_uv_sources() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"bdist\.[^/\\\s]+-[^/\\\s]+", "bdist.linux-x86_64"),
|
||||
(r"\\\.", ""),
|
||||
])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let build = context.temp_dir.child("backend");
|
||||
build.child("pyproject.toml").write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "backend"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["typing-extensions>=3.10"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
build
|
||||
.child("src")
|
||||
.child("backend")
|
||||
.child("__init__.py")
|
||||
.write_str(indoc! { r#"
|
||||
def hello() -> str:
|
||||
return "Hello, world!"
|
||||
"#})?;
|
||||
build.child("README.md").touch()?;
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
||||
project.child("pyproject.toml").write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["iniconfig>1"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42", "backend==0.1.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.uv.sources]
|
||||
backend = { path = "../backend" }
|
||||
"#,
|
||||
)?;
|
||||
|
||||
project.child("setup.py").write_str(indoc! {r"
|
||||
from setuptools import setup
|
||||
|
||||
from backend import hello
|
||||
|
||||
hello()
|
||||
|
||||
setup()
|
||||
",
|
||||
})?;
|
||||
|
||||
uv_snapshot!(filters, context.build().current_dir(project.path()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Building source distribution...
|
||||
running egg_info
|
||||
creating project.egg-info
|
||||
writing project.egg-info/PKG-INFO
|
||||
writing dependency_links to project.egg-info/dependency_links.txt
|
||||
writing requirements to project.egg-info/requires.txt
|
||||
writing top-level names to project.egg-info/top_level.txt
|
||||
writing manifest file 'project.egg-info/SOURCES.txt'
|
||||
reading manifest file 'project.egg-info/SOURCES.txt'
|
||||
writing manifest file 'project.egg-info/SOURCES.txt'
|
||||
running sdist
|
||||
running egg_info
|
||||
writing project.egg-info/PKG-INFO
|
||||
writing dependency_links to project.egg-info/dependency_links.txt
|
||||
writing requirements to project.egg-info/requires.txt
|
||||
writing top-level names to project.egg-info/top_level.txt
|
||||
reading manifest file 'project.egg-info/SOURCES.txt'
|
||||
writing manifest file 'project.egg-info/SOURCES.txt'
|
||||
warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md
|
||||
|
||||
running check
|
||||
creating project-0.1.0
|
||||
creating project-0.1.0/project.egg-info
|
||||
copying files to project-0.1.0...
|
||||
copying pyproject.toml -> project-0.1.0
|
||||
copying setup.py -> project-0.1.0
|
||||
copying project.egg-info/PKG-INFO -> project-0.1.0/project.egg-info
|
||||
copying project.egg-info/SOURCES.txt -> project-0.1.0/project.egg-info
|
||||
copying project.egg-info/dependency_links.txt -> project-0.1.0/project.egg-info
|
||||
copying project.egg-info/requires.txt -> project-0.1.0/project.egg-info
|
||||
copying project.egg-info/top_level.txt -> project-0.1.0/project.egg-info
|
||||
copying project.egg-info/SOURCES.txt -> project-0.1.0/project.egg-info
|
||||
Writing project-0.1.0/setup.cfg
|
||||
Creating tar archive
|
||||
removing 'project-0.1.0' (and everything under it)
|
||||
Building wheel from source distribution...
|
||||
running egg_info
|
||||
writing project.egg-info/PKG-INFO
|
||||
writing dependency_links to project.egg-info/dependency_links.txt
|
||||
writing requirements to project.egg-info/requires.txt
|
||||
writing top-level names to project.egg-info/top_level.txt
|
||||
reading manifest file 'project.egg-info/SOURCES.txt'
|
||||
writing manifest file 'project.egg-info/SOURCES.txt'
|
||||
running bdist_wheel
|
||||
running build
|
||||
installing to build/bdist.linux-x86_64/wheel
|
||||
running install
|
||||
running install_egg_info
|
||||
running egg_info
|
||||
writing project.egg-info/PKG-INFO
|
||||
writing dependency_links to project.egg-info/dependency_links.txt
|
||||
writing requirements to project.egg-info/requires.txt
|
||||
writing top-level names to project.egg-info/top_level.txt
|
||||
reading manifest file 'project.egg-info/SOURCES.txt'
|
||||
writing manifest file 'project.egg-info/SOURCES.txt'
|
||||
Copying project.egg-info to build/bdist.linux-x86_64/wheel/project-0.1.0-py3.12.egg-info
|
||||
running install_scripts
|
||||
creating build/bdist.linux-x86_64/wheel/project-0.1.0.dist-info/WHEEL
|
||||
creating '[TEMP_DIR]/project/dist/[TMP]/wheel' to it
|
||||
adding 'project-0.1.0.dist-info/METADATA'
|
||||
adding 'project-0.1.0.dist-info/WHEEL'
|
||||
adding 'project-0.1.0.dist-info/top_level.txt'
|
||||
adding 'project-0.1.0.dist-info/RECORD'
|
||||
removing build/bdist.linux-x86_64/wheel
|
||||
Successfully built dist/project-0.1.0.tar.gz and dist/project-0.1.0-py3-none-any.whl
|
||||
"###);
|
||||
|
||||
project
|
||||
.child("dist")
|
||||
.child("project-0.1.0.tar.gz")
|
||||
.assert(predicate::path::is_file());
|
||||
project
|
||||
.child("dist")
|
||||
.child("project-0.1.0-py3-none-any.whl")
|
||||
.assert(predicate::path::is_file());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check that we have a working git boundary for builds from source dist to wheel in `dist/`.
|
||||
#[test]
|
||||
fn git_boundary_in_dist_build() -> Result<()> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue