From 97ba101c39a2d24ea7d7088585cfff323bf9397b Mon Sep 17 00:00:00 2001 From: Thomas Dy Date: Wed, 31 May 2023 08:57:49 +0900 Subject: [PATCH 1/2] fix(fslib): allow symlinks in MountFS --- .yarn/versions/757578fa.yml | 37 +++++++++++++++++++++++ packages/yarnpkg-fslib/sources/MountFS.ts | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 .yarn/versions/757578fa.yml diff --git a/.yarn/versions/757578fa.yml b/.yarn/versions/757578fa.yml new file mode 100644 index 000000000000..6654e34b4500 --- /dev/null +++ b/.yarn/versions/757578fa.yml @@ -0,0 +1,37 @@ +releases: + "@yarnpkg/builder": patch + "@yarnpkg/cli": patch + "@yarnpkg/core": patch + "@yarnpkg/doctor": patch + "@yarnpkg/extensions": patch + "@yarnpkg/fslib": minor + "@yarnpkg/libzip": patch + "@yarnpkg/nm": patch + "@yarnpkg/plugin-compat": patch + "@yarnpkg/plugin-constraints": patch + "@yarnpkg/plugin-dlx": patch + "@yarnpkg/plugin-essentials": patch + "@yarnpkg/plugin-exec": patch + "@yarnpkg/plugin-file": patch + "@yarnpkg/plugin-git": patch + "@yarnpkg/plugin-github": patch + "@yarnpkg/plugin-http": patch + "@yarnpkg/plugin-init": patch + "@yarnpkg/plugin-interactive-tools": patch + "@yarnpkg/plugin-link": patch + "@yarnpkg/plugin-nm": patch + "@yarnpkg/plugin-npm": patch + "@yarnpkg/plugin-npm-cli": patch + "@yarnpkg/plugin-pack": patch + "@yarnpkg/plugin-patch": patch + "@yarnpkg/plugin-pnp": patch + "@yarnpkg/plugin-pnpm": patch + "@yarnpkg/plugin-stage": patch + "@yarnpkg/plugin-typescript": patch + "@yarnpkg/plugin-version": patch + "@yarnpkg/plugin-workspace-tools": patch + "@yarnpkg/pnp": patch + "@yarnpkg/pnpify": patch + "@yarnpkg/sdks": patch + "@yarnpkg/shell": patch + vscode-zipfs: patch diff --git a/packages/yarnpkg-fslib/sources/MountFS.ts b/packages/yarnpkg-fslib/sources/MountFS.ts index 90ea4c94048c..5732abda4b6e 100644 --- a/packages/yarnpkg-fslib/sources/MountFS.ts +++ b/packages/yarnpkg-fslib/sources/MountFS.ts @@ -1013,7 +1013,7 @@ export class MountFS extends BasePortableFakeFS { continue; try { - if (this.typeCheck !== null && (this.baseFs.lstatSync(filePath).mode & constants.S_IFMT) !== this.typeCheck) { + if (this.typeCheck !== null && (this.baseFs.statSync(filePath).mode & constants.S_IFMT) !== this.typeCheck) { this.notMount.add(filePath); continue; } From 870da4646b3e38f6e88f71f3959b68a5369299a1 Mon Sep 17 00:00:00 2001 From: Thomas Dy Date: Fri, 2 Jun 2023 10:08:07 +0900 Subject: [PATCH 2/2] test: ensure symlink zips work --- .../sources/commands/install.test.ts | 27 ++++++++++++++++++ .../pkg-tests-specs/sources/pnp.test.js | 27 ++++++++++++++++++ .../yarnpkg-libzip/tests/ZipOpenFS.test.ts | 13 +++++++++ .../tests/fixtures/symlink-source.zip | Bin 0 -> 154 bytes .../yarnpkg-libzip/tests/fixtures/symlink.zip | 1 + 5 files changed, 68 insertions(+) create mode 100644 packages/yarnpkg-libzip/tests/fixtures/symlink-source.zip create mode 120000 packages/yarnpkg-libzip/tests/fixtures/symlink.zip diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts b/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts index 345eb98a2545..cf0134f01c6c 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts +++ b/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts @@ -109,6 +109,33 @@ describe(`Commands`, () => { }), ); + tests.testIf( + () => process.platform !== `win32`, + `it should install from zips that are symlinks`, + makeTemporaryEnv({ + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }, async ({path, run, source}) => { + await run(`install`); + + const allFiles = await xfs.readdirPromise(ppath.join(path, `.yarn/cache`)); + const zipFiles = allFiles.filter(file => file.endsWith(`.zip`)); + + await xfs.mkdirPromise(ppath.join(path, `store`)); + for (const filename of zipFiles) { + const zipFile = ppath.join(path, `.yarn/cache`, filename); + const storePath = ppath.join(path, `store`, filename); + await xfs.movePromise(zipFile, storePath); + await xfs.symlinkPromise(storePath, zipFile); + } + + await xfs.removePromise(ppath.join(path, Filename.pnpCjs)); + + await run(`install`, `--immutable`); + }), + ); + test( `it should refuse to create a lockfile when using --immutable`, makeTemporaryEnv({ diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/pnp.test.js b/packages/acceptance-tests/pkg-tests-specs/sources/pnp.test.js index e19584439a89..f8dd453a089a 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/pnp.test.js +++ b/packages/acceptance-tests/pkg-tests-specs/sources/pnp.test.js @@ -2253,4 +2253,31 @@ describe(`Plug'n'Play`, () => { }); }), ); + + testIf( + () => process.platform !== `win32`, + `it can resolve files from zips that are symlinks`, + makeTemporaryEnv({ + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }, async ({path, run, source}) => { + await run(`install`); + + const allFiles = await xfs.readdirPromise(ppath.join(path, `.yarn/cache`)); + const zipFiles = allFiles.filter(file => file.endsWith(`.zip`)); + + await xfs.mkdirPromise(ppath.join(path, `store`)); + for (const filename of zipFiles) { + const zipFile = ppath.join(path, `.yarn/cache`, filename); + const storePath = ppath.join(path, `store`, filename); + await xfs.movePromise(zipFile, storePath); + await xfs.symlinkPromise(storePath, zipFile); + } + + await expect( + source(`require('no-deps')`), + ).resolves.toEqual({name: `no-deps`, version: `1.0.0`}); + }), + ); }); diff --git a/packages/yarnpkg-libzip/tests/ZipOpenFS.test.ts b/packages/yarnpkg-libzip/tests/ZipOpenFS.test.ts index 216251432aef..a1e7e3386dc3 100644 --- a/packages/yarnpkg-libzip/tests/ZipOpenFS.test.ts +++ b/packages/yarnpkg-libzip/tests/ZipOpenFS.test.ts @@ -13,10 +13,15 @@ export const ZIP_DIR3 = ppath.join( npath.toPortablePath(__dirname), `fixtures/foo.hiddenzip` as Filename, ); +export const ZIP_DIR4 = ppath.join( + npath.toPortablePath(__dirname), + `fixtures/symlink.zip` as Filename, +); export const ZIP_FILE1 = ppath.join(ZIP_DIR1, `foo.txt`); export const ZIP_FILE2 = ppath.join(ZIP_DIR2, `foo.txt`); export const ZIP_FILE3 = ppath.join(ZIP_DIR3, `foo.txt`); +export const ZIP_FILE4 = ppath.join(ZIP_DIR4, `foo.txt`); afterEach(() => { jest.useRealTimers(); @@ -81,6 +86,14 @@ describe(`ZipOpenFS`, () => { fs.discardAndClose(); }); + it(`can read from a zip file that's a symlink`, () => { + const fs = new ZipOpenFS(); + + expect(fs.readFileSync(ZIP_FILE4, `utf8`)).toEqual(`foo\n`); + + fs.discardAndClose(); + }); + it(`doesn't close a ZipFS instance with open handles`, () => { const fs = new ZipOpenFS({maxOpenFiles: 1}); diff --git a/packages/yarnpkg-libzip/tests/fixtures/symlink-source.zip b/packages/yarnpkg-libzip/tests/fixtures/symlink-source.zip new file mode 100644 index 0000000000000000000000000000000000000000..b93c88559ed342fc378d682fd2c8e391bf7df63d GIT binary patch literal 154 zcmWIWW@Zs#U|`^2h?;&WU`47?9UG9x0>tb