summaryrefslogtreecommitdiff
path: root/deps/npm/lib/publish.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/lib/publish.js')
-rw-r--r--deps/npm/lib/publish.js188
1 files changed, 64 insertions, 124 deletions
diff --git a/deps/npm/lib/publish.js b/deps/npm/lib/publish.js
index 25f2134b1b..e81fc1a057 100644
--- a/deps/npm/lib/publish.js
+++ b/deps/npm/lib/publish.js
@@ -3,20 +3,20 @@
const BB = require('bluebird')
const cacache = require('cacache')
-const createReadStream = require('graceful-fs').createReadStream
-const getPublishConfig = require('./utils/get-publish-config.js')
+const figgyPudding = require('figgy-pudding')
+const libpub = require('libnpm/publish')
+const libunpub = require('libnpm/unpublish')
const lifecycle = BB.promisify(require('./utils/lifecycle.js'))
const log = require('npmlog')
-const mapToRegistry = require('./utils/map-to-registry.js')
-const npa = require('npm-package-arg')
-const npm = require('./npm.js')
+const npa = require('libnpm/parse-arg')
+const npmConfig = require('./config/figgy-config.js')
const output = require('./utils/output.js')
+const otplease = require('./utils/otplease.js')
const pack = require('./pack')
-const pacote = require('pacote')
-const pacoteOpts = require('./config/pacote')
+const { tarball, extract } = require('libnpm')
const path = require('path')
+const readFileAsync = BB.promisify(require('graceful-fs').readFile)
const readJson = BB.promisify(require('read-package-json'))
-const readUserInfo = require('./utils/read-user-info.js')
const semver = require('semver')
const statAsync = BB.promisify(require('graceful-fs').stat)
@@ -31,6 +31,16 @@ publish.completion = function (opts, cb) {
return cb()
}
+const PublishConfig = figgyPudding({
+ dryRun: 'dry-run',
+ 'dry-run': { default: false },
+ force: { default: false },
+ json: { default: false },
+ Promise: { default: () => Promise },
+ tag: { default: 'latest' },
+ tmp: {}
+})
+
module.exports = publish
function publish (args, isRetry, cb) {
if (typeof cb !== 'function') {
@@ -42,15 +52,16 @@ function publish (args, isRetry, cb) {
log.verbose('publish', args)
- const t = npm.config.get('tag').trim()
+ const opts = PublishConfig(npmConfig())
+ const t = opts.tag.trim()
if (semver.validRange(t)) {
return cb(new Error('Tag name must not be a valid SemVer range: ' + t))
}
- return publish_(args[0])
+ return publish_(args[0], opts)
.then((tarball) => {
const silent = log.level === 'silent'
- if (!silent && npm.config.get('json')) {
+ if (!silent && opts.json) {
output(JSON.stringify(tarball, null, 2))
} else if (!silent) {
output(`+ ${tarball.id}`)
@@ -59,7 +70,7 @@ function publish (args, isRetry, cb) {
.nodeify(cb)
}
-function publish_ (arg) {
+function publish_ (arg, opts) {
return statAsync(arg).then((stat) => {
if (stat.isDirectory()) {
return stat
@@ -69,17 +80,17 @@ function publish_ (arg) {
throw err
}
}).then(() => {
- return publishFromDirectory(arg)
+ return publishFromDirectory(arg, opts)
}, (err) => {
if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
throw err
} else {
- return publishFromPackage(arg)
+ return publishFromPackage(arg, opts)
}
})
}
-function publishFromDirectory (arg) {
+function publishFromDirectory (arg, opts) {
// All this readJson is because any of the given scripts might modify the
// package.json in question, so we need to refresh after every step.
let contents
@@ -90,12 +101,12 @@ function publishFromDirectory (arg) {
}).then(() => {
return readJson(path.join(arg, 'package.json'))
}).then((pkg) => {
- return cacache.tmp.withTmp(npm.tmp, {tmpPrefix: 'fromDir'}, (tmpDir) => {
+ return cacache.tmp.withTmp(opts.tmp, {tmpPrefix: 'fromDir'}, (tmpDir) => {
const target = path.join(tmpDir, 'package.tgz')
return pack.packDirectory(pkg, arg, target, null, true)
.tap((c) => { contents = c })
- .then((c) => !npm.config.get('json') && pack.logContents(c))
- .then(() => upload(arg, pkg, false, target))
+ .then((c) => !opts.json && pack.logContents(c))
+ .then(() => upload(pkg, false, target, opts))
})
}).then(() => {
return readJson(path.join(arg, 'package.json'))
@@ -107,121 +118,50 @@ function publishFromDirectory (arg) {
.then(() => contents)
}
-function publishFromPackage (arg) {
- return cacache.tmp.withTmp(npm.tmp, {tmpPrefix: 'fromPackage'}, (tmp) => {
+function publishFromPackage (arg, opts) {
+ return cacache.tmp.withTmp(opts.tmp, {tmpPrefix: 'fromPackage'}, tmp => {
const extracted = path.join(tmp, 'package')
const target = path.join(tmp, 'package.json')
- const opts = pacoteOpts()
- return pacote.tarball.toFile(arg, target, opts)
- .then(() => pacote.extract(arg, extracted, opts))
+ return tarball.toFile(arg, target, opts)
+ .then(() => extract(arg, extracted, opts))
.then(() => readJson(path.join(extracted, 'package.json')))
.then((pkg) => {
return BB.resolve(pack.getContents(pkg, target))
- .tap((c) => !npm.config.get('json') && pack.logContents(c))
- .tap(() => upload(arg, pkg, false, target))
+ .tap((c) => !opts.json && pack.logContents(c))
+ .tap(() => upload(pkg, false, target, opts))
})
})
}
-function upload (arg, pkg, isRetry, cached) {
- if (!pkg) {
- return BB.reject(new Error('no package.json file found'))
- }
- if (pkg.private) {
- return BB.reject(new Error(
- 'This package has been marked as private\n' +
- "Remove the 'private' field from the package.json to publish it."
- ))
- }
- const mappedConfig = getPublishConfig(
- pkg.publishConfig,
- npm.config,
- npm.registry
- )
- const config = mappedConfig.config
- const registry = mappedConfig.client
-
- pkg._npmVersion = npm.version
- pkg._nodeVersion = process.versions.node
-
- delete pkg.modules
-
- return BB.fromNode((cb) => {
- mapToRegistry(pkg.name, config, (err, registryURI, auth, registryBase) => {
- if (err) { return cb(err) }
- cb(null, [registryURI, auth, registryBase])
- })
- }).spread((registryURI, auth, registryBase) => {
- // we just want the base registry URL in this case
- log.verbose('publish', 'registryBase', registryBase)
- log.silly('publish', 'uploading', cached)
-
- pkg._npmUser = {
- name: auth.username,
- email: auth.email
- }
-
- const params = {
- metadata: pkg,
- body: !npm.config.get('dry-run') && createReadStream(cached),
- auth: auth
- }
-
- function closeFile () {
- if (!npm.config.get('dry-run')) {
- params.body.close()
- }
- }
-
- // registry-frontdoor cares about the access level, which is only
- // configurable for scoped packages
- if (config.get('access')) {
- if (!npa(pkg.name).scope && config.get('access') === 'restricted') {
- throw new Error("Can't restrict access to unscoped packages.")
- }
-
- params.access = config.get('access')
- }
-
- if (npm.config.get('dry-run')) {
- log.verbose('publish', '--dry-run mode enabled. Skipping upload.')
- return BB.resolve()
- }
-
- log.showProgress('publish:' + pkg._id)
- return BB.fromNode((cb) => {
- registry.publish(registryBase, params, cb)
- }).catch((err) => {
- if (
- err.code === 'EPUBLISHCONFLICT' &&
- npm.config.get('force') &&
- !isRetry
- ) {
- log.warn('publish', 'Forced publish over ' + pkg._id)
- return BB.fromNode((cb) => {
- npm.commands.unpublish([pkg._id], cb)
- }).finally(() => {
- // close the file we are trying to upload, we will open it again.
- closeFile()
- // ignore errors. Use the force. Reach out with your feelings.
- return upload(arg, pkg, true, cached).catch(() => {
- // but if it fails again, then report the first error.
- throw err
+function upload (pkg, isRetry, cached, opts) {
+ if (!opts.dryRun) {
+ return readFileAsync(cached).then(tarball => {
+ return otplease(opts, opts => {
+ return libpub(pkg, tarball, opts)
+ }).catch(err => {
+ if (
+ err.code === 'EPUBLISHCONFLICT' &&
+ opts.force &&
+ !isRetry
+ ) {
+ log.warn('publish', 'Forced publish over ' + pkg._id)
+ return otplease(opts, opts => libunpub(
+ npa.resolve(pkg.name, pkg.version), opts
+ )).finally(() => {
+ // ignore errors. Use the force. Reach out with your feelings.
+ return otplease(opts, opts => {
+ return upload(pkg, true, tarball, opts)
+ }).catch(() => {
+ // but if it fails again, then report the first error.
+ throw err
+ })
})
- })
- } else {
- // close the file we are trying to upload, all attempts to resume will open it again
- closeFile()
- throw err
- }
- })
- }).catch((err) => {
- if (err.code !== 'EOTP' && !(err.code === 'E401' && /one-time pass/.test(err.message))) throw err
- // we prompt on stdout and read answers from stdin, so they need to be ttys.
- if (!process.stdin.isTTY || !process.stdout.isTTY) throw err
- return readUserInfo.otp().then((otp) => {
- npm.config.set('otp', otp)
- return upload(arg, pkg, isRetry, cached)
+ } else {
+ throw err
+ }
+ })
})
- })
+ } else {
+ return opts.Promise.resolve(true)
+ }
}