diff --git a/crates/uv-cache/src/lib.rs b/crates/uv-cache/src/lib.rs index 10c4f532f..9ab8ec315 100644 --- a/crates/uv-cache/src/lib.rs +++ b/crates/uv-cache/src/lib.rs @@ -251,15 +251,6 @@ impl Cache { Err(err) => return Err(err), } - // Add a phony .git, if it doesn't exist, to ensure that the cache isn't considered to be - // part of a Git repository. (Some packages will include Git metadata (like a hash) in the - // built version if they're in a Git repository, but the cache should be viewed as an - // isolated store.) - fs::OpenOptions::new() - .create(true) - .write(true) - .open(root.join(".git"))?; - // Add an empty .gitignore to the build bucket, to ensure that the cache's own .gitignore // doesn't interfere with source distribution builds. Build backends (like hatchling) will // traverse upwards to look for .gitignore files. @@ -273,6 +264,18 @@ impl Cache { Err(err) => return Err(err), } + // Add a phony .git, if it doesn't exist, to ensure that the cache isn't considered to be + // part of a Git repository. (Some packages will include Git metadata (like a hash) in the + // built version if they're in a Git repository, but the cache should be viewed as an + // isolated store.). + // We have to put this below the gitignore. Otherwise, if the build backend uses the rust + // ignore crate it will walk up to the top level .gitignore and ignore its python source + // files. + fs::OpenOptions::new() + .create(true) + .write(true) + .open(root.join(CacheBucket::BuiltWheels.to_str()).join(".git"))?; + fs::canonicalize(root) } diff --git a/crates/uv/tests/pip_install.rs b/crates/uv/tests/pip_install.rs index a3ece68b2..6dfbd764d 100644 --- a/crates/uv/tests/pip_install.rs +++ b/crates/uv/tests/pip_install.rs @@ -6,10 +6,12 @@ use assert_fs::prelude::*; use base64::{prelude::BASE64_STANDARD as base64, Engine}; use indoc::indoc; use itertools::Itertools; +use std::env::current_dir; use std::process::Command; use url::Url; use common::{uv_snapshot, TestContext, EXCLUDE_NEWER, INSTA_FILTERS}; +use uv_fs::Simplified; use crate::common::get_bin; @@ -2952,3 +2954,57 @@ fn install_site_packages_mtime_updated() -> Result<()> { Ok(()) } + +/// We had a bug where maturin would walk up to the top level gitignore of the cache with a `*` +/// entry (because we want to ignore the entire cache from outside), ignoring all python source +/// files. +#[test] +fn deptry_gitignore() -> Result<()> { + let context = TestContext::new("3.12"); + + let project_root = current_dir()? + .parent() + .unwrap() + .parent() + .unwrap() + .to_path_buf(); + let source_dist_dir = project_root + .join("scripts") + .join("packages") + .join("deptry_reproducer"); + let filter_path = regex::escape( + Url::from_directory_path(source_dist_dir.simplified_display().to_string()) + .unwrap() + .to_string() + .trim_end_matches('/'), + ); + let filters: Vec<_> = [(filter_path.as_str(), "[SOURCE_DIST_DIR]")] + .into_iter() + .chain(INSTA_FILTERS.to_vec()) + .collect(); + + uv_snapshot!(filters, command(&context) + .arg(format!("deptry_reproducer @ {}/deptry_reproducer-0.1.0.tar.gz", source_dist_dir.simplified_display())) + .arg("--strict") + .current_dir(source_dist_dir), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 3 packages in [TIME] + Downloaded 3 packages in [TIME] + Installed 3 packages in [TIME] + + cffi==1.16.0 + + deptry-reproducer==0.1.0 (from [SOURCE_DIST_DIR]/deptry_reproducer-0.1.0.tar.gz) + + pycparser==2.21 + "### + ); + + // Check that we packed the python source files + context + .assert_command("import deptry_reproducer.foo") + .success(); + + Ok(()) +} diff --git a/scripts/packages/deptry_reproducer/.gitignore b/scripts/packages/deptry_reproducer/.gitignore new file mode 100644 index 000000000..ea8c4bf7f --- /dev/null +++ b/scripts/packages/deptry_reproducer/.gitignore @@ -0,0 +1 @@ +/target diff --git a/scripts/packages/deptry_reproducer/Cargo.lock b/scripts/packages/deptry_reproducer/Cargo.lock new file mode 100644 index 000000000..1c831357b --- /dev/null +++ b/scripts/packages/deptry_reproducer/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "deptry_reproducer" +version = "0.1.0" diff --git a/scripts/packages/deptry_reproducer/Cargo.toml b/scripts/packages/deptry_reproducer/Cargo.toml new file mode 100644 index 000000000..d685993bd --- /dev/null +++ b/scripts/packages/deptry_reproducer/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "deptry_reproducer" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "deptry_reproducer" +crate-type = ["cdylib"] + +[dependencies] diff --git a/scripts/packages/deptry_reproducer/deptry_reproducer-0.1.0.tar.gz b/scripts/packages/deptry_reproducer/deptry_reproducer-0.1.0.tar.gz new file mode 100644 index 000000000..b76ecee2e Binary files /dev/null and b/scripts/packages/deptry_reproducer/deptry_reproducer-0.1.0.tar.gz differ diff --git a/scripts/packages/deptry_reproducer/pyproject.toml b/scripts/packages/deptry_reproducer/pyproject.toml new file mode 100644 index 000000000..cf8864fb5 --- /dev/null +++ b/scripts/packages/deptry_reproducer/pyproject.toml @@ -0,0 +1,21 @@ +[build-system] +requires = ["maturin>=1,<2.0"] +build-backend = "maturin" + +[project] +name = "deptry_reproducer" +requires-python = ">=3.8" +classifiers = [ + "Programming Language :: Rust", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] +dependencies = ["cffi"] +dynamic = ["version"] +[project.optional-dependencies] +tests = [ + "pytest", +] +[tool.maturin] +bindings = "cffi" +python-source = "python" diff --git a/scripts/packages/deptry_reproducer/python/deptry_reproducer/__init__.py b/scripts/packages/deptry_reproducer/python/deptry_reproducer/__init__.py new file mode 100644 index 000000000..a95c6b977 --- /dev/null +++ b/scripts/packages/deptry_reproducer/python/deptry_reproducer/__init__.py @@ -0,0 +1,6 @@ +from .deptry_reproducer import * + + +__doc__ = deptry_reproducer.__doc__ +if hasattr(deptry_reproducer, "__all__"): + __all__ = deptry_reproducer.__all__ diff --git a/scripts/packages/deptry_reproducer/python/deptry_reproducer/foo.py b/scripts/packages/deptry_reproducer/python/deptry_reproducer/foo.py new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/packages/deptry_reproducer/src/lib.rs b/scripts/packages/deptry_reproducer/src/lib.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/scripts/packages/deptry_reproducer/src/lib.rs @@ -0,0 +1 @@ +