Skip to content

Commit

Permalink
chore(check-node-modules): make check/reinstall node_modules work acr…
Browse files Browse the repository at this point in the history
…oss platforms

The previous implementations (based on shell scripts) threw errors on
Windows, because it was not able to `rm -rf` 'node_modules' (due to the
255 character limit in file-paths).

This implementation works consistently across platforms and is heavily based on
'https://github.com/angular/angular/blob/3b9c08676a4c921bbfa847802e08566fb601ba7a/tools/npm/check-node-modules.js'.

Fixes angular#11143
Closes angular#11353

Closes angular#12792
  • Loading branch information
gkalpak committed Sep 22, 2015
1 parent b7e5133 commit d3de006
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ install:
- npm config set loglevel http
- npm install -g npm@2.5
# Instal npm dependecies and ensure that npm cache is not stale
- scripts/npm/install-dependencies.sh
- npm install

before_script:
- mkdir -p $LOGS_DIR
Expand Down
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ module.exports = function(grunt) {

shell: {
"npm-install": {
command: path.normalize('scripts/npm/install-dependencies.sh')
command: 'node scripts/npm/check-node-modules.js'
},

"promises-aplus-tests": {
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
"npm": "~2.5"
},
"engineStrict": true,
"scripts": {
"preinstall": "node scripts/npm/check-node-modules.js --purge",
"postinstall": "node scripts/npm/copy-npm-shrinkwrap.js"
},
"devDependencies": {
"angular-benchpress": "0.x.x",
"benchmark": "1.x.x",
Expand Down
74 changes: 74 additions & 0 deletions scripts/npm/check-node-modules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Implementation based on:
// https://github.com/angular/angular/blob/3b9c08676a4c921bbfa847802e08566fb601ba7a/tools/npm/check-node-modules.js
'use strict';

// Imports
var fs = require('fs');
var path = require('path');

// Constants
var PROJECT_ROOT = path.join(__dirname, '../../');
var NODE_MODULES_DIR = 'node_modules';
var NPM_SHRINKWRAP_FILE = 'npm-shrinkwrap.json';
var NPM_SHRINKWRAP_CACHED_FILE = NODE_MODULES_DIR + '/npm-shrinkwrap.cached.json';

// Run
_main();

// Functions - Definitions
function _main() {
var purgeIfStale = process.argv.indexOf('--purge') !== -1;

process.chdir(PROJECT_ROOT);
checkNodeModules(purgeIfStale);
}

function checkNodeModules(purgeIfStale) {
var nodeModulesOk = compareMarkerFiles(NPM_SHRINKWRAP_FILE, NPM_SHRINKWRAP_CACHED_FILE);

if (nodeModulesOk) {
console.log(':-) npm dependencies are looking good!');
} else if (purgeIfStale) {
console.log(':-( npm dependencies are stale or in an unknown state!');
console.log(' Purging \'' + NODE_MODULES_DIR + '\'...');
deleteDirSync(NODE_MODULES_DIR);
} else {
var separator = new Array(81).join('!');

console.warn(separator);
console.warn(':-( npm dependencies are stale or in an unknown state!');
console.warn('You can rebuild the dependencies by running `npm install`.');
console.warn(separator);
}

return nodeModulesOk;
}

function compareMarkerFiles(markerFilePath, cachedMarkerFilePath) {
if (!fs.existsSync(cachedMarkerFilePath)) return false;

var opts = {encoding: 'utf-8'};
var markerContent = fs.readFileSync(markerFilePath, opts);
var cachedMarkerContent = fs.readFileSync(cachedMarkerFilePath, opts);

return markerContent === cachedMarkerContent;
}

// Custom implementation of `rm -rf` that works consistently across OSes
function deleteDirSync(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach(deleteDirOrFileSync);
fs.rmdirSync(path);
}

// Helpers
function deleteDirOrFileSync(subpath) {
var curPath = path + '/' + subpath;

if (fs.lstatSync(curPath).isDirectory()) {
deleteDirSync(curPath);
} else {
fs.unlinkSync(curPath);
}
}
}
60 changes: 60 additions & 0 deletions scripts/npm/copy-npm-shrinkwrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use strict';

// Imports
var fs = require('fs');
var path = require('path');

// Constants
var PROJECT_ROOT = path.join(__dirname, '../../');
var NODE_MODULES_DIR = 'node_modules';
var NPM_SHRINKWRAP_FILE = 'npm-shrinkwrap.json';
var NPM_SHRINKWRAP_CACHED_FILE = NODE_MODULES_DIR + '/npm-shrinkwrap.cached.json';

// Run
_main();

// Functions - Definitions
function _main() {
process.chdir(PROJECT_ROOT);
copyFile(NPM_SHRINKWRAP_FILE, NPM_SHRINKWRAP_CACHED_FILE, onCopied);
}

// Implementation based on:
// https://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js#answer-21995878
function copyFile(srcPath, dstPath, callback) {
var callbackCalled = false;

if (!fs.existsSync(srcPath)) {
done(new Error('Missing source file: ' + srcPath));
return;
}

var rs = fs.createReadStream(srcPath);
rs.on('error', done);

var ws = fs.createWriteStream(dstPath);
ws.on('error', done);
ws.on('finish', done);

rs.pipe(ws);

// Helpers
function done(err) {
if (callback && !callbackCalled) {
callbackCalled = true;
callback(err);
}
}
}

function onCopied(err) {
if (err) {
var separator = new Array(81).join('!');

console.error(separator);
console.error(
'Failed to copy `' + NPM_SHRINKWRAP_FILE + '` to `' + NPM_SHRINKWRAP_CACHED_FILE + '`:');
console.error(err);
console.error(separator);
}
}
16 changes: 0 additions & 16 deletions scripts/npm/install-dependencies.sh

This file was deleted.

0 comments on commit d3de006

Please sign in to comment.