mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
14
.changeset/lovely-swans-exist.md
Normal file
14
.changeset/lovely-swans-exist.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
"@pnpm/modules-cleaner": major
|
||||
"@pnpm/package-requester": major
|
||||
"@pnpm/package-store": major
|
||||
"@pnpm/plugin-commands-installation": major
|
||||
"@pnpm/plugin-commands-store": major
|
||||
"@pnpm/server": major
|
||||
"@pnpm/store-connection-manager": minor
|
||||
"@pnpm/store-controller-types": major
|
||||
"supi": minor
|
||||
"@pnpm/types": major
|
||||
---
|
||||
|
||||
Remove state from store. The store should not store the information about what projects on the computer use what dependencies. This information was needed for pruning in pnpm v4. Also, without this information, we cannot have the `pnpm store usages` command. So `pnpm store usages` is deprecated.
|
||||
@@ -157,15 +157,6 @@ export default async function prune (
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
const addedDepPaths = R.difference(newDepPaths, oldDepPaths)
|
||||
const addedPkgIds = new Set(R.props<string, string>(addedDepPaths, wantedPkgIdsByDepPaths))
|
||||
|
||||
await opts.storeController.updateConnections(path.dirname(opts.virtualStoreDir), {
|
||||
addDependencies: Array.from(addedPkgIds),
|
||||
prune: opts.pruneStore || false,
|
||||
removeDependencies: Array.from(orphanPkgIds),
|
||||
})
|
||||
}
|
||||
|
||||
return new Set(orphanDepPaths)
|
||||
|
||||
@@ -32,10 +32,7 @@ import {
|
||||
RequestPackageOptions,
|
||||
WantedDependency,
|
||||
} from '@pnpm/store-controller-types'
|
||||
import {
|
||||
DependencyManifest,
|
||||
StoreIndex,
|
||||
} from '@pnpm/types'
|
||||
import { DependencyManifest } from '@pnpm/types'
|
||||
import loadJsonFile = require('load-json-file')
|
||||
import * as fs from 'mz/fs'
|
||||
import pDefer = require('p-defer')
|
||||
@@ -73,7 +70,6 @@ export default function (
|
||||
ignoreFile?: (filename: string) => boolean,
|
||||
networkConcurrency?: number,
|
||||
storeDir: string,
|
||||
storeIndex: StoreIndex,
|
||||
verifyStoreIntegrity: boolean,
|
||||
},
|
||||
): RequestPackageFunction & {
|
||||
@@ -102,7 +98,6 @@ export default function (
|
||||
getFilePathInCafs,
|
||||
requestsQueue,
|
||||
storeDir: opts.storeDir,
|
||||
storeIndex: opts.storeIndex,
|
||||
verifyStoreIntegrity: opts.verifyStoreIntegrity,
|
||||
})
|
||||
const requestPackage = resolveAndFetch.bind(null, {
|
||||
@@ -268,7 +263,6 @@ function fetchToStore (
|
||||
getFilePathInCafs: (integrity: string, fileType: FileType) => string,
|
||||
getFilePathByModeInCafs: (integrity: string, mode: number) => string,
|
||||
requestsQueue: {add: <T>(fn: () => Promise<T>, opts: {priority: number}) => Promise<T>},
|
||||
storeIndex: StoreIndex,
|
||||
storeDir: string,
|
||||
verifyStoreIntegrity: boolean,
|
||||
},
|
||||
@@ -489,7 +483,6 @@ function fetchToStore (
|
||||
await fs.writeFile(path.join(target, TARBALL_INTEGRITY_FILENAME), opts.resolution['integrity'], 'utf8') // tslint:disable-line:no-string-literal
|
||||
}
|
||||
|
||||
ctx.storeIndex[opts.pkgId] = ctx.storeIndex[opts.pkgId] || []
|
||||
files.resolve({
|
||||
filesIndex: integrity,
|
||||
fromStore: false,
|
||||
|
||||
@@ -40,11 +40,9 @@ const fetch = createFetcher({
|
||||
test('request package', async t => {
|
||||
const storeDir = tempy.directory()
|
||||
t.comment(storeDir)
|
||||
const storeIndex = {}
|
||||
const requestPackage = createPackageRequester(resolve, fetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
t.equal(typeof requestPackage, 'function')
|
||||
@@ -81,8 +79,6 @@ test('request package', async t => {
|
||||
|
||||
t.ok(pkgResponse.finishing!())
|
||||
|
||||
t.deepEqual(storeIndex, { 'registry.npmjs.org/is-positive/1.0.0': [] })
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
@@ -90,7 +86,6 @@ test('request package but skip fetching', async t => {
|
||||
const requestPackage = createPackageRequester(resolve, fetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir: '.store',
|
||||
storeIndex: {},
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
t.equal(typeof requestPackage, 'function')
|
||||
@@ -130,7 +125,6 @@ test('request package but skip fetching, when resolution is already available',
|
||||
const requestPackage = createPackageRequester(resolve, fetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir: '.store',
|
||||
storeIndex: {},
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
t.equal(typeof requestPackage, 'function')
|
||||
@@ -200,12 +194,10 @@ test('refetch local tarball if its integrity has changed', async t => {
|
||||
skipFetch: true,
|
||||
update: false,
|
||||
}
|
||||
const storeIndex = {}
|
||||
|
||||
{
|
||||
const requestPackage = createPackageRequester(localResolver as ResolveFunction, fetch, {
|
||||
storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -233,7 +225,6 @@ test('refetch local tarball if its integrity has changed', async t => {
|
||||
{
|
||||
const requestPackage = createPackageRequester(localResolver as ResolveFunction, fetch, {
|
||||
storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -255,7 +246,6 @@ test('refetch local tarball if its integrity has changed', async t => {
|
||||
{
|
||||
const requestPackage = createPackageRequester(localResolver as ResolveFunction, fetch, {
|
||||
storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -295,12 +285,10 @@ test('refetch local tarball if its integrity has changed. The requester does not
|
||||
registry,
|
||||
update: false,
|
||||
}
|
||||
const storeIndex = {}
|
||||
|
||||
{
|
||||
const requestPackage = createPackageRequester(localResolver as ResolveFunction, fetch, {
|
||||
storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -322,7 +310,6 @@ test('refetch local tarball if its integrity has changed. The requester does not
|
||||
{
|
||||
const requestPackage = createPackageRequester(localResolver as ResolveFunction, fetch, {
|
||||
storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -341,7 +328,6 @@ test('refetch local tarball if its integrity has changed. The requester does not
|
||||
{
|
||||
const requestPackage = createPackageRequester(localResolver as ResolveFunction, fetch, {
|
||||
storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -363,7 +349,6 @@ test('fetchPackageToStore()', async (t) => {
|
||||
const packageRequester = createPackageRequester(resolve, fetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir: tempy.directory(),
|
||||
storeIndex: {},
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -423,7 +408,6 @@ test('fetchPackageToStore() concurrency check', async (t) => {
|
||||
const packageRequester = createPackageRequester(resolve, fetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir,
|
||||
storeIndex: {},
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -511,7 +495,6 @@ test('fetchPackageToStore() does not cache errors', async (t) => {
|
||||
const packageRequester = createPackageRequester(resolve, noRetryFetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir: tempy.directory(),
|
||||
storeIndex: {},
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -563,7 +546,6 @@ test('always return a package manifest in the response', async t => {
|
||||
const requestPackage = createPackageRequester(resolve, fetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir: tempy.directory(),
|
||||
storeIndex: {},
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
t.equal(typeof requestPackage, 'function')
|
||||
@@ -622,7 +604,6 @@ test('fetchPackageToStore() fetch raw manifest of cached package', async (t) =>
|
||||
const packageRequester = createPackageRequester(resolve, fetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir: tempy.directory(),
|
||||
storeIndex: {},
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -656,7 +637,6 @@ test('refetch package to store if it has been modified', async (t) => {
|
||||
nock.cleanAll()
|
||||
const storeDir = tempy.directory()
|
||||
const cafsDir = path.join(storeDir, 'files')
|
||||
const storeIndex = {}
|
||||
const lockfileDir = tempy.directory()
|
||||
t.comment(`store location: ${storeDir}`)
|
||||
|
||||
@@ -671,7 +651,6 @@ test('refetch package to store if it has been modified', async (t) => {
|
||||
const packageRequester = createPackageRequester(resolve, fetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
@@ -697,7 +676,6 @@ test('refetch package to store if it has been modified', async (t) => {
|
||||
const packageRequester = createPackageRequester(resolve, fetch, {
|
||||
networkConcurrency: 1,
|
||||
storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: true,
|
||||
})
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
"@pnpm/cafs": "workspace:1.0.0-alpha.3",
|
||||
"@pnpm/core-loggers": "workspace:4.0.1",
|
||||
"@pnpm/fetcher-base": "workspace:7.0.0-alpha.2",
|
||||
"@pnpm/fs-locker": "3.0.1",
|
||||
"@pnpm/package-requester": "workspace:12.0.0-alpha.3",
|
||||
"@pnpm/pkgid-to-filename": "3.0.0-0",
|
||||
"@pnpm/resolver-base": "workspace:7.0.0",
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { StoreIndex } from '@pnpm/types'
|
||||
import loadJsonFile = require('load-json-file')
|
||||
import path = require('path')
|
||||
import writeJsonFile = require('write-json-file')
|
||||
|
||||
const STORE_JSON = 'store.json'
|
||||
|
||||
export async function read (storePath: string): Promise<StoreIndex | null> {
|
||||
const storeJsonPath = path.join(storePath, STORE_JSON)
|
||||
try {
|
||||
return await loadJsonFile<StoreIndex>(storeJsonPath)
|
||||
} catch (err) {
|
||||
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
throw err
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function save (storePath: string, store: StoreIndex) {
|
||||
const storeJsonPath = path.join(storePath, STORE_JSON)
|
||||
return writeJsonFile(storeJsonPath, store)
|
||||
}
|
||||
|
||||
export function saveSync (storePath: string, store: StoreIndex) {
|
||||
const storeJsonPath = path.join(storePath, STORE_JSON)
|
||||
return writeJsonFile.sync(storeJsonPath, store)
|
||||
}
|
||||
@@ -1,11 +1,5 @@
|
||||
import { read, save } from './fs/storeIndex'
|
||||
import createStore from './storeController'
|
||||
|
||||
export default createStore
|
||||
|
||||
export {
|
||||
read,
|
||||
save,
|
||||
}
|
||||
|
||||
export * from '@pnpm/store-controller-types'
|
||||
|
||||
@@ -1,28 +1,18 @@
|
||||
import { getFilePathByModeInCafs as _getFilePathByModeInCafs } from '@pnpm/cafs'
|
||||
import { FetchFunction } from '@pnpm/fetcher-base'
|
||||
import lock from '@pnpm/fs-locker'
|
||||
import { globalWarn } from '@pnpm/logger'
|
||||
import createPackageRequester, { getCacheByEngine } from '@pnpm/package-requester'
|
||||
import pkgIdToFilename from '@pnpm/pkgid-to-filename'
|
||||
import { ResolveFunction } from '@pnpm/resolver-base'
|
||||
import {
|
||||
ImportPackageFunction,
|
||||
PackageUsagesBySearchQueries,
|
||||
StoreController,
|
||||
} from '@pnpm/store-controller-types'
|
||||
import { StoreIndex } from '@pnpm/types'
|
||||
import rimraf = require('@zkochan/rimraf')
|
||||
import pFilter = require('p-filter')
|
||||
import pLimit from 'p-limit'
|
||||
import path = require('path')
|
||||
import exists = require('path-exists')
|
||||
import R = require('ramda')
|
||||
import writeJsonFile = require('write-json-file')
|
||||
import {
|
||||
read as readStore,
|
||||
save as saveStore,
|
||||
saveSync as saveStoreSync,
|
||||
} from '../fs/storeIndex'
|
||||
import createImportPackage from './createImportPackage'
|
||||
import prune from './prune'
|
||||
|
||||
@@ -31,29 +21,17 @@ export default async function (
|
||||
fetchers: {[type: string]: FetchFunction},
|
||||
initOpts: {
|
||||
ignoreFile?: (filename: string) => boolean,
|
||||
locks?: string,
|
||||
lockStaleDuration?: number,
|
||||
storeDir: string,
|
||||
networkConcurrency?: number,
|
||||
packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone',
|
||||
verifyStoreIntegrity: boolean,
|
||||
},
|
||||
): Promise<StoreController & { closeSync: () => void, saveStateSync: () => void }> {
|
||||
): Promise<StoreController> {
|
||||
const storeDir = initOpts.storeDir
|
||||
const unlock = initOpts.locks
|
||||
? await lock(initOpts.storeDir, {
|
||||
locks: initOpts.locks,
|
||||
stale: initOpts.lockStaleDuration || 60 * 1000, // 1 minute,
|
||||
whenLocked: () => globalWarn(`waiting for the store at "${initOpts.storeDir}" to be unlocked...`),
|
||||
})
|
||||
: null
|
||||
|
||||
const storeIndex = await readStore(initOpts.storeDir) || {}
|
||||
const packageRequester = createPackageRequester(resolve, fetchers, {
|
||||
ignoreFile: initOpts.ignoreFile,
|
||||
networkConcurrency: initOpts.networkConcurrency,
|
||||
storeDir: initOpts.storeDir,
|
||||
storeIndex,
|
||||
verifyStoreIntegrity: initOpts.verifyStoreIntegrity,
|
||||
})
|
||||
|
||||
@@ -69,20 +47,12 @@ export default async function (
|
||||
}
|
||||
|
||||
return {
|
||||
close: unlock ? async () => { await unlock() } : () => Promise.resolve(undefined),
|
||||
closeSync: unlock ? () => unlock.sync() : () => undefined,
|
||||
close: async () => {}, // tslint:disable-line:no-empty
|
||||
fetchPackage: packageRequester.fetchPackageToStore,
|
||||
findPackageUsages,
|
||||
getPackageLocation,
|
||||
importPackage,
|
||||
prune: prune.bind(null, storeDir),
|
||||
requestPackage: packageRequester.requestPackage,
|
||||
saveState: saveStore.bind(null, initOpts.storeDir, storeIndex),
|
||||
saveStateSync: saveStoreSync.bind(null, initOpts.storeDir, storeIndex),
|
||||
updateConnections: async (prefix: string, opts: {addDependencies: string[], removeDependencies: string[], prune: boolean}) => {
|
||||
await removeDependencies(prefix, opts.removeDependencies, { prune: opts.prune })
|
||||
await addDependencies(prefix, opts.addDependencies)
|
||||
},
|
||||
upload,
|
||||
}
|
||||
|
||||
@@ -110,47 +80,6 @@ export default async function (
|
||||
}
|
||||
}
|
||||
|
||||
async function removeDependencies (prefix: string, dependencyPkgIds: string[], opts: {prune: boolean}) {
|
||||
await Promise.all(dependencyPkgIds.map(async (notDependent) => {
|
||||
if (storeIndex[notDependent]) {
|
||||
storeIndex[notDependent].splice(storeIndex[notDependent].indexOf(prefix), 1)
|
||||
if (opts.prune && !storeIndex[notDependent].length) {
|
||||
delete storeIndex[notDependent]
|
||||
await rimraf(path.join(storeDir, notDependent))
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
async function addDependencies (prefix: string, dependencyPkgIds: string[]) {
|
||||
dependencyPkgIds.forEach((newDependent) => {
|
||||
storeIndex[newDependent] = storeIndex[newDependent] || []
|
||||
if (!storeIndex[newDependent].includes(prefix)) {
|
||||
storeIndex[newDependent].push(prefix)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function findPackageUsages (searchQueries: string[]): Promise<PackageUsagesBySearchQueries> {
|
||||
const results = {} as PackageUsagesBySearchQueries
|
||||
|
||||
// FIXME Inefficient looping over all packages. Don't think there's a better way.
|
||||
// Note we can't directly resolve packages because user may not specify package version
|
||||
Object.keys(storeIndex).forEach(packageId => {
|
||||
searchQueries
|
||||
.filter((searchQuery) => packageId.indexOf(searchQuery) > -1)
|
||||
.forEach((searchQuery) => {
|
||||
results[searchQuery] = results[searchQuery] || []
|
||||
results[searchQuery].push({
|
||||
packageId,
|
||||
usages: storeIndex[packageId] as string[],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
async function upload (builtPkgLocation: string, opts: {packageId: string, engine: string}) {
|
||||
const filesIndex = await packageRequester.cafs.addFilesFromDir(builtPkgLocation)
|
||||
// TODO: move this to a function
|
||||
@@ -171,15 +100,3 @@ export default async function (
|
||||
await writeJsonFile(path.join(cachePath, 'integrity.json'), integrity, { indent: undefined })
|
||||
}
|
||||
}
|
||||
|
||||
const limitExistsCheck = pLimit(10)
|
||||
|
||||
async function getRemovedProject (storeIndex: StoreIndex) {
|
||||
const allProjects = R.uniq(R.unnest(Object.values(storeIndex)))
|
||||
|
||||
return pFilter(allProjects,
|
||||
(projectPath: string) => limitExistsCheck(async () => {
|
||||
const modulesDir = path.join(projectPath, 'node_modules')
|
||||
return !await exists(modulesDir)
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
///<reference path="../../../typings/index.d.ts"/>
|
||||
import createResolver from '@pnpm/npm-resolver'
|
||||
import createStore, * as packageStore from '@pnpm/package-store'
|
||||
import createStore from '@pnpm/package-store'
|
||||
import { ResolveFunction } from '@pnpm/resolver-base'
|
||||
import createFetcher from '@pnpm/tarball-fetcher'
|
||||
import path = require('path')
|
||||
@@ -8,11 +8,6 @@ import test = require('tape')
|
||||
import tempy = require('tempy')
|
||||
import './createImportPackage.spec'
|
||||
|
||||
test('public API', t => {
|
||||
t.equal(typeof packageStore.read, 'function')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('store.importPackage()', async (t) => {
|
||||
const storeDir = tempy.directory()
|
||||
const registry = 'https://registry.npmjs.org/'
|
||||
|
||||
@@ -104,16 +104,6 @@ export default async function recursive (
|
||||
|
||||
const store = await createOrConnectStoreController(opts)
|
||||
|
||||
// It is enough to save the store.json file once,
|
||||
// once all installations are done.
|
||||
// That's why saveState that is passed to the install engine
|
||||
// does nothing.
|
||||
const saveState = store.ctrl.saveState
|
||||
const storeController = {
|
||||
...store.ctrl,
|
||||
saveState: async () => undefined,
|
||||
}
|
||||
|
||||
const workspacePackages = cmdFullName !== 'unlink'
|
||||
? arrayOfWorkspacePackagesToMap(allProjects)
|
||||
: {}
|
||||
@@ -123,7 +113,7 @@ export default async function recursive (
|
||||
peer: opts.savePeer,
|
||||
pruneLockfileImporters: (!opts.ignoredPackages || opts.ignoredPackages.size === 0)
|
||||
&& pkgs.length === allProjects.length,
|
||||
storeController,
|
||||
storeController: store.ctrl,
|
||||
storeDir: store.dir,
|
||||
targetDependenciesField,
|
||||
workspacePackages,
|
||||
@@ -336,7 +326,7 @@ export default async function recursive (
|
||||
...installOpts.rawConfig,
|
||||
...localConfig,
|
||||
},
|
||||
storeController,
|
||||
storeController: store.ctrl,
|
||||
},
|
||||
)
|
||||
if (opts.save !== false) {
|
||||
@@ -361,11 +351,6 @@ export default async function recursive (
|
||||
}),
|
||||
))
|
||||
|
||||
await saveState()
|
||||
// The store should be unlocked because otherwise rebuild will not be able
|
||||
// to access it
|
||||
await storeController.close()
|
||||
|
||||
if (
|
||||
!opts.lockfileOnly && !opts.ignoreScripts && (
|
||||
cmdFullName === 'add' ||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Config, types as allTypes } from '@pnpm/config'
|
||||
import PnpmError from '@pnpm/error'
|
||||
import logger, { globalInfo, LogBase } from '@pnpm/logger'
|
||||
import { createOrConnectStoreController, CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
|
||||
import { PackageUsages } from '@pnpm/store-controller-types'
|
||||
import storePath from '@pnpm/store-path'
|
||||
import archy = require('archy')
|
||||
import { oneLine } from 'common-tags'
|
||||
@@ -12,7 +11,6 @@ import renderHelp = require('render-help')
|
||||
import storeAdd from './storeAdd'
|
||||
import storePrune from './storePrune'
|
||||
import storeStatus from './storeStatus'
|
||||
import storeUsages from './storeUsages'
|
||||
|
||||
export const rcOptionsTypes = cliOptionsTypes
|
||||
|
||||
@@ -45,10 +43,6 @@ export function help () {
|
||||
description: 'Adds new packages to the store. Example: pnpm store add express@4 typescript@2.1.0',
|
||||
name: 'add <pkg>...',
|
||||
},
|
||||
{
|
||||
description: 'Lists all pnpm projects on the current filesystem that depend on the specified packages. Example: pnpm store usages flatmap-stream',
|
||||
name: 'usages <pkg>...',
|
||||
},
|
||||
{
|
||||
description: oneLine`
|
||||
Removes unreferenced (extraneous, orphan) packages from the store.
|
||||
@@ -98,14 +92,6 @@ export async function handler (opts: StoreCommandOptions, params: string[]) {
|
||||
storeController: store.ctrl,
|
||||
tag: opts.tag,
|
||||
})
|
||||
case 'usages':
|
||||
store = await createOrConnectStoreController(opts)
|
||||
const packageSelectors = params.slice(1)
|
||||
const packageUsagesBySelectors = await storeUsages(packageSelectors, {
|
||||
reporter: opts.reporter,
|
||||
storeController: store.ctrl,
|
||||
})
|
||||
return prettyPrintUsages(packageSelectors, packageUsagesBySelectors)
|
||||
default:
|
||||
return help()
|
||||
if (params[0]) {
|
||||
@@ -128,54 +114,3 @@ async function statusCmd (opts: StoreCommandOptions) {
|
||||
|
||||
throw new StoreStatusError(modifiedPkgs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses archy to output package usages in a directory-tree like format.
|
||||
* @param packageUsages a list of PackageUsage, one per query
|
||||
*/
|
||||
function prettyPrintUsages (selectors: string[], packageUsagesBySelectors: { [packageSelector: string]: PackageUsages[] }) {
|
||||
|
||||
// Create nodes for top level usage response
|
||||
const packageUsageNodes: archy.Data[] = selectors.map((selector) => {
|
||||
// Create label for root node
|
||||
const label = `Package: ${selector}`
|
||||
|
||||
if (!packageUsagesBySelectors[selector].length) {
|
||||
// If not found in store, just output string
|
||||
return {
|
||||
label,
|
||||
nodes: [
|
||||
'Not found in store',
|
||||
],
|
||||
} as archy.Data
|
||||
}
|
||||
|
||||
// This package was found in the store, create children for all package ids
|
||||
const foundPackagesNodes: archy.Data[] = packageUsagesBySelectors[selector].map((foundPackage) => {
|
||||
const label = `Package in store: ${foundPackage.packageId}`
|
||||
|
||||
// Now create children for all locations this package id is used
|
||||
const locations: string[] = foundPackage.usages
|
||||
const locationNodes: archy.Data[] = locations.map(location => {
|
||||
return {
|
||||
label: 'Project with dependency: ' + location,
|
||||
} as archy.Data
|
||||
})
|
||||
|
||||
// Now create node for the package found in the store
|
||||
return {
|
||||
label,
|
||||
nodes: locationNodes.length === 0 ? ['No pnpm projects using this package'] : locationNodes,
|
||||
} as archy.Data
|
||||
})
|
||||
|
||||
// Now create node for the original query
|
||||
return {
|
||||
label,
|
||||
nodes: foundPackagesNodes,
|
||||
} as archy.Data
|
||||
})
|
||||
|
||||
const rootTrees = packageUsageNodes.map(node => archy(node))
|
||||
return rootTrees.join('\n')
|
||||
}
|
||||
|
||||
@@ -45,8 +45,6 @@ export default async function (
|
||||
}
|
||||
}))
|
||||
|
||||
await opts.storeController.saveState()
|
||||
|
||||
if (reporter) {
|
||||
streamParser.removeListener('data', reporter)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ export default async function (
|
||||
streamParser.on('data', reporter)
|
||||
}
|
||||
await opts.storeController.prune()
|
||||
await opts.storeController.saveState()
|
||||
await opts.storeController.close()
|
||||
|
||||
if (reporter) {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { streamParser } from '@pnpm/logger'
|
||||
import parseWantedDependency from '@pnpm/parse-wanted-dependency'
|
||||
import { PackageUsages, StoreController } from '@pnpm/store-controller-types'
|
||||
import { ReporterFunction } from './types'
|
||||
|
||||
export default async function (
|
||||
packageSelectors: string[],
|
||||
opts: {
|
||||
reporter?: ReporterFunction,
|
||||
storeController: StoreController,
|
||||
},
|
||||
): Promise<{ [packageSelector: string]: PackageUsages[] }> {
|
||||
const reporter = opts?.reporter
|
||||
if (reporter) {
|
||||
streamParser.on('data', reporter)
|
||||
}
|
||||
|
||||
const packageSelectorsBySearchQueries = packageSelectors.reduce((acc, packageSelector) => {
|
||||
const searchQuery = parsedPackageSelectorToSearchQuery(parseWantedDependency(packageSelector))
|
||||
acc[searchQuery] = packageSelector
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const packageUsagesBySearchQueries = await opts.storeController.findPackageUsages(Object.keys(packageSelectorsBySearchQueries))
|
||||
|
||||
const results = {}
|
||||
|
||||
for (const searchQuery of Object.keys(packageSelectorsBySearchQueries)) {
|
||||
results[packageSelectorsBySearchQueries[searchQuery]] = packageUsagesBySearchQueries[searchQuery] || []
|
||||
}
|
||||
|
||||
if (reporter) {
|
||||
streamParser.removeListener('data', reporter)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
function parsedPackageSelectorToSearchQuery (parsedPackageSelector: {alias: string} | {pref: string} | {alias: string, pref: string}) {
|
||||
if (!parsedPackageSelector['alias']) return parsedPackageSelector['pref']
|
||||
if (!parsedPackageSelector['pref']) return `/${parsedPackageSelector['alias']}/`
|
||||
return `/${parsedPackageSelector['alias']}/${parsedPackageSelector['pref']}`
|
||||
}
|
||||
@@ -2,4 +2,3 @@
|
||||
import './storeAdd'
|
||||
import './storePrune'
|
||||
import './storeStatus'
|
||||
import './storeUsages'
|
||||
|
||||
@@ -17,7 +17,6 @@ test('pnpm store add express@4.16.3', async function (t) {
|
||||
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: true,
|
||||
rawConfig: {
|
||||
registry: `http://localhost:${REGISTRY_MOCK_PORT}/`,
|
||||
},
|
||||
@@ -28,14 +27,6 @@ test('pnpm store add express@4.16.3', async function (t) {
|
||||
const { cafsHas } = assertStore(t, path.join(storeDir, STORE_VERSION))
|
||||
await cafsHas('sha1-avilAjUNsyRuzEvs9rWjTSL37VM=')
|
||||
|
||||
const storeIndex = await loadJsonFile(path.join(storeDir, STORE_VERSION, 'store.json'))
|
||||
t.deepEqual(
|
||||
storeIndex,
|
||||
{
|
||||
[`localhost+${REGISTRY_MOCK_PORT}/express/4.16.3`]: [],
|
||||
},
|
||||
'package has been added to the store index',
|
||||
)
|
||||
t.end()
|
||||
})
|
||||
|
||||
@@ -46,7 +37,6 @@ test('pnpm store add scoped package that uses not the standard registry', async
|
||||
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: true,
|
||||
rawConfig: {
|
||||
registry: 'https://registry.npmjs.org/',
|
||||
},
|
||||
@@ -60,14 +50,6 @@ test('pnpm store add scoped package that uses not the standard registry', async
|
||||
const { cafsHas } = assertStore(t, path.join(storeDir, STORE_VERSION))
|
||||
await cafsHas('@foo/no-deps', '1.0.0')
|
||||
|
||||
const storeIndex = await loadJsonFile(path.join(storeDir, STORE_VERSION, 'store.json'))
|
||||
t.deepEqual(
|
||||
storeIndex,
|
||||
{
|
||||
[`localhost+${REGISTRY_MOCK_PORT}/@foo/no-deps/1.0.0`]: [],
|
||||
},
|
||||
'package has been added to the store index',
|
||||
)
|
||||
t.end()
|
||||
})
|
||||
|
||||
@@ -81,7 +63,6 @@ test('should fail if some packages can not be added', async (t) => {
|
||||
try {
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: true,
|
||||
rawConfig: {
|
||||
registry: 'https://registry.npmjs.org/',
|
||||
},
|
||||
|
||||
@@ -27,7 +27,6 @@ test('remove unreferenced packages', async (t) => {
|
||||
const reporter = sinon.spy()
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: true,
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
@@ -46,7 +45,6 @@ test('remove unreferenced packages', async (t) => {
|
||||
reporter.resetHistory()
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: true,
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
@@ -76,7 +74,6 @@ test.skip('remove packages that are used by project that no longer exist', async
|
||||
const reporter = sinon.spy()
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: true,
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
@@ -117,7 +114,6 @@ test('keep dependencies used by others', async (t) => {
|
||||
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: true,
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
@@ -139,7 +135,6 @@ test('keep dependency used by package', async (t) => {
|
||||
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: true,
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
|
||||
@@ -23,7 +23,6 @@ test('CLI fails when store status finds modified packages', async function (t) {
|
||||
try {
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: false,
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
@@ -49,7 +48,6 @@ test('CLI does not fail when store status does not find modified packages', asyn
|
||||
|
||||
await store.handler({
|
||||
dir: process.cwd(),
|
||||
lock: false,
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
import assertStore from '@pnpm/assert-store'
|
||||
import { store } from '@pnpm/plugin-commands-store'
|
||||
import prepare, { prepareEmpty } from '@pnpm/prepare'
|
||||
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
import { stripIndent } from 'common-tags'
|
||||
import execa = require('execa')
|
||||
import path = require('path')
|
||||
import exists = require('path-exists')
|
||||
import ssri = require('ssri')
|
||||
import test = require('tape')
|
||||
|
||||
const STORE_VERSION = 'v3'
|
||||
const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}/`
|
||||
const DEFAULT_OPTS = {
|
||||
lock: false,
|
||||
rawConfig: {
|
||||
registry: REGISTRY,
|
||||
},
|
||||
registries: { default: REGISTRY },
|
||||
}
|
||||
const pnpmBin = path.join(__dirname, '../../pnpm/bin/pnpm.js')
|
||||
|
||||
test('find usages for single package in store and in a project', async (t) => {
|
||||
const project = prepare(t)
|
||||
const storeDir = path.resolve('store')
|
||||
|
||||
// Install deps
|
||||
await execa('node', [pnpmBin, 'add', 'is-negative@2.1.0', 'is-odd@3.0.0', '--store-dir', storeDir, '--registry', REGISTRY])
|
||||
await project.cafsHas(ssri.fromHex('f0d86377aa15a64c34961f38ac2a9be2b40a1187', 'sha1').toString())
|
||||
|
||||
{
|
||||
const output = await store.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
storeDir,
|
||||
}, ['usages', 'is-negative'])
|
||||
t.equal(
|
||||
output,
|
||||
stripIndent`
|
||||
Package: is-negative
|
||||
└─┬ Package in store: localhost+${REGISTRY_MOCK_PORT}/is-negative/2.1.0
|
||||
└── Project with dependency: ${path.resolve('node_modules')}` + '\n',
|
||||
'finds usages by package name',
|
||||
)
|
||||
}
|
||||
{
|
||||
const output = await store.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
storeDir,
|
||||
}, ['usages', 'is-negative@2.1.0'])
|
||||
t.equal(
|
||||
output,
|
||||
stripIndent`
|
||||
Package: is-negative@2.1.0
|
||||
└─┬ Package in store: localhost+${REGISTRY_MOCK_PORT}/is-negative/2.1.0
|
||||
└── Project with dependency: ${path.resolve('node_modules')}` + '\n',
|
||||
'finds usages by package name and version',
|
||||
)
|
||||
}
|
||||
{
|
||||
await project.storeHasNot('should-not-exist-uhsalzkj')
|
||||
const output = await store.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
storeDir,
|
||||
}, ['usages', 'should-not-exist-uhsalzkj'])
|
||||
t.equal(
|
||||
output,
|
||||
stripIndent`
|
||||
Package: should-not-exist-uhsalzkj
|
||||
└── Not found in store` + '\n',
|
||||
'cannot find usages if package does not exist',
|
||||
)
|
||||
}
|
||||
{
|
||||
const output = await store.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
storeDir,
|
||||
}, ['usages', 'is-negative', 'is-odd'])
|
||||
t.equal(
|
||||
output,
|
||||
stripIndent`
|
||||
Package: is-negative
|
||||
└─┬ Package in store: localhost+${REGISTRY_MOCK_PORT}/is-negative/2.1.0
|
||||
└── Project with dependency: ${path.resolve('node_modules')}
|
||||
|
||||
Package: is-odd
|
||||
└─┬ Package in store: localhost+${REGISTRY_MOCK_PORT}/is-odd/3.0.0
|
||||
└── Project with dependency: ${path.resolve('node_modules')}` + '\n',
|
||||
'finds usages of two packages',
|
||||
)
|
||||
}
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('find usages for package(s) in store but not in any projects', async (t) => {
|
||||
prepareEmpty(t)
|
||||
const storeDir = path.resolve('store')
|
||||
const { cafsHas } = assertStore(t, path.join(storeDir, STORE_VERSION))
|
||||
|
||||
// Add dependency directly to store (not to the project)
|
||||
await store.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
storeDir,
|
||||
}, ['add', 'is-negative@2.1.0'])
|
||||
await cafsHas(ssri.fromHex('f0d86377aa15a64c34961f38ac2a9be2b40a1187', 'sha1').toString())
|
||||
|
||||
{
|
||||
const output = await store.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
storeDir,
|
||||
}, ['usages', 'is-negative'])
|
||||
t.equal(
|
||||
output,
|
||||
stripIndent`
|
||||
Package: is-negative
|
||||
└─┬ Package in store: localhost+${REGISTRY_MOCK_PORT}/is-negative/2.1.0
|
||||
└── No pnpm projects using this package` + '\n',
|
||||
'finds usage of package',
|
||||
)
|
||||
}
|
||||
await store.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
storeDir,
|
||||
}, ['add', 'is-negative@2.0.0'])
|
||||
await cafsHas(ssri.fromHex('09f4cb20dd1bddff37cb6630c618a9bc57915fd6', 'sha1').toString())
|
||||
{
|
||||
const output = await store.handler({
|
||||
...DEFAULT_OPTS,
|
||||
dir: process.cwd(),
|
||||
storeDir,
|
||||
}, ['usages', 'is-negative'])
|
||||
t.equal(
|
||||
output,
|
||||
stripIndent`
|
||||
Package: is-negative
|
||||
├─┬ Package in store: localhost+${REGISTRY_MOCK_PORT}/is-negative/2.1.0
|
||||
│ └── No pnpm projects using this package
|
||||
└─┬ Package in store: localhost+${REGISTRY_MOCK_PORT}/is-negative/2.0.0
|
||||
└── No pnpm projects using this package` + '\n',
|
||||
'finds usages of packages',
|
||||
)
|
||||
}
|
||||
|
||||
t.end()
|
||||
})
|
||||
@@ -480,9 +480,6 @@ test('recursive install with link-workspace-packages and shared-workspace-lockfi
|
||||
const outputs = await import(path.resolve('output.json')) as string[]
|
||||
t.deepEqual(outputs, ['is-positive', 'project-1'])
|
||||
|
||||
const storeJson = await loadJsonFile<object>(path.resolve('store/v3/store.json'))
|
||||
t.deepEqual(storeJson[`localhost+${REGISTRY_MOCK_PORT}/is-negative/1.0.0`].length, 1, 'new connections saved in store.json')
|
||||
|
||||
await execPnpm(['recursive', 'install', 'pkg-with-1-dep', '--link-workspace-packages', '--shared-workspace-lockfile=true', '--store-dir', 'store'])
|
||||
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
FetchPackageToStoreOptions,
|
||||
PackageFilesResponse,
|
||||
PackageResponse,
|
||||
PackageUsagesBySearchQueries,
|
||||
RequestPackageOptions,
|
||||
StoreController,
|
||||
WantedDependency,
|
||||
@@ -31,9 +30,6 @@ export default function (
|
||||
resolve({
|
||||
close: async () => { return },
|
||||
fetchPackage: fetchPackage.bind(null, remotePrefix, limitedFetch),
|
||||
findPackageUsages: async (searchQueries: string[]): Promise<PackageUsagesBySearchQueries> => {
|
||||
return await limitedFetch(`${remotePrefix}/findPackageUsages`, { searchQueries }) as PackageUsagesBySearchQueries
|
||||
},
|
||||
getPackageLocation: async (
|
||||
packageId: string,
|
||||
packageName: string,
|
||||
@@ -61,16 +57,7 @@ export default function (
|
||||
await limitedFetch(`${remotePrefix}/prune`, {})
|
||||
},
|
||||
requestPackage: requestPackage.bind(null, remotePrefix, limitedFetch),
|
||||
saveState: async () => {
|
||||
await limitedFetch(`${remotePrefix}/saveState`, {})
|
||||
},
|
||||
stop: async () => { await limitedFetch(`${remotePrefix}/stop`, {}) },
|
||||
updateConnections: async (prefix: string, opts: {addDependencies: string[], removeDependencies: string[], prune: boolean}) => {
|
||||
await limitedFetch(`${remotePrefix}/updateConnections`, {
|
||||
opts,
|
||||
prefix,
|
||||
})
|
||||
},
|
||||
upload: async (builtPkgLocation: string, opts: {packageId: string, engine: string}) => {
|
||||
await limitedFetch(`${remotePrefix}/upload`, {
|
||||
builtPkgLocation,
|
||||
|
||||
@@ -126,20 +126,11 @@ export default function (
|
||||
delete rawManifestPromises[body.msgId]
|
||||
res.end(JSON.stringify(manifestResponse))
|
||||
break
|
||||
case '/updateConnections':
|
||||
body = await bodyPromise
|
||||
await store.updateConnections(body.prefix, body.opts)
|
||||
res.end(JSON.stringify('OK'))
|
||||
break
|
||||
case '/prune':
|
||||
// Disable store pruning when a server is running
|
||||
res.statusCode = 403
|
||||
res.end()
|
||||
break
|
||||
case '/saveState':
|
||||
await store.saveState()
|
||||
res.end(JSON.stringify('OK'))
|
||||
break
|
||||
case '/importPackage':
|
||||
const importPackageBody = (await bodyPromise) as any // tslint:disable-line:no-any
|
||||
await store.importPackage(importPackageBody.to, importPackageBody.opts)
|
||||
@@ -173,10 +164,6 @@ export default function (
|
||||
res.end(JSON.stringify(pkgLocation))
|
||||
break
|
||||
}
|
||||
case '/findPackageUsages':
|
||||
body = await bodyPromise
|
||||
res.end(JSON.stringify(await store.findPackageUsages(body.searchQueries)))
|
||||
break
|
||||
default:
|
||||
res.statusCode = 404
|
||||
const error = { error: `${req.url} does not match any route` }
|
||||
|
||||
@@ -32,8 +32,6 @@ async function createStoreController (storeDir?: string) {
|
||||
strictSsl: true,
|
||||
})
|
||||
return createStore(resolve, fetchers, {
|
||||
locks: undefined,
|
||||
lockStaleDuration: 100,
|
||||
networkConcurrency: 1,
|
||||
storeDir,
|
||||
verifyStoreIntegrity: true,
|
||||
@@ -300,58 +298,6 @@ test('disallow store prune', async t => {
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('find package usages', async t => {
|
||||
const port = 5813
|
||||
const hostname = '127.0.0.1'
|
||||
const remotePrefix = `http://${hostname}:${port}`
|
||||
const storeCtrlForServer = await createStoreController()
|
||||
const server = createServer(storeCtrlForServer, {
|
||||
hostname,
|
||||
port,
|
||||
})
|
||||
const storeCtrl = await connectStoreController({ remotePrefix, concurrency: 100 })
|
||||
|
||||
const dependency = { alias: 'is-positive', pref: '1.0.0' }
|
||||
|
||||
const projectDir = process.cwd()
|
||||
// First install a dependency
|
||||
const requestResponse = await storeCtrl.requestPackage(
|
||||
dependency,
|
||||
{
|
||||
downloadPriority: 0,
|
||||
lockfileDir: projectDir,
|
||||
preferredVersions: {},
|
||||
projectDir,
|
||||
registry,
|
||||
sideEffectsCache: false,
|
||||
},
|
||||
)
|
||||
await requestResponse.bundledManifest!()
|
||||
await requestResponse.finishing!()
|
||||
|
||||
// For debugging purposes
|
||||
await storeCtrl.saveState()
|
||||
|
||||
// Now check if usages shows up
|
||||
const packageUsagesByPackageSelectors = await storeCtrl.findPackageUsages(['/is-positive/1.0.0'])
|
||||
|
||||
t.deepEqual(
|
||||
packageUsagesByPackageSelectors,
|
||||
{
|
||||
'/is-positive/1.0.0': [
|
||||
{
|
||||
packageId: 'registry.npmjs.org/is-positive/1.0.0',
|
||||
usages: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
await server.close()
|
||||
await storeCtrl.close()
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('server should only allow POST', async (t) => {
|
||||
const port = 5813
|
||||
const hostname = '127.0.0.1'
|
||||
|
||||
@@ -7,8 +7,6 @@ import createResolver, { CreateResolverOptions } from './createResolver'
|
||||
|
||||
export type CreateNewStoreControllerOptions = CreateResolverOptions & Pick<Config,
|
||||
'alwaysAuth' |
|
||||
'lock' |
|
||||
'lockStaleDuration' |
|
||||
'networkConcurrency' |
|
||||
'packageImportMethod' |
|
||||
'registry' |
|
||||
@@ -22,7 +20,6 @@ export default async (
|
||||
) => {
|
||||
// TODO: either print a warning or just log if --no-lock is used
|
||||
const sopts = Object.assign(opts, {
|
||||
locks: opts.lock ? path.join(opts.storeDir, '_locks') : undefined,
|
||||
registry: opts.registry || 'https://registry.npmjs.org/',
|
||||
})
|
||||
const resolve = createResolver(sopts)
|
||||
@@ -31,8 +28,6 @@ export default async (
|
||||
return {
|
||||
ctrl: await createStore(resolve, fetchers as {}, {
|
||||
ignoreFile: sopts.ignoreFile,
|
||||
locks: sopts.locks,
|
||||
lockStaleDuration: sopts.lockStaleDuration,
|
||||
networkConcurrency: sopts.networkConcurrency,
|
||||
packageImportMethod: sopts.packageImportMethod,
|
||||
storeDir: sopts.storeDir,
|
||||
|
||||
@@ -41,20 +41,8 @@ export interface StoreController {
|
||||
fetchPackage: FetchPackageToStoreFunction,
|
||||
importPackage: ImportPackageFunction,
|
||||
close (): Promise<void>,
|
||||
updateConnections (prefix: string, opts: {addDependencies: string[], removeDependencies: string[], prune: boolean}): Promise<void>,
|
||||
prune (): Promise<void>,
|
||||
saveState (): Promise<void>,
|
||||
upload (builtPkgLocation: string, opts: {packageId: string, engine: string}): Promise<void>,
|
||||
findPackageUsages (searchQueries: string[]): Promise<PackageUsagesBySearchQueries>,
|
||||
}
|
||||
|
||||
export type PackageUsagesBySearchQueries = {
|
||||
[searchQuery: string]: PackageUsages[],
|
||||
}
|
||||
|
||||
export type PackageUsages = {
|
||||
packageId: string,
|
||||
usages: string[], // paths to node projects
|
||||
}
|
||||
|
||||
export type FetchPackageToStoreFunction = (
|
||||
|
||||
@@ -153,19 +153,15 @@ export async function mutateModules (
|
||||
}
|
||||
|
||||
let result!: Array<{ rootDir: string, manifest: ProjectManifest }>
|
||||
try {
|
||||
if (opts.lock) {
|
||||
result = await lock(ctx.lockfileDir, _install, {
|
||||
locks: opts.locks,
|
||||
prefix: ctx.lockfileDir,
|
||||
stale: opts.lockStaleDuration,
|
||||
storeController: opts.storeController,
|
||||
})
|
||||
} else {
|
||||
result = await _install()
|
||||
}
|
||||
} finally {
|
||||
await opts.storeController.saveState()
|
||||
if (opts.lock) {
|
||||
result = await lock(ctx.lockfileDir, _install, {
|
||||
locks: opts.locks,
|
||||
prefix: ctx.lockfileDir,
|
||||
stale: opts.lockStaleDuration,
|
||||
storeController: opts.storeController,
|
||||
})
|
||||
} else {
|
||||
result = await _install()
|
||||
}
|
||||
|
||||
if (reporter) {
|
||||
|
||||
@@ -1092,33 +1092,6 @@ test('subdep symlinks are updated if the lockfile has new subdep versions specif
|
||||
t.ok(await exists(path.resolve(`node_modules/.pnpm/localhost+${REGISTRY_MOCK_PORT}/pkg-with-1-dep@100.0.0/node_modules/dep-of-pkg-with-1-dep/package.json`)))
|
||||
})
|
||||
|
||||
test("store metadata is always saved, even if there's a fatal error", async (t: tape.Test) => {
|
||||
prepareEmpty(t)
|
||||
const opts = await testDefaults()
|
||||
const saveStateSpy = sinon.spy()
|
||||
opts.storeController.saveState = saveStateSpy
|
||||
|
||||
let err!: Error
|
||||
try {
|
||||
await mutateModules([
|
||||
{
|
||||
buildIndex: 0,
|
||||
manifest: {
|
||||
dependencies: {
|
||||
'@pnpm/this-does-not-exist': '1.0.0',
|
||||
},
|
||||
},
|
||||
mutation: 'install',
|
||||
rootDir: process.cwd(),
|
||||
},
|
||||
], opts)
|
||||
} catch (_err) {
|
||||
err = _err
|
||||
}
|
||||
t.ok(err)
|
||||
t.ok(saveStateSpy.calledOnce)
|
||||
})
|
||||
|
||||
test('fail if none of the available resolvers support a version spec', async (t: tape.Test) => {
|
||||
prepareEmpty(t)
|
||||
|
||||
|
||||
@@ -35,10 +35,6 @@ test('peer dependency is grouped with dependency when peer is resolved not from
|
||||
t.ok(await exists(path.resolve(`node_modules/.pnpm/localhost+${REGISTRY_MOCK_PORT}/ajv-keywords@1.5.0_ajv@4.10.4/node_modules/ajv`)), 'peer dependency is linked')
|
||||
t.equal(deepRequireCwd(['using-ajv', 'ajv-keywords', 'ajv', './package.json']).version, '4.10.4')
|
||||
|
||||
const storeIndex = await loadJsonFile<object>(path.join(opts.storeDir, 'store.json'))
|
||||
t.ok(storeIndex[`localhost+${REGISTRY_MOCK_PORT}/ajv-keywords/1.5.0`], `localhost+${REGISTRY_MOCK_PORT}/ajv-keywords/1.5.0 added to store index`)
|
||||
t.ok(storeIndex[`localhost+${REGISTRY_MOCK_PORT}/using-ajv/1.0.0`], `localhost+${REGISTRY_MOCK_PORT}/using-ajv/1.0.0 added to store index`)
|
||||
|
||||
// testing that peers are reinstalled correctly using info from the lockfile
|
||||
await rimraf('node_modules')
|
||||
await rimraf(path.resolve('..', '.store'))
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from './misc'
|
||||
export * from './options'
|
||||
export * from './package'
|
||||
export * from './store'
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export interface StoreIndex {
|
||||
// package ID => paths of dependent projects
|
||||
[pkgId: string]: string[],
|
||||
}
|
||||
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
@@ -1297,7 +1297,6 @@ importers:
|
||||
'@pnpm/cafs': 'link:../cafs'
|
||||
'@pnpm/core-loggers': 'link:../core-loggers'
|
||||
'@pnpm/fetcher-base': 'link:../fetcher-base'
|
||||
'@pnpm/fs-locker': 3.0.1
|
||||
'@pnpm/package-requester': 'link:../package-requester'
|
||||
'@pnpm/pkgid-to-filename': 3.0.0-0
|
||||
'@pnpm/resolver-base': 'link:../resolver-base'
|
||||
@@ -1332,7 +1331,6 @@ importers:
|
||||
'@pnpm/cafs': 'workspace:1.0.0-alpha.3'
|
||||
'@pnpm/core-loggers': 'workspace:4.0.1'
|
||||
'@pnpm/fetcher-base': 'workspace:7.0.0-alpha.2'
|
||||
'@pnpm/fs-locker': 3.0.1
|
||||
'@pnpm/logger': 3.2.2
|
||||
'@pnpm/npm-resolver': 'workspace:*'
|
||||
'@pnpm/package-requester': 'workspace:12.0.0-alpha.3'
|
||||
|
||||
@@ -32,13 +32,11 @@
|
||||
},
|
||||
"repository": "https://github.com/pnpm/pnpm/blob/master/privatePackages/assert-store",
|
||||
"scripts": {
|
||||
"commit": "commit",
|
||||
"commitmsg": "commitlint -e",
|
||||
"compile": "rimraf lib tsconfig.tsbuildinfo && tsc --build",
|
||||
"lint": "tslint -c ../../tslint.json src/**/*.ts test/**/*.ts",
|
||||
"tsc": "rimraf lib && tsc",
|
||||
"prepublishOnly": "pnpm run tsc",
|
||||
"prepublishOnly": "pnpm run compile",
|
||||
"pretest": "pnpm install -C test/fixture/project --force --no-shared-workspace-lockfile",
|
||||
"test": "pnpm run tsc && ts-node test"
|
||||
"test": "pnpm run compile && ts-node test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pnpm/cafs": "workspace:^1.0.0-alpha.3",
|
||||
|
||||
Reference in New Issue
Block a user