@pnpm/lockfile.fs 1100.2.4 → 1100.2.6

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,32 @@
1
1
  # @pnpm/lockfile-file
2
2
 
3
+ ## 1100.2.6
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed `pnpm install` failing with `ERR_PNPM_LOCKFILE_IS_SYMLINK` in a project with config dependencies when `pnpm-lock.yaml` is a symlink, as build sandboxes such as Bazel and Nix stage it. pnpm no longer rewrites the lockfile when the recorded config dependencies are unchanged. Writing changed config dependencies through a symlinked lockfile is still refused. A lockfile that starts with a byte order mark now keeps its main document when its config dependencies are updated [#14372](https://github.com/pnpm/pnpm/issues/14372).
8
+
9
+ - `pnpm install` no longer lets a symlink swapped into the path of `pnpm-lock.yaml` during a config dependency update redirect the lockfile write to the symlink target [pnpm/pnpm#14322](https://github.com/pnpm/pnpm/issues/14322).
10
+
11
+ - `pnpm install` now relinks workspace packages when `publishConfig.linkDirectory` changes. Frozen installs report an outdated lockfile until it is regenerated [pnpm/pnpm#14488](https://github.com/pnpm/pnpm/issues/14488).
12
+
13
+ - Updated dependencies:
14
+ - @pnpm/error@1100.1.4
15
+ - @pnpm/lockfile.merger@1100.0.22
16
+ - @pnpm/lockfile.types@1100.1.1
17
+ - @pnpm/lockfile.utils@1102.1.1
18
+
19
+ ## 1100.2.5
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies:
24
+ - @pnpm/deps.path@1101.0.1
25
+ - @pnpm/lockfile.merger@1100.0.21
26
+ - @pnpm/lockfile.types@1100.1.0
27
+ - @pnpm/lockfile.utils@1102.1.0
28
+ - @pnpm/types@1102.1.0
29
+
3
30
  ## 1100.2.4
4
31
 
5
32
  ### Patch Changes
@@ -1,4 +1,8 @@
1
1
  import type { EnvLockfile } from '@pnpm/lockfile.types';
2
2
  export declare function createEnvLockfile(): EnvLockfile;
3
3
  export declare function readEnvLockfile(rootDir: string): Promise<EnvLockfile | null>;
4
+ /**
5
+ * Replaces the env document that leads `pnpm-lock.yaml`, preserving the main
6
+ * document after it. An unchanged document is not rewritten.
7
+ */
4
8
  export declare function writeEnvLockfile(rootDir: string, lockfile: EnvLockfile): Promise<void>;
@@ -1,10 +1,9 @@
1
1
  import path from 'node:path';
2
2
  import { LOCKFILE_VERSION, WANTED_LOCKFILE } from '@pnpm/constants';
3
3
  import yaml from 'js-yaml';
4
- import writeFileAtomic from 'write-file-atomic';
5
4
  import { sortLockfileKeys } from './sortLockfileKeys.js';
6
- import { lockfileYamlDump } from './write.js';
7
- import { extractMainDocument, readLockfileToStringNoFollow, streamReadFirstYamlDocument } from './yamlDocuments.js';
5
+ import { lockfileYamlDump, writeWantedLockfileAtomic } from './write.js';
6
+ import { extractMainDocument, readLockfileToString, streamReadFirstYamlDocument, YAML_DOCUMENT_SEPARATOR, YAML_DOCUMENT_START, } from './yamlDocuments.js';
8
7
  export function createEnvLockfile() {
9
8
  return {
10
9
  lockfileVersion: LOCKFILE_VERSION,
@@ -49,13 +48,19 @@ export async function readEnvLockfile(rootDir) {
49
48
  }
50
49
  return envLockfile;
51
50
  }
51
+ /**
52
+ * Replaces the env document that leads `pnpm-lock.yaml`, preserving the main
53
+ * document after it. An unchanged document is not rewritten.
54
+ */
52
55
  export async function writeEnvLockfile(rootDir, lockfile) {
53
56
  const lockfilePath = path.join(rootDir, WANTED_LOCKFILE);
54
57
  const sorted = sortLockfileKeys(lockfile);
55
58
  const envYaml = lockfileYamlDump(sorted);
56
- const existing = await readLockfileToStringNoFollow(lockfilePath);
59
+ const existing = await readLockfileToString(lockfilePath);
57
60
  const mainDoc = existing == null ? '' : extractMainDocument(existing);
58
- const combined = `---\n${envYaml}\n---\n${mainDoc}`;
59
- return writeFileAtomic(lockfilePath, combined);
61
+ const combined = `${YAML_DOCUMENT_START}${envYaml}${YAML_DOCUMENT_SEPARATOR}${mainDoc}`;
62
+ if (existing === combined)
63
+ return;
64
+ await writeWantedLockfileAtomic(lockfilePath, combined);
60
65
  }
61
66
  //# sourceMappingURL=envLockfile.js.map
@@ -63,6 +63,9 @@ function normalizeLockfile(lockfile) {
63
63
  if (importer.publishDirectory) {
64
64
  normalizedImporter.publishDirectory = importer.publishDirectory;
65
65
  }
66
+ if (importer.linkDirectory === false) {
67
+ normalizedImporter.linkDirectory = false;
68
+ }
66
69
  return normalizedImporter;
67
70
  }, lockfile.importers ?? {}),
68
71
  };
package/lib/write.d.ts CHANGED
@@ -13,6 +13,12 @@ export declare function writeWantedLockfile(pkgPath: string, wantedLockfile: Loc
13
13
  lockfileName?: string;
14
14
  }): Promise<LockfileObject>;
15
15
  export declare function writeCurrentLockfile(virtualStoreDir: string, currentLockfile: LockfileObject): Promise<LockfileObject | undefined>;
16
+ /**
17
+ * Publishes with `rename`, not the `write-file-atomic` used elsewhere here:
18
+ * `rename` never resolves the final path component, so a symlink swapped in
19
+ * after {@link ensureLockfileIsNotSymlink} cannot redirect the write.
20
+ */
21
+ export declare function writeWantedLockfileAtomic(lockfilePath: string, content: string): Promise<void>;
16
22
  export declare function writeLockfileFile(lockfilePath: string, wantedLockfile: LockfileFile): Promise<void>;
17
23
  export declare function isEmptyLockfile(lockfile: LockfileObject): boolean;
18
24
  export interface WriteLockfilesResult {
package/lib/write.js CHANGED
@@ -76,7 +76,7 @@ async function writeLockfileDoc(lockfilePath, lockfileName, mainDoc) {
76
76
  * `rename` never resolves the final path component, so a symlink swapped in
77
77
  * after {@link ensureLockfileIsNotSymlink} cannot redirect the write.
78
78
  */
79
- async function writeWantedLockfileAtomic(lockfilePath, content) {
79
+ export async function writeWantedLockfileAtomic(lockfilePath, content) {
80
80
  await ensureLockfileIsNotSymlink(lockfilePath);
81
81
  const targetStat = await fs.lstat(lockfilePath).catch((error) => {
82
82
  if (error.code === 'ENOENT')
@@ -8,7 +8,6 @@ export declare const YAML_DOCUMENT_START = "---\n";
8
8
  */
9
9
  export declare function streamReadFirstYamlDocument(filePath: string, readBufferSize?: number): Promise<string | null>;
10
10
  export declare function readLockfileToString(filePath: string): Promise<string | null>;
11
- export declare function readLockfileToStringNoFollow(filePath: string): Promise<string | null>;
12
11
  /**
13
12
  * Refuses a symlinked lockfile before a write, which would land on the link's
14
13
  * target — any file the user can write. Reads may follow it: sandboxes stage
@@ -7,7 +7,6 @@ import stripBom from 'strip-bom';
7
7
  export const YAML_DOCUMENT_SEPARATOR = '\n---\n';
8
8
  export const YAML_DOCUMENT_START = '---\n';
9
9
  const READ_BUFFER_SIZE = 64 * 1024;
10
- const LOCKFILE_READ_FLAGS = constants.O_RDONLY | (process.platform === 'win32' ? 0 : constants.O_NOFOLLOW);
11
10
  /**
12
11
  * Reads the first YAML document from a multi-document YAML file using streaming.
13
12
  * The file must start with "---\n" to indicate it contains an env lockfile document.
@@ -74,34 +73,6 @@ export async function readLockfileToString(filePath) {
74
73
  throw err;
75
74
  }
76
75
  }
77
- export async function readLockfileToStringNoFollow(filePath) {
78
- let fileHandle;
79
- try {
80
- fileHandle = await openLockfileNoFollow(filePath);
81
- return await fileHandle.readFile('utf8');
82
- }
83
- catch (err) {
84
- if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
85
- return null;
86
- }
87
- throw err;
88
- }
89
- finally {
90
- await fileHandle?.close().catch(() => { });
91
- }
92
- }
93
- async function openLockfileNoFollow(filePath) {
94
- await ensureLockfileIsNotSymlink(filePath);
95
- try {
96
- return await open(filePath, LOCKFILE_READ_FLAGS);
97
- }
98
- catch (err) {
99
- if (util.types.isNativeError(err) && 'code' in err && err.code === 'ELOOP') {
100
- throw symlinkedLockfileError(filePath);
101
- }
102
- throw err;
103
- }
104
- }
105
76
  /**
106
77
  * Refuses a symlinked lockfile before a write, which would land on the link's
107
78
  * target — any file the user can write. Reads may follow it: sandboxes stage
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/lockfile.fs",
3
- "version": "1100.2.4",
3
+ "version": "1100.2.6",
4
4
  "description": "Read/write pnpm-lock.yaml files",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -30,14 +30,14 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "@pnpm/constants": "1102.0.0",
33
- "@pnpm/deps.path": "1101.0.0",
34
- "@pnpm/error": "1100.1.3",
35
- "@pnpm/lockfile.merger": "1100.0.20",
36
- "@pnpm/lockfile.types": "1100.0.20",
37
- "@pnpm/lockfile.utils": "1102.0.0",
33
+ "@pnpm/deps.path": "1101.0.1",
34
+ "@pnpm/error": "1100.1.4",
35
+ "@pnpm/lockfile.merger": "1100.0.22",
36
+ "@pnpm/lockfile.types": "1100.1.1",
37
+ "@pnpm/lockfile.utils": "1102.1.1",
38
38
  "@pnpm/network.git-utils": "1100.0.3",
39
39
  "@pnpm/object.key-sorting": "1100.0.2",
40
- "@pnpm/types": "1102.0.0",
40
+ "@pnpm/types": "1102.1.0",
41
41
  "@zkochan/rimraf": "^4.0.0",
42
42
  "comver-to-semver": "^2.0.0",
43
43
  "js-yaml": "npm:@zkochan/js-yaml@0.0.11",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@jest/globals": "30.4.1",
55
- "@pnpm/lockfile.fs": "1100.2.4",
55
+ "@pnpm/lockfile.fs": "1100.2.6",
56
56
  "@pnpm/logger": "1100.0.0",
57
57
  "@types/js-yaml": "^4.0.9",
58
58
  "@types/normalize-path": "^3.0.2",