fix: don't copy file during linking if the target exists

This commit is contained in:
Zoltan Kochan
2020-10-26 03:09:48 +02:00
parent c700c4865c
commit 01aecf0386
3 changed files with 17 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/package-store": patch
---
Do not try to copy a file during linking, if the target already exists.

View File

@@ -120,6 +120,9 @@ async function linkOrCopy (existingPath: string, newPath: string) {
try {
await fs.link(existingPath, newPath)
} catch (err) {
// If a hard link to the same file already exists
// then trying to copy it will make an empty file from it.
if (err['code'] === 'EEXIST') return
// In some VERY rare cases (1 in a thousand), hard-link creation fails on Windows.
// In that case, we just fall back to copying.
// This issue is reproducible with "pnpm add @material-ui/icons@4.9.1"

View File

@@ -120,7 +120,12 @@ test('packageImportMethod=auto: chooses copying if cloning and hard linking is n
test('packageImportMethod=hardlink: fall back to copying if hardlinking fails', async () => {
const importPackage = createImportPackage('hardlink')
fsMock.link = jest.fn(() => {
fsMock.link = jest.fn((src: string, dest: string) => {
if (dest.endsWith('license')) {
const err = new Error('')
err['code'] = 'EEXIST'
throw err
}
throw new Error('This file system does not support hard linking')
})
fsMock.copyFile = jest.fn()
@@ -128,11 +133,13 @@ test('packageImportMethod=hardlink: fall back to copying if hardlinking fails',
filesMap: {
'index.js': 'hash2',
'package.json': 'hash1',
license: 'hash3',
},
force: false,
fromStore: false,
})).toBe('hardlink')
expect(fsMock.link).toBeCalled()
expect(fsMock.link).toBeCalledTimes(3)
expect(fsMock.copyFile).toBeCalledTimes(2) // One time the target already exists, so it won't be copied
expect(fsMock.copyFile).toBeCalledWith(path.join('hash1'), path.join('project', '_tmp', 'package.json'))
expect(fsMock.copyFile).toBeCalledWith(path.join('hash2'), path.join('project', '_tmp', 'index.js'))
})