feat: reduce directory nesting in virtual store directory (#3117)

ref #3115
This commit is contained in:
Zoltan Kochan
2021-02-02 03:32:52 +02:00
parent 66f96b457e
commit f2bb5cbeba
8 changed files with 57 additions and 38 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/constants": major
---
Bump layout version to 5.

View File

@@ -0,0 +1,6 @@
---
"dependency-path": major
"pnpm": major
---
All packages inside the virtual store directory should be on the same depth. Instead of subdirectories, one directory is used with # instead of slashes.

View File

@@ -2,6 +2,6 @@ export const WANTED_LOCKFILE = 'pnpm-lock.yaml'
export const LOCKFILE_VERSION = 5.2
export const ENGINE_NAME = `${process.platform}-${process.arch}-node-${process.version.split('.')[0]}`
export const LAYOUT_VERSION = 4
export const LAYOUT_VERSION = 5
export const WORKSPACE_MANIFEST_FILENAME = 'pnpm-workspace.yaml'

View File

@@ -1,4 +1,5 @@
import { Registries } from '@pnpm/types'
import crypto = require('crypto')
import encodeRegistry = require('encode-registry')
import normalize = require('normalize-path')
import path = require('path')
@@ -130,6 +131,14 @@ export function parse (dependencyPath: string) {
}
export function depPathToFilename (depPath: string, lockfileDir: string) {
const filename = depPathToFilenameUnescaped(depPath, lockfileDir).replace(/\//g, '#')
if (filename.length > 120) {
return `${filename.substring(0, 50)}_${crypto.createHash('md5').update(filename).digest('hex')}`
}
return filename
}
function depPathToFilenameUnescaped (depPath: string, lockfileDir: string) {
if (depPath.indexOf('file:') !== 0) {
if (depPath.startsWith('/')) {
depPath = depPath.substring(1)
@@ -139,6 +148,5 @@ export function depPathToFilename (depPath: string, lockfileDir: string) {
}
const absolutePath = normalize(path.join(lockfileDir, depPath.slice(5)))
const lastSlash = absolutePath.lastIndexOf('/')
return `local/${encodeURIComponent(absolutePath.substr(0, lastSlash + 1))}${absolutePath.substr(lastSlash + 1)}`
return `local#${absolutePath}`
}

View File

@@ -120,9 +120,11 @@ test('resolve()', () => {
test('depPathToFilename()', () => {
expect(depPathToFilename('/foo/1.0.0', process.cwd())).toBe('foo@1.0.0')
expect(depPathToFilename('/@foo/bar/1.0.0', process.cwd())).toBe('@foo/bar@1.0.0')
expect(depPathToFilename('github.com/something/foo/0000', process.cwd())).toBe('github.com/something/foo@0000')
expect(depPathToFilename('/@foo/bar/1.0.0', process.cwd())).toBe('@foo#bar@1.0.0')
expect(depPathToFilename('github.com/something/foo/0000', process.cwd())).toBe('github.com#something#foo@0000')
const filename = depPathToFilename('file:./test/foo-1.0.0.tgz_foo@2.0.0', process.cwd())
expect(filename).toMatch(/%2Ffoo-1.0.0.tgz_foo@2.0.0$/)
expect(filename).toMatch(/^local#.*#foo-1\.0\.0\.tgz_foo@2\.0\.0$/)
expect(depPathToFilename('abcd/'.repeat(200), process.cwd())).toBe('abcd#abcd#abcd#abcd#abcd#abcd#abcd#abcd#abcd#abcd#_36cae148b21d1f0b46577e42f8f4dbae')
})

View File

@@ -5,28 +5,23 @@ Object {
"entries": Object {
".pnpm": Object {
"entries": Object {
"@zkochan": Object {
"@zkochan#git-config@0.1.0": Object {
"entries": Object {
"git-config@0.1.0": Object {
"node_modules": Object {
"entries": Object {
"node_modules": Object {
"@zkochan": Object {
"entries": Object {
"@zkochan": Object {
"entries": Object {
"git-config": Object {
"depPath": "/@zkochan/git-config/0.1.0",
"entryType": "index",
},
},
"entryType": "directory",
},
"ini": Object {
"entryType": "symlink",
"target": "../../../ini@1.3.8/node_modules/ini",
"git-config": Object {
"depPath": "/@zkochan/git-config/0.1.0",
"entryType": "index",
},
},
"entryType": "directory",
},
"ini": Object {
"entryType": "symlink",
"target": "../../ini@1.3.8/node_modules/ini",
},
},
"entryType": "directory",
},
@@ -68,7 +63,7 @@ Object {
"entries": Object {
"git-config": Object {
"entryType": "symlink",
"target": "./.pnpm/@zkochan/git-config@0.1.0/node_modules/@zkochan/git-config",
"target": "./.pnpm/@zkochan#git-config@0.1.0/node_modules/@zkochan/git-config",
},
},
"entryType": "directory",

View File

@@ -26,7 +26,7 @@ describe('FUSE handlers', () => {
handlers.readdir('/.pnpm', (returnCode, files) => {
expect(returnCode).toBe(0)
expect(files!.sort()).toStrictEqual([
'@zkochan',
'@zkochan#git-config@0.1.0',
'ini@1.3.8',
'is-positive@1.0.0',
].sort())
@@ -39,11 +39,11 @@ describe('FUSE handlers', () => {
expect(returnCode).toBe(0)
expect(files).toStrictEqual(['is-positive'])
})
handlers.readdir('/.pnpm/@zkochan/git-config@0.1.0/node_modules/@zkochan', (returnCode, files) => {
handlers.readdir('/.pnpm/@zkochan#git-config@0.1.0/node_modules/@zkochan', (returnCode, files) => {
expect(returnCode).toBe(0)
expect(files).toStrictEqual(['git-config'])
})
handlers.readdir('/.pnpm/@zkochan/git-config@0.1.0/node_modules/@zkochan/git-config', (returnCode, files) => {
handlers.readdir('/.pnpm/@zkochan#git-config@0.1.0/node_modules/@zkochan/git-config', (returnCode, files) => {
expect(returnCode).toBe(0)
expect(files!.sort()).toStrictEqual([
'package.json',
@@ -57,14 +57,14 @@ describe('FUSE handlers', () => {
'index.js',
].sort())
})
handlers.readdir('/.pnpm/@zkochan/git-config@0.1.0/node_modules/@zkochan/git-config/test', (returnCode, files) => {
handlers.readdir('/.pnpm/@zkochan#git-config@0.1.0/node_modules/@zkochan/git-config/test', (returnCode, files) => {
expect(returnCode).toBe(0)
expect(files!.sort()).toStrictEqual([
'index.js',
'fixtures',
].sort())
})
handlers.readdir('/.pnpm/@zkochan/git-config@0.1.0/node_modules/@zkochan/git-config/does-not-exist', (returnCode, files) => {
handlers.readdir('/.pnpm/@zkochan#git-config@0.1.0/node_modules/@zkochan/git-config/does-not-exist', (returnCode, files) => {
expect(returnCode).toBe(Fuse.ENOENT)
})
handlers.readdir('/.pnpm/is-positive@1.0.0/node_modules/is-positive', (returnCode, files) => {
@@ -76,20 +76,20 @@ describe('FUSE handlers', () => {
'readme.md',
].sort())
})
handlers.readdir('/.pnpm/@zkochan/git-config@0.1.0/node_modules/@types', (returnCode) => {
handlers.readdir('/.pnpm/@zkochan#git-config@0.1.0/node_modules/@types', (returnCode) => {
expect(returnCode).toBe(Fuse.ENOENT)
})
})
it('getattr', () => {
handlers.getattr('/.pnpm/@zkochan/git-config@0.1.0/node_modules/@zkochan/git-config/index.js', (returnCode, stat) => {
handlers.getattr('/.pnpm/@zkochan#git-config@0.1.0/node_modules/@zkochan/git-config/index.js', (returnCode, stat) => {
expect(returnCode).toBe(0)
expect(stat.mode).toBe(33188)
})
handlers.getattr('/.pnpm/@zkochan/git-config@0.1.0/node_modules/@zkochan/git-config/test/fixtures', (returnCode, stat) => {
handlers.getattr('/.pnpm/@zkochan#git-config@0.1.0/node_modules/@zkochan/git-config/test/fixtures', (returnCode, stat) => {
expect(returnCode).toBe(0)
expect(stat.mode).toBe(16877)
})
handlers.getattr('/.pnpm/@zkochan/git-config@0.1.0/node_modules/@zkochan/git-config/index.jsx', (returnCode, stat) => {
handlers.getattr('/.pnpm/@zkochan#git-config@0.1.0/node_modules/@zkochan/git-config/index.jsx', (returnCode, stat) => {
expect(returnCode).toBe(Fuse.ENOENT)
})
handlers.getattr('/.pnpm/is-positive@1.0.0/node_modules/is-positive/package.json', (returnCode, stat) => {
@@ -98,7 +98,7 @@ describe('FUSE handlers', () => {
})
})
it('open and read', (done) => {
const p = '/.pnpm/@zkochan/git-config@0.1.0/node_modules/@zkochan/git-config/index.js'
const p = '/.pnpm/@zkochan#git-config@0.1.0/node_modules/@zkochan/git-config/index.js'
handlers.open(p, 0, (exitCode, fd) => {
expect(exitCode).toBe(0)
expect(fd && fd > 0).toBeTruthy()

View File

@@ -250,7 +250,6 @@ test('top peer dependency is linked on subsequent install', async () => {
test('top peer dependency is linked on subsequent install. Reverse order', async () => {
prepareEmpty()
console.log(process.cwd())
const manifest = await addDependenciesToPackage({}, ['abc-parent-with-ab@1.0.0'], await testDefaults())
@@ -364,7 +363,7 @@ test('scoped peer dependency is linked', async () => {
prepareEmpty()
await addDependenciesToPackage({}, ['for-testing-scoped-peers'], await testDefaults())
const pkgVariation = path.resolve('node_modules/.pnpm/@having/scoped-peer@1.0.0_@scoped+peer@1.0.0/node_modules')
const pkgVariation = path.resolve('node_modules/.pnpm/@having#scoped-peer@1.0.0_@scoped+peer@1.0.0/node_modules')
await okFile(path.join(pkgVariation, '@having', 'scoped-peer'))
await okFile(path.join(pkgVariation, '@scoped', 'peer'))
})
@@ -851,10 +850,10 @@ test('local tarball dependency with peer dependency', async () => {
'foo@100.0.0',
], await testDefaults({ reporter }))
const localPkgDirs = await fs.readdir('node_modules/.pnpm/local')
const integrityLocalPkgDirs = (await fs.readdir('node_modules/.pnpm'))
.filter((dir) => dir.startsWith('local#'))
expect(localPkgDirs.length).toBe(1)
expect(localPkgDirs[0].endsWith('_bar@100.0.0+foo@100.0.0')).toBeTruthy()
expect(integrityLocalPkgDirs.length).toBe(1)
await rimraf('node_modules')
@@ -867,7 +866,11 @@ test('local tarball dependency with peer dependency', async () => {
},
], await testDefaults())
expect(await fs.readdir('node_modules/.pnpm/local')).toStrictEqual(localPkgDirs)
{
const updatedLocalPkgDirs = (await fs.readdir('node_modules/.pnpm'))
.filter((dir) => dir.startsWith('local#'))
expect(updatedLocalPkgDirs).toStrictEqual(integrityLocalPkgDirs)
}
})
test('peer dependency that is resolved by a dev dependency', async () => {