Skip to content
This repository was archived by the owner on Feb 18, 2021. It is now read-only.

Commit 1915eb5

Browse files
committed
Implement check
1 parent b2be60f commit 1915eb5

8 files changed

+155
-10
lines changed

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,18 @@ Options:
196196

197197
- `--dirname` defaults to `process.cwd()`
198198

199+
#### `npm-shrinkwrap check`
200+
201+
Asserts that your `npm-shrinkwrap.json` file and node_modules
202+
directory are in sync. If any excess modules are in your
203+
node_modules folder, `check` will return an error and print
204+
a list of the excess dependencies that are installed.
205+
206+
Options:
207+
--dirname sets the directory of the npm-shrinkwrap.json
208+
209+
- `--dirname` defaults to `process.cwd()`
210+
199211
#### `npm-shrinkwrap install`
200212

201213
Will write a `shrinkwrap` script to your `package.json` file.

bin/cli.js

+47
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,53 @@ function main(opts, callback) {
7474
console.log('synced npm-shrinkwrap.json ' +
7575
'into node_modules');
7676
});
77+
} else if (command === 'check') {
78+
// Otherwise, we check to see if any erroneous dependencies are
79+
// installed.
80+
//
81+
// We set opts.dry to true, which suppresses all side effects in the
82+
// shrinkShrinkwrap routine.
83+
opts.dry = true;
84+
85+
return syncShrinkwrap(opts, function (err, errorReport) {
86+
if (callback) {
87+
return callback(err, errorReport);
88+
}
89+
90+
if (err) {
91+
if (errorReport === undefined) {
92+
console.log('error', err);
93+
console.error('stack', new Error().stack);
94+
throw err;
95+
}
96+
97+
if (errorReport.excessPackageJsonDependencies !== null &&
98+
errorReport.excessPackageJsonDependencies.length !== 0) {
99+
console.error('package.json has dependencies that are ' +
100+
'not present in npm-shrinkwrap.json');
101+
console.log(errorReport.excessPackageJsonDependencies);
102+
}
103+
104+
if (errorReport.excessShrinkwrapDependencies !== null &&
105+
errorReport.excessShrinkwrapDependencies.length !== 0) {
106+
console.error('npm-shrinkwrap.json has dependencies that are ' +
107+
'not present in package.json');
108+
console.log(errorReport.excessShrinkwrapDependencies);
109+
}
110+
111+
if (errorReport.erroneouslyInstalledDependencies !== null &&
112+
errorReport.erroneouslyInstalledDependencies.length !== 0) {
113+
console.error('npm-shrinkwrap.json is out of sync ' +
114+
'with node_modules');
115+
console.log(errorReport.erroneouslyInstalledDependencies);
116+
}
117+
118+
return process.exit(1);
119+
}
120+
121+
console.log('npm-shrinkwrap.json is in sync ' +
122+
'with package.json');
123+
});
77124
}
78125

79126
shrinkwrap(opts, function (err, warnings) {

bin/usage.md

+12
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ Options:
3434

3535
- `--dirname` defaults to `process.cwd()`
3636

37+
## `{cmd} check`
38+
39+
Asserts that your `npm-shrinkwrap.json` file and node_modules
40+
directory are in sync. If any excess modules are in your
41+
node_modules folder, `check` will return an error and print
42+
a list of the excess dependencies that are installed.
43+
44+
Options:
45+
--dirname sets the directory of the npm-shrinkwrap.json
46+
47+
- `--dirname` defaults to `process.cwd()`
48+
3749
## `{cmd} install`
3850

3951
Will write a `shrinkwrap` script to your `package.json` file.

sync/force-install.js

+18-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ function forceInstall(nodeModules, shrinkwrap, opts, cb) {
2020

2121
// if no dependencies object then terminate recursion
2222
if (shrinkwrap.name && !shrinkwrap.dependencies) {
23-
return purgeExcess(nodeModules, shrinkwrap, opts, cb);
23+
return purgeExcess(nodeModules, shrinkwrap, opts, function(err, results) {
24+
cb(err, results || []);
25+
});
2426
}
2527

2628
var deps = shrinkwrap.dependencies;
@@ -46,7 +48,7 @@ function forceInstall(nodeModules, shrinkwrap, opts, cb) {
4648
opts.dev = false;
4749

4850
// remove purgeExcess result
49-
results.pop();
51+
var excess = results.pop();
5052

5153
var incorrects = results.filter(function (dep) {
5254
return !dep.correct;
@@ -78,7 +80,6 @@ function forceInstall(nodeModules, shrinkwrap, opts, cb) {
7880
var name = correct.name;
7981
var folder = path.join(nodeModules, name,
8082
'node_modules');
81-
8283
return forceInstall.bind(
8384
null, folder, correct, opts);
8485
});
@@ -90,7 +91,20 @@ function forceInstall(nodeModules, shrinkwrap, opts, cb) {
9091

9192
var tasks = [].concat(inCorrectTasks, correctTasks);
9293

93-
parallel(tasks, cb);
94+
parallel(tasks, function(err, results) {
95+
if (err) {
96+
return cb(err);
97+
}
98+
99+
// Results is an array of arrays representing the excess
100+
// installed dependencies of our children.
101+
var flattened = [].concat.apply([], results);
102+
103+
/*
104+
return the excess dependencies that may have been purged
105+
*/
106+
cb(null, (excess || []).concat(flattened));
107+
});
94108
});
95109
}
96110

sync/index.js

+48-3
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,64 @@ function syncShrinkwrap(opts, cb) {
3636

3737
parallel({
3838
shrinkwrap: read.shrinkwrap.bind(null, dirname),
39-
devDependencies: read.devDependencies.bind(null, dirname)
39+
dependencies: read.dependencies.bind(null, dirname)
4040
}, function (err, tuple) {
4141
if (err) {
4242
return cb(err);
4343
}
4444

4545
var nodeModules = path.join(dirname, 'node_modules');
46+
var dependencies = tuple.dependencies;
4647
var shrinkwrap = tuple.shrinkwrap;
47-
shrinkwrap.devDependencies = tuple.devDependencies;
48+
49+
// first, we check that package.json dependencies and shrinkwrap
50+
// top-level dependencies are in sync. this should cover the case
51+
// where a dependency was added or removed to package.json, but
52+
// shrinkwrap was not subsequently run.
53+
var packageJsonDependencies =
54+
Object.keys(dependencies.dependencies);
55+
var shrinkwrapTopLevelDependencies =
56+
Object.keys(shrinkwrap.dependencies);
57+
58+
var excessPackageJsonDependencies = packageJsonDependencies
59+
.filter(function (x) {
60+
return shrinkwrapTopLevelDependencies.indexOf(x) === -1;
61+
});
62+
var excessShrinkwrapDependencies = shrinkwrapTopLevelDependencies
63+
.filter(function (x) {
64+
return packageJsonDependencies.indexOf(x) === -1;
65+
});
66+
67+
shrinkwrap.devDependencies = tuple.dependencies.devDependencies;
4868

4969
opts.dev = true;
5070

51-
forceInstall(nodeModules, shrinkwrap, opts, cb);
71+
forceInstall(nodeModules, shrinkwrap, opts,
72+
function(err, erroneousDependencies) {
73+
// If there is a legitimate error, or we are not running
74+
// `check`, bubble it up immediately
75+
if (err || opts.dry !== true) {
76+
return cb(err);
77+
}
78+
79+
// Generate the error report
80+
if (erroneousDependencies.length !== 0 ||
81+
excessPackageJsonDependencies.length !== 0 ||
82+
excessShrinkwrapDependencies.length !== 0
83+
) {
84+
return cb(
85+
new Error('npm-shrinkwrap.json is out of sync'),
86+
{
87+
excessPackageJsonDependencies:
88+
excessPackageJsonDependencies,
89+
excessShrinkwrapDependencies:
90+
excessShrinkwrapDependencies,
91+
erroneouslyInstalledDependencies:
92+
erroneousDependencies,
93+
});
94+
}
95+
cb(null);
96+
});
5297
});
5398
});
5499
}

sync/install-module.js

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ module.exports = installModule;
1111
1212
*/
1313
function installModule(nodeModules, dep, opts, cb) {
14+
// Suppress side-effects if running `check`
15+
if (opts.dry === true) {
16+
return cb(null, dep);
17+
}
18+
1419
var where = path.join(nodeModules, '..');
1520

1621
console.log('installing ', where, dep.resolved);

sync/purge-excess.js

+7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ function purgeExcess(dir, shrinkwrap, opts, cb) {
2828

2929
var tasks = excessFiles.map(function (file) {
3030
var filePath = path.join(dir, file);
31+
32+
// Suppress side-effects if running `check`
33+
if (opts.dry === true) {
34+
return function (cb) {
35+
return cb(null, filePath);
36+
};
37+
}
3138
console.log('removing', filePath);
3239
return rimraf.bind(null, filePath);
3340
});

sync/read.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var FileNotFound = TypedError({
1212
module.exports = {
1313
shrinkwrap: readShrinkwrap,
1414
package: readPackage,
15-
devDependencies: readDevDependencies
15+
dependencies: readDependencies
1616
};
1717

1818
function readPackage(dirname, cb) {
@@ -33,12 +33,15 @@ function readShrinkwrap(dirname, cb) {
3333
});
3434
}
3535

36-
function readDevDependencies(dirname, cb) {
36+
function readDependencies(dirname, cb) {
3737
readPackage(dirname, function (err, json) {
3838
if (err) {
3939
return cb(err);
4040
}
4141

42-
cb(null, json.devDependencies);
42+
cb(null, {
43+
dependencies: json.dependencies,
44+
devDependencies: json.devDependencies
45+
});
4346
});
4447
}

0 commit comments

Comments
 (0)