mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-18 22:02:53 -04:00
feat: add layoutVersion to .modules.yaml
BREAKING CHANGE: The new layout is not compatible with previous versions.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import {stripIndent, oneLine} from 'common-tags'
|
||||
import {Modules} from '../fs/modulesController'
|
||||
import {Modules, LAYOUT_VERSION} from '../fs/modulesController'
|
||||
import {PnpmError, PnpmErrorCode} from '../errorTypes'
|
||||
import semver = require('semver')
|
||||
|
||||
@@ -41,24 +41,6 @@ class BreakingChangeError extends PnpmError {
|
||||
additionalInformation?: string
|
||||
}
|
||||
|
||||
type StoreBreakingChangeErrorOptions = ErrorRelatedSources & {
|
||||
storePath: string,
|
||||
}
|
||||
|
||||
class StoreBreakingChangeError extends BreakingChangeError {
|
||||
constructor (opts: StoreBreakingChangeErrorOptions) {
|
||||
super({
|
||||
code: 'STORE_BREAKING_CHANGE',
|
||||
message: `The store structure was changed. Try running the same command with the --force parameter.`,
|
||||
additionalInformation: opts.additionalInformation,
|
||||
relatedIssue: opts.relatedIssue,
|
||||
relatedPR: opts.relatedPR,
|
||||
})
|
||||
this.storePath = opts.storePath
|
||||
}
|
||||
storePath: string
|
||||
}
|
||||
|
||||
type ModulesBreakingChangeErrorOptions = ErrorRelatedSources & {
|
||||
modulesPath: string,
|
||||
}
|
||||
@@ -90,75 +72,11 @@ export default function checkCompatibility (
|
||||
actualStorePath: opts.storePath,
|
||||
})
|
||||
}
|
||||
if (!modules.packageManager) {
|
||||
if (!modules.layoutVersion || modules.layoutVersion !== LAYOUT_VERSION) {
|
||||
throw new ModulesBreakingChangeError({
|
||||
modulesPath: opts.modulesPath,
|
||||
additionalInformation: 'The change was needed to allow machine stores and dependency locks',
|
||||
relatedPR: 524,
|
||||
})
|
||||
}
|
||||
const pnpmVersion = getPackageManagerVersion(modules.packageManager)
|
||||
check(pnpmVersion, opts.storePath, opts.modulesPath)
|
||||
}
|
||||
|
||||
function getPackageManagerVersion(packageManager: string) {
|
||||
// handle the case when the package is scoped: @scope/pkgname
|
||||
if (packageManager.startsWith('@')) {
|
||||
return packageManager.split('@')[2]
|
||||
} else {
|
||||
return packageManager.split('@')[1]
|
||||
}
|
||||
}
|
||||
|
||||
function check (pnpmVersion: string, storePath: string, modulesPath: string) {
|
||||
if (!pnpmVersion || semver.lt(pnpmVersion, '0.28.0')) {
|
||||
throw new StoreBreakingChangeError({
|
||||
storePath,
|
||||
relatedIssue: 276,
|
||||
})
|
||||
}
|
||||
if (semver.lt(pnpmVersion, '0.33.0')) {
|
||||
throw new StoreBreakingChangeError({
|
||||
storePath,
|
||||
additionalInformation: 'The change was needed to fix the GitHub rate limit issue',
|
||||
relatedIssue: 361,
|
||||
relatedPR: 363,
|
||||
})
|
||||
}
|
||||
if (semver.lt(pnpmVersion, '0.37.0')) {
|
||||
throw new StoreBreakingChangeError({
|
||||
storePath,
|
||||
additionalInformation: 'The structure of store.json/dependencies was changed to map dependencies to their fullnames',
|
||||
})
|
||||
}
|
||||
if (semver.lt(pnpmVersion, '0.38.0')) {
|
||||
throw new StoreBreakingChangeError({
|
||||
storePath,
|
||||
additionalInformation: 'The structure of store.json/dependencies was changed to not include the redundunt package.json at the end',
|
||||
})
|
||||
}
|
||||
if (!pnpmVersion || semver.lt(pnpmVersion, '0.48.0')) {
|
||||
throw new ModulesBreakingChangeError({ modulesPath, relatedPR: 534 })
|
||||
}
|
||||
if (semver.lt(pnpmVersion, '0.51.0')) {
|
||||
throw new ModulesBreakingChangeError({ modulesPath, relatedPR: 576 })
|
||||
}
|
||||
if (semver.lt(pnpmVersion, '0.52.0')) {
|
||||
throw new ModulesBreakingChangeError({ modulesPath, relatedPR: 593 })
|
||||
}
|
||||
if (semver.lt(pnpmVersion, '0.62.0')) {
|
||||
throw new ModulesBreakingChangeError({
|
||||
modulesPath,
|
||||
relatedPR: 660,
|
||||
additionalInformation: 'Information about the node_modules structure is stored in a node_modules/.shrinkwrap.yaml file instead of a node_modules/.graph.yaml file'
|
||||
})
|
||||
}
|
||||
if (semver.lt(pnpmVersion, '0.64.0')) {
|
||||
throw new ModulesBreakingChangeError({
|
||||
modulesPath,
|
||||
relatedPR: 694,
|
||||
relatedIssue: 678,
|
||||
additionalInformation: 'Packages having peer dependencies are linked to different variations. The variations depend on the set of resolved peer dependencies'
|
||||
additionalInformation: 'The change was needed to make `independent-leafs` not the default installation layout',
|
||||
relatedIssue: 821,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,10 @@ import {
|
||||
ResolvedDependencies,
|
||||
} from 'pnpm-lockfile'
|
||||
import {pkgIdToRef} from '../fs/shrinkwrap'
|
||||
import {save as saveModules} from '../fs/modulesController'
|
||||
import {
|
||||
save as saveModules,
|
||||
LAYOUT_VERSION,
|
||||
} from '../fs/modulesController'
|
||||
import mkdirp = require('mkdirp-promise')
|
||||
import createMemoize, {MemoizedFunc} from '../memoize'
|
||||
import {Package} from '../types'
|
||||
@@ -381,6 +384,7 @@ async function installInContext (
|
||||
packageManager: `${pnpmPkgJson.name}@${pnpmPkgJson.version}`,
|
||||
storePath: ctx.storePath,
|
||||
skipped: Array.from(installCtx.skipped),
|
||||
layoutVersion: LAYOUT_VERSION,
|
||||
})
|
||||
|
||||
// postinstall hooks
|
||||
|
||||
@@ -12,7 +12,8 @@ import {
|
||||
prune as pruneShrinkwrap,
|
||||
} from 'pnpm-lockfile'
|
||||
import {
|
||||
save as saveModules
|
||||
save as saveModules,
|
||||
LAYOUT_VERSION,
|
||||
} from '../fs/modulesController'
|
||||
import removeOrphanPkgs from './removeOrphanPkgs'
|
||||
import {PackageSpec} from '../resolve'
|
||||
@@ -58,6 +59,7 @@ export async function uninstallInContext (pkgsToUninstall: string[], ctx: PnpmCo
|
||||
packageManager: `${pnpmPkgJson.name}@${pnpmPkgJson.version}`,
|
||||
storePath: ctx.storePath,
|
||||
skipped: Array.from(ctx.skipped).filter(pkgId => removedPkgIds.indexOf(pkgId) === -1),
|
||||
layoutVersion: LAYOUT_VERSION,
|
||||
})
|
||||
await removeOuterLinks(pkgsToUninstall, path.join(ctx.root, 'node_modules'), {storePath: ctx.storePath})
|
||||
}
|
||||
|
||||
@@ -6,10 +6,13 @@ import writeYamlFile = require('write-yaml-file')
|
||||
// thinks that it is an extraneous package.
|
||||
const modulesFileName = '.modules.yaml'
|
||||
|
||||
export const LAYOUT_VERSION = 1
|
||||
|
||||
export type Modules = {
|
||||
packageManager: string,
|
||||
storePath: string,
|
||||
skipped: string[],
|
||||
layoutVersion: number,
|
||||
}
|
||||
|
||||
export async function read (modulesPath: string): Promise<Modules | null> {
|
||||
|
||||
@@ -50,20 +50,6 @@ test('fail on non-compatible node_modules when forced with a named installation'
|
||||
}
|
||||
})
|
||||
|
||||
test('fail on non-compatible store', async t => {
|
||||
const project = prepare(t)
|
||||
const opts = testDefaults()
|
||||
|
||||
await saveModulesYaml('0.32.0', path.join(opts.store, STORE_VERSION))
|
||||
|
||||
try {
|
||||
await installPkgs(['is-negative'], opts)
|
||||
t.fail('should have failed')
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'STORE_BREAKING_CHANGE', 'store breaking change error is thrown')
|
||||
}
|
||||
})
|
||||
|
||||
test("don't fail on non-compatible store when forced", async t => {
|
||||
const project = prepare(t)
|
||||
const opts = testDefaults({force: true})
|
||||
|
||||
Reference in New Issue
Block a user