commit 98f1ac5edbd716791f19140e90b1ea37acbefad8
parent cd6079d869a325d64605f4666ffa09853f7bbe9a
Author: Dan Stillman <dstillman@zotero.org>
Date: Tue, 6 Jun 2017 02:18:45 -0400
Merge pull request #1240 from tnajdek/master
Tweaks to make build work on Windows
Diffstat:
5 files changed, 87 insertions(+), 40 deletions(-)
diff --git a/.babelrc b/.babelrc
@@ -11,6 +11,7 @@
"resource/react.js",
"resource/react-dom.js",
"resource/bluebird.js",
+ "resource/bluebird/*.js",
"test/resource/httpd.js",
"test/resource/mocha.js",
"test/resource/co-mocha.js"
diff --git a/gulp/babel-worker.js b/gulp/babel-worker.js
@@ -4,6 +4,7 @@
const fs = require('fs');
const path = require('path');
const babel = require('babel-core');
+const minimatch = require('minimatch')
const mkdirp = require('mkdirp');
const options = JSON.parse(fs.readFileSync('.babelrc'));
@@ -11,35 +12,41 @@ const options = JSON.parse(fs.readFileSync('.babelrc'));
onmessage = (ev) => {
const t1 = Date.now();
const sourcefile = path.normalize(ev.data);
- let isError = false;
+ let error = null;
let isSkipped = false;
-
+
fs.readFile(sourcefile, 'utf8', (err, data) => {
var transformed;
if(sourcefile === 'resource/react-dom.js') {
transformed = data.replace(/ownerDocument\.createElement\((.*?)\)/gi, 'ownerDocument.createElementNS(DOMNamespaces.html, $1)');
- } else if('ignore' in options && options.ignore.includes(sourcefile)) {
+ } else if('ignore' in options && options.ignore.some(ignoreGlob => minimatch(sourcefile, ignoreGlob))) {
transformed = data;
isSkipped = true;
} else {
- transformed = babel.transform(data, options).code;
+ try {
+ transformed = babel.transform(data, options).code;
+ } catch(c) {
+ transformed = data;
+ isSkipped = true;
+ error = c.message;
+ }
}
const outfile = path.join('build', sourcefile);
- isError = !!err;
+ error = error || err;
mkdirp(path.dirname(outfile), err => {
- isError = !!err;
+ error = error || err;
fs.writeFile(outfile, transformed, err => {
- isError = !!err;
- const t2 = Date.now();
+ error = error || err;
+ const t2 = Date.now();
postMessage({
- isError,
isSkipped,
sourcefile,
outfile,
+ error,
processingTime: t2 - t1
});
});
diff --git a/gulpfile.js b/gulpfile.js
@@ -1,6 +1,5 @@
'use strict';
-const path = require('path');
const gulp = require('gulp');
const del = require('del');
const vfs = require('vinyl-fs');
@@ -12,15 +11,24 @@ const glob = require('glob');
const Worker = require('tiny-worker');
const merge = require('merge-stream');
const tap = require('gulp-tap');
-const rename = require("gulp-rename");
+const rename = require('gulp-rename');
const browserify = require('browserify');
const reactPatcher = require('./gulp/gulp-react-patcher');
+const isWindows = /^win/.test(process.platform);
const NODE_ENV = process.env.NODE_ENV;
+const workers = [];
+var isExiting = false;
const formatDirsforMatcher = dirs => {
return dirs.length > 1 ? `{${dirs.join(',')}}` : dirs[0];
};
+const killAllWorkers = () => {
+ for(let worker of workers) {
+ worker.terminate();
+ }
+};
+
// list of folders from where .js files are compiled and non-js files are symlinked
const dirs = [
'chrome',
@@ -72,16 +80,24 @@ const browserifyConfigs = [
const jsGlob = `./\{${dirs.join(',')}\}/**/*.js`;
const jsGlobIgnore = `./\{${symlinkDirs.concat(copyDirs).join(',')}\}/**/*.js`;
-function onError(err) {
- gutil.log(gutil.colors.red('Error:'), err);
- this.emit('end');
+function onError(shouldExit, err) {
+ if(shouldExit) {
+ isExiting = true;
+ killAllWorkers();
+ throw new Error(err);
+ } else {
+ gutil.log(gutil.colors.red('Error:'), err);
+ this.emit('end');
+ }
}
function onSuccess(msg) {
- gutil.log(gutil.colors.green('Build:'), msg);
+ if(!isExiting) {
+ gutil.log(gutil.colors.green('Build:'), msg);
+ }
}
-function getBrowserify() {
+function getBrowserify(exitOnError = true) {
const streams = browserifyConfigs.map(config => {
return gulp
.src(config.src)
@@ -89,39 +105,49 @@ function getBrowserify() {
file.contents = browserify(file.path, config.config).bundle();
}))
.pipe(rename(config.dest))
+ .on('error', function(err) { onError.bind(this)(exitOnError, err); })
+ .on('data', file => {
+ onSuccess(`[browserify] ${file.path}`);
+ })
.pipe(gulp.dest('build'));
});
return merge.apply(merge, streams);
}
-function getJS(source, sourceIgnore) {
+function getJS(source, sourceIgnore, exitOnError = true) {
if (sourceIgnore) {
source = [source, '!' + sourceIgnore];
}
return gulp.src(source, { base: '.' })
.pipe(babel())
- .pipe(reactPatcher())
- .on('error', onError)
+ .on('error', function(err) { onError.bind(this)(exitOnError, err); })
.on('data', file => {
onSuccess(`[js] ${file.path}`);
})
+ .pipe(reactPatcher())
.pipe(gulp.dest('./build'));
}
-function getJSParallel(source, sourceIgnore) {
+function getJSParallel(source, sourceIgnore, exitOnError = true) {
const jsFiles = glob.sync(source, { ignore: sourceIgnore });
const cpuCount = os.cpus().length;
const threadCount = Math.min(cpuCount, jsFiles.length);
let threadsActive = threadCount;
+ let isError = false;
return new Promise((resolve, reject) => {
for(let i = 0; i < threadCount; i++) {
let worker = new Worker('gulp/babel-worker.js');
+ workers[i] = worker;
worker.onmessage = ev => {
- if(ev.data.isError) {
- reject(`Failed while processing ${ev.data.sourcefile}`);
+ if(ev.data.error) {
+ isError = true;
+ let errorMsg = `Failed while processing ${ev.data.sourcefile}: ${ev.data.error}`;
+ NODE_ENV == 'debug' && console.log(`process ${i}: ${errorMsg}`);
+ onError(exitOnError, errorMsg);
+ reject(errorMsg);
}
NODE_ENV == 'debug' && console.log(`process ${i} took ${ev.data.processingTime} ms to process ${ev.data.sourcefile}`);
@@ -132,11 +158,13 @@ function getJSParallel(source, sourceIgnore) {
}
let nextFile = jsFiles.pop();
- if(nextFile) {
+ if(!isError && nextFile) {
+ NODE_ENV == 'debug' && console.log(`process ${i} scheduled to process ${nextFile}`);
worker.postMessage(nextFile);
} else {
NODE_ENV == 'debug' && console.log(`process ${i} has terminated`);
worker.terminate();
+ workers.splice(i, 1);
if(!--threadsActive) {
resolve();
}
@@ -149,7 +177,7 @@ function getJSParallel(source, sourceIgnore) {
});
}
-function getSymlinks() {
+function getSymlinks(exitOnError = true) {
const match = symlinkFiles
.concat(dirs.map(d => `${d}/**`))
.concat(symlinkDirs.map(d => `${d}/**`))
@@ -157,27 +185,28 @@ function getSymlinks() {
.concat([`!./${formatDirsforMatcher(copyDirs)}/**`]);
return gulp
- .src(match, { nodir: true, base: '.', read: false })
- .on('error', onError)
+ .src(match, { nodir: true, base: '.', read: isWindows })
+ .on('error', function(err) { onError.bind(this)(exitOnError, err); })
.on('data', file => {
onSuccess(`[ln] ${file.path.substr(__dirname.length + 1)}`);
})
- .pipe(vfs.symlink('build/'));
+ .pipe(isWindows ? gulp.dest('build/') : vfs.symlink('build/'));
}
-function getCopy() {
+function getCopy(exitOnError = true) {
return gulp
.src(copyDirs.map(d => `${d}/**`), { base: '.' })
.on('data', file => {
onSuccess(`[cp] ${file.path.substr(__dirname.length + 1)}`);
})
+ .on('error', function(err) { onError.bind(this)(exitOnError, err); })
.pipe(gulp.dest('build/'));
}
-function getSass() {
+function getSass(exitOnError = true) {
return gulp
.src('scss/*.scss')
- .on('error', onError)
+ .on('error', function(err) { onError.bind(this)(exitOnError, err); })
.pipe(sass())
.pipe(gulp.dest('./build/chrome/skin/default/zotero/components/'));
}
@@ -192,7 +221,11 @@ gulp.task('symlink', ['clean'], () => {
});
gulp.task('js', done => {
- getJSParallel(jsGlob, jsGlobIgnore).then(() => done());
+ getJSParallel(jsGlob, jsGlobIgnore)
+ .then(done)
+ .catch(errorMsg => {
+ onError(errorMsg);
+ });
});
gulp.task('browserify', () => {
@@ -209,16 +242,21 @@ gulp.task('sass', () => {
gulp.task('build', ['js', 'sass', 'symlink', 'browserify', 'copy']);
+gulp.task('build-clean', ['clean'], () => {
+ gulp.start('build');
+});
+
gulp.task('dev', ['clean'], () => {
var interval = 750;
- let watcher = gulp.watch(jsGlob, { interval });
+ gulp.watch(jsGlob, { interval }).on('change', event => {
+ getJS(event.path, jsGlobIgnore, false);
+ });
- watcher.on('change', function(event) {
- getJS(event.path, jsGlobIgnore);
+ gulp.watch('src/styles/*.scss', { interval }).on('change', () => {
+ getSass(false);
});
- gulp.watch('src/styles/*.scss', { interval }, ['sass']);
gulp.start('build');
});
diff --git a/package.json b/package.json
@@ -6,16 +6,16 @@
"main": "",
"scripts": {
"start": "./node_modules/.bin/gulp",
- "build": "./node_modules/.bin/gulp",
+ "build": "./node_modules/.bin/gulp build-clean",
"sass": "./node_modules/.bin/gulp sass",
"clean": "./node_modules/.bin/gulp clean"
},
"license": "",
"dependencies": {
"bluebird": "3.4.7",
- "zotero-web-library": "next",
"react": "^15.3.2",
- "react-dom": "^15.3.2"
+ "react-dom": "^15.3.2",
+ "zotero-web-library": "next"
},
"devDependencies": {
"babel-core": "^6.24.1",
@@ -43,6 +43,7 @@
"gulp-tap": "^1.0.1",
"gulp-util": "^3.0.7",
"merge-stream": "^1.0.1",
+ "minimatch": "^3.0.4",
"mocha": "^3.4.2",
"sinon": "^2.3.1",
"through2": "^2.0.1",
diff --git a/test/runtests.sh b/test/runtests.sh
@@ -1,8 +1,8 @@
#!/bin/bash
CWD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-case "$(uname -s)" in
- CYGWIN*) IS_CYGWIN=1 ;;
+case "$OSTYPE" in
+ msys*|mingw*|cygwin*) IS_CYGWIN=1 ;;
esac
function makePath {