mirror of
https://github.com/pnpm/pnpm.git
synced 2026-04-10 18:18:56 -04:00
fix(store prune): will not fail if store dir does not exist (#8555)
* fix(store prune): will not fail if store dir does not exist * fix(store prune): will not fail if store dir does not exist * refactor: package-store --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
5
.changeset/silly-teachers-cry.md
Normal file
5
.changeset/silly-teachers-cry.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/package-store": patch
|
||||
---
|
||||
|
||||
`pnpm store prune` should not fail if the store directory doesn't exist.
|
||||
@@ -1,4 +1,5 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import { type Dirent, promises as fs } from 'fs'
|
||||
import util from 'util'
|
||||
import path from 'path'
|
||||
import { type PackageFilesIndex } from '@pnpm/store.cafs'
|
||||
import { globalInfo, globalWarn } from '@pnpm/logger'
|
||||
@@ -24,9 +25,7 @@ export async function prune ({ cacheDir, storeDir }: PruneOptions, removeAlienFi
|
||||
globalInfo('Removed all cached metadata files')
|
||||
const pkgIndexFiles = [] as string[]
|
||||
const removedHashes = new Set<string>()
|
||||
const dirs = (await fs.readdir(cafsDir, { withFileTypes: true }))
|
||||
.filter(entry => entry.isDirectory())
|
||||
.map(dir => dir.name)
|
||||
const dirs = await getSubdirsSafely(cafsDir)
|
||||
let fileCounter = 0
|
||||
await Promise.all(dirs.map(async (dir) => {
|
||||
const subdir = path.join(cafsDir, dir)
|
||||
@@ -67,3 +66,18 @@ export async function prune ({ cacheDir, storeDir }: PruneOptions, removeAlienFi
|
||||
}))
|
||||
globalInfo(`Removed ${pkgCounter} package${pkgCounter === 1 ? '' : 's'}`)
|
||||
}
|
||||
|
||||
async function getSubdirsSafely (dir: string): Promise<string[]> {
|
||||
let entries: Dirent[]
|
||||
try {
|
||||
entries = await fs.readdir(dir, { withFileTypes: true }) as Dirent[]
|
||||
} catch (err: unknown) {
|
||||
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
|
||||
return []
|
||||
}
|
||||
throw err
|
||||
}
|
||||
return entries
|
||||
.filter(entry => entry.isDirectory())
|
||||
.map(dir => dir.name)
|
||||
}
|
||||
|
||||
@@ -281,6 +281,67 @@ test('prune removes alien files from the store if the --force flag is used', asy
|
||||
expect(fs.existsSync(alienDir)).toBeFalsy()
|
||||
})
|
||||
|
||||
describe('prune when store directory is not properly configured', () => {
|
||||
test('prune will not fail if the store directory does not exist (ENOENT)', async () => {
|
||||
prepareEmpty()
|
||||
const nonExistentStoreDir = path.resolve('store')
|
||||
const reporter = jest.fn()
|
||||
|
||||
await expect(
|
||||
store.handler({
|
||||
cacheDir: path.resolve('cache'),
|
||||
dir: process.cwd(),
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
registries: { default: REGISTRY },
|
||||
reporter,
|
||||
storeDir: nonExistentStoreDir,
|
||||
userConfig: {},
|
||||
dlxCacheMaxAge: Infinity,
|
||||
virtualStoreDirMaxLength: 120,
|
||||
}, ['prune'])
|
||||
).resolves.toBeUndefined()
|
||||
|
||||
expect(reporter).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
level: 'info',
|
||||
message: 'Removed 0 files',
|
||||
})
|
||||
)
|
||||
|
||||
expect(reporter).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
level: 'info',
|
||||
message: 'Removed 0 packages',
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
test('prune will fail for other file-related errors (i.e.; not ENOENT)', async () => {
|
||||
prepareEmpty()
|
||||
const fileInPlaceOfStoreDir = path.resolve('store')
|
||||
fs.writeFileSync(fileInPlaceOfStoreDir, '')
|
||||
await expect(
|
||||
store.handler({
|
||||
cacheDir: path.resolve('cache'),
|
||||
dir: process.cwd(),
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
registries: { default: REGISTRY },
|
||||
reporter: jest.fn(),
|
||||
storeDir: fileInPlaceOfStoreDir,
|
||||
userConfig: {},
|
||||
dlxCacheMaxAge: Infinity,
|
||||
virtualStoreDirMaxLength: 120,
|
||||
}, ['prune'])
|
||||
).rejects.toThrow(/^ENOTDIR/)
|
||||
})
|
||||
})
|
||||
|
||||
function createSampleDlxCacheLinkTarget (dirPath: string): void {
|
||||
fs.mkdirSync(path.join(dirPath, 'node_modules', '.pnpm'), { recursive: true })
|
||||
fs.mkdirSync(path.join(dirPath, 'node_modules', '.bin'), { recursive: true })
|
||||
|
||||
Reference in New Issue
Block a user