mirror of
https://github.com/pnpm/pnpm.git
synced 2026-01-09 07:28:37 -05:00
fix: cross-device link not permitted when node-linker=hoisted (#5993)
close #5992
This commit is contained in:
5
.changeset/selfish-bears-matter.md
Normal file
5
.changeset/selfish-bears-matter.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/fs.hard-link-dir": patch
|
||||
---
|
||||
|
||||
Fall back to copying files if creating hard links fails with cross-device linking error [#5992](https://github.com/pnpm/pnpm/issues/5992).
|
||||
6
.changeset/wicked-owls-brush.md
Normal file
6
.changeset/wicked-owls-brush.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/fs.indexed-pkg-importer": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Fix "cross-device link not permitted" error when `node-linker` is set to `hoisted` [#5992](https://github.com/pnpm/pnpm/issues/5992).
|
||||
@@ -1,6 +1,6 @@
|
||||
# @pnpm/fs.hard-link-dir
|
||||
|
||||
> Hard link all files from a directory to several target directories.
|
||||
> Hard link (or copy if linking fails) all files from a directory to several target directories.
|
||||
|
||||
<!--@shields('npm')-->
|
||||
[](https://www.npmjs.com/package/@pnpm/fs.hard-link-dir)
|
||||
@@ -14,4 +14,4 @@ pnpm add @pnpm/fs.hard-link-dir
|
||||
|
||||
## License
|
||||
|
||||
MIT © [Zoltan Kochan](https://www.kochan.io)
|
||||
MIT
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@pnpm/fs.hard-link-dir",
|
||||
"version": "1.0.1",
|
||||
"description": "Hard link all files from a directory to several target directories.",
|
||||
"description": "Hard link (or copy if linking fails) all files from a directory to several target directories.",
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"lib",
|
||||
|
||||
@@ -28,11 +28,11 @@ export async function hardLinkDir (src: string, destDirs: string[]) {
|
||||
destDirs.map(async (destDir) => {
|
||||
const destFile = path.join(destDir, file)
|
||||
try {
|
||||
await fs.link(srcFile, destFile)
|
||||
await linkOrCopy(srcFile, destFile)
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (err.code === 'ENOENT') {
|
||||
await fs.mkdir(destDir, { recursive: true })
|
||||
await fs.link(srcFile, destFile)
|
||||
await linkOrCopy(srcFile, destFile)
|
||||
return
|
||||
}
|
||||
if (err.code !== 'EEXIST') {
|
||||
@@ -44,3 +44,16 @@ export async function hardLinkDir (src: string, destDirs: string[]) {
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* This function could be optimized because we don't really need to try linking again
|
||||
* if linking failed once.
|
||||
*/
|
||||
async function linkOrCopy (srcFile: string, destFile: string) {
|
||||
try {
|
||||
await fs.link(srcFile, destFile)
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (err.code !== 'EXDEV') throw err
|
||||
await fs.copyFile(srcFile, destFile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"@pnpm/core-loggers": "workspace:*",
|
||||
"@pnpm/store-controller-types": "workspace:*",
|
||||
"@zkochan/rimraf": "^2.1.2",
|
||||
"fs-extra": "^11.1.0",
|
||||
"make-empty-dir": "^2.0.0",
|
||||
"p-limit": "^3.1.0",
|
||||
"path-exists": "^4.0.0",
|
||||
@@ -27,7 +28,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@pnpm/fs.indexed-pkg-importer": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*"
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@types/fs-extra": "^9.0.13"
|
||||
},
|
||||
"directories": {
|
||||
"test": "test"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import { copy } from 'fs-extra'
|
||||
import path from 'path'
|
||||
import { globalWarn, logger } from '@pnpm/logger'
|
||||
import rimraf from '@zkochan/rimraf'
|
||||
@@ -118,7 +119,7 @@ function getUniqueFileMap (fileMap: Record<string, string>) {
|
||||
|
||||
async function moveOrMergeModulesDirs (src: string, dest: string) {
|
||||
try {
|
||||
await fs.rename(src, dest)
|
||||
await renameEvenAcrossDevices(src, dest)
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
switch (err.code) {
|
||||
case 'ENOENT':
|
||||
@@ -135,9 +136,18 @@ async function moveOrMergeModulesDirs (src: string, dest: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function renameEvenAcrossDevices (src: string, dest: string) {
|
||||
try {
|
||||
await fs.rename(src, dest)
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (err.code !== 'EXDEV') throw err
|
||||
await copy(src, dest)
|
||||
}
|
||||
}
|
||||
|
||||
async function mergeModulesDirs (src: string, dest: string) {
|
||||
const srcFiles = await fs.readdir(src)
|
||||
const destFiles = new Set(await fs.readdir(dest))
|
||||
const filesToMove = srcFiles.filter((file) => !destFiles.has(file))
|
||||
await Promise.all(filesToMove.map((file) => fs.rename(path.join(src, file), path.join(dest, file))))
|
||||
await Promise.all(filesToMove.map((file) => renameEvenAcrossDevices(path.join(src, file), path.join(dest, file))))
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ jest.mock('fs', () => {
|
||||
})
|
||||
jest.mock('path-temp', () => (dir: string) => path.join(dir, '_tmp'))
|
||||
jest.mock('rename-overwrite', () => jest.fn())
|
||||
jest.mock('fs-extra', () => ({
|
||||
copy: jest.fn(),
|
||||
}))
|
||||
const globalInfo = jest.fn()
|
||||
const globalWarn = jest.fn()
|
||||
const logger = jest.fn(() => ({ debug: jest.fn() }))
|
||||
|
||||
123
pnpm-lock.yaml
generated
123
pnpm-lock.yaml
generated
@@ -1500,6 +1500,9 @@ importers:
|
||||
'@zkochan/rimraf':
|
||||
specifier: ^2.1.2
|
||||
version: 2.1.2
|
||||
fs-extra:
|
||||
specifier: ^11.1.0
|
||||
version: 11.1.0
|
||||
make-empty-dir:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
@@ -1525,6 +1528,9 @@ importers:
|
||||
'@pnpm/prepare':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/prepare
|
||||
'@types/fs-extra':
|
||||
specifier: ^9.0.13
|
||||
version: 9.0.13
|
||||
|
||||
fs/read-modules-dir:
|
||||
dependencies:
|
||||
@@ -6598,15 +6604,15 @@ packages:
|
||||
'@commitlint/execute-rule': 17.4.0
|
||||
'@commitlint/resolve-extends': 17.4.0
|
||||
'@commitlint/types': 17.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
chalk: 4.1.2
|
||||
cosmiconfig: 8.0.0
|
||||
cosmiconfig-typescript-loader: 4.3.0(@types/node@14.18.36)(cosmiconfig@8.0.0)(ts-node@10.9.1)(typescript@4.9.4)
|
||||
cosmiconfig-typescript-loader: 4.3.0(@types/node@18.11.18)(cosmiconfig@8.0.0)(ts-node@10.9.1)(typescript@4.9.4)
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
lodash.uniq: 4.5.0
|
||||
resolve-from: 5.0.0
|
||||
ts-node: 10.9.1(@types/node@14.18.36)(typescript@4.9.4)
|
||||
ts-node: 10.9.1(@types/node@18.11.18)(typescript@4.9.4)
|
||||
typescript: 4.9.4
|
||||
transitivePeerDependencies:
|
||||
- '@swc/core'
|
||||
@@ -6973,7 +6979,7 @@ packages:
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
chalk: 4.1.2
|
||||
jest-message-util: 29.4.0
|
||||
jest-util: 29.4.0
|
||||
@@ -6994,14 +7000,14 @@ packages:
|
||||
'@jest/test-result': 29.4.0
|
||||
'@jest/transform': 29.4.0(@babel/types@7.20.7)
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.7.1
|
||||
exit: 0.1.2
|
||||
graceful-fs: 4.2.10
|
||||
jest-changed-files: 29.4.0
|
||||
jest-config: 29.4.0(@babel/types@7.20.7)(@types/node@14.18.36)(ts-node@10.9.1)
|
||||
jest-config: 29.4.0(@babel/types@7.20.7)(@types/node@18.11.18)(ts-node@10.9.1)
|
||||
jest-haste-map: 29.4.0
|
||||
jest-message-util: 29.4.0
|
||||
jest-regex-util: 29.2.0
|
||||
@@ -7029,7 +7035,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/fake-timers': 29.4.0
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
jest-mock: 29.4.0
|
||||
dev: true
|
||||
|
||||
@@ -7056,7 +7062,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/types': 29.4.0
|
||||
'@sinonjs/fake-timers': 10.0.2
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
jest-message-util: 29.4.0
|
||||
jest-mock: 29.4.0
|
||||
jest-util: 29.4.0
|
||||
@@ -7089,7 +7095,7 @@ packages:
|
||||
'@jest/transform': 29.4.0(@babel/types@7.20.7)
|
||||
'@jest/types': 29.4.0
|
||||
'@jridgewell/trace-mapping': 0.3.17
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
chalk: 4.1.2
|
||||
collect-v8-coverage: 1.0.1
|
||||
exit: 0.1.2
|
||||
@@ -7179,7 +7185,7 @@ packages:
|
||||
'@jest/schemas': 29.4.0
|
||||
'@types/istanbul-lib-coverage': 2.0.4
|
||||
'@types/istanbul-reports': 3.0.1
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
'@types/yargs': 17.0.20
|
||||
chalk: 4.1.2
|
||||
dev: true
|
||||
@@ -10501,7 +10507,7 @@ packages:
|
||||
object-assign: 4.1.1
|
||||
vary: 1.1.2
|
||||
|
||||
/cosmiconfig-typescript-loader@4.3.0(@types/node@14.18.36)(cosmiconfig@8.0.0)(ts-node@10.9.1)(typescript@4.9.4):
|
||||
/cosmiconfig-typescript-loader@4.3.0(@types/node@18.11.18)(cosmiconfig@8.0.0)(ts-node@10.9.1)(typescript@4.9.4):
|
||||
resolution: {integrity: sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
peerDependencies:
|
||||
@@ -10510,9 +10516,9 @@ packages:
|
||||
ts-node: '>=10'
|
||||
typescript: '>=3'
|
||||
dependencies:
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
cosmiconfig: 8.0.0
|
||||
ts-node: 10.9.1(@types/node@14.18.36)(typescript@4.9.4)
|
||||
ts-node: 10.9.1(@types/node@18.11.18)(typescript@4.9.4)
|
||||
typescript: 4.9.4
|
||||
dev: true
|
||||
|
||||
@@ -12843,7 +12849,7 @@ packages:
|
||||
'@jest/expect': 29.4.0
|
||||
'@jest/test-result': 29.4.0
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
chalk: 4.1.2
|
||||
co: 4.6.0
|
||||
dedent: 0.7.0
|
||||
@@ -12933,6 +12939,47 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/jest-config@29.4.0(@babel/types@7.20.7)(@types/node@18.11.18)(ts-node@10.9.1):
|
||||
resolution: {integrity: sha512-jtgd72nN4Mob4Oego3N/pLRVfR2ui1hv+yO6xR/SUi5G7NtZ/grr95BJ1qRSDYZshuA0Jw57fnttZHZKb04+CA==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
'@types/node': '*'
|
||||
ts-node: '>=9.0.0'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
ts-node:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/core': 7.20.12
|
||||
'@jest/test-sequencer': 29.4.0
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 18.11.18
|
||||
babel-jest: 29.4.0(@babel/core@7.20.12)(@babel/types@7.20.7)
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.7.1
|
||||
deepmerge: 4.2.2
|
||||
glob: 7.2.3
|
||||
graceful-fs: 4.2.10
|
||||
jest-circus: 29.4.0(@babel/types@7.20.7)
|
||||
jest-environment-node: 29.4.0
|
||||
jest-get-type: 29.2.0
|
||||
jest-regex-util: 29.2.0
|
||||
jest-resolve: 29.4.0
|
||||
jest-runner: 29.4.0(@babel/types@7.20.7)
|
||||
jest-util: 29.4.0
|
||||
jest-validate: 29.4.0
|
||||
micromatch: 4.0.5
|
||||
parse-json: 5.2.0
|
||||
pretty-format: 29.4.0
|
||||
slash: 3.0.0
|
||||
strip-json-comments: 3.1.1
|
||||
ts-node: 10.9.1(@types/node@14.18.36)(typescript@4.9.4)
|
||||
transitivePeerDependencies:
|
||||
- '@babel/types'
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/jest-diff@29.3.1:
|
||||
resolution: {integrity: sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
@@ -12978,7 +13025,7 @@ packages:
|
||||
'@jest/environment': 29.4.0
|
||||
'@jest/fake-timers': 29.4.0
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
jest-mock: 29.4.0
|
||||
jest-util: 29.4.0
|
||||
dev: true
|
||||
@@ -12994,7 +13041,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/types': 29.4.0
|
||||
'@types/graceful-fs': 4.1.6
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
anymatch: 3.1.3
|
||||
fb-watchman: 2.0.2
|
||||
graceful-fs: 4.2.10
|
||||
@@ -13045,7 +13092,7 @@ packages:
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
jest-util: 29.4.0
|
||||
dev: true
|
||||
|
||||
@@ -13100,7 +13147,7 @@ packages:
|
||||
'@jest/test-result': 29.4.0
|
||||
'@jest/transform': 29.4.0(@babel/types@7.20.7)
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
chalk: 4.1.2
|
||||
emittery: 0.13.1
|
||||
graceful-fs: 4.2.10
|
||||
@@ -13132,7 +13179,7 @@ packages:
|
||||
'@jest/test-result': 29.4.0
|
||||
'@jest/transform': 29.4.0(@babel/types@7.20.7)
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
chalk: 4.1.2
|
||||
cjs-module-lexer: 1.2.2
|
||||
collect-v8-coverage: 1.0.1
|
||||
@@ -13190,7 +13237,7 @@ packages:
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.7.1
|
||||
graceful-fs: 4.2.10
|
||||
@@ -13215,7 +13262,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/test-result': 29.4.0
|
||||
'@jest/types': 29.4.0
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
emittery: 0.13.1
|
||||
@@ -13227,7 +13274,7 @@ packages:
|
||||
resolution: {integrity: sha512-dICMQ+Q4W0QVMsaQzWlA1FVQhKNz7QcDCOGtbk1GCAd0Lai+wdkQvfmQwL4MjGumineh1xz+6M5oMj3rfWS02A==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@types/node': 14.18.36
|
||||
'@types/node': 18.11.18
|
||||
jest-util: 29.4.0
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
@@ -14438,6 +14485,7 @@ packages:
|
||||
|
||||
/npmlog@4.1.2:
|
||||
resolution: {integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
are-we-there-yet: 1.1.7
|
||||
console-control-strings: 1.1.0
|
||||
@@ -16573,6 +16621,37 @@ packages:
|
||||
yn: 3.1.1
|
||||
dev: true
|
||||
|
||||
/ts-node@10.9.1(@types/node@18.11.18)(typescript@4.9.4):
|
||||
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@swc/core': '>=1.2.50'
|
||||
'@swc/wasm': '>=1.2.50'
|
||||
'@types/node': '*'
|
||||
typescript: '>=2.7'
|
||||
peerDependenciesMeta:
|
||||
'@swc/core':
|
||||
optional: true
|
||||
'@swc/wasm':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@tsconfig/node10': 1.0.9
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.3
|
||||
'@types/node': 18.11.18
|
||||
acorn: 8.8.2
|
||||
acorn-walk: 8.2.0
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
diff: 4.0.2
|
||||
make-error: 1.3.6
|
||||
typescript: 4.9.4
|
||||
v8-compile-cache-lib: 3.0.1
|
||||
yn: 3.1.1
|
||||
dev: true
|
||||
|
||||
/ts-toolbelt@6.15.5:
|
||||
resolution: {integrity: sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==}
|
||||
dev: true
|
||||
|
||||
Reference in New Issue
Block a user