Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions lib/dir.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
const { resolve } = require('node:path')
const packlist = require('npm-packlist')
const runScript = require('@npmcli/run-script')
const tar = require('tar')
const { Minipass } = require('minipass')
const { lazyRunScript, lazyMinipass, lazyNpmPacklist, lazyTar, lazyFileFetcher } = require('./lazy.js')
const Fetcher = require('./fetcher.js')
const FileFetcher = require('./file.js')
const _ = require('./util/protected.js')
const tarCreateOptions = require('./util/tar-create-options.js')

Expand Down Expand Up @@ -41,7 +37,7 @@ class DirFetcher extends Fetcher {
// but this function is *also* run when installing git deps
const stdio = this.opts.foregroundScripts ? 'inherit' : 'pipe'

return runScript({
return lazyRunScript()({
// this || undefined is because runScript will be unhappy with the default null value
scriptShell: this.opts.scriptShell || undefined,
pkg: mani,
Expand All @@ -62,6 +58,7 @@ class DirFetcher extends Fetcher {
throw new Error('DirFetcher requires either a tree or an Arborist constructor to pack')
}

const { Minipass } = lazyMinipass()
const stream = new Minipass()
stream.resolved = this.resolved
stream.integrity = this.integrity
Expand All @@ -76,9 +73,9 @@ class DirFetcher extends Fetcher {
const arb = new this.Arborist({ path: this.resolved })
this.tree = await arb.loadActual()
}
return packlist(this.tree, { path: this.resolved, prefix, workspaces })
return lazyNpmPacklist()(this.tree, { path: this.resolved, prefix, workspaces })
})
.then(files => tar.c(tarCreateOptions(this.package), files)
.then(files => lazyTar().c(tarCreateOptions(this.package), files)
.on('error', er => stream.emit('error', er)).pipe(stream))
.catch(er => stream.emit('error', er))
return stream
Expand All @@ -99,7 +96,7 @@ class DirFetcher extends Fetcher {
}

packument () {
return FileFetcher.prototype.packument.apply(this)
return lazyFileFetcher().prototype.packument.apply(this)
}
}
module.exports = DirFetcher
59 changes: 30 additions & 29 deletions lib/fetcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,25 @@

const { basename, dirname } = require('node:path')
const { rm, mkdir } = require('node:fs/promises')
const PackageJson = require('@npmcli/package-json')
const cacache = require('cacache')
const fsm = require('fs-minipass')
const getContents = require('@npmcli/installed-package-contents')
const npa = require('npm-package-arg')
const retry = require('promise-retry')
const ssri = require('ssri')
const tar = require('tar')
const { Minipass } = require('minipass')
const { log } = require('proc-log')
const _ = require('./util/protected.js')
const cacheDir = require('./util/cache-dir.js')
const isPackageBin = require('./util/is-package-bin.js')
const removeTrailingSlashes = require('./util/trailing-slashes.js')
const { lazyMinipass, lazyPackageJson, lazyNpa, lazySsri, lazyCacache, lazyFsm, lazyTar } = require('./lazy.js')

// Pacote is only concerned with the package.json contents
const packageJsonPrepare = (p) => PackageJson.prepare(p).then(pkg => pkg.content)
const packageJsonNormalize = (p) => PackageJson.normalize(p).then(pkg => pkg.content)
const packageJsonPrepare = (p) => lazyPackageJson().prepare(p).then(pkg => pkg.content)
const packageJsonNormalize = (p) => lazyPackageJson().normalize(p).then(pkg => pkg.content)

class FetcherBase {
constructor (spec, opts) {
if (!opts || typeof opts !== 'object') {
throw new TypeError('options object is required')
}
this.spec = npa(spec, opts.where)
this.spec = lazyNpa()(spec, opts.where)

this.allowGitIgnore = !!opts.allowGitIgnore

Expand Down Expand Up @@ -57,7 +51,7 @@ class FetcherBase {
this.defaultIntegrityAlgorithm = opts.defaultIntegrityAlgorithm || 'sha512'

if (typeof opts.integrity === 'string') {
this.opts.integrity = ssri.parse(opts.integrity)
this.opts.integrity = lazySsri().parse(opts.integrity)
}

this.package = null
Expand Down Expand Up @@ -130,7 +124,7 @@ class FetcherBase {
return
}

i = ssri.parse(i)
i = lazySsri().parse(i)
const current = this.opts.integrity

// do not ever update an existing hash value, but do
Expand Down Expand Up @@ -189,7 +183,7 @@ class FetcherBase {
// Note: cacache will raise a EINTEGRITY error if the integrity doesn't match
#tarballFromCache () {
const startTime = Date.now()
const stream = cacache.get.stream.byDigest(this.cache, this.integrity, this.opts)
const stream = lazyCacache().get.stream.byDigest(this.cache, this.integrity, this.opts)
const elapsedTime = Date.now() - startTime
// cache is good, so log it as a hit in particular since there was no fetch logged
log.http(
Expand All @@ -213,7 +207,7 @@ class FetcherBase {
return stream
}

const istream = ssri.integrityStream(this.opts)
const istream = lazySsri().integrityStream(this.opts)
istream.on('integrity', i => this.integrity = i)
stream.on('error', err => istream.emit('error', err))
return stream.pipe(istream)
Expand All @@ -226,10 +220,11 @@ class FetcherBase {
// the cache AFTER we pipe into the middleStream. Since the cache stream
// has an asynchronous flush to write its contents to disk, we need to
// defer the middleStream end until the cache stream ends.
const { Minipass } = lazyMinipass()
const middleStream = new Minipass()
stream.on('error', err => middleStream.emit('error', err))
stream.pipe(middleStream, { end: false })
const cstream = cacache.put.stream(
const cstream = lazyCacache().put.stream(
this.opts.cache,
`pacote:tarball:${this.from}`,
this.opts
Expand Down Expand Up @@ -340,7 +335,7 @@ class FetcherBase {
}

cleanupCached () {
return cacache.rm.content(this.cache, this.integrity, this.opts)
return lazyCacache().rm.content(this.cache, this.integrity, this.opts)
}

#empty (path) {
Expand All @@ -361,6 +356,8 @@ class FetcherBase {
}

#toFile (dest) {
const fsm = lazyFsm()

return this.tarballStream(str => new Promise((res, rej) => {
const writer = new fsm.WriteStream(dest)
str.on('error', er => writer.emit('error', er))
Expand All @@ -382,6 +379,7 @@ class FetcherBase {
}

#extract (dest, tarball) {
const tar = lazyTar()
const extractor = tar.x(this.#tarxOptions({ cwd: dest }))
const p = new Promise((resolve, reject) => {
extractor.on('end', () => {
Expand Down Expand Up @@ -462,34 +460,37 @@ class FetcherBase {

module.exports = FetcherBase

// Child classes
const GitFetcher = require('./git.js')
const RegistryFetcher = require('./registry.js')
const FileFetcher = require('./file.js')
const DirFetcher = require('./dir.js')
const RemoteFetcher = require('./remote.js')

// Get an appropriate fetcher object from a spec and options
FetcherBase.get = (rawSpec, opts = {}) => {
const spec = npa(rawSpec, opts.where)
const spec = lazyNpa()(rawSpec, opts.where)
switch (spec.type) {
case 'git':
case 'git': {
const GitFetcher = require('./git.js')
return new GitFetcher(spec, opts)
}

case 'remote':
case 'remote': {
const RemoteFetcher = require('./remote.js')
return new RemoteFetcher(spec, opts)
}

case 'version':
case 'range':
case 'tag':
case 'alias':
case 'alias': {
const RegistryFetcher = require('./registry.js')
return new RegistryFetcher(spec.subSpec || spec, opts)
}

case 'file':
case 'file': {
const FileFetcher = require('./file.js')
return new FileFetcher(spec, opts)
}

case 'directory':
case 'directory': {
const DirFetcher = require('./dir.js')
return new DirFetcher(spec, opts)
}

default:
throw new TypeError('Unknown spec type: ' + spec.type)
Expand Down
6 changes: 3 additions & 3 deletions lib/file.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
const { resolve } = require('node:path')
const { stat, chmod } = require('node:fs/promises')
const cacache = require('cacache')
const fsm = require('fs-minipass')
const Fetcher = require('./fetcher.js')
const _ = require('./util/protected.js')
const { lazyCacache, lazyFsm } = require('./lazy.js')

class FileFetcher extends Fetcher {
constructor (spec, opts) {
Expand All @@ -22,7 +21,7 @@ class FileFetcher extends Fetcher {
}

// have to unpack the tarball for this.
return cacache.tmp.withTmp(this.cache, this.opts, dir =>
return lazyCacache().tmp.withTmp(this.cache, this.opts, dir =>
this.extract(dir)
.then(() => this[_.readPackageJson](dir))
.then(mani => this.package = {
Expand Down Expand Up @@ -67,6 +66,7 @@ class FileFetcher extends Fetcher {
}

[_.tarballFromResolved] () {
const fsm = lazyFsm()
// create a read stream and return it
return new fsm.ReadStream(this.resolved)
}
Expand Down
28 changes: 13 additions & 15 deletions lib/git.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
const cacache = require('cacache')
const git = require('@npmcli/git')
const npa = require('npm-package-arg')
const pickManifest = require('npm-pick-manifest')
const { Minipass } = require('minipass')
const { lazyGit, lazyNpa, lazyPickManifest, lazyMinipass, lazyCacache } = require('./lazy.js')
const { log } = require('proc-log')
const DirFetcher = require('./dir.js')
const Fetcher = require('./fetcher.js')
const FileFetcher = require('./file.js')
const RemoteFetcher = require('./remote.js')
const _ = require('./util/protected.js')
const addGitSha = require('./util/add-git-sha.js')
const npm = require('./util/npm.js')
Expand Down Expand Up @@ -87,7 +80,7 @@ class GitFetcher extends Fetcher {
#resolvedFromHosted (hosted) {
return this.#resolvedFromRepo(hosted.https && hosted.https()).catch(er => {
// Throw early since we know pathspec errors will fail again if retried
if (er instanceof git.errors.GitPathspecError) {
if (er instanceof lazyGit().errors.GitPathspecError) {
throw er
}
const ssh = hosted.sshurl && hosted.sshurl()
Expand All @@ -106,8 +99,8 @@ class GitFetcher extends Fetcher {
}
const gitRange = this.spec.gitRange
const name = this.spec.name
return git.revs(gitRemote, this.opts).then(remoteRefs => {
return gitRange ? pickManifest({
return lazyGit().revs(gitRemote, this.opts).then(remoteRefs => {
return gitRange ? lazyPickManifest()({
versions: remoteRefs.versions,
'dist-tags': remoteRefs['dist-tags'],
name,
Expand All @@ -134,7 +127,7 @@ class GitFetcher extends Fetcher {
// we haven't cloned, so a tgz download is still faster
// of course, if it's not a known host, we can't do that.
this.resolved = !this.spec.hosted ? withSha
: repoUrl(npa(withSha).hosted, { noCommittish: false })
: repoUrl(lazyNpa()(withSha).hosted, { noCommittish: false })
}

// when we get the git sha, we affix it to our spec to build up
Expand Down Expand Up @@ -191,10 +184,12 @@ class GitFetcher extends Fetcher {
}

[_.tarballFromResolved] () {
const { Minipass } = lazyMinipass()
const stream = new Minipass()
stream.resolved = this.resolved
stream.from = this.from

const DirFetcher = require('./dir.js')
// check it out and then shell out to the DirFetcher tarball packer
this.#clone(dir => this.#prepareDir(dir)
.then(() => new Promise((res, rej) => {
Expand Down Expand Up @@ -235,10 +230,11 @@ class GitFetcher extends Fetcher {
tarballOk = tarballOk &&
h && resolved === repoUrl(h, { noCommittish: false }) && h.tarball

return cacache.tmp.withTmp(this.cache, o, async tmp => {
return lazyCacache().tmp.withTmp(this.cache, o, async tmp => {
// if we're resolved, and have a tarball url, shell out to RemoteFetcher
if (tarballOk) {
const nameat = this.spec.name ? `${this.spec.name}@` : ''
const RemoteFetcher = require('./remote.js')
return new RemoteFetcher(h.tarball({ noCommittish: false }), {
...this.opts,
allowGitIgnore: true,
Expand Down Expand Up @@ -277,7 +273,7 @@ class GitFetcher extends Fetcher {
return this.#cloneRepo(hosted.https({ noCommittish: true }), ref, tmp)
.catch(er => {
// Throw early since we know pathspec errors will fail again if retried
if (er instanceof git.errors.GitPathspecError) {
if (er instanceof lazyGit().errors.GitPathspecError) {
throw er
}
const ssh = hosted.sshurl && hosted.sshurl({ noCommittish: true })
Expand All @@ -291,14 +287,15 @@ class GitFetcher extends Fetcher {

#cloneRepo (repo, ref, tmp) {
const { opts, spec } = this
return git.clone(repo, ref, tmp, { ...opts, spec })
return lazyGit().clone(repo, ref, tmp, { ...opts, spec })
}

manifest () {
if (this.package) {
return Promise.resolve(this.package)
}

const FileFetcher = require('./file.js')
return this.spec.hosted && this.resolved
? FileFetcher.prototype.manifest.apply(this)
: this.#clone(dir =>
Expand All @@ -311,6 +308,7 @@ class GitFetcher extends Fetcher {
}

packument () {
const FileFetcher = require('./file.js')
return FileFetcher.prototype.packument.apply(this)
}
}
Expand Down
Loading