StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics
https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
5.5 KiB
162 lines
5.5 KiB
4 years ago
|
const Fetcher = require('./fetcher.js')
|
||
|
const RemoteFetcher = require('./remote.js')
|
||
|
const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved')
|
||
|
const pacoteVersion = require('../package.json').version
|
||
|
const npa = require('npm-package-arg')
|
||
|
const pickManifest = require('npm-pick-manifest')
|
||
|
const ssri = require('ssri')
|
||
|
const Minipass = require('minipass')
|
||
|
|
||
|
// Corgis are cute. 🐕🐶
|
||
|
const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'
|
||
|
const fullDoc = 'application/json'
|
||
|
|
||
|
const fetch = require('npm-registry-fetch')
|
||
|
|
||
|
// TODO: memoize reg requests, so we don't even have to check cache
|
||
|
|
||
|
const _headers = Symbol('_headers')
|
||
|
class RegistryFetcher extends Fetcher {
|
||
|
constructor (spec, opts) {
|
||
|
super(spec, opts)
|
||
|
|
||
|
// try to use corgis if available
|
||
|
this.fullMetadata = !!opts.fullMetadata
|
||
|
|
||
|
// handle case when npm-package-arg guesses wrong.
|
||
|
if (this.spec.type === 'tag' &&
|
||
|
this.spec.rawSpec === '' &&
|
||
|
this.tag !== 'latest')
|
||
|
this.spec = npa(`${this.spec.name}@${this.tag}`)
|
||
|
this.registry = fetch.pickRegistry(spec, opts)
|
||
|
this.packumentUrl = this.registry.replace(/\/*$/, '/') +
|
||
|
this.spec.escapedName
|
||
|
|
||
|
// XXX pacote <=9 has some logic to ignore opts.resolved if
|
||
|
// the resolved URL doesn't go to the same registry.
|
||
|
// Consider reproducing that here, to throw away this.resolved
|
||
|
// in that case.
|
||
|
}
|
||
|
|
||
|
resolve () {
|
||
|
if (this.resolved)
|
||
|
return Promise.resolve(this.resolved)
|
||
|
|
||
|
// fetching the manifest sets resolved and (usually) integrity
|
||
|
return this.manifest().then(() => {
|
||
|
if (this.resolved)
|
||
|
return this.resolved
|
||
|
|
||
|
throw Object.assign(
|
||
|
new Error('Invalid package manifest: no `dist.tarball` field'),
|
||
|
{ package: this.spec.toString() }
|
||
|
)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
[_headers] () {
|
||
|
return {
|
||
|
// npm will override UA, but ensure that we always send *something*
|
||
|
'user-agent': this.opts['user-agent'] ||
|
||
|
`pacote/${pacoteVersion} node/${process.version}`,
|
||
|
...(this.opts.headers || {}),
|
||
|
'pacote-version': pacoteVersion,
|
||
|
'pacote-req-type': 'packument',
|
||
|
'pacote-pkg-id': `registry:${this.spec.name}`,
|
||
|
accept: this.fullMetadata ? fullDoc : corgiDoc,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
packument () {
|
||
|
// npm-registry-fetch the packument
|
||
|
// set the appropriate header for corgis if fullMetadata isn't set
|
||
|
// return the res.json() promise
|
||
|
return fetch(this.packumentUrl, {
|
||
|
...this.opts,
|
||
|
headers: this[_headers](),
|
||
|
spec: this.spec,
|
||
|
// never check integrity for packuments themselves
|
||
|
integrity: null,
|
||
|
}).then(res => res.json().then(packument => {
|
||
|
packument._cached = res.headers.has('x-local-cache')
|
||
|
packument._contentLength = +res.headers.get('content-length')
|
||
|
return packument
|
||
|
})).catch(er => {
|
||
|
if (er.code === 'E404' && !this.fullMetadata) {
|
||
|
// possible that corgis are not supported by this registry
|
||
|
this.fullMetadata = true
|
||
|
return this.packument()
|
||
|
}
|
||
|
throw er
|
||
|
})
|
||
|
}
|
||
|
|
||
|
manifest () {
|
||
|
if (this.package)
|
||
|
return Promise.resolve(this.package)
|
||
|
|
||
|
return this.packument()
|
||
|
.then(packument => pickManifest(packument, this.spec.fetchSpec, {
|
||
|
...this.opts,
|
||
|
defaultTag: this.tag,
|
||
|
enjoyBy: this.enjoyBy,
|
||
|
}) /* XXX add ETARGET and E403 revalidation of cached packuments here */)
|
||
|
.then(mani => {
|
||
|
// add _resolved and _integrity from dist object
|
||
|
const { dist } = mani
|
||
|
if (dist) {
|
||
|
this.resolved = mani._resolved = dist.tarball
|
||
|
mani._from = this.from
|
||
|
const distIntegrity = dist.integrity ? ssri.parse(dist.integrity)
|
||
|
: dist.shasum ? ssri.fromHex(dist.shasum, 'sha1', this.opts)
|
||
|
: null
|
||
|
if (distIntegrity) {
|
||
|
if (!this.integrity)
|
||
|
this.integrity = distIntegrity
|
||
|
else if (!this.integrity.match(distIntegrity)) {
|
||
|
// only bork if they have algos in common.
|
||
|
// otherwise we end up breaking if we have saved a sha512
|
||
|
// previously for the tarball, but the manifest only
|
||
|
// provides a sha1, which is possible for older publishes.
|
||
|
// Otherwise, this is almost certainly a case of holding it
|
||
|
// wrong, and will result in weird or insecure behavior
|
||
|
// later on when building package tree.
|
||
|
for (const algo of Object.keys(this.integrity)) {
|
||
|
if (distIntegrity[algo]) {
|
||
|
throw Object.assign(new Error(
|
||
|
`Integrity checksum failed when using ${algo}: `+
|
||
|
`wanted ${this.integrity} but got ${distIntegrity}.`
|
||
|
), { code: 'EINTEGRITY' })
|
||
|
}
|
||
|
}
|
||
|
// made it this far, the integrity is worthwhile. accept it.
|
||
|
this.integrity = this.integrity.concat(distIntegrity)
|
||
|
this.opts.integrity = this.integrity
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (this.integrity)
|
||
|
mani._integrity = String(this.integrity)
|
||
|
return this.package = mani
|
||
|
})
|
||
|
}
|
||
|
|
||
|
[_tarballFromResolved] () {
|
||
|
// we use a RemoteFetcher to get the actual tarball stream
|
||
|
return new RemoteFetcher(this.resolved, {
|
||
|
...this.opts,
|
||
|
resolved: this.resolved,
|
||
|
pkgid: `registry:${this.spec.name}@${this.resolved}`,
|
||
|
})[_tarballFromResolved]()
|
||
|
}
|
||
|
|
||
|
get types () {
|
||
|
return [
|
||
|
'tag',
|
||
|
'version',
|
||
|
'range',
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
module.exports = RegistryFetcher
|