fix(store): return only directory names when clean expired cache (#10384)

* fix(store): return only directory names when clean expired cache

* docs: add changeset

* test: clean dlx cache

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
Junius Chen
2025-12-31 01:01:53 +08:00
committed by GitHub
parent 3c72b6b2de
commit b773199eb0
3 changed files with 44 additions and 1 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/plugin-commands-store": patch
"pnpm": patch
---
`pnpm store prune` should not fail if the dlx cache directory has files, not only directories [#10384](https://github.com/pnpm/pnpm/pull/10384)

View File

@@ -192,3 +192,31 @@ test("cleanOrphans deletes dirs that don't contain `link` and subdirs that aren'
// expecting directory that doesn't contain `link` to be deleted.
expect(fs.existsSync(path.join(cacheDir, 'dlx', createCacheKey('bar')))).toBe(false)
})
test('cleanExpiredDlxCache ignores files in the dlx cache directory', async () => {
prepareEmpty()
const cacheDir = path.resolve('cache')
const dlxCacheMaxAge = 0
const now = new Date()
// Create a directory that should be cleaned
createSampleDlxCacheItem(cacheDir, 'foo', now, 1)
// Create a file in the dlx directory (simulating the bug/noise)
const dlxDir = path.join(cacheDir, 'dlx')
fsOriginal.mkdirSync(dlxDir, { recursive: true })
fsOriginal.writeFileSync(path.join(dlxDir, 'some-random-file'), 'hello')
await cleanExpiredDlxCache({
cacheDir,
dlxCacheMaxAge,
now,
})
// The directory should be gone (cleaned)
expect(fsOriginal.existsSync(path.join(dlxDir, createCacheKey('foo')))).toBeFalsy()
// The file should still be there (ignored)
expect(fsOriginal.existsSync(path.join(dlxDir, 'some-random-file'))).toBeTruthy()
})

View File

@@ -74,7 +74,16 @@ async function getStats (path: string): Promise<Stats | 'ENOENT'> {
function readOptDir (dirPath: string): string[] | null {
try {
return readdirSync(dirPath, 'utf-8')
const dirEntries: string[] = []
for (const entry of readdirSync(dirPath, {
encoding: 'utf-8',
withFileTypes: true,
})) {
if (entry.isDirectory()) {
dirEntries.push(entry.name)
}
}
return dirEntries
} catch (err) {
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
return null