@pnpm/workspace.injected-deps-syncer 1100.0.37 → 1100.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @pnpm/workspace.injected-deps-syncer
2
2
 
3
+ ## 1100.0.39
4
+
5
+ ### Patch Changes
6
+
7
+ - `syncInjectedDepsAfterScripts` now copies files into injected dependencies when `node_modules` is on another filesystem than the package sources. The sync previously failed with a cross-device link error and made the script run exit with an error [pnpm/pnpm#14703](https://github.com/pnpm/pnpm/issues/14703).
8
+
9
+ - Fixed injected workspace dependency synchronization failing with `EPERM` on Windows when removing nested directories.
10
+
11
+ - Updated dependencies:
12
+ - @pnpm/bins.linker@1100.0.33
13
+ - @pnpm/bins.remover@1100.0.25
14
+ - @pnpm/bins.resolver@1100.0.17
15
+ - @pnpm/error@1100.2.0
16
+ - @pnpm/fetching.directory-fetcher@1100.0.35
17
+ - @pnpm/fs.graceful-fs@1100.2.3
18
+ - @pnpm/installing.modules-yaml@1101.0.4
19
+ - @pnpm/pkg-manifest.reader@1100.0.20
20
+ - @pnpm/types@1102.1.1
21
+ - @pnpm/workspace.projects-reader@1101.1.0
22
+
23
+ ## 1100.0.38
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies:
28
+ - @pnpm/bins.linker@1100.0.32
29
+ - @pnpm/bins.remover@1100.0.24
30
+ - @pnpm/fetching.directory-fetcher@1100.0.34
31
+ - @pnpm/installing.modules-yaml@1101.0.3
32
+ - @pnpm/workspace.projects-reader@1101.0.28
33
+
3
34
  ## 1100.0.37
4
35
 
5
36
  ### Patch Changes
package/lib/DirPatcher.js CHANGED
@@ -2,6 +2,8 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import util from 'node:util';
4
4
  import { fetchFromDir } from '@pnpm/fetching.directory-fetcher';
5
+ import { renameFileWithRetry } from '@pnpm/fs.graceful-fs';
6
+ import { pathTemp } from 'path-temp';
5
7
  export const DIR = Symbol('Path is a directory');
6
8
  // length comparison should place every directory before the files it contains because
7
9
  // a directory path is always shorter than any file path it contains
@@ -39,12 +41,41 @@ export async function applyPatch(optimizedDirPatch, sourceDir, targetDir) {
39
41
  }
40
42
  else if (typeof value === 'string') {
41
43
  fs.mkdirSync(path.dirname(targetPath), { recursive: true });
42
- await retryOverBlockingInode(targetPath, async () => fs.promises.link(sourcePath, targetPath));
44
+ await retryOverBlockingInode(targetPath, async () => linkOrCopy(sourcePath, targetPath));
43
45
  }
44
46
  else {
45
47
  const _ = value; // static type guard
46
48
  }
47
49
  }
50
+ async function linkOrCopy(sourcePath, targetPath) {
51
+ try {
52
+ await fs.promises.link(sourcePath, targetPath);
53
+ }
54
+ catch (error) {
55
+ if (util.types.isNativeError(error) && 'code' in error && error.code === 'EXDEV') {
56
+ await copyIntoPlace(sourcePath, targetPath);
57
+ return;
58
+ }
59
+ throw error;
60
+ }
61
+ }
62
+ /**
63
+ * Copy through a temp sibling, so that a reader of the target never sees a
64
+ * partial copy. The rename replaces a symlink at the target without following
65
+ * it.
66
+ */
67
+ async function copyIntoPlace(sourcePath, targetPath) {
68
+ // A random name, since concurrent syncs share the thread that writes it.
69
+ const tempPath = pathTemp(path.dirname(targetPath));
70
+ try {
71
+ await fs.promises.copyFile(sourcePath, tempPath, fs.constants.COPYFILE_EXCL);
72
+ renameFileWithRetry(tempPath, targetPath);
73
+ }
74
+ catch (error) {
75
+ await fs.promises.rm(tempPath, { force: true });
76
+ throw error;
77
+ }
78
+ }
48
79
  /**
49
80
  * The target may hold an inode that {@link extendFilesMap} skips — a FIFO, a
50
81
  * socket, a device. The diff cannot see it, so it is never scheduled for
@@ -93,9 +124,9 @@ export async function applyPatch(optimizedDirPatch, sourceDir, targetDir) {
93
124
  // files a sibling had already linked. A path the target holds as a file and
94
125
  // the source as a directory lands in `modified` rather than `added`, so both
95
126
  // arrays feed the directory pass.
96
- await Promise.all(optimizedDirPatch.removed.map(async (item) => {
97
- await removeRecursive(path.join(targetDir, item.path));
98
- }));
127
+ for (const item of optimizedDirPatch.removed) {
128
+ await removeRecursive(path.join(targetDir, item.path)); // eslint-disable-line no-await-in-loop
129
+ }
99
130
  for (const item of newDirs) {
100
131
  await applyChange(item); // eslint-disable-line no-await-in-loop
101
132
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/workspace.injected-deps-syncer",
3
- "version": "1100.0.37",
3
+ "version": "1100.0.39",
4
4
  "description": "Update all injected replica of a workspace package",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -27,18 +27,20 @@
27
27
  "!*.map"
28
28
  ],
29
29
  "dependencies": {
30
- "@pnpm/bins.linker": "1100.0.31",
31
- "@pnpm/bins.remover": "1100.0.23",
32
- "@pnpm/bins.resolver": "1100.0.16",
33
- "@pnpm/error": "1100.1.4",
34
- "@pnpm/fetching.directory-fetcher": "1100.0.33",
35
- "@pnpm/installing.modules-yaml": "1101.0.2",
36
- "@pnpm/pkg-manifest.reader": "1100.0.19",
30
+ "@pnpm/bins.linker": "1100.0.33",
31
+ "@pnpm/bins.remover": "1100.0.25",
32
+ "@pnpm/bins.resolver": "1100.0.17",
33
+ "@pnpm/error": "1100.2.0",
34
+ "@pnpm/fetching.directory-fetcher": "1100.0.35",
35
+ "@pnpm/fs.graceful-fs": "1100.2.3",
36
+ "@pnpm/installing.modules-yaml": "1101.0.4",
37
+ "@pnpm/pkg-manifest.reader": "1100.0.20",
37
38
  "@pnpm/text.ordinal-comparator": "1100.0.0",
38
- "@pnpm/types": "1102.1.0",
39
- "@pnpm/workspace.projects-reader": "1101.0.27",
39
+ "@pnpm/types": "1102.1.1",
40
+ "@pnpm/workspace.projects-reader": "1101.1.0",
40
41
  "@types/normalize-path": "^3.0.2",
41
- "normalize-path": "^3.0.0"
42
+ "normalize-path": "^3.0.0",
43
+ "path-temp": "^3.0.0"
42
44
  },
43
45
  "peerDependencies": {
44
46
  "@pnpm/logger": "^1100.0.0"
@@ -46,8 +48,8 @@
46
48
  "devDependencies": {
47
49
  "@jest/globals": "30.4.1",
48
50
  "@pnpm/logger": "1100.0.0",
49
- "@pnpm/prepare": "1100.0.30",
50
- "@pnpm/workspace.injected-deps-syncer": "1100.0.37",
51
+ "@pnpm/prepare": "1100.0.32",
52
+ "@pnpm/workspace.injected-deps-syncer": "1100.0.39",
51
53
  "@types/is-windows": "^1.0.2",
52
54
  "is-windows": "^1.0.2"
53
55
  },