diff --git a/README.md b/README.md index 3f0a08af..6294d88c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,21 @@ For local development, **node.js** build system is used. 1. Install node.js 1. From project folder run `npm install` -1. To build JS and CSS use ` ./node_modules/gulp/bin/gulp.js` +1. To build the JS and CSS files and start the configurator: + - With NW.js: Run `npm start`. + - With Chrome: Run `./node_modules/gulp/bin/gulp.js`. Then open `chrome://extensions`, enable + the `Developer mode`, click on the `Load unpacked extension...` button and select the `inav-configurator` directory. + +Other tasks are also defined in `gulpfile.js`. To run a task, use `./node_modules/gulp/bin/gulp.js task-name`. Available ones are: + +- **build**: Generate JS and CSS output files used by the configurator from their sources. It must be run whenever changes are made to any `.js` or `.css` files in order to have those changes appear +in the configurator. If new files are added, they must be included in `gulpfile.js`. See the comments at the top of `gulpfile.js` to learn how to do so. See also the `watch` task. +- **watch**: Watch JS and CSS sources for changes and run the `build` task whenever they're edited. +- **dist**: Create a distribution of the app (valid for packaging both as a Chrome app or a NW.js app) +in the `./dist/` directory. +- **release**: Create NW.js apps for each supported platform (win32, osx64 and linux64) in the `./apps` +directory. Running this task on macOS or Linux requires Wine, since it's needed to set the icon +for the Windows app. ## Authors diff --git a/gulpfile.js b/gulpfile.js index 5a4e2205..ad1e9557 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,14 +1,42 @@ 'use strict'; -var gulp = require('gulp'); -var rename = require('gulp-rename'); -var uglify = require('gulp-uglify'); -var concat = require('gulp-concat'); -var minifyCSS = require('gulp-minify-css'); +var child_process = require('child_process'); +var fs = require('fs'); +var path = require('path'); + +var archiver = require('archiver'); var del = require('del'); -var runSequence = require('run-sequence'); var NwBuilder = require('nw-builder'); +var gulp = require('gulp'); +var concat = require('gulp-concat'); +var runSequence = require('run-sequence'); + + +// Each key in the *sources* variable must be an array of +// the source files that will be combined into a single +// file and stored in *outputDir*. Each key in *sources* +// must be also present in *output*, whose value indicates +// the filename for the output file which combines the +// contents of the source files. +// +// Keys must be camel cased and end with either 'Css' or +// 'Js' (e.g. someSourcesCss or someSourcesJs). For each +// key, a build task will be generated named by prepending +// 'build-' and converting the key to dash-separated words +// (e.g. someSourcesCss will generate build-some-sources-css). +// +// Tasks with names ending with '-js' will be executed by the +// build-all-js task, while the ones ending with '-css' will +// be done by build-all-css. There's also a build task which +// runs both build-all-css and build-all-js. +// +// The watch task will monitor any files mentioned in the *sources* +// variable and regenerate the corresponding output file when +// they change. +// +// See README.md for details on the other tasks. + var sources = {}; sources.css = [ @@ -94,6 +122,10 @@ sources.receiverJs = [ './tabs/receiver_msp.js' ]; +sources.hexParserJs = [ + './js/workers/hex_parser.js', +]; + var output = { css: 'styles.css', js: 'script.js', @@ -101,87 +133,52 @@ var output = { mapJs: 'map.js', receiverCss: 'receiver-msp.css', receiverJs: 'receiver-msp.js', + hexParserJs: 'hex_parser.js', }; + var outputDir = './build/'; var distDir = './dist/'; +var appsDir = './apps/'; -gulp.task('build-css', function () { - - return gulp.src(sources.css) - .pipe(concat(output.css)) - .pipe(gulp.dest(outputDir)); -}); - -gulp.task('build-js', function () { - - return gulp.src(sources.js) - .pipe(concat(output.js)) - .pipe(gulp.dest(outputDir)); -}); - -gulp.task('build-map-css', function () { - - return gulp.src(sources.mapCss) - .pipe(concat(output.mapCss)) - .pipe(gulp.dest(outputDir)); -}); - -gulp.task('build-map-js', function () { - - return gulp.src(sources.mapJs) - .pipe(concat(output.mapJs)) - .pipe(gulp.dest(outputDir)); -}); - -gulp.task('build-receiver-css', function () { - - return gulp.src(sources.receiverCss) - .pipe(concat(output.receiverCss)) - .pipe(gulp.dest(outputDir)); -}); - -gulp.task('build-receiver-msp-js', function () { - - return gulp.src(sources.receiverJs) - .pipe(concat(output.receiverJs)) - .pipe(gulp.dest(outputDir)); -}); - -gulp.task('build-all-js', ['build-js', 'build-receiver-msp-js', 'build-map-js']); -gulp.task('build-all-css', ['build-css', 'build-receiver-css', 'build-map-css']); -gulp.task('build', ['build-all-css', 'build-all-js']); - -function get_outputs(ext) { - var src = []; - for (var k in output) { - var val = output[k]; - if (val.endsWith('.' + ext)) { - src.push(outputDir + val); - } - } - return src; +function get_task_name(key) { + return 'build-' + key.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();}); } -gulp.task('minify-js', ['build-all-js'], function () { - return gulp.src(get_outputs('js')) - .pipe(uglify()) - .pipe(gulp.dest(outputDir)); -}); +// Define build tasks dynamically based on the sources +// and output variables. +var buildCssTasks = []; +var buildJsTasks = []; +(function() { + // Convers fooBarBaz to foo-bar-baz + for (var k in output) { + (function (key) { + var name = get_task_name(key); + if (name.endsWith('-css')) { + buildCssTasks.push(name); + } else if (name.endsWith('-js')) { + buildJsTasks.push(name); + } else { + throw 'Invalid task name: "' + name + '": must end with -css or -js'; + } + gulp.task(name, function() { + return gulp.src(sources[key]) + .pipe(concat(output[key])) + .pipe(gulp.dest(outputDir)); + }); + })(k); + } +})(); -gulp.task('minify-css', ['build-all-css'], function () { - return gulp.src(get_outputs('css')) - .pipe(minifyCSS()) - .pipe(gulp.dest(outputDir)); -}); - -gulp.task('minify', ['minify-css', 'minify-js']); +gulp.task('build-all-js', buildJsTasks); +gulp.task('build-all-css', buildCssTasks); +gulp.task('build', ['build-all-css', 'build-all-js']); gulp.task('clean', function() { return del(['./build/**', './dist/**'], {force: true}); }); // Real work for dist task. Done in another task to call it via // run-sequence. -gulp.task('dist-build', ['minify'], function() { +gulp.task('dist-build', ['build'], function() { var distSources = [ './package.json', // For NW.js './manifest.json', // For Chrome app @@ -196,7 +193,6 @@ gulp.task('dist-build', ['minify'], function() { './resources/models/*', './resources/osd/*.mcm', './resources/motor_order/*.svg', - './js/workers/hex_parser.js', ]; return gulp.src(distSources, { base: '.' }) .pipe(gulp.dest(distDir)); @@ -206,31 +202,76 @@ gulp.task('dist', function() { return runSequence('clean', 'dist-build'); }); -// Create app packages in ./apps -gulp.task('release', ['dist'], function(done) { +// Create app directories in ./apps +gulp.task('apps', ['dist'], function(done) { var builder = new NwBuilder({ files: './dist/**/*', - buildDir: './apps', + buildDir: appsDir, platforms: ['win32', 'osx64', 'linux64'], flavor: 'normal', + macIcns: './images/inav.icns', + winIco: './images/inav.ico', }); builder.on('log', console.log); builder.build(function (err) { if (err) { console.log("Error building NW apps:" + err); + done(); + return; } + // Package apps as .zip files done(); }); }); +function get_release_filename(platform, ext) { + var pkg = require('./package.json'); + return 'INAV-Configurator_' + platform + '_' + pkg.version + '.' + ext; +} + +gulp.task('release-windows', function() { + var pkg = require('./package.json'); + var src = path.join(appsDir, pkg.name, 'win32'); + var output = fs.createWriteStream(path.join(appsDir, get_release_filename('win32', 'zip'))); + var archive = archiver('zip', { + zlib: { level: 9 } + }); + archive.on('warning', function(err) { throw err; }); + archive.on('error', function(err) { throw err; }); + archive.pipe(output); + archive.directory(src, 'INAV Configurator'); + return archive.finalize(); +}); + +gulp.task('release-macos', function() { + var pkg = require('./package.json'); + var src = path.join(appsDir, pkg.name, 'osx64', pkg.name + '.app'); + // Check if we want to sign the .app bundle + if (process.env.CODESIGN_IDENTITY) { + var sign_cmd = 'codesign --verbose --force --sign "' + process.env.CODESIGN_IDENTITY + '" ' + src; + child_process.execSync(sign_cmd); + } + var output = fs.createWriteStream(path.join(appsDir, get_release_filename('macOS', 'zip'))); + var archive = archiver('zip', { + zlib: { level: 9 } + }); + archive.on('warning', function(err) { throw err; }); + archive.on('error', function(err) { throw err; }); + archive.pipe(output); + archive.directory(src, 'INAV Configurator.app'); + return archive.finalize(); +}); + +// Create distributable .zip files in ./apps +gulp.task('release', function() { + // TODO: Linux + return runSequence('apps', 'release-macos'); +}); + gulp.task('watch', function () { - gulp.watch('js/**/*.js', ['build-js']); - gulp.watch('css/*.css', ['build-css']); - gulp.watch('main.css', ['build-css']); - gulp.watch('main.js', ['build-js']); - gulp.watch('tabs/*.js', ['build-js']); - gulp.watch('tabs/*.css', ['build-css']); - gulp.watch('eventPage.js', ['build-js']); + for(var k in output) { + gulp.watch(sources[k], [get_task_name(k)]); + } }); gulp.task('default', ['build']); diff --git a/images/inav.icns b/images/inav.icns new file mode 100644 index 00000000..9417e7ca Binary files /dev/null and b/images/inav.icns differ diff --git a/images/inav.ico b/images/inav.ico new file mode 100644 index 00000000..e180941b Binary files /dev/null and b/images/inav.ico differ diff --git a/package.json b/package.json index 1e24b1f9..0395f6b9 100755 --- a/package.json +++ b/package.json @@ -21,13 +21,11 @@ "author": "iNavFlight", "license": "GPL-3.0", "dependencies": { + "archiver": "^2.0.3", "bluebird": "3.4.1", "del": "^3.0.0", "gulp": "~3.9.1", "gulp-concat": "~2.6.1", - "gulp-minify-css": "~1.2.4", - "gulp-rename": "~1.2.2", - "gulp-uglify": "~3.0.0", "inflection": "1.12.0", "jquery": "2.1.4", "jquery-ui-npm": "1.12.0", diff --git a/tabs/firmware_flasher.js b/tabs/firmware_flasher.js index 88b8f894..b286a81e 100755 --- a/tabs/firmware_flasher.js +++ b/tabs/firmware_flasher.js @@ -29,7 +29,7 @@ TABS.firmware_flasher.initialize = function (callback) { function parse_hex(str, callback) { // parsing hex in different thread - var worker = new Worker('./js/workers/hex_parser.js'); + var worker = new Worker('./build/hex_parser.js'); // "callback" worker.onmessage = function (event) {