From eb594480bb697558e357a1f406ee301784874fe6 Mon Sep 17 00:00:00 2001 From: Jamie Mason Date: Thu, 4 Aug 2016 00:33:09 +0100 Subject: [PATCH] refactor(): analyse and update dependency objects --- .gitignore | 30 ------ index.js | 54 +--------- src/addToBundle.js | 27 ----- src/addToCache.js | 22 ----- .../create-bundle-directory.js} | 13 ++- src/analyse/dependency/bundle.js | 19 ++++ src/analyse/dependency/cache.js | 19 ++++ src/analyse/dependency/index.js | 98 +++++++++++++++++++ src/analyse/dependency/resolve.js | 24 +++++ src/analyse/get-dependencies.js | 19 ++++ src/analyse/get-graph.js | 19 ++++ src/analyse/get-npm-version.js | 19 ++++ .../getPaths.js => analyse/get-paths.js} | 15 +-- src/analyse/get-stats.js | 41 ++++++++ src/analyse/get-unused-dependencies.js | 22 +++++ src/analyse/index.js | 94 ++++++++++++++++++ src/analyse/read-bundle.js | 29 ++++++ src/analyse/read-npm-cache.js | 70 +++++++++++++ src/analyse/rewrite-graph.js | 23 +++++ src/cli/describeChanges.js | 24 ----- .../{displayFailure.js => display-failure.js} | 2 +- src/cli/display-summary.js | 21 ++++ src/cli/displaySummary.js | 21 ---- src/cli/index.js | 23 ++--- src/init/getDeps/getDiff.js | 49 ---------- src/init/getDeps/index.js | 33 ------- src/init/getDeps/readGraph/index.js | 54 ---------- src/init/getGraph.js | 20 ---- src/init/index.js | 58 ----------- src/init/readNpmCache.js | 65 ------------ src/lib/child-process.js | 17 ++++ src/lib/copy-file.js | 33 +++++++ src/lib/copyFile.js | 37 ------- src/lib/delete-file.js | 19 ++++ .../for-each-nested-dependency.js} | 18 ++-- src/lib/fs.js | 22 +++++ ...{getTimeBetween.js => get-time-between.js} | 10 +- src/lib/isNpm3Up.js | 16 --- src/lib/{rateLimit.js => rate-limit.js} | 0 src/lib/removeFile.js | 22 ----- src/lib/shell.js | 22 ----- src/removeFromBundle.js | 27 ----- src/resolveTarball/index.js | 38 ------- src/resolveTarball/resolveLocally/index.js | 39 -------- src/resolveTarball/resolveLocally/npm2.js | 36 ------- src/resolveTarball/resolveLocally/npm3.js | 16 --- src/resolveTarball/resolveRemotely.js | 35 ------- src/rewriteGraph.js | 18 ---- src/update/add-used-dependencies.js | 14 +++ src/update/delete-unused-dependencies.js | 27 +++++ src/update/index.js | 25 +++++ 51 files changed, 719 insertions(+), 799 deletions(-) delete mode 100644 src/addToBundle.js delete mode 100644 src/addToCache.js rename src/{init/createBundleDirectory.js => analyse/create-bundle-directory.js} (53%) create mode 100644 src/analyse/dependency/bundle.js create mode 100644 src/analyse/dependency/cache.js create mode 100644 src/analyse/dependency/index.js create mode 100644 src/analyse/dependency/resolve.js create mode 100644 src/analyse/get-dependencies.js create mode 100644 src/analyse/get-graph.js create mode 100644 src/analyse/get-npm-version.js rename src/{init/getPaths.js => analyse/get-paths.js} (57%) create mode 100644 src/analyse/get-stats.js create mode 100644 src/analyse/get-unused-dependencies.js create mode 100644 src/analyse/index.js create mode 100644 src/analyse/read-bundle.js create mode 100644 src/analyse/read-npm-cache.js create mode 100644 src/analyse/rewrite-graph.js delete mode 100644 src/cli/describeChanges.js rename src/cli/{displayFailure.js => display-failure.js} (91%) create mode 100644 src/cli/display-summary.js delete mode 100644 src/cli/displaySummary.js delete mode 100644 src/init/getDeps/getDiff.js delete mode 100644 src/init/getDeps/index.js delete mode 100644 src/init/getDeps/readGraph/index.js delete mode 100644 src/init/getGraph.js delete mode 100644 src/init/index.js delete mode 100644 src/init/readNpmCache.js create mode 100644 src/lib/child-process.js create mode 100644 src/lib/copy-file.js delete mode 100644 src/lib/copyFile.js create mode 100644 src/lib/delete-file.js rename src/{init/getDeps/readGraph/recurse.js => lib/for-each-nested-dependency.js} (54%) create mode 100644 src/lib/fs.js rename src/lib/{getTimeBetween.js => get-time-between.js} (73%) delete mode 100644 src/lib/isNpm3Up.js rename src/lib/{rateLimit.js => rate-limit.js} (100%) delete mode 100644 src/lib/removeFile.js delete mode 100644 src/lib/shell.js delete mode 100644 src/removeFromBundle.js delete mode 100644 src/resolveTarball/index.js delete mode 100644 src/resolveTarball/resolveLocally/index.js delete mode 100644 src/resolveTarball/resolveLocally/npm2.js delete mode 100644 src/resolveTarball/resolveLocally/npm3.js delete mode 100644 src/resolveTarball/resolveRemotely.js delete mode 100644 src/rewriteGraph.js create mode 100644 src/update/add-used-dependencies.js create mode 100644 src/update/delete-unused-dependencies.js create mode 100644 src/update/index.js diff --git a/.gitignore b/.gitignore index dde9153..a7a3d2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,3 @@ -# Logs -logs *.log - -# Runtime data -pids -*.pid -*.seed - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directory -# Commenting this out is preferred by some people, see -# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- node_modules - -# Users Environment Variables -.lock-wscript - -npm-debug.log - -# Testing artifacts test/sinopia/storage diff --git a/index.js b/index.js index 755b432..68ff1f4 100755 --- a/index.js +++ b/index.js @@ -1,55 +1,9 @@ -var task = { - init: require('./src/init'), - resolveTarball: require('./src/resolveTarball'), - addToCache: require('./src/addToCache'), - addToBundle: require('./src/addToBundle'), - rewriteGraph: require('./src/rewriteGraph'), - removeFromBundle: require('./src/removeFromBundle') -}; +// modules +var analyse = require('./src/analyse'); +var update = require('./src/update'); +// public module.exports = { analyse: analyse, update: update }; - -function analyse (directory) { - return Promise.resolve(task.init(directory)); -} - -function update (config) { - return resolveTarball() - .then(addToCache, onFail) - .then(addToBundle, onFail) - .then(removeFromBundle, onFail) - .then(rewriteGraph, onFail) - .then(onSuccess, onFail) - .catch(onFail); - - function resolveTarball () { - return task.resolveTarball(config.deps.missingAndUnresolved); - } - - function addToCache () { - return task.addToCache(config.deps.missingFromCache); - } - - function addToBundle () { - return task.addToBundle(config.deps.missingFromBundle); - } - - function rewriteGraph () { - return task.rewriteGraph(config.path.graph, config.deps.all, config.graph); - } - - function removeFromBundle () { - return task.removeFromBundle(config.deps.removeFromBundle); - } - - function onSuccess () { - return config; - } - - function onFail (err) { - return Promise.reject(err); - } -} diff --git a/src/addToBundle.js b/src/addToBundle.js deleted file mode 100644 index e051813..0000000 --- a/src/addToBundle.js +++ /dev/null @@ -1,27 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); - -// modules -var copyFile = require('./lib/copyFile'); - -// public -module.exports = addToBundle; - -// implementation -function addToBundle (deps) { - return Promise.all(deps.map(bundlePackage)); -} - -function bundlePackage (dep) { - return copyFile(dep.tarball.npm, dep.tarball.shrinkpack) - .then(success, fail); - - function success () { - console.info(chalk.green('+ %s'), dep.id); - } - - function fail (err) { - console.error(chalk.red('! failed to shrinkpack %s'), dep.id); - throw err; - } -} diff --git a/src/addToCache.js b/src/addToCache.js deleted file mode 100644 index 04ceb22..0000000 --- a/src/addToCache.js +++ /dev/null @@ -1,22 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); -var shell = require('./lib/shell'); - -// public -module.exports = addToCache; - -// implementation -function addToCache (deps) { - return Promise.all(deps.map(cachePackage)); -} - -function cachePackage (dep) { - console.info(chalk.yellow('↓ %s from %s'), dep.id, dep.shrinkwrap.resolved); - return shell('npm cache --scope=' + dep.scope + ' add ' + dep.shrinkwrap.resolved) - .catch(fail); - - function fail (err) { - console.error(chalk.red('! failed to download %s'), dep.id); - throw err; - } -} diff --git a/src/init/createBundleDirectory.js b/src/analyse/create-bundle-directory.js similarity index 53% rename from src/init/createBundleDirectory.js rename to src/analyse/create-bundle-directory.js index 9c205e0..f1b2876 100644 --- a/src/init/createBundleDirectory.js +++ b/src/analyse/create-bundle-directory.js @@ -1,20 +1,19 @@ -// 3rd party modules -var fs = require('graceful-fs'); -var whenNode = require('when/node'); +// modules +var fs = require('../lib/fs'); // public module.exports = createBundleDirectory; // implementation -function createBundleDirectory (location) { - return whenNode.call(fs.mkdir, location) +function createBundleDirectory(location) { + return fs.mkdir(location) .then(onSuccess, onError); - function onSuccess () { + function onSuccess() { return location; } - function onError (err) { + function onError(err) { if (err.code !== 'EEXIST') { throw new Error('! failed to create node_shrinkwrap directory'); } diff --git a/src/analyse/dependency/bundle.js b/src/analyse/dependency/bundle.js new file mode 100644 index 0000000..1e235aa --- /dev/null +++ b/src/analyse/dependency/bundle.js @@ -0,0 +1,19 @@ +// modules +var copyFile = require('../../lib/copy-file'); + +// public +module.exports = bundle; + +// implementation +function bundle(dependency) { + return copyFile(dependency.getPathToNpmCache(), dependency.getPathToBundle()) + .then(onSuccess, onError); + + function onSuccess() { + return dependency; + } + + function onError() { + throw new Error('! failed to shrinkpack ' + dependency.getId()); + } +} diff --git a/src/analyse/dependency/cache.js b/src/analyse/dependency/cache.js new file mode 100644 index 0000000..1ca706a --- /dev/null +++ b/src/analyse/dependency/cache.js @@ -0,0 +1,19 @@ +// modules +var childProcess = require('../../lib/child-process'); + +// public +module.exports = cache; + +// implementation +function cache(dependency) { + return childProcess.exec('npm cache --scope=' + dependency.getScope() + ' add ' + dependency.graph.resolved, {encoding: 'utf8'}) + .then(onSuccess, onError); + + function onSuccess() { + return dependency; + } + + function onError() { + throw new Error('! failed to download ' + dependency.getId()); + } +} diff --git a/src/analyse/dependency/index.js b/src/analyse/dependency/index.js new file mode 100644 index 0000000..e9a9eeb --- /dev/null +++ b/src/analyse/dependency/index.js @@ -0,0 +1,98 @@ +// node modules +var path = require('path'); + +// 3rd party modules +var chalk = require('chalk'); +var when = require('when'); + +// modules +var bundle = require('./bundle'); +var cache = require('./cache'); +var resolve = require('./resolve'); + +// public +module.exports = Dependency; + +// implementation +function Dependency(name, graph) { + this.graph = graph; + this.name = name; +} + +// statics +Dependency.setConfig = function (config) { + Dependency.prototype.config = config; +}; + +// shared +Dependency.prototype = { + bundle: function () { + if (!this.isBundled()) { + return bundle(this).then(function (dependency) { + console.info(chalk.green('+ %s'), dependency.getId()); + return dependency; + }); + } + return when(this); + }, + cache: function () { + if (!this.isCached() && !this.isBundled()) { + return cache(this).then(function (dependency) { + console.info(chalk.yellow('↓ %s from %s'), dependency.getId(), dependency.graph.resolved); + return dependency; + }); + } + return when(this); + }, + config: null, + getId: function () { + return this.name + '@' + this.graph.version; + }, + getPathToBundle: function () { + var directory = this.config.path.shrinkpack; + var name = this.name.replace(/\//g, '-'); + var version = this.graph.version; + return path.join(directory, name + '-' + version + '.tgz'); + }, + getPathToNpmCache: function () { + return path.join(this.config.path.npmCache, this.name, this.graph.version, 'package.tgz'); + }, + getScope: function () { + var scope = this.name.substring(0, this.name.indexOf('/')); + return scope === this.name ? '' : scope; + }, + isBundled: function () { + return this.getPathToBundle() in this.config.bundle; + }, + isCached: function () { + return this.getPathToNpmCache() in this.config.npmCache; + }, + isResolved: function () { + return Boolean(this.graph.resolved); + }, + resolve: function () { + if (!this.isResolved()) { + return resolve(this).then(function (dependency) { + console.info(chalk.green('✓ set missing "resolved" property for %s to %s'), dependency.getId(), dependency.graph.resolved); + return dependency; + }); + } + return when(this); + }, + rewriteGraph: function () { + var relative = path.relative(this.config.path.project, this.getPathToBundle()); + this.graph.resolved = './' + relative.split('\\').join('/'); + return when(this); + }, + synchronise: function () { + return when(this) + .then(this.resolve.bind(this)) + .then(this.cache.bind(this)) + .then(this.bundle.bind(this)) + .then(this.rewriteGraph.bind(this)) + .catch(function (err) { + console.error(chalk.red('! failed to resolve tarball for %s'), this.getId()); + console.error(err); + }.bind(this)); + } +}; diff --git a/src/analyse/dependency/resolve.js b/src/analyse/dependency/resolve.js new file mode 100644 index 0000000..fdbfca6 --- /dev/null +++ b/src/analyse/dependency/resolve.js @@ -0,0 +1,24 @@ +// modules +var childProcess = require('../../lib/child-process'); + +// public +module.exports = resolve; + +// implementation +function resolve(dependency) { + return childProcess.exec('npm view ' + dependency.getId() + ' --json', {encoding: 'utf8'}) + .then(onSuccess, onError); + + function onSuccess(res) { + var json = JSON.parse(res.join('')); + if (json && json.dist && json.dist.tarball) { + dependency.graph.resolved = json.dist.tarball; + return dependency; + } + throw new Error('! ' + dependency.getId() + ' has no "dist.tarball" in `npm view ' + dependency.getId() + ' --json`'); + } + + function onError() { + throw new Error('! failed to call `npm view ' + dependency.getId() + ' --json`'); + } +} diff --git a/src/analyse/get-dependencies.js b/src/analyse/get-dependencies.js new file mode 100644 index 0000000..2cc2bf5 --- /dev/null +++ b/src/analyse/get-dependencies.js @@ -0,0 +1,19 @@ +// 3rd party modules +var when = require('when'); + +// modules +var forEachNestedDependency = require('../lib/for-each-nested-dependency'); +var Dependency = require('./dependency'); + +// public +module.exports = getDependencies; + +// implementation +function getDependencies(config) { + Dependency.setConfig(config); + var dependencies = []; + forEachNestedDependency(config.graph, function (name, graph) { + dependencies.push(new Dependency(name, graph)); + }); + return when(dependencies); +} diff --git a/src/analyse/get-graph.js b/src/analyse/get-graph.js new file mode 100644 index 0000000..7784fc0 --- /dev/null +++ b/src/analyse/get-graph.js @@ -0,0 +1,19 @@ +// modules +var fs = require('../lib/fs'); + +// public +module.exports = getGraph; + +// implementation +function getGraph(location) { + return fs.readFile(location, {encoding: 'utf8'}) + .then(onSuccess, onError); + + function onSuccess(graph) { + return JSON.parse(graph); + } + + function onError() { + throw new Error('! npm-shrinkwrap.json is missing, create it using `npm shrinkwrap --dev` then try again'); + } +} diff --git a/src/analyse/get-npm-version.js b/src/analyse/get-npm-version.js new file mode 100644 index 0000000..b229c6a --- /dev/null +++ b/src/analyse/get-npm-version.js @@ -0,0 +1,19 @@ +// modules +var childProcess = require('../lib/child-process'); + +// public +module.exports = getNpmVersion; + +// implementation +function getNpmVersion() { + return childProcess.exec('npm --version', {encoding: 'utf8'}) + .then(onSuccess, onError); + + function onSuccess(npmVersion) { + return npmVersion.join('').trim(); + } + + function onError() { + throw new Error('! failed to determine version of npm'); + } +} diff --git a/src/init/getPaths.js b/src/analyse/get-paths.js similarity index 57% rename from src/init/getPaths.js rename to src/analyse/get-paths.js index 8a412fa..bbd9884 100644 --- a/src/init/getPaths.js +++ b/src/analyse/get-paths.js @@ -1,17 +1,18 @@ -// 3rd party modules -var childProcess = require('child_process'); +// node modules var path = require('path'); -var whenNode = require('when/node'); + +// modules +var childProcess = require('../lib/child-process'); // public module.exports = getPaths; // implementation -function getPaths (directory) { - return whenNode.call(childProcess.exec, 'npm config get cache', { encoding: 'utf8' }) +function getPaths(directory) { + return childProcess.exec('npm config get cache', {encoding: 'utf8'}) .then(onSuccess, onError); - function onSuccess (npmCachePath) { + function onSuccess(npmCachePath) { return { graph: path.join(directory, 'npm-shrinkwrap.json'), npmCache: npmCachePath.join('').trim(), @@ -20,7 +21,7 @@ function getPaths (directory) { }; } - function onError () { + function onError() { throw new Error('! failed to locate the npm cache'); } } diff --git a/src/analyse/get-stats.js b/src/analyse/get-stats.js new file mode 100644 index 0000000..5943f0a --- /dev/null +++ b/src/analyse/get-stats.js @@ -0,0 +1,41 @@ +// 3rd party modules +var when = require('when'); + +// public +module.exports = getStats; + +// implementation +function getStats(config) { + var bundled = Object.keys(config.bundle); + var unused = Object.keys(config.unusedDependencies); + var unbundled = config.deps.filter(isNotBundled); + var uncached = unbundled.filter(isNotCached); + var unresolved = unbundled.filter(isNotResolved); + var cached = unbundled.length - uncached.length; + + return when({ + bundled: { + used: bundled.length, + unused: unused.length + }, + total: config.deps.length, + unbundled: { + cached: cached, + total: unbundled.length, + uncached: uncached.length, + unresolved: unresolved.length + } + }); + + function isNotBundled(dependency) { + return !dependency.isBundled(); + } + + function isNotCached(dependency) { + return !dependency.isCached(); + } + + function isNotResolved(dependency) { + return !dependency.isResolved(); + } +} diff --git a/src/analyse/get-unused-dependencies.js b/src/analyse/get-unused-dependencies.js new file mode 100644 index 0000000..ee025a7 --- /dev/null +++ b/src/analyse/get-unused-dependencies.js @@ -0,0 +1,22 @@ +// 3rd party modules +var when = require('when'); + +// public +module.exports = getUnusedDependencies; + +// implementation +function getUnusedDependencies(config) { + return when(config.deps.reduce(updateIndex, clone(config.bundle))); + + function updateIndex(unused, dependency) { + var location = dependency.getPathToBundle(); + if (location in unused) { + delete unused[location]; + } + return unused; + } + + function clone(value) { + return JSON.parse(JSON.stringify(value)); + } +} diff --git a/src/analyse/index.js b/src/analyse/index.js new file mode 100644 index 0000000..e6afd50 --- /dev/null +++ b/src/analyse/index.js @@ -0,0 +1,94 @@ +// 3rd party modules +var assign = require('lodash.assign'); +var when = require('when'); + +// modules +var createBundleDirectory = require('./create-bundle-directory'); +var getDependencies = require('./get-dependencies'); +var getGraph = require('./get-graph'); +var getNpmVersion = require('./get-npm-version'); +var getPaths = require('./get-paths'); +var getStats = require('./get-stats'); +var getUnusedDependencies = require('./get-unused-dependencies'); +var readBundle = require('./read-bundle'); +var readNpmCache = require('./read-npm-cache'); + +// public +module.exports = init; + +// implementation +function init(directory) { + return when({startTime: new Date()}) + .then(getConfigWithNpmVersion) + .then(getConfigWithPaths) + .then(getConfigWithGraph) + .then(ensureBundleExists) + .then(getConfigWithNpmCacheContents) + .then(getConfigWithBundleContents) + .then(getConfigWithDependencies) + .then(getConfigWithUnusedDependencies) + .then(getConfigWithStats); + + function getConfigWithNpmVersion(config) { + return getNpmVersion() + .then(function (npmVersion) { + return assign(config, {npmVersion: npmVersion}); + }); + } + + function getConfigWithPaths(config) { + return getPaths(directory) + .then(function (paths) { + return assign(config, {path: paths}); + }); + } + + function getConfigWithGraph(config) { + return getGraph(config.path.graph) + .then(function (graph) { + return assign(config, {graph: graph}); + }); + } + + function ensureBundleExists(config) { + return createBundleDirectory(config.path.shrinkpack) + .then(function () { + return config; + }); + } + + function getConfigWithNpmCacheContents(config) { + return readNpmCache(config.path.npmCache) + .then(function (npmCache) { + return assign(config, {npmCache: npmCache}); + }); + } + + function getConfigWithBundleContents(config) { + return readBundle(config.path.shrinkpack) + .then(function (bundle) { + return assign(config, {bundle: bundle}); + }); + } + + function getConfigWithDependencies(config) { + return getDependencies(config) + .then(function (deps) { + return assign(config, {deps: deps}); + }); + } + + function getConfigWithUnusedDependencies(config) { + return getUnusedDependencies(config) + .then(function (unusedDependencies) { + return assign(config, {unusedDependencies: unusedDependencies}); + }); + } + + function getConfigWithStats(config) { + return getStats(config) + .then(function (stats) { + return assign(config, {stats: stats}); + }); + } +} diff --git a/src/analyse/read-bundle.js b/src/analyse/read-bundle.js new file mode 100644 index 0000000..15f5edd --- /dev/null +++ b/src/analyse/read-bundle.js @@ -0,0 +1,29 @@ +// node modules +var path = require('path'); + +// modules +var fs = require('../lib/fs'); + +// public +module.exports = readBundle; + +// implementation +function readBundle(pathToBundle) { + return fs.readdir(pathToBundle) + .then(indexByPath, onError); + + function indexByPath(filenames) { + return filenames.reduce(function (memo, filename) { + memo[getAbsolutePath(filename)] = true; + return memo; + }, {}); + } + + function getAbsolutePath(filename) { + return path.join(pathToBundle, filename); + } + + function onError() { + throw new Error('! failed to read contents of node_shrinkwrap'); + } +} diff --git a/src/analyse/read-npm-cache.js b/src/analyse/read-npm-cache.js new file mode 100644 index 0000000..6394e2f --- /dev/null +++ b/src/analyse/read-npm-cache.js @@ -0,0 +1,70 @@ +// node modules +var os = require('os'); +var path = require('path'); + +// 3rd party modules +var when = require('when'); + +// modules +var childProcess = require('../lib/child-process'); + +// public +module.exports = readNpmCache; + +// implementation +function readNpmCache() { + var home = os.homedir(); + + return getCacheContents() + .then(toArray) + .then(getPackages) + .then(indexByPath); + + function getCacheContents() { + var allData = ''; + var deferred = when.defer(); + var npmCache = childProcess.spawn('npm', ['cache', 'ls']); + + npmCache.stdout.setEncoding('utf8'); + npmCache.stdout.on('data', onData); + npmCache.on('close', onClose); + + return deferred.promise; + + function onData(data) { + allData += data; + } + + function onClose(code) { + if (code === 1) { + deferred.reject(new Error('! failed to read contents of npm cache')); + } else { + deferred.resolve(allData); + } + } + } + + function toArray(stdout) { + return stdout.trim().split('\n'); + } + + function getPackages(cacheContents) { + return cacheContents.filter(function isPackage(location) { + return location.indexOf('package.tgz') !== -1; + }); + } + + function indexByPath(packages) { + return packages.reduce(function (memo, location) { + memo[path.resolve(expandTilde(location))] = true; + return memo; + }, {}); + } + + function expandTilde(location) { + if (home) { + return location.replace(/^~($|\/|\\)/, home + '$1'); + } + return location; + } +} diff --git a/src/analyse/rewrite-graph.js b/src/analyse/rewrite-graph.js new file mode 100644 index 0000000..a8d9055 --- /dev/null +++ b/src/analyse/rewrite-graph.js @@ -0,0 +1,23 @@ +// 3rd party modules +var chalk = require('chalk'); + +// modules +var fs = require('../lib/fs'); + +// public +module.exports = getGraph; + +// implementation +function getGraph(config) { + chalk.blue('i rewriting ' + config.path.shrinkwrap); + return fs.writeFile(config.path.shrinkwrap, JSON.stringify(config.graph, null, 2), {encoding: 'utf8'}) + .then(onSuccess, onError); + + function onSuccess() { + return config.path.shrinkwrap; + } + + function onError() { + throw new Error('! failed to write to npm-shrinkwrap.json'); + } +} diff --git a/src/cli/describeChanges.js b/src/cli/describeChanges.js deleted file mode 100644 index 8fb11ca..0000000 --- a/src/cli/describeChanges.js +++ /dev/null @@ -1,24 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); - -// public -module.exports = describeChanges; - -// implementation -function describeChanges (config) { - var totalDeps = config.deps.all.length; - var totalMissingAndUnresolved = config.deps.missingAndUnresolved.length; - var totalAdd = config.deps.missingFromBundle.length; - var totalUncached = config.deps.missingFromCache.length; - var totalRemove = config.deps.removeFromBundle.length; - var totalCached = totalAdd - totalUncached; - - console.info(chalk.blue('i %s dependencies in npm-shrinkwrap.json'), totalDeps); - console.info(chalk.blue('i %s need removing from ./node_shrinkwrap'), totalRemove); - console.info(chalk.blue('i %s need adding to ./node_shrinkwrap'), totalAdd); - console.info(chalk.blue('i %s are in your npm cache'), totalCached); - console.info(chalk.blue('i %s need downloading'), totalUncached); - console.info(chalk.blue('i %s have a missing "resolved" property'), totalMissingAndUnresolved); - - return config; -} diff --git a/src/cli/displayFailure.js b/src/cli/display-failure.js similarity index 91% rename from src/cli/displayFailure.js rename to src/cli/display-failure.js index 4600dde..bf87ac2 100644 --- a/src/cli/displayFailure.js +++ b/src/cli/display-failure.js @@ -5,7 +5,7 @@ var chalk = require('chalk'); module.exports = displayFailure; // implementation -function displayFailure (err) { +function displayFailure(err) { console.error( chalk.red('! Please raise an issue at %s\n\n%s'), chalk.underline('https://github.com/JamieMason/shrinkpack/issues'), diff --git a/src/cli/display-summary.js b/src/cli/display-summary.js new file mode 100644 index 0000000..a171617 --- /dev/null +++ b/src/cli/display-summary.js @@ -0,0 +1,21 @@ +// 3rd party modules +var chalk = require('chalk'); + +// modules +var getTimeBetween = require('../lib/get-time-between'); + +// public +module.exports = displaySummary; + +// implementation +function displaySummary(config) { + console.info([ + 'shrinkpack', + chalk.green('+' + config.stats.unbundled.total), + chalk.red('-' + config.stats.bundled.unused), + chalk.yellow('↓' + config.stats.unbundled.uncached), + chalk.magenta('→' + config.stats.unbundled.cached), + chalk.green('✓' + config.stats.unbundled.unresolved), + chalk.grey(getTimeBetween(config.startTime, new Date())) + ].join(' ')); +} diff --git a/src/cli/displaySummary.js b/src/cli/displaySummary.js deleted file mode 100644 index abec7c0..0000000 --- a/src/cli/displaySummary.js +++ /dev/null @@ -1,21 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); - -// modules -var getTimeBetween = require('../lib/getTimeBetween'); - -// public -module.exports = displaySummary; - -// implementation -function displaySummary (config) { - console.info([ - 'shrinkpack', - chalk.green('+' + config.deps.missingFromBundle.length), - chalk.red('-' + config.deps.removeFromBundle.length), - chalk.yellow('↓' + config.deps.missingFromCache.length), - chalk.green('✓' + config.deps.missingAndUnresolved.length), - chalk.grey(getTimeBetween(config.startTime, new Date())) - ].join(' ')); - process.exit(0); -} diff --git a/src/cli/index.js b/src/cli/index.js index f15b63a..b640432 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -1,21 +1,22 @@ +// modules +var analyse = require('../analyse'); +var update = require('../update'); +var displayFailure = require('./display-failure'); +var displaySummary = require('./display-summary'); + +// public module.exports = { run: runCli }; -// modules -var shrinkpack = require('../../index'); -var describeChanges = require('./describeChanges'); -var displayFailure = require('./displayFailure'); -var displaySummary = require('./displaySummary'); - -function runCli (directory) { - return shrinkpack.analyse(directory) - .then(describeChanges, onFail) - .then(shrinkpack.update, onFail) +// implementation +function runCli(directory) { + return analyse(directory) + .then(update, onFail) .then(displaySummary, onFail) .catch(onFail); } -function onFail (err) { +function onFail(err) { displayFailure(err); } diff --git a/src/init/getDeps/getDiff.js b/src/init/getDeps/getDiff.js deleted file mode 100644 index 3119b33..0000000 --- a/src/init/getDeps/getDiff.js +++ /dev/null @@ -1,49 +0,0 @@ -// node modules -var path = require('path'); - -// 3rd party modules -var fs = require('graceful-fs'); -var uniq = require('lodash.uniq'); - -// public -module.exports = getDiff; - -// implementation -function getDiff (pathToBundle, deps, npmCache) { - var uniqueDeps = uniq(deps, getId); - var requiredTars = uniqueDeps.map(getTarballPath); - var bundledTars = fs.readdirSync(pathToBundle).map(getAbsolutePath); - var missingFromBundle = uniqueDeps.filter(isNotInBundle); - var missingFromCache = missingFromBundle.filter(isNotInCache); - var removeFromBundle = bundledTars.filter(isNotInShrinkwrap); - - return { - missingFromBundle: uniq(missingFromBundle, getId), - missingFromCache: uniq(missingFromCache, getId), - removeFromBundle: uniq(removeFromBundle, getId) - }; - - function getAbsolutePath (filename) { - return path.join(pathToBundle, filename); - } - - function getTarballPath (dep) { - return dep.tarball.shrinkpack; - } - - function isNotInBundle (dep) { - return bundledTars.indexOf(dep.tarball.shrinkpack) === -1; - } - - function isNotInCache (dep) { - return typeof npmCache[dep.id] === 'undefined'; - } - - function isNotInShrinkwrap (tar) { - return requiredTars.indexOf(tar) === -1; - } - - function getId (dep) { - return dep.id; - } -} diff --git a/src/init/getDeps/index.js b/src/init/getDeps/index.js deleted file mode 100644 index b1a047d..0000000 --- a/src/init/getDeps/index.js +++ /dev/null @@ -1,33 +0,0 @@ -// 3rd party modules -var when = require('when'); - -// modules -var getDiff = require('./getDiff'); -var readGraph = require('./readGraph'); - -// public -module.exports = getDeps; - -// implementation -function getDeps (config) { - var deps = readGraph(config.graph, config.path.shrinkpack, config.path.npmCache); - var diff = getDiff(config.path.shrinkpack, deps, config.npmCache); - var unresolved = deps.filter(isUnresolved); - - return when({ - all: deps, - missingAndUnresolved: unresolved.filter(needsResolving), - missingFromBundle: diff.missingFromBundle, - missingFromCache: diff.missingFromCache, - removeFromBundle: diff.removeFromBundle, - unresolved: unresolved - }); - - function needsResolving (dep) { - return diff.missingFromBundle.indexOf(dep) !== -1 && diff.missingFromCache.indexOf(dep) !== -1; - } - - function isUnresolved (dep) { - return !dep.shrinkwrap.resolved; - } -} diff --git a/src/init/getDeps/readGraph/index.js b/src/init/getDeps/readGraph/index.js deleted file mode 100644 index b7c66ec..0000000 --- a/src/init/getDeps/readGraph/index.js +++ /dev/null @@ -1,54 +0,0 @@ -// 3rd party modules -var path = require('path'); - -// modules -var recurse = require('./recurse'); - -// public -module.exports = readGraph; - -// implementation -function readGraph (graph, pathToBundle, npmCachePath) { - var deps = []; - - recurse(graph, function (name, dep) { - deps.push(decorate(name, dep)); - }); - - return deps; - - function decorate (name, meta) { - return { - bundle: getShrinkwrapEntry(name, meta), - id: name + '@' + meta.version, - name: name, - scope: getPackageScope(name), - shrinkwrap: meta, - tarball: { - shrinkpack: getShrinkpackPath(name, meta), - npm: getNpmCachePath(name, meta) - } - }; - } - - function getShrinkwrapEntry (name, meta) { - return './node_shrinkwrap/' + getTarballName(name, meta.version); - } - - function getShrinkpackPath (name, meta) { - return path.join(pathToBundle, getTarballName(name, meta.version)); - } - - function getNpmCachePath (name, meta) { - return path.join(npmCachePath, name, meta.version, 'package.tgz'); - } - - function getTarballName (name, version) { - return name.replace(/\//g, '-') + '-' + version + '.tgz'; - } - - function getPackageScope (name) { - var scope = name.substring(0, name.indexOf('/')); - return (scope !== name) ? scope : ''; - } -} diff --git a/src/init/getGraph.js b/src/init/getGraph.js deleted file mode 100644 index a596237..0000000 --- a/src/init/getGraph.js +++ /dev/null @@ -1,20 +0,0 @@ -// 3rd party modules -var fs = require('graceful-fs'); -var whenNode = require('when/node'); - -// public -module.exports = getGraph; - -// implementation -function getGraph (location) { - return whenNode.call(fs.readFile, location, { encoding: 'utf8' }) - .then(onSuccess, onError); - - function onSuccess (graph) { - return JSON.parse(graph); - } - - function onError () { - throw new Error('! npm-shrinkwrap.json is missing, create it using `npm shrinkwrap --dev` then try again'); - } -} diff --git a/src/init/index.js b/src/init/index.js deleted file mode 100644 index d5b7b47..0000000 --- a/src/init/index.js +++ /dev/null @@ -1,58 +0,0 @@ -// 3rd party modules -var assign = require('lodash.assign'); -var when = require('when'); - -// modules -var createBundleDirectory = require('./createBundleDirectory'); -var getDeps = require('./getDeps'); -var getGraph = require('./getGraph'); -var getPaths = require('./getPaths'); -var readNpmCache = require('./readNpmCache'); - -// public -module.exports = init; - -// implementation -function init (directory) { - return when({ startTime: new Date() }) - .then(getConfigWithPath) - .then(getConfigWithGraph) - .then(ensureBundleExists) - .then(getConfigWithNpmCache) - .then(getConfigWithDeps); - - function getConfigWithPath (config) { - return getPaths(directory) - .then(function (paths) { - return assign(config, { path: paths }); - }); - } - - function getConfigWithGraph (config) { - return getGraph(config.path.graph) - .then(function (graph) { - return assign(config, { graph: graph }); - }); - } - - function ensureBundleExists (config) { - return createBundleDirectory(config.path.shrinkpack) - .then(function () { - return config; - }); - } - - function getConfigWithNpmCache (config) { - return readNpmCache(config.path.npmCache) - .then(function (npmCache) { - return assign(config, { npmCache: npmCache }); - }); - } - - function getConfigWithDeps (config) { - return getDeps(config) - .then(function (deps) { - return assign(config, { deps: deps }); - }); - } -} diff --git a/src/init/readNpmCache.js b/src/init/readNpmCache.js deleted file mode 100644 index f1eb6f3..0000000 --- a/src/init/readNpmCache.js +++ /dev/null @@ -1,65 +0,0 @@ -// node modules -var childProcess = require('child_process'); -var path = require('path'); - -// 3rd party modules -var when = require('when'); - -// public -module.exports = readNpmCache; - -// implementation -function readNpmCache () { - return getCacheContents() - .then(toArray) - .then(getPackages) - .then(indexPathsByVersion); - - function getCacheContents () { - var allData = ''; - var deferred = when.defer(); - var npmCache = childProcess.spawn('npm', ['cache', 'ls']); - - npmCache.stdout.setEncoding('utf8'); - npmCache.stdout.on('data', onData); - npmCache.on('close', onClose); - - return deferred.promise; - - function onData (data) { - allData += data; - } - - function onClose (code) { - if (code === 1) { - deferred.reject(new Error('! failed to read contents of npm cache')); - } else { - deferred.resolve(allData); - } - } - } - - function toArray (stdout) { - return stdout.trim().split('\n'); - } - - function getPackages (cacheContents) { - return cacheContents.filter(isPackage); - } - - function isPackage (location) { - return location.indexOf('package.tgz') !== -1; - } - - function indexPathsByVersion (packages) { - return packages.reduce(addPackageToIndex, {}); - } - - function addPackageToIndex (index, location) { - var parts = location.split(path.sep); - var name = parts[parts.length - 3]; - var version = parts[parts.length - 2]; - index[name + '@' + version] = path.resolve(location); - return index; - } -} diff --git a/src/lib/child-process.js b/src/lib/child-process.js new file mode 100644 index 0000000..216ff14 --- /dev/null +++ b/src/lib/child-process.js @@ -0,0 +1,17 @@ +// 3rd party modules +var childProcess = require('child_process'); +var guard = require('when/guard'); +var whenNode = require('when/node'); + +// modules +var rateLimit = require('./rate-limit'); + +// public +module.exports = { + exec: wrap(childProcess.exec), + spawn: childProcess.spawn +}; + +function wrap(fn) { + return guard(rateLimit, whenNode.lift(fn)); +} diff --git a/src/lib/copy-file.js b/src/lib/copy-file.js new file mode 100644 index 0000000..74b439a --- /dev/null +++ b/src/lib/copy-file.js @@ -0,0 +1,33 @@ +// 3rd party modules +var chalk = require('chalk'); +var fs = require('graceful-fs'); + +// public +module.exports = copyFile; + +// implementation +function copyFile(source, target) { + return new Promise(function (resolve, reject) { + var read$ = fs.createReadStream(source); + var write$ = fs.createWriteStream(target); + + read$.on('error', onReadError); + write$.on('error', onWriteError); + write$.on('finish', onWriteEnd); + read$.pipe(write$); + + function onReadError(err) { + console.error(chalk.red('! failed to read file %s'), source); + reject(err); + } + + function onWriteError(err) { + console.error(chalk.red('! failed to write file %s'), target); + reject(err); + } + + function onWriteEnd() { + resolve(); + } + }); +} diff --git a/src/lib/copyFile.js b/src/lib/copyFile.js deleted file mode 100644 index 3ea0af4..0000000 --- a/src/lib/copyFile.js +++ /dev/null @@ -1,37 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); -var fs = require('graceful-fs'); -var guard = require('when/guard'); - -// modules -var rateLimit = require('./rateLimit'); - -// public -module.exports = guard(rateLimit, copyFile); - -// implementation -function copyFile (source, target) { - return new Promise(function (resolve, reject) { - var readStream = fs.createReadStream(source); - var writeStream = fs.createWriteStream(target); - - readStream.on('error', onReadError); - writeStream.on('error', onWriteError); - writeStream.on('finish', onWriteEnd); - readStream.pipe(writeStream); - - function onReadError (err) { - console.error(chalk.red('! failed to read file %s'), source); - reject(err); - } - - function onWriteError (err) { - console.error(chalk.red('! failed to write file %s'), target); - reject(err); - } - - function onWriteEnd () { - resolve(); - } - }); -} diff --git a/src/lib/delete-file.js b/src/lib/delete-file.js new file mode 100644 index 0000000..b34b6ea --- /dev/null +++ b/src/lib/delete-file.js @@ -0,0 +1,19 @@ +// modules +var fs = require('./fs'); + +// public +module.exports = deleteFile; + +// implementation +function deleteFile(location) { + return fs.unlink(location) + .then(onSuccess, onError); + + function onSuccess() { + return location; + } + + function onError() { + throw new Error('! failed to delete ' + location); + } +} diff --git a/src/init/getDeps/readGraph/recurse.js b/src/lib/for-each-nested-dependency.js similarity index 54% rename from src/init/getDeps/readGraph/recurse.js rename to src/lib/for-each-nested-dependency.js index cc263a6..5bc4a8e 100644 --- a/src/init/getDeps/readGraph/recurse.js +++ b/src/lib/for-each-nested-dependency.js @@ -1,8 +1,8 @@ // public -module.exports = recurse; +module.exports = forEachNestedDependency; // implementation -function recurse (value, handler, key) { +function forEachNestedDependency(value, handler, key) { if (isObject(value)) { if (isRootNode(value, key)) { stepInto(value.dependencies, handler); @@ -15,24 +15,24 @@ function recurse (value, handler, key) { } } -function isRootNode (value, key) { +function isRootNode(value, key) { return !key; } -function isPackage (value, key) { +function isPackage(value, key) { return key !== 'dependencies'; } -function isDependencyMap (value, key) { +function isDependencyMap(value, key) { return key === 'dependencies'; } -function stepInto (value, handler) { +function stepInto(value, handler) { for (var key in value) { - recurse(value[key], handler, key); + forEachNestedDependency(value[key], handler, key); } } -function isObject (value) { - return !!value && (value.constructor === Object); +function isObject(value) { + return Boolean(value) && (value.constructor === Object); } diff --git a/src/lib/fs.js b/src/lib/fs.js new file mode 100644 index 0000000..053349a --- /dev/null +++ b/src/lib/fs.js @@ -0,0 +1,22 @@ +// 3rd party modules +var fs = require('graceful-fs'); +var guard = require('when/guard'); +var whenNode = require('when/node'); + +// modules +var rateLimit = require('./rate-limit'); + +// public +module.exports = { + createReadStream: fs.createReadStream, + createWriteStream: fs.createWriteStream, + mkdir: wrap(fs.mkdir), + readdir: wrap(fs.readdir), + readFile: wrap(fs.readFile), + unlink: wrap(fs.unlink), + writeFile: wrap(fs.writeFile) +}; + +function wrap(fn) { + return guard(rateLimit, whenNode.lift(fn)); +} diff --git a/src/lib/getTimeBetween.js b/src/lib/get-time-between.js similarity index 73% rename from src/lib/getTimeBetween.js rename to src/lib/get-time-between.js index c3c8e68..ddade5f 100644 --- a/src/lib/getTimeBetween.js +++ b/src/lib/get-time-between.js @@ -2,25 +2,25 @@ module.exports = getTimeBetween; // implementation -function getTimeBetween (dateFrom, dateTo) { +function getTimeBetween(dateFrom, dateTo) { return msToTime(dateTo.getTime() - dateFrom.getTime()); } -function msToTime (ms) { +function msToTime(ms) { var mins = msToMins(ms); var secs = msToSecs(ms); return pad(mins) + ':' + pad(secs); } -function msToMins (ms) { +function msToMins(ms) { return Math.floor(ms ? (ms / 1000) / 60 : 0); } -function msToSecs (ms) { +function msToSecs(ms) { return Math.floor(ms ? (ms / 1000) % 60 : 0); } -function pad (value) { +function pad(value) { var whole = Math.floor(value); return whole < 10 ? '0' + whole : whole; } diff --git a/src/lib/isNpm3Up.js b/src/lib/isNpm3Up.js deleted file mode 100644 index 0adaca4..0000000 --- a/src/lib/isNpm3Up.js +++ /dev/null @@ -1,16 +0,0 @@ -// 3rd party modules -var childProcess = require('child_process'); - -// public -module.exports = isNpm3Up; - -// implementation -function isNpm3Up () { - return parseFloat(getNpmVersion()) >= 3; -} - -function getNpmVersion () { - return childProcess.execSync('npm --version', { - encoding: 'utf8' - }).trim(); -} diff --git a/src/lib/rateLimit.js b/src/lib/rate-limit.js similarity index 100% rename from src/lib/rateLimit.js rename to src/lib/rate-limit.js diff --git a/src/lib/removeFile.js b/src/lib/removeFile.js deleted file mode 100644 index 972ecd6..0000000 --- a/src/lib/removeFile.js +++ /dev/null @@ -1,22 +0,0 @@ -// 3rd party modules -var fs = require('graceful-fs'); -var guard = require('when/guard'); - -// modules -var rateLimit = require('./rateLimit'); - -// public -module.exports = guard(rateLimit, removeFile); - -// implementation -function removeFile (source) { - return new Promise(function (resolve, reject) { - fs.unlink(source, function onRemoveFile (err) { - if (err) { - reject(err); - } else { - resolve(); - } - }); - }); -} diff --git a/src/lib/shell.js b/src/lib/shell.js deleted file mode 100644 index d0cae7e..0000000 --- a/src/lib/shell.js +++ /dev/null @@ -1,22 +0,0 @@ -// 3rd party modules -var exec = require('child_process').exec; -var guard = require('when/guard'); - -// modules -var rateLimit = require('./rateLimit'); - -// public -module.exports = guard(rateLimit, shell); - -// implementation -function shell (command) { - return new Promise(function (resolve, reject) { - exec(command, function onExec (err, stdout) { - if (err) { - reject(err); - } else { - resolve(String(stdout).trim()); - } - }); - }); -} diff --git a/src/removeFromBundle.js b/src/removeFromBundle.js deleted file mode 100644 index 82fcb6d..0000000 --- a/src/removeFromBundle.js +++ /dev/null @@ -1,27 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); - -// modules -var removeFile = require('./lib/removeFile'); - -// public -module.exports = removeFromBundle; - -// implementation -function removeFromBundle (tarPaths) { - return Promise.all(tarPaths.map(removeDep)); -} - -function removeDep (tarPath) { - return removeFile(tarPath) - .then(success, fail); - - function success () { - console.info(chalk.red('- %s'), tarPath.replace(/.+\//, '')); - } - - function fail (err) { - console.error(chalk.red('! failed to remove %s'), tarPath); - throw err; - } -} diff --git a/src/resolveTarball/index.js b/src/resolveTarball/index.js deleted file mode 100644 index b0d0b7c..0000000 --- a/src/resolveTarball/index.js +++ /dev/null @@ -1,38 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); - -// modules -var resolveLocally = require('./resolveLocally'); -var resolveRemotely = require('./resolveRemotely'); - -// public -module.exports = resolveTarball; - -// implementation -function resolveTarball (deps) { - return Promise.all(deps.map(resolveDep)); -} - -function resolveDep (dep) { - return resolveLocally(dep) - .then(onLocalAttempt) - .then(onFinalAttempt); - - function onLocalAttempt (tarballUrl) { - if (!tarballUrl) { - console.info(chalk.gray('? %s contacting registry...'), dep.id); - return resolveRemotely(dep); - } - return tarballUrl; - } - - function onFinalAttempt (tarballUrl) { - if (tarballUrl) { - dep.shrinkwrap.resolved = tarballUrl; - console.info(chalk.green('✓ set missing "resolved" property for %s to %s'), dep.id, tarballUrl); - } else { - console.error(chalk.red('! failed to resolve tarball for %s'), dep.id); - process.exit(1); - } - } -} diff --git a/src/resolveTarball/resolveLocally/index.js b/src/resolveTarball/resolveLocally/index.js deleted file mode 100644 index 0557ee5..0000000 --- a/src/resolveTarball/resolveLocally/index.js +++ /dev/null @@ -1,39 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); - -// modules -var getNpm2PkgPath = require('./npm2'); -var getNpm3PkgPath = require('./npm3'); -var isNpm3Up = require('../../lib/isNpm3Up'); - -// public -module.exports = resolveLocally; - -// implementation -var getPkgPath = isNpm3Up() ? getNpm3PkgPath : getNpm2PkgPath; - -function resolveLocally (dep) { - return getPkgPath(dep) - .then(function (pkgPath) { - if (!pkgPath) { - console.info(chalk.gray('? %s has no package.json that I can find locally'), dep.id); - return ''; - } - return readPkgJson(dep, pkgPath); - }); -} - -function readPkgJson (dep, pkgPath) { - return new Promise(function (resolve) { - var meta = require(pkgPath); - if (!meta || meta.version !== dep.shrinkwrap.version) { - console.info(chalk.gray('? %s version mismatch in %s'), dep.id, pkgPath); - resolve(''); - } else if (!meta || !meta.dist || !meta.dist.tarball || meta.version !== dep.shrinkwrap.version) { - console.info(chalk.gray('? %s has no "dist.tarball" in %s'), dep.id, pkgPath); - resolve(''); - } else { - resolve(meta.dist.tarball); - } - }); -} diff --git a/src/resolveTarball/resolveLocally/npm2.js b/src/resolveTarball/resolveLocally/npm2.js deleted file mode 100644 index 80b0cbf..0000000 --- a/src/resolveTarball/resolveLocally/npm2.js +++ /dev/null @@ -1,36 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); -var glob = require('glob'); -var path = require('path'); - -// public -module.exports = getPkgPathNpm2; - -// implementation -var pkgPathByName = null; - -function getPkgPathNpm2 (dep) { - return pkgPathByName - ? getPkgPath(dep) - : buildIndex(dep).then(getPkgPath.bind(null, dep)); -} - -function buildIndex (dep, done) { - console.info(chalk.gray('? indexing package.json files... (not needed in npm3+)'), dep.id); - return new Promise(function (resolve) { - var files = glob.sync('node_modules/**/package.json'); - pkgPathByName = files.reduce(addPathToIndex, {}); - resolve(); - - function addPathToIndex (index, pkgPath) { - var name = pkgPath.replace('/package.json', '').replace(/.*\//, ''); - index[name] = pkgPath; - return index; - } - }); -} - -function getPkgPath (dep) { - var pkgPath = pkgPathByName[dep.name]; - return Promise.resolve(pkgPath ? path.resolve(pkgPath) : ''); -} diff --git a/src/resolveTarball/resolveLocally/npm3.js b/src/resolveTarball/resolveLocally/npm3.js deleted file mode 100644 index 1dd3a3e..0000000 --- a/src/resolveTarball/resolveLocally/npm3.js +++ /dev/null @@ -1,16 +0,0 @@ -// 3rd party modules -var fs = require('fs'); -var path = require('path'); - -// public -module.exports = getPkgPathNpm3; - -// implementation -function getPkgPathNpm3 (dep) { - return new Promise(function (resolve) { - var pkgPath = path.resolve('node_modules', dep.name, 'package.json'); - fs.access(pkgPath, fs.R_OK, function onFileCheck (err) { - resolve(err ? '' : pkgPath); - }); - }); -} diff --git a/src/resolveTarball/resolveRemotely.js b/src/resolveTarball/resolveRemotely.js deleted file mode 100644 index 8dd7e7c..0000000 --- a/src/resolveTarball/resolveRemotely.js +++ /dev/null @@ -1,35 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); - -// modules -var shell = require('../lib/shell'); - -// public -module.exports = resolveRemotely; - -// implementation -function resolveRemotely (dep) { - return shell('npm view ' + dep.id + ' --json') - .then(success, fail) - .catch(fail); - - function success (json) { - return readPkgJson(dep, json); - } - - function fail () { - return ''; - } -} - -function readPkgJson (dep, json) { - return new Promise(function (resolve) { - var meta = JSON.parse(json); - if (!meta || !meta.dist || !meta.dist.tarball) { - console.info(chalk.gray('? %s has no "dist.tarball" in `npm view %s --json`'), dep.id, dep.id); - resolve(''); - } else { - resolve(meta.dist.tarball); - } - }); -} diff --git a/src/rewriteGraph.js b/src/rewriteGraph.js deleted file mode 100644 index 2b1bb1e..0000000 --- a/src/rewriteGraph.js +++ /dev/null @@ -1,18 +0,0 @@ -// 3rd party modules -var chalk = require('chalk'); -var fs = require('graceful-fs'); - -// public -module.exports = rewriteGraph; - -// implementation -function rewriteGraph (pathToGraph, deps, graph) { - chalk.blue('i rewriting npm-shrinkwrap.json'); - deps.forEach(setResolved); - fs.writeFileSync(pathToGraph, JSON.stringify(graph, null, 2), 'utf8'); - return Promise.resolve(); -} - -function setResolved (dep) { - dep.shrinkwrap.resolved = dep.bundle; -} diff --git a/src/update/add-used-dependencies.js b/src/update/add-used-dependencies.js new file mode 100644 index 0000000..ade6e8e --- /dev/null +++ b/src/update/add-used-dependencies.js @@ -0,0 +1,14 @@ +// 3rd party modules +var when = require('when'); + +// public +module.exports = addUsedDependencies; + +// implementation +function addUsedDependencies(config) { + return when.all( + config.deps.map(function (dependency) { + return dependency.synchronise(); + }) + ); +} diff --git a/src/update/delete-unused-dependencies.js b/src/update/delete-unused-dependencies.js new file mode 100644 index 0000000..5fb6c5b --- /dev/null +++ b/src/update/delete-unused-dependencies.js @@ -0,0 +1,27 @@ +// 3rd party modules +var chalk = require('chalk'); +var when = require('when'); + +// modules +var deleteFile = require('../lib/delete-file'); + +// public +module.exports = deleteUnusedDependencies; + +// implementation +function deleteUnusedDependencies(config) { + var deletions = []; + for (var location in config.unusedDependencies) { + deletions.push(performDeletion(location)); + } + return when.all(deletions); + + function performDeletion(location) { + return deleteFile(location) + .then(onSuccess); + } + + function onSuccess(location) { + console.info(chalk.red('- %s'), location.replace(/.+\//, '')); + } +} diff --git a/src/update/index.js b/src/update/index.js new file mode 100644 index 0000000..b4b76d3 --- /dev/null +++ b/src/update/index.js @@ -0,0 +1,25 @@ +// 3rd party modules +var when = require('when'); + +// modules +var addUsedDependencies = require('./add-used-dependencies'); +var deleteUnusedDependencies = require('./delete-unused-dependencies'); + +// public +module.exports = update; + +// implementation +function update(config) { + return when(config) + .then(synchronise) + .then(function () { + return config; + }); + + function synchronise(config) { + return when.join( + addUsedDependencies(config), + deleteUnusedDependencies(config) + ); + } +}