feat(reporter): show the progress of adding pkgs to virtual store

close #2832
PR #2845
This commit is contained in:
Zoltan Kochan
2020-09-13 12:12:01 +03:00
committed by GitHub
parent bf526e4850
commit 86cd72de33
19 changed files with 157 additions and 82 deletions

View File

@@ -0,0 +1,5 @@
---
"pnpm": minor
---
The progress indicator now also shows the number of dependencies that are being added to the modules direcotory.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/core-loggers": major
---
Remove `importingLogger`. Importing should be logged by a new type of progress log status: `imported`.

View File

@@ -0,0 +1,6 @@
---
"@pnpm/headless": minor
"supi": patch
---
After a package is linked, copied, or cloned to the virtual store, a progress log is logged with the `imported` status.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/default-reporter": minor
---
Show the progress of adding packages to the virtual store.

View File

@@ -0,0 +1,7 @@
---
"@pnpm/package-store": major
"@pnpm/server": major
"@pnpm/store-controller-types": major
---
The `importPackage` function of the store controller returns the `importMethod` that was used to link the package to the virtual store. If importing was not needed, `importMethod` is `undefined`.

View File

@@ -2,7 +2,6 @@ export * from './contextLogger'
export * from './deprecationLogger' export * from './deprecationLogger'
export * from './fetchingProgressLogger' export * from './fetchingProgressLogger'
export * from './hookLogger' export * from './hookLogger'
export * from './importingLogger'
export * from './installCheckLogger' export * from './installCheckLogger'
export * from './lifecycleLogger' export * from './lifecycleLogger'
export * from './linkLogger' export * from './linkLogger'

View File

@@ -1,13 +0,0 @@
import baseLogger, {
LogBase,
} from '@pnpm/logger'
export const importingLogger = baseLogger('importing')
export interface ImportingMessage {
from: string
method: string
to: string
}
export type ImportingLog = {name: 'pnpm:importing'} & LogBase & ImportingMessage

View File

@@ -3,7 +3,6 @@ import {
DeprecationLog, DeprecationLog,
FetchingProgressLog, FetchingProgressLog,
HookLog, HookLog,
ImportingLog,
InstallCheckLog, InstallCheckLog,
LifecycleLog, LifecycleLog,
LinkLog, LinkLog,
@@ -27,7 +26,6 @@ export type Log =
| DeprecationLog | DeprecationLog
| FetchingProgressLog | FetchingProgressLog
| HookLog | HookLog
| ImportingLog
| InstallCheckLog | InstallCheckLog
| LifecycleLog | LifecycleLog
| LinkLog | LinkLog

View File

@@ -5,10 +5,15 @@ import baseLogger, {
export const progressLogger = baseLogger('progress') as Logger<ProgressMessage> // eslint-disable-line export const progressLogger = baseLogger('progress') as Logger<ProgressMessage> // eslint-disable-line
export interface ProgressMessage { export type ProgressMessage = {
packageId: string packageId: string
requester: string requester: string
status: 'fetched' | 'found_in_store' | 'resolved' status: 'fetched' | 'found_in_store' | 'resolved'
} | {
status: 'imported'
method: string
requester: string
to: string
} }
export type ProgressLog = {name: 'pnpm:progress'} & LogBase & ProgressMessage export type ProgressLog = {name: 'pnpm:progress'} & LogBase & ProgressMessage

View File

@@ -154,10 +154,10 @@ export function toOutput$ (
case 'pnpm:request-retry': case 'pnpm:request-retry':
requestRetryPushStream.next(log) requestRetryPushStream.next(log)
break break
case 'pnpm' as any: // eslint-disable-line case 'pnpm' as any: // eslint-disable-line
case 'pnpm:global' as any: // eslint-disable-line case 'pnpm:global' as any: // eslint-disable-line
case 'pnpm:store' as any: // eslint-disable-line case 'pnpm:store' as any: // eslint-disable-line
case 'pnpm:lockfile' as any: // eslint-disable-line case 'pnpm:lockfile' as any: // eslint-disable-line
otherPushStream.next(log) otherPushStream.next(log)
break break
} }

View File

@@ -2,6 +2,7 @@ import { Config } from '@pnpm/config'
import * as logs from '@pnpm/core-loggers' import * as logs from '@pnpm/core-loggers'
import { LogLevel } from '@pnpm/logger' import { LogLevel } from '@pnpm/logger'
import * as Rx from 'rxjs' import * as Rx from 'rxjs'
import { throttleTime } from 'rxjs/operators'
import reportBigTarballsProgress from './reportBigTarballsProgress' import reportBigTarballsProgress from './reportBigTarballsProgress'
import reportContext from './reportContext' import reportContext from './reportContext'
import reportDeprecations from './reportDeprecations' import reportDeprecations from './reportDeprecations'
@@ -52,11 +53,14 @@ export default function (
): Array<Rx.Observable<Rx.Observable<{msg: string}>>> { ): Array<Rx.Observable<Rx.Observable<{msg: string}>>> {
const width = opts.width ?? process.stdout.columns ?? 80 const width = opts.width ?? process.stdout.columns ?? 80
const cwd = opts.pnpmConfig?.dir ?? process.cwd() const cwd = opts.pnpmConfig?.dir ?? process.cwd()
const throttle = typeof opts.throttleProgress === 'number' && opts.throttleProgress > 0
? throttleTime(opts.throttleProgress)
: undefined
const outputs: Array<Rx.Observable<Rx.Observable<{msg: string}>>> = [ const outputs: Array<Rx.Observable<Rx.Observable<{msg: string}>>> = [
reportProgress(log$, { reportProgress(log$, {
cwd, cwd,
throttleProgress: opts.throttleProgress, throttle,
}), }),
reportLifecycleScripts(log$, { reportLifecycleScripts(log$, {
appendOnly: opts.appendOnly === true || opts.streamLifecycleOutput, appendOnly: opts.appendOnly === true || opts.streamLifecycleOutput,

View File

@@ -1,11 +1,12 @@
import { ProgressLog, StageLog } from '@pnpm/core-loggers' import { ProgressLog, StageLog } from '@pnpm/core-loggers'
import * as Rx from 'rxjs' import * as Rx from 'rxjs'
import { filter, map, mapTo, sampleTime, takeWhile, startWith, take } from 'rxjs/operators' import { filter, map, mapTo, takeWhile, startWith, take } from 'rxjs/operators'
import { hlValue } from './outputConstants' import { hlValue } from './outputConstants'
import { zoomOut } from './utils/zooming' import { zoomOut } from './utils/zooming'
interface ProgressStats { interface ProgressStats {
fetched: number fetched: number
imported: number
resolved: number resolved: number
reused: number reused: number
} }
@@ -23,12 +24,11 @@ export default (
}, },
opts: { opts: {
cwd: string cwd: string
throttleProgress?: number // eslint-disable-next-line @typescript-eslint/no-explicit-any
throttle?: Rx.OperatorFunction<any, any>
} }
) => { ) => {
const progressOutput = typeof opts.throttleProgress === 'number' && opts.throttleProgress > 0 const progressOutput = throttledProgressOutput.bind(null, opts.throttle)
? throttledProgressOutput.bind(null, opts.throttleProgress)
: nonThrottledProgressOutput
return getModulesInstallProgress$(log$.stage, log$.progress).pipe( return getModulesInstallProgress$(log$.stage, log$.progress).pipe(
map(({ importingDone$, progress$, requirer }) => { map(({ importingDone$, progress$, requirer }) => {
@@ -48,14 +48,15 @@ export default (
} }
function throttledProgressOutput ( function throttledProgressOutput (
throttleProgress: number, // eslint-disable-next-line @typescript-eslint/no-explicit-any
throttle: Rx.OperatorFunction<any, any> | undefined,
importingDone$: Rx.Observable<boolean>, importingDone$: Rx.Observable<boolean>,
progress$: Rx.Observable<ProgressStats> progress$: Rx.Observable<ProgressStats>
) { ) {
// Reporting is done every `throttleProgress` milliseconds // Reporting is done every `throttleProgress` milliseconds
// and once all packages are fetched. // and once all packages are fetched.
return Rx.combineLatest( return Rx.combineLatest(
progress$.pipe(sampleTime(throttleProgress)), throttle ? progress$.pipe(throttle) : progress$,
importingDone$ importingDone$
) )
.pipe( .pipe(
@@ -66,17 +67,6 @@ function throttledProgressOutput (
) )
} }
function nonThrottledProgressOutput (
importingDone$: Rx.Observable<boolean>,
progress$: Rx.Observable<ProgressStats>
) {
return Rx.combineLatest(
progress$,
importingDone$
)
.pipe(map(createStatusMessage))
}
function getModulesInstallProgress$ ( function getModulesInstallProgress$ (
stage$: Rx.Observable<StageLog>, stage$: Rx.Observable<StageLog>,
progress$: Rx.Observable<ProgressLog> progress$: Rx.Observable<ProgressLog>
@@ -132,6 +122,7 @@ function getProgessStatsPushStreamByRequirer (progress$: Rx.Observable<ProgressL
if (!previousProgressStatsByRequirer[log.requester]) { if (!previousProgressStatsByRequirer[log.requester]) {
previousProgressStatsByRequirer[log.requester] = { previousProgressStatsByRequirer[log.requester] = {
fetched: 0, fetched: 0,
imported: 0,
resolved: 0, resolved: 0,
reused: 0, reused: 0,
} }
@@ -146,6 +137,9 @@ function getProgessStatsPushStreamByRequirer (progress$: Rx.Observable<ProgressL
case 'found_in_store': case 'found_in_store':
previousProgressStatsByRequirer[log.requester].reused++ previousProgressStatsByRequirer[log.requester].reused++
break break
case 'imported':
previousProgressStatsByRequirer[log.requester].imported++
break
} }
if (!progessStatsPushStreamByRequirer[log.requester]) { if (!progessStatsPushStreamByRequirer[log.requester]) {
progessStatsPushStreamByRequirer[log.requester] = new Rx.Subject<ProgressStats>() progessStatsPushStreamByRequirer[log.requester] = new Rx.Subject<ProgressStats>()
@@ -158,7 +152,7 @@ function getProgessStatsPushStreamByRequirer (progress$: Rx.Observable<ProgressL
} }
function createStatusMessage ([progress, importingDone]: [ProgressStats, boolean]) { function createStatusMessage ([progress, importingDone]: [ProgressStats, boolean]) {
const msg = `Resolving: total ${hlValue(progress.resolved.toString())}, reused ${hlValue(progress.reused.toString())}, downloaded ${hlValue(progress.fetched.toString())}` const msg = `Progress: resolved ${hlValue(progress.resolved.toString())}, reused ${hlValue(progress.reused.toString())}, downloaded ${hlValue(progress.fetched.toString())}, added ${hlValue(progress.imported.toString())}`
if (importingDone) { if (importingDone) {
return { return {
done: true, done: true,

View File

@@ -45,7 +45,53 @@ test('prints progress beginning', t => {
complete: () => t.end(), complete: () => t.end(),
error: t.end, error: t.end,
next: output => { next: output => {
t.equal(output, `Resolving: total ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}`) t.equal(output, `Progress: resolved ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}`)
},
})
})
test('prints all progress stats', t => {
const output$ = toOutput$({
context: {
argv: ['install'],
config: { dir: '/src/project' } as Config,
},
streamParser: createStreamParser(),
})
stageLogger.debug({
prefix: '/src/project',
stage: 'resolution_started',
})
progressLogger.debug({
packageId: 'registry.npmjs.org/foo/1.0.0',
requester: '/src/project',
status: 'resolved',
})
progressLogger.debug({
packageId: 'registry.npmjs.org/foo/1.0.0',
requester: '/src/project',
status: 'fetched',
})
progressLogger.debug({
packageId: 'registry.npmjs.org/bar/1.0.0',
requester: '/src/project',
status: 'found_in_store',
})
progressLogger.debug({
method: 'hardlink',
requester: '/src/project',
status: 'imported',
to: '/node_modules/.pnpm/foo@1.0.0',
})
t.plan(1)
output$.pipe(skip(3), take(1)).subscribe({
complete: () => t.end(),
error: t.end,
next: output => {
t.equal(output, `Progress: resolved ${hlValue('1')}, reused ${hlValue('1')}, downloaded ${hlValue('1')}, added ${hlValue('1')}`)
}, },
}) })
}) })
@@ -75,7 +121,7 @@ test('prints progress beginning of node_modules from not cwd', t => {
complete: () => t.end(), complete: () => t.end(),
error: t.end, error: t.end,
next: output => { next: output => {
t.equal(output, `foo | Resolving: total ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}`) t.equal(output, `foo | Progress: resolved ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}`)
}, },
}) })
}) })
@@ -108,7 +154,7 @@ test('prints progress beginning when appendOnly is true', t => {
complete: () => t.end(), complete: () => t.end(),
error: t.end, error: t.end,
next: output => { next: output => {
t.equal(output, `Resolving: total ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}`) t.equal(output, `Progress: resolved ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}`)
}, },
}) })
}) })
@@ -141,7 +187,7 @@ test('prints progress beginning during recursive install', t => {
complete: () => t.end(), complete: () => t.end(),
error: t.end, error: t.end,
next: output => { next: output => {
t.equal(output, `Resolving: total ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}`) t.equal(output, `Progress: resolved ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}`)
}, },
}) })
}) })
@@ -162,7 +208,7 @@ test('prints progress on first download', async t => {
complete: () => t.end(), complete: () => t.end(),
error: t.end, error: t.end,
next: output => { next: output => {
t.equal(output, `Resolving: total ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('1')}`) t.equal(output, `Progress: resolved ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('1')}, added ${hlValue('0')}`)
}, },
}) })
@@ -202,7 +248,7 @@ test('moves fixed line to the end', async t => {
error: t.end, error: t.end,
next: output => { next: output => {
t.equal(output, `${WARN} foo` + EOL + t.equal(output, `${WARN} foo` + EOL +
`Resolving: total ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('1')}, done`) `Progress: resolved ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('1')}, added ${hlValue('0')}, done`)
}, },
}) })
@@ -278,33 +324,33 @@ test('prints progress of big files download', async t => {
map((output, index) => { map((output, index) => {
switch (index) { switch (index) {
case 0: case 0:
t.equal(output, `Resolving: total ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}`) t.equal(output, `Progress: resolved ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}`)
return return
case 1: case 1:
t.equal(output, `\ t.equal(output, `\
Resolving: total ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')} Progress: resolved ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}
Downloading ${hlPkgId(pkgId1)}: ${hlValue('0 B')}/${hlValue('10.5 MB')}`) Downloading ${hlPkgId(pkgId1)}: ${hlValue('0 B')}/${hlValue('10.5 MB')}`)
return return
case 2: case 2:
t.equal(output, `\ t.equal(output, `\
Resolving: total ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')} Progress: resolved ${hlValue('1')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}
Downloading ${hlPkgId(pkgId1)}: ${hlValue('5.77 MB')}/${hlValue('10.5 MB')}`) Downloading ${hlPkgId(pkgId1)}: ${hlValue('5.77 MB')}/${hlValue('10.5 MB')}`)
return return
case 4: case 4:
t.equal(output, `\ t.equal(output, `\
Resolving: total ${hlValue('2')}, reused ${hlValue('0')}, downloaded ${hlValue('0')} Progress: resolved ${hlValue('2')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}
Downloading ${hlPkgId(pkgId1)}: ${hlValue('7.34 MB')}/${hlValue('10.5 MB')}`, 'downloading of small package not reported') Downloading ${hlPkgId(pkgId1)}: ${hlValue('7.34 MB')}/${hlValue('10.5 MB')}`, 'downloading of small package not reported')
return return
case 7: case 7:
t.equal(output, `\ t.equal(output, `\
Resolving: total ${hlValue('3')}, reused ${hlValue('0')}, downloaded ${hlValue('0')} Progress: resolved ${hlValue('3')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}
Downloading ${hlPkgId(pkgId1)}: ${hlValue('7.34 MB')}/${hlValue('10.5 MB')} Downloading ${hlPkgId(pkgId1)}: ${hlValue('7.34 MB')}/${hlValue('10.5 MB')}
Downloading ${hlPkgId(pkgId3)}: ${hlValue('19.9 MB')}/${hlValue('21 MB')}`) Downloading ${hlPkgId(pkgId3)}: ${hlValue('19.9 MB')}/${hlValue('21 MB')}`)
return return
case 8: case 8:
t.equal(output, `\ t.equal(output, `\
Downloading ${hlPkgId(pkgId1)}: ${hlValue('10.5 MB')}/${hlValue('10.5 MB')}, done Downloading ${hlPkgId(pkgId1)}: ${hlValue('10.5 MB')}/${hlValue('10.5 MB')}, done
Resolving: total ${hlValue('3')}, reused ${hlValue('0')}, downloaded ${hlValue('0')} Progress: resolved ${hlValue('3')}, reused ${hlValue('0')}, downloaded ${hlValue('0')}, added ${hlValue('0')}
Downloading ${hlPkgId(pkgId3)}: ${hlValue('19.9 MB')}/${hlValue('21 MB')}`) Downloading ${hlPkgId(pkgId3)}: ${hlValue('19.9 MB')}/${hlValue('21 MB')}`)
return // eslint-disable-line return // eslint-disable-line
} }

View File

@@ -224,6 +224,7 @@ export default async (opts: HeadlessOptions) => {
}), }),
linkAllPkgs(opts.storeController, depNodes, { linkAllPkgs(opts.storeController, depNodes, {
force: opts.force, force: opts.force,
lockfileDir: opts.lockfileDir,
targetEngine: opts.sideEffectsCacheRead && ENGINE_NAME || undefined, targetEngine: opts.sideEffectsCacheRead && ENGINE_NAME || undefined,
}), }),
]) ])
@@ -646,6 +647,7 @@ function linkAllPkgs (
depNodes: DependenciesGraphNode[], depNodes: DependenciesGraphNode[],
opts: { opts: {
force: boolean force: boolean
lockfileDir: string
targetEngine?: string targetEngine?: string
} }
) { ) {
@@ -653,11 +655,19 @@ function linkAllPkgs (
depNodes.map(async (depNode) => { depNodes.map(async (depNode) => {
const filesResponse = await depNode.fetchingFiles() const filesResponse = await depNode.fetchingFiles()
const { isBuilt } = await storeController.importPackage(depNode.dir, { const { importMethod, isBuilt } = await storeController.importPackage(depNode.dir, {
filesResponse, filesResponse,
force: opts.force, force: opts.force,
targetEngine: opts.targetEngine, targetEngine: opts.targetEngine,
}) })
if (importMethod) {
progressLogger.debug({
method: importMethod,
requester: opts.lockfileDir,
status: 'imported',
to: depNode.dir,
})
}
depNode.isBuilt = isBuilt depNode.isBuilt = isBuilt
}) })
) )

View File

@@ -1,4 +1,4 @@
import { importingLogger, packageImportMethodLogger } from '@pnpm/core-loggers' import { packageImportMethodLogger } from '@pnpm/core-loggers'
import { globalInfo, globalWarn } from '@pnpm/logger' import { globalInfo, globalWarn } from '@pnpm/logger'
import importIndexedDir, { ImportFile } from '../fs/importIndexedDir' import importIndexedDir, { ImportFile } from '../fs/importIndexedDir'
import path = require('path') import path = require('path')
@@ -14,15 +14,13 @@ interface ImportOptions {
fromStore: boolean fromStore: boolean
} }
type ImportFunction = (to: string, opts: ImportOptions) => Promise<void> type ImportFunction = (to: string, opts: ImportOptions) => Promise<string | undefined>
export default ( export default (
packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone' packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone'
): ImportFunction => { ): ImportFunction => {
const importPackage = createImportPackage(packageImportMethod) const importPackage = createImportPackage(packageImportMethod)
return (to, opts) => limitLinking(async () => { return (to, opts) => limitLinking(() => importPackage(to, opts))
await importPackage(to, opts)
})
} }
function createImportPackage (packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone') { function createImportPackage (packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone') {
@@ -52,34 +50,32 @@ function createImportPackage (packageImportMethod?: 'auto' | 'hardlink' | 'copy'
function createAutoImporter (): ImportFunction { function createAutoImporter (): ImportFunction {
let auto = initialAuto let auto = initialAuto
return async (to, opts) => { return (to, opts) => auto(to, opts)
await auto(to, opts)
}
async function initialAuto ( async function initialAuto (
to: string, to: string,
opts: ImportOptions opts: ImportOptions
): Promise<boolean> { ): Promise<string | undefined> {
try { try {
if (!await clonePkg(to, opts)) return false if (!await clonePkg(to, opts)) return undefined
packageImportMethodLogger.debug({ method: 'clone' }) packageImportMethodLogger.debug({ method: 'clone' })
auto = clonePkg auto = clonePkg
return true return 'clone'
} catch (err) { } catch (err) {
// ignore // ignore
} }
try { try {
if (!await hardlinkPkg(fs.link, to, opts)) return false if (!await hardlinkPkg(fs.link, to, opts)) return undefined
packageImportMethodLogger.debug({ method: 'hardlink' }) packageImportMethodLogger.debug({ method: 'hardlink' })
auto = hardlinkPkg.bind(null, linkOrCopy) auto = hardlinkPkg.bind(null, linkOrCopy)
return true return 'hardlink'
} catch (err) { } catch (err) {
if (err.code === 'EINVAL') { if (err.code === 'EINVAL') {
// This error sometimes happens on Windows. // This error sometimes happens on Windows.
// We still choose hard linking that will fall back to copying in edge cases. // We still choose hard linking that will fall back to copying in edge cases.
packageImportMethodLogger.debug({ method: 'hardlink' }) packageImportMethodLogger.debug({ method: 'hardlink' })
auto = hardlinkPkg.bind(null, linkOrCopy) auto = hardlinkPkg.bind(null, linkOrCopy)
return true return 'hardlink'
} }
if (!err.message.startsWith('EXDEV: cross-device link not permitted')) throw err if (!err.message.startsWith('EXDEV: cross-device link not permitted')) throw err
globalWarn(err.message) globalWarn(err.message)
@@ -99,10 +95,9 @@ async function clonePkg (
if (!opts.fromStore || opts.force || !await exists(pkgJsonPath)) { if (!opts.fromStore || opts.force || !await exists(pkgJsonPath)) {
await importIndexedDir(cloneFile, to, opts.filesMap) await importIndexedDir(cloneFile, to, opts.filesMap)
importingLogger.debug({ to, method: 'clone' }) return 'clone'
return true
} }
return false return undefined
} }
async function cloneFile (from: string, to: string) { async function cloneFile (from: string, to: string) {
@@ -118,10 +113,9 @@ async function hardlinkPkg (
if (!opts.fromStore || opts.force || !await exists(pkgJsonPath) || !await pkgLinkedToStore(pkgJsonPath, opts.filesMap['package.json'], to)) { if (!opts.fromStore || opts.force || !await exists(pkgJsonPath) || !await pkgLinkedToStore(pkgJsonPath, opts.filesMap['package.json'], to)) {
await importIndexedDir(importFile, to, opts.filesMap) await importIndexedDir(importFile, to, opts.filesMap)
importingLogger.debug({ to, method: 'hardlink' }) return 'hardlink'
return true
} }
return false return undefined
} }
async function linkOrCopy (existingPath: string, newPath: string) { async function linkOrCopy (existingPath: string, newPath: string) {
@@ -158,8 +152,7 @@ export async function copyPkg (
if (!opts.fromStore || opts.force || !await exists(pkgJsonPath)) { if (!opts.fromStore || opts.force || !await exists(pkgJsonPath)) {
await importIndexedDir(fs.copyFile, to, opts.filesMap) await importIndexedDir(fs.copyFile, to, opts.filesMap)
importingLogger.debug({ to, method: 'copy' }) return 'copy'
return true
} }
return false return undefined
} }

View File

@@ -52,8 +52,8 @@ export default async function (
for (const [fileName, fileMeta] of Object.entries(filesIndex)) { for (const [fileName, fileMeta] of Object.entries(filesIndex)) {
filesMap[fileName] = getFilePathByModeInCafs(fileMeta.integrity, fileMeta.mode) filesMap[fileName] = getFilePathByModeInCafs(fileMeta.integrity, fileMeta.mode)
} }
await impPkg(to, { filesMap, fromStore: opts.filesResponse.fromStore, force: opts.force }) const importMethod = await impPkg(to, { filesMap, fromStore: opts.filesResponse.fromStore, force: opts.force })
return { isBuilt } return { importMethod, isBuilt }
} }
return { return {

View File

@@ -37,7 +37,7 @@ export default function (
return limitedFetch(`${remotePrefix}/importPackage`, { return limitedFetch(`${remotePrefix}/importPackage`, {
opts, opts,
to, to,
}) as Promise<{ isBuilt: boolean }> }) as Promise<{ importMethod: string | undefined, isBuilt: boolean }>
}, },
prune: async () => { prune: async () => {
await limitedFetch(`${remotePrefix}/prune`, {}) await limitedFetch(`${remotePrefix}/prune`, {})

View File

@@ -61,7 +61,7 @@ export type ImportPackageFunction = (
filesResponse: PackageFilesResponse filesResponse: PackageFilesResponse
force: boolean force: boolean
} }
) => Promise<{ isBuilt: boolean }> ) => Promise<{ isBuilt: boolean, importMethod: undefined | string }>
export interface PackageFileInfo { export interface PackageFileInfo {
integrity: string integrity: string

View File

@@ -1,5 +1,6 @@
import { ENGINE_NAME } from '@pnpm/constants' import { ENGINE_NAME } from '@pnpm/constants'
import { import {
progressLogger,
rootLogger, rootLogger,
stageLogger, stageLogger,
statsLogger, statsLogger,
@@ -317,6 +318,7 @@ async function linkNewPackages (
}), }),
linkAllPkgs(opts.storeController, newPkgs, { linkAllPkgs(opts.storeController, newPkgs, {
force: opts.force, force: opts.force,
lockfileDir: opts.lockfileDir,
targetEngine: opts.sideEffectsCacheRead && ENGINE_NAME || undefined, targetEngine: opts.sideEffectsCacheRead && ENGINE_NAME || undefined,
}), }),
]) ])
@@ -362,6 +364,7 @@ function linkAllPkgs (
depNodes: DependenciesGraphNode[], depNodes: DependenciesGraphNode[],
opts: { opts: {
force: boolean force: boolean
lockfileDir: string
targetEngine?: string targetEngine?: string
} }
) { ) {
@@ -369,11 +372,19 @@ function linkAllPkgs (
depNodes.map(async (depNode) => { depNodes.map(async (depNode) => {
const filesResponse = await depNode.fetchingFiles() const filesResponse = await depNode.fetchingFiles()
const { isBuilt } = await storeController.importPackage(depNode.dir, { const { importMethod, isBuilt } = await storeController.importPackage(depNode.dir, {
filesResponse, filesResponse,
force: opts.force, force: opts.force,
targetEngine: opts.targetEngine, targetEngine: opts.targetEngine,
}) })
if (importMethod) {
progressLogger.debug({
method: importMethod,
requester: opts.lockfileDir,
status: 'imported',
to: depNode.dir,
})
}
depNode.isBuilt = isBuilt depNode.isBuilt = isBuilt
}) })
) )