Skip to content

Commit e11d11d

Browse files
branchseerclaude
andcommitted
fix(cache): match negative input globs against package-relative paths
Negative input globs (like `!dist/**`) were being matched against workspace-relative paths (e.g., `packages/sub-pkg/dist/output.js`), so exclusions silently failed for subpackages. Now paths are converted to package-relative before matching, fixing the issue. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3ced295 commit e11d11d

File tree

3 files changed

+22
-4
lines changed

3 files changed

+22
-4
lines changed

crates/vite_task/src/session/execute/fingerprint.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,13 @@ impl PostRunFingerprint {
7474
/// # Arguments
7575
/// * `path_reads` - Map of paths that were read during execution (from fspy)
7676
/// * `base_dir` - Workspace root for resolving relative paths
77+
/// * `glob_base` - Package directory where the task is defined (negative globs are relative to this)
7778
/// * `input_config` - Resolved input configuration controlling what to fingerprint
7879
#[tracing::instrument(level = "debug", skip_all, name = "create_post_run_fingerprint")]
7980
pub fn create(
8081
path_reads: &HashMap<RelativePathBuf, PathRead>,
8182
base_dir: &AbsolutePath,
83+
glob_base: &AbsolutePath,
8284
input_config: &ResolvedInputConfig,
8385
) -> anyhow::Result<Self> {
8486
// If inference is disabled, return empty inferred_inputs
@@ -91,11 +93,23 @@ impl PostRunFingerprint {
9193
let negative_matcher =
9294
if patterns.is_empty() { None } else { Some(GlobPatternSet::new(&patterns)?) };
9395

96+
// Compute the package path relative to workspace root so we can convert
97+
// workspace-relative paths to package-relative paths for negative glob matching.
98+
// Negative globs like `!dist/**` are written relative to the package directory.
99+
let package_prefix = glob_base.strip_prefix(base_dir).ok().flatten();
100+
94101
let inferred_inputs = path_reads
95102
.par_iter()
96103
.filter(|(path, _)| {
97-
// Apply negative patterns to exclude from inferred inputs
98-
negative_matcher.as_ref().is_none_or(|matcher| !matcher.is_match(path.as_str()))
104+
// Apply negative patterns to exclude from inferred inputs.
105+
// Paths must be made package-relative before matching, since negative
106+
// globs are relative to the package directory, not the workspace root.
107+
negative_matcher.as_ref().is_none_or(|matcher| {
108+
let path_to_match =
109+
package_prefix.as_ref().and_then(|prefix| path.strip_prefix(prefix));
110+
path_to_match
111+
.map_or(true, |pkg_relative| !matcher.is_match(pkg_relative.as_str()))
112+
})
99113
})
100114
.map(|(relative_path, path_read)| {
101115
let full_path = Arc::<AbsolutePath>::from(base_dir.join(relative_path));

crates/vite_task/src/session/execute/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ pub async fn execute_spawn(
361361
match PostRunFingerprint::create(
362362
path_reads,
363363
cache_base_path,
364+
&cache_metadata.glob_base,
364365
&cache_metadata.input_config,
365366
) {
366367
Ok(post_run_fingerprint) => {

crates/vite_task_bin/tests/e2e_snapshots/fixtures/inputs-negative-glob-subpackage/snapshots/subpackage auto with negative - hit on excluded inferred file.snap

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ export const main = 'initial';
99
> replace-file-content packages/sub-pkg/dist/output.js initial modified
1010

1111
> vp run sub-pkg#auto-with-negative
12-
~/packages/sub-pkg$ print-file src/main.ts dist/output.js cache miss: content of input 'packages/sub-pkg/dist/output.js' changed, executing
12+
~/packages/sub-pkg$ print-file src/main.ts dist/output.js cache hit, replaying
1313
export const main = 'initial';
14-
// modified output
14+
// initial output
15+
16+
---
17+
[vp run] cache hit, <duration> saved.

0 commit comments

Comments
 (0)