diff options
author | Kat Marchán <kzm@sykosomatic.org> | 2017-05-16 06:44:53 +0300 |
---|---|---|
committer | Rebecca Turner <me@re-becca.org> | 2017-05-26 04:55:23 +0300 |
commit | 180e2981a5a2a7c43a2b35fda73b641abfde704c (patch) | |
tree | ba1f352aaaf683feabb23a18ceea9120eb5b8f07 /lib | |
parent | 2d346e9ba9e64cffffd2bdd0d19a2be2413ebb61 (diff) |
feat(shrinkwrap): support extra metadata fields
Diffstat (limited to 'lib')
-rw-r--r-- | lib/install/read-shrinkwrap.js | 26 | ||||
-rw-r--r-- | lib/shrinkwrap.js | 59 |
2 files changed, 70 insertions, 15 deletions
diff --git a/lib/install/read-shrinkwrap.js b/lib/install/read-shrinkwrap.js index bf941a49c..b18265bd4 100644 --- a/lib/install/read-shrinkwrap.js +++ b/lib/install/read-shrinkwrap.js @@ -8,6 +8,7 @@ const inflateShrinkwrap = require('./inflate-shrinkwrap.js') const log = require('npmlog') const parseJSON = require('../utils/parse-json.js') const path = require('path') +const ssri = require('ssri') const readFileAsync = BB.promisify(fs.readFile) @@ -15,28 +16,37 @@ module.exports = readShrinkwrap function readShrinkwrap (child, next) { if (child.package._shrinkwrap) return process.nextTick(next) BB.join( - readLockfile('npm-shrinkwrap.json', child), + maybeReadFile('npm-shrinkwrap.json', child), // Don't read non-root lockfiles - child.isTop && readLockfile('package-lock.json', child), - (shrinkwrap, lockfile) => { + child.isTop && maybeReadFile('package-lock.json', child), + child.isTop && maybeReadFile('package.json', child), + (shrinkwrap, lockfile, pkgJson) => { if (shrinkwrap && lockfile) { log.warn('read-shrinkwrap', 'Ignoring package-lock.json because there is already an npm-shrinkwrap.json. Please use only one of the two.') } + let parsed = null if (shrinkwrap || lockfile) { try { - child.package._shrinkwrap = parseJSON(shrinkwrap || lockfile) + parsed = parseJSON(shrinkwrap || lockfile) } catch (ex) { - child.package._shrinkwrap = null throw ex } - } else { - child.package._shrinkwrap = null } + if ( + pkgJson && + parsed && + parsed.packageIntegrity && + !ssri.checkData(pkgJson, parsed.packageIntegrity) + ) { + let name = shrinkwrap ? 'npm-shrinkwrap.json' : 'package-lock.json' + log.info('read-shrinkwrap', `${name} will be updated because package.json does not match what it was generated against.`) + } + child.package._shrinkwrap = parsed } ).then(() => next(), next) } -function readLockfile (name, child) { +function maybeReadFile (name, child) { return readFileAsync( path.join(child.path, name) ).catch({code: 'ENOENT'}, () => null) diff --git a/lib/shrinkwrap.js b/lib/shrinkwrap.js index 832479e73..c764d3837 100644 --- a/lib/shrinkwrap.js +++ b/lib/shrinkwrap.js @@ -26,12 +26,14 @@ const writeFileAtomic = require('write-file-atomic') const PKGLOCK = 'package-lock.json' const SHRINKWRAP = 'npm-shrinkwrap.json' +const PKGLOCK_VERSION = 1 // emit JSON describing versions of all packages currently installed (for later // use with shrinkwrap install) shrinkwrap.usage = 'npm shrinkwrap' module.exports = exports = shrinkwrap +module.exports.PKGLOCK_VERSION = PKGLOCK_VERSION function shrinkwrap (args, silent, cb) { if (typeof cb !== 'function') { cb = silent @@ -74,8 +76,7 @@ module.exports.createShrinkwrap = createShrinkwrap function createShrinkwrap (tree, opts, cb) { opts = opts || {} lifecycle(tree.package, 'preshrinkwrap', tree.path, function () { - var pkginfo = treeToShrinkwrap(tree) - + const pkginfo = treeToShrinkwrap(tree) chain([ [lifecycle, tree.package, 'shrinkwrap', tree.path], [shrinkwrap_, tree.path, pkginfo, opts], @@ -182,14 +183,19 @@ function save (dir, pkginfo, opts, cb) { const info = ( shrinkwrap || lockfile || - [path.resolve(dir, opts.defaultFile || PKGLOCK), (pkg && pkg[1]) || 2] + { + path: path.resolve(dir, opts.defaultFile || PKGLOCK), + data: '{}', + indent: (pkg && pkg.indent) || 2 + } ) - const swdata = JSON.stringify(pkginfo, null, info[1]) + '\n' - writeFileAtomic(info[0], swdata, (err) => { + const updated = updateLockfileMetadata(pkginfo, pkg && pkg.data) + const swdata = JSON.stringify(updated, null, info.indent) + '\n' + writeFileAtomic(info.path, swdata, (err) => { if (err) return cb(err) if (opts.silent) return cb(null, pkginfo) if (!shrinkwrap && !lockfile) { - log.notice('', `created a lockfile as ${path.basename(info[0])}. You should commit this file.`) + log.notice('', `created a lockfile as ${path.basename(info.path)}. You should commit this file.`) } cb(null, pkginfo) }) @@ -198,12 +204,51 @@ function save (dir, pkginfo, opts, cb) { }, cb) } +function updateLockfileMetadata (pkginfo, pkgJson) { + // This is a lot of work just to make sure the extra metadata fields are + // between version and dependencies fields, without affecting any other stuff + const newPkg = {} + let metainfoWritten = false + const metainfo = new Set([ + 'createdWith', + 'lockfileVersion', + 'packageIntegrity' + ]) + Object.keys(pkginfo).forEach((k) => { + if (k === 'dependencies') { + writeMetainfo(newPkg) + } + if (!metainfo.has(k)) { + newPkg[k] = pkginfo[k] + } + if (k === 'version') { + writeMetainfo(newPkg) + } + }) + if (!metainfoWritten) { + writeMetainfo(newPkg) + } + function writeMetainfo (pkginfo) { + pkginfo.createdWith = `npm@${npm.version}` + pkginfo.lockfileVersion = PKGLOCK_VERSION + pkginfo.packageIntegrity = pkgJson && ssri.fromData(pkgJson, { + algorithms: ['sha512'] + }).toString() + metainfoWritten = true + } + return newPkg +} + function checkPackageFile (dir, name) { const file = path.resolve(dir, name) return fs.readFileAsync( file, 'utf8' ).then((data) => { - return [file, detectIndent(data).indent || ' '] + return { + path: file, + data, + indent: detectIndent(data).indent || 2 + } }).catch({code: 'ENOENT'}, () => {}) } |