diff --git a/index.js b/index.js index 5b30a80..1e11874 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,7 @@ const Promise = require('bluebird'); const semver = require('semver'); // Start up the watcher, but don't watch any files yet. -// We'll add the files we want to watch later, in the startWatching() method. +// We'll add the files we want to watch later, in the init() method. const watcher = chokidar.watch([ '!**/*___jb_*___', // Ignore temp files created by JetBrains IDEs '!**/node_modules/**', // Ignore node_modules folders @@ -166,10 +166,17 @@ module.exports.init = function (rootPath, nodecgVersion, nodecgConfig, Logger) { // Once all the bowerPromises have been resolved, start up the bundle watcher and emit "allLoaded" return Promise.all(bowerPromises).then(() => { - watcher.add([ - bundlesPath + '/**/dashboard/**', // Watch dashboard folders - bundlesPath + '/**/package.json' // Watch bundle package.json files - ]); + // Workaround for https://github.com/paulmillr/chokidar/issues/419 + // This workaround is necessary to fully support symlinks. + fs.readdirSync(bundlesPath) + .map(name => path.join(bundlesPath, name)) + .filter(source => fs.statSync(source).isDirectory()) + .forEach(bundlePath => { + watcher.add([ + path.join(bundlePath, 'dashboard'), // Watch dashboard folders + path.join(bundlePath, '/package.json') // Watch bundle package.json files + ]); + }); }).catch( /* istanbul ignore next */ err => { @@ -240,10 +247,7 @@ module.exports.remove = function (bundleName) { * Only used by tests. */ module.exports._stopWatching = function () { - watcher.unwatch([ - bundlesPath + '/**/dashboard/**', // Unwatch dashboard folders - bundlesPath + '/**/package.json' // Unwatch bundle package.json files - ]); + watcher.close(); }; /** diff --git a/lib/npm_installer.js b/lib/npm_installer.js index 4e72854..0230ba9 100644 --- a/lib/npm_installer.js +++ b/lib/npm_installer.js @@ -1,6 +1,6 @@ 'use strict'; -const execSync = require('child_process').execSync; +const spawn = require('cross-spawn'); const util = require('util'); const os = require('os'); const format = require('util').format; @@ -24,7 +24,7 @@ module.exports = function (config, Logger) { */ try { process.stdout.write(format('Verifying/installing npm deps for bundle %s...', bundle.name)); - execSync('npm install --production', { + spawn.sync('npm', ['install', '--production'], { cwd: bundle.dir, stdio: ['pipe', 'pipe', 'pipe'], env: npmEnv diff --git a/package-lock.json b/package-lock.json index eaa3833..a249ca3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -519,7 +519,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, "requires": { "lru-cache": "4.1.1", "shebang-command": "1.2.0", @@ -562,7 +561,7 @@ "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "requires": { - "es5-ext": "0.10.26" + "es5-ext": "0.10.29" } }, "dashdash": { @@ -708,9 +707,9 @@ "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" }, "es5-ext": { - "version": "0.10.26", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.26.tgz", - "integrity": "sha1-UbISilMbcMT2dkCTpzy+u4IYY3I=", + "version": "0.10.29", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.29.tgz", + "integrity": "sha512-KXla9NXo5sdaEkGSmbFPYgjH6m75kxsthL6GDRSug/Y2OiMoYm0I9giL39j4cgmaFmAbkIFJ6gG+SGKnLSmOvA==", "requires": { "es6-iterator": "2.0.1", "es6-symbol": "3.1.1" @@ -722,7 +721,7 @@ "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.26", + "es5-ext": "0.10.29", "es6-symbol": "3.1.1" } }, @@ -732,7 +731,7 @@ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.26", + "es5-ext": "0.10.29", "es6-iterator": "2.0.1", "es6-set": "0.1.5", "es6-symbol": "3.1.1", @@ -745,7 +744,7 @@ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.26", + "es5-ext": "0.10.29", "es6-iterator": "2.0.1", "es6-symbol": "3.1.1", "event-emitter": "0.3.5" @@ -757,7 +756,7 @@ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.26" + "es5-ext": "0.10.29" } }, "es6-weak-map": { @@ -766,7 +765,7 @@ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.26", + "es5-ext": "0.10.29", "es6-iterator": "2.0.1", "es6-symbol": "3.1.1" } @@ -1130,7 +1129,7 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.26" + "es5-ext": "0.10.29" } }, "exit-hook": { @@ -2082,7 +2081,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "dev": true, "requires": { "pseudomap": "1.0.2", "yallist": "2.1.2" @@ -2242,9 +2240,7 @@ "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=" }, "nodecg-bundle-parser": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/nodecg-bundle-parser/-/nodecg-bundle-parser-0.3.4.tgz", - "integrity": "sha1-/Sfr9BcmUpTjuxAdtBXSqSzHSx8=", + "version": "github:nodecg/nodecg-bundle-parser#83d14fd72fc6994447db4910f451c76cf7b7760c", "requires": { "cheerio": "0.22.0", "eslint": "3.19.0", @@ -2497,8 +2493,7 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "punycode": { "version": "1.4.1", @@ -2739,7 +2734,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, "requires": { "shebang-regex": "1.0.0" } @@ -2747,8 +2741,7 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "shelljs": { "version": "0.7.8", @@ -3129,8 +3122,7 @@ "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, "yargs": { "version": "3.10.0", diff --git a/package.json b/package.json index 8895d21..79fa80d 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,8 @@ "dependencies": { "bluebird": "^3.4.6", "bower": "^1.7.1", - "chokidar": "^1.4.1", + "chokidar": "^1.7.0", + "cross-spawn": "^5.1.0", "extend": "^3.0.0", "fs.extra": "^1.3.2", "nodecg-bundle-parser": "^0.3.4", diff --git a/test/fixtures/change-panel-symlink-target/dashboard/panel.html b/test/fixtures/change-panel-symlink-target/dashboard/panel.html new file mode 100644 index 0000000..e149a39 --- /dev/null +++ b/test/fixtures/change-panel-symlink-target/dashboard/panel.html @@ -0,0 +1,10 @@ + + + + + Title + + + + + diff --git a/test/fixtures/change-panel-symlink-target/package.json b/test/fixtures/change-panel-symlink-target/package.json new file mode 100644 index 0000000..fbc4906 --- /dev/null +++ b/test/fixtures/change-panel-symlink-target/package.json @@ -0,0 +1,18 @@ +{ + "name": "change-panel-symlink", + "version": "0.0.1", + "homepage": "http://github.com/nodecg", + "author": "Alex Van Camp ", + "description": "A test bundle", + "license": "MIT", + "nodecg": { + "compatibleRange": "~0.7.0", + "dashboardPanels": [ + { + "name": "panel", + "title": "Panel", + "file": "panel.html" + } + ] + } +} diff --git a/test/manager.spec.js b/test/manager.spec.js index 40f0ff4..897a88c 100644 --- a/test/manager.spec.js +++ b/test/manager.spec.js @@ -17,6 +17,10 @@ before(function (done) { } wrench.copyDirSyncRecursive('test/fixtures', '_workingTest', {forceDelete: true}); + fs.symlinkSync( + path.resolve('_workingTest/change-panel-symlink-target'), + path.resolve('_workingTest/bundles/change-panel-symlink') + ); const nodecgConfig = { bundles: { @@ -98,6 +102,18 @@ describe('watcher', () => { fs.writeFileSync(panelPath, panel); }); + it('should detect panel HTML file changes when the bundle is symlinked', function (done) { + this.bundleManager.once('bundleChanged', bundle => { + expect(bundle.name).to.equal('change-panel-symlink'); + done(); + }); + + const panelPath = '_workingTest/bundles/change-panel-symlink/dashboard/panel.html'; + let panel = fs.readFileSync(panelPath); + panel += '\n'; + fs.writeFileSync(panelPath, panel); + }); + it('should reload the bundle\'s config when the bundle is reloaded due to a change', function (done) { const manifest = JSON.parse(fs.readFileSync('_workingTest/bundles/change-config/package.json')); const config = JSON.parse(fs.readFileSync('_workingTest/cfg/change-config.json'));