aboutsummaryrefslogtreecommitdiff
path: root/deps/node/deps/npm/lib/version.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/node/deps/npm/lib/version.js')
-rw-r--r--deps/node/deps/npm/lib/version.js345
1 files changed, 345 insertions, 0 deletions
diff --git a/deps/node/deps/npm/lib/version.js b/deps/node/deps/npm/lib/version.js
new file mode 100644
index 00000000..265b049b
--- /dev/null
+++ b/deps/node/deps/npm/lib/version.js
@@ -0,0 +1,345 @@
+'use strict'
+const BB = require('bluebird')
+
+const assert = require('assert')
+const chain = require('slide').chain
+const detectIndent = require('detect-indent')
+const detectNewline = require('detect-newline')
+const fs = require('graceful-fs')
+const readFile = BB.promisify(require('graceful-fs').readFile)
+const git = require('./utils/git.js')
+const lifecycle = require('./utils/lifecycle.js')
+const log = require('npmlog')
+const npm = require('./npm.js')
+const output = require('./utils/output.js')
+const parseJSON = require('./utils/parse-json.js')
+const path = require('path')
+const semver = require('semver')
+const stringifyPackage = require('stringify-package')
+const writeFileAtomic = require('write-file-atomic')
+
+version.usage = 'npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]' +
+ '\n(run in package dir)\n' +
+ "'npm -v' or 'npm --version' to print npm version " +
+ '(' + npm.version + ')\n' +
+ "'npm view <pkg> version' to view a package's " +
+ 'published version\n' +
+ "'npm ls' to inspect current package/dependency versions"
+
+// npm version <newver>
+module.exports = version
+function version (args, silent, cb_) {
+ if (typeof cb_ !== 'function') {
+ cb_ = silent
+ silent = false
+ }
+ if (args.length > 1) return cb_(version.usage)
+
+ readPackage(function (er, data, indent, newline) {
+ if (!args.length) return dump(data, cb_)
+
+ if (er) {
+ log.error('version', 'No valid package.json found')
+ return cb_(er)
+ }
+
+ if (args[0] === 'from-git') {
+ retrieveTagVersion(silent, data, cb_)
+ } else {
+ var newVersion = semver.valid(args[0])
+ if (!newVersion) newVersion = semver.inc(data.version, args[0], npm.config.get('preid'))
+ if (!newVersion) return cb_(version.usage)
+ persistVersion(newVersion, silent, data, cb_)
+ }
+ })
+}
+
+function retrieveTagVersion (silent, data, cb_) {
+ chain([
+ verifyGit,
+ parseLastGitTag
+ ], function (er, results) {
+ if (er) return cb_(er)
+ var localData = {
+ hasGit: true,
+ existingTag: true
+ }
+
+ var version = results[results.length - 1]
+ persistVersion(version, silent, data, localData, cb_)
+ })
+}
+
+function parseLastGitTag (cb) {
+ var options = { env: process.env }
+ git.whichAndExec(['describe', '--abbrev=0'], options, function (er, stdout) {
+ if (er) {
+ if (er.message.indexOf('No names found') !== -1) return cb(new Error('No tags found'))
+ return cb(er)
+ }
+
+ var tag = stdout.trim()
+ var prefix = npm.config.get('tag-version-prefix')
+ // Strip the prefix from the start of the tag:
+ if (tag.indexOf(prefix) === 0) tag = tag.slice(prefix.length)
+ var version = semver.valid(tag)
+ if (!version) return cb(new Error(tag + ' is not a valid version'))
+ cb(null, version)
+ })
+}
+
+function persistVersion (newVersion, silent, data, localData, cb_) {
+ if (typeof localData === 'function') {
+ cb_ = localData
+ localData = {}
+ }
+
+ if (!npm.config.get('allow-same-version') && data.version === newVersion) {
+ return cb_(new Error('Version not changed, might want --allow-same-version'))
+ }
+ data.version = newVersion
+ var lifecycleData = Object.create(data)
+ lifecycleData._id = data.name + '@' + newVersion
+
+ var where = npm.prefix
+ chain([
+ !localData.hasGit && [checkGit, localData],
+ [lifecycle, lifecycleData, 'preversion', where],
+ [updatePackage, newVersion, silent],
+ [lifecycle, lifecycleData, 'version', where],
+ [commit, localData, newVersion],
+ [lifecycle, lifecycleData, 'postversion', where]
+ ], cb_)
+}
+
+function readPackage (cb) {
+ var packagePath = path.join(npm.localPrefix, 'package.json')
+ fs.readFile(packagePath, 'utf8', function (er, data) {
+ if (er) return cb(new Error(er))
+ var indent
+ var newline
+ try {
+ indent = detectIndent(data).indent
+ newline = detectNewline(data)
+ data = JSON.parse(data)
+ } catch (e) {
+ er = e
+ data = null
+ }
+ cb(er, data, indent, newline)
+ })
+}
+
+function updatePackage (newVersion, silent, cb_) {
+ function cb (er) {
+ if (!er && !silent) output('v' + newVersion)
+ cb_(er)
+ }
+
+ readPackage(function (er, data, indent, newline) {
+ if (er) return cb(new Error(er))
+ data.version = newVersion
+ write(data, 'package.json', indent, newline, cb)
+ })
+}
+
+function commit (localData, newVersion, cb) {
+ updateShrinkwrap(newVersion, function (er, hasShrinkwrap, hasLock) {
+ if (er || !localData.hasGit) return cb(er)
+ localData.hasShrinkwrap = hasShrinkwrap
+ localData.hasPackageLock = hasLock
+ _commit(newVersion, localData, cb)
+ })
+}
+
+const SHRINKWRAP = 'npm-shrinkwrap.json'
+const PKGLOCK = 'package-lock.json'
+
+function readLockfile (name) {
+ return readFile(
+ path.join(npm.localPrefix, name), 'utf8'
+ ).catch({code: 'ENOENT'}, () => null)
+}
+
+function updateShrinkwrap (newVersion, cb) {
+ BB.join(
+ readLockfile(SHRINKWRAP),
+ readLockfile(PKGLOCK),
+ (shrinkwrap, lockfile) => {
+ if (!shrinkwrap && !lockfile) {
+ return cb(null, false, false)
+ }
+ const file = shrinkwrap ? SHRINKWRAP : PKGLOCK
+ let data
+ let indent
+ let newline
+ try {
+ data = parseJSON(shrinkwrap || lockfile)
+ indent = detectIndent(shrinkwrap || lockfile).indent
+ newline = detectNewline(shrinkwrap || lockfile)
+ } catch (err) {
+ log.error('version', `Bad ${file} data.`)
+ return cb(err)
+ }
+ data.version = newVersion
+ write(data, file, indent, newline, (err) => {
+ if (err) {
+ log.error('version', `Failed to update version in ${file}`)
+ return cb(err)
+ } else {
+ return cb(null, !!shrinkwrap, !!lockfile)
+ }
+ })
+ }
+ )
+}
+
+function dump (data, cb) {
+ var v = {}
+
+ if (data && data.name && data.version) v[data.name] = data.version
+ v.npm = npm.version
+ Object.keys(process.versions).sort().forEach(function (k) {
+ v[k] = process.versions[k]
+ })
+
+ if (npm.config.get('json')) v = JSON.stringify(v, null, 2)
+
+ output(v)
+ cb()
+}
+
+function statGitFolder (cb) {
+ fs.stat(path.join(npm.localPrefix, '.git'), cb)
+}
+
+function callGitStatus (cb) {
+ git.whichAndExec(
+ [ 'status', '--porcelain' ],
+ { env: process.env },
+ cb
+ )
+}
+
+function cleanStatusLines (stdout) {
+ var lines = stdout.trim().split('\n').filter(function (line) {
+ return line.trim() && !line.match(/^\?\? /)
+ }).map(function (line) {
+ return line.trim()
+ })
+
+ return lines
+}
+
+function verifyGit (cb) {
+ function checkStatus (er) {
+ if (er) return cb(er)
+ callGitStatus(checkStdout)
+ }
+
+ function checkStdout (er, stdout) {
+ if (er) return cb(er)
+ var lines = cleanStatusLines(stdout)
+ if (lines.length > 0) {
+ return cb(new Error(
+ 'Git working directory not clean.\n' + lines.join('\n')
+ ))
+ }
+
+ cb()
+ }
+
+ statGitFolder(checkStatus)
+}
+
+function checkGit (localData, cb) {
+ statGitFolder(function (er) {
+ var doGit = !er && npm.config.get('git-tag-version')
+ if (!doGit) {
+ if (er) log.verbose('version', 'error checking for .git', er)
+ log.verbose('version', 'not tagging in git')
+ return cb(null, false)
+ }
+
+ // check for git
+ callGitStatus(function (er, stdout) {
+ if (er && er.code === 'ENOGIT') {
+ log.warn(
+ 'version',
+ 'This is a Git checkout, but the git command was not found.',
+ 'npm could not create a Git tag for this release!'
+ )
+ return cb(null, false)
+ }
+
+ var lines = cleanStatusLines(stdout)
+ if (lines.length && !npm.config.get('force')) {
+ return cb(new Error(
+ 'Git working directory not clean.\n' + lines.join('\n')
+ ))
+ }
+ localData.hasGit = true
+ cb(null, true)
+ })
+ })
+}
+
+module.exports.buildCommitArgs = buildCommitArgs
+function buildCommitArgs (args) {
+ args = args || [ 'commit' ]
+ if (!npm.config.get('commit-hooks')) args.push('-n')
+ return args
+}
+
+function _commit (version, localData, cb) {
+ const options = { env: process.env }
+ const message = npm.config.get('message').replace(/%s/g, version)
+ const signTag = npm.config.get('sign-git-tag')
+ const signCommit = npm.config.get('sign-git-commit')
+ const commitArgs = buildCommitArgs([
+ 'commit',
+ ...(signCommit ? ['-S', '-m'] : ['-m']),
+ message
+ ])
+ const flagForTag = signTag ? '-sm' : '-am'
+
+ stagePackageFiles(localData, options).then(() => {
+ return git.exec(commitArgs, options)
+ }).then(() => {
+ if (!localData.existingTag) {
+ return git.exec([
+ 'tag', npm.config.get('tag-version-prefix') + version,
+ flagForTag, message
+ ], options)
+ }
+ }).nodeify(cb)
+}
+
+function stagePackageFiles (localData, options) {
+ return addLocalFile('package.json', options, false).then(() => {
+ if (localData.hasShrinkwrap) {
+ return addLocalFile('npm-shrinkwrap.json', options, true)
+ } else if (localData.hasPackageLock) {
+ return addLocalFile('package-lock.json', options, true)
+ }
+ })
+}
+
+function addLocalFile (file, options, ignoreFailure) {
+ const p = git.exec(['add', path.join(npm.localPrefix, file)], options)
+ return ignoreFailure
+ ? p.catch(() => {})
+ : p
+}
+
+function write (data, file, indent, newline, cb) {
+ assert(data && typeof data === 'object', 'must pass data to version write')
+ assert(typeof file === 'string', 'must pass filename to write to version write')
+
+ log.verbose('version.write', 'data', data, 'to', file)
+ writeFileAtomic(
+ path.join(npm.localPrefix, file),
+ stringifyPackage(data, indent, newline),
+ cb
+ )
+}