diff --git a/.travis.yml b/.travis.yml index 9583c8fe37..ba06f3a8fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ install: ./scripts/build/docker/run-command.sh -r "${TARGET_ARCH}" -s "${PWD}" -c "make info && make electron-develop"; else pip install codespell==1.9.2 awscli; - npm install -g bower asar; + npm install -g asar; brew install afsctool jq; make info; travis_wait make electron-develop; diff --git a/Makefile b/Makefile index 670943cccf..35650e69a7 100644 --- a/Makefile +++ b/Makefile @@ -135,6 +135,18 @@ endif endif endif +# --------------------------------------------------------------------- +# Analytics +# --------------------------------------------------------------------- + +ifndef ANALYTICS_SENTRY_TOKEN +$(warning No Sentry token found (ANALYTICS_SENTRY_TOKEN is not set)) +endif + +ifndef ANALYTICS_MIXPANEL_TOKEN +$(warning No Mixpanel token found (ANALYTICS_MIXPANEL_TOKEN is not set)) +endif + # --------------------------------------------------------------------- # Extra variables # --------------------------------------------------------------------- @@ -189,18 +201,27 @@ $(BUILD_DIRECTORY)/node-$(TARGET_PLATFORM)-$(TARGET_ARCH)-dependencies/node_modu -t node \ -s "$(TARGET_PLATFORM)" -$(BUILD_DIRECTORY)/electron-$(TARGET_PLATFORM)-$(TARGET_ARCH)-dependencies/bower_components: bower.json \ - | $(BUILD_DIRECTORY)/electron-$(TARGET_PLATFORM)-$(TARGET_ARCH)-dependencies - ./scripts/build/dependencies-bower.sh -p -x $| - $(BUILD_DIRECTORY)/electron-$(TARGET_PLATFORM)-$(APPLICATION_VERSION)-$(TARGET_ARCH)-app: \ $(BUILD_DIRECTORY)/electron-$(TARGET_PLATFORM)-$(TARGET_ARCH)-dependencies/node_modules \ - $(BUILD_DIRECTORY)/electron-$(TARGET_PLATFORM)-$(TARGET_ARCH)-dependencies/bower_components \ - | $(BUILD_DIRECTORY) + | $(BUILD_DIRECTORY) $(BUILD_TEMPORARY_DIRECTORY) ./scripts/build/electron-create-resources-app.sh -s . -o $@ \ -v $(APPLICATION_VERSION) \ -f "$(APPLICATION_FILES)" - $(foreach prerequisite,$^,$(call execute-command,cp -RLf $(prerequisite) $@)) + cp -RLf $< $@ + +ifdef ANALYTICS_SENTRY_TOKEN + ./scripts/build/jq-inplace.sh \ + -c ".analytics.sentry.token = \"$(ANALYTICS_SENTRY_TOKEN)\"" \ + -f $@/package.json \ + -t $(BUILD_TEMPORARY_DIRECTORY) +endif + +ifdef ANALYTICS_MIXPANEL_TOKEN + ./scripts/build/jq-inplace.sh \ + -c ".analytics.mixpanel.token = \"$(ANALYTICS_MIXPANEL_TOKEN)\"" \ + -f $@/package.json \ + -t $(BUILD_TEMPORARY_DIRECTORY) +endif $(BUILD_DIRECTORY)/electron-$(TARGET_PLATFORM)-$(APPLICATION_VERSION)-$(TARGET_ARCH)-app.asar: \ $(BUILD_DIRECTORY)/electron-$(TARGET_PLATFORM)-$(APPLICATION_VERSION)-$(TARGET_ARCH)-app \ @@ -484,7 +505,6 @@ electron-develop: -v "$(ELECTRON_VERSION)" \ -t electron \ -s "$(TARGET_PLATFORM)" - ./scripts/build/dependencies-bower.sh help: @echo "Available targets: $(TARGETS)" @@ -510,6 +530,5 @@ clean: distclean: clean rm -rf node_modules - rm -rf bower_components .DEFAULT_GOAL = help diff --git a/appveyor.yml b/appveyor.yml index 10f5b6ccdd..4d3f4bf6ac 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,7 +25,7 @@ matrix: install: - ps: Install-Product node $env:nodejs_version x64 - npm install -g npm@4.4.4 - - npm install -g bower rimraf asar + - npm install -g rimraf asar - choco install nsis -version 2.51 - choco install jq - choco install curl diff --git a/bower.json b/bower.json deleted file mode 100644 index 527e89c23b..0000000000 --- a/bower.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "etcher", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ], - "dependencies": { - "angular-mixpanel": "~1.1.2" - } -} diff --git a/docs/RUNNING-LOCALLY.md b/docs/RUNNING-LOCALLY.md index 4a76e9b97c..7c634d23dd 100644 --- a/docs/RUNNING-LOCALLY.md +++ b/docs/RUNNING-LOCALLY.md @@ -10,7 +10,6 @@ Prerequisites ### Common - [NodeJS](https://nodejs.org) (at least v6) -- [Bower](http://bower.io) - [Python](https://www.python.org) - [jq](https://stedolan.github.io/jq/) - [Asar](https://github.com/electron/asar) diff --git a/lib/gui/index.html b/lib/gui/index.html index 2f4e398ea7..4bd730a694 100644 --- a/lib/gui/index.html +++ b/lib/gui/index.html @@ -11,17 +11,6 @@ - - - diff --git a/lib/gui/modules/analytics.js b/lib/gui/modules/analytics.js index bb8a771bb0..0171283647 100644 --- a/lib/gui/modules/analytics.js +++ b/lib/gui/modules/analytics.js @@ -20,85 +20,32 @@ * @module Etcher.Modules.Analytics */ -const _ = require('lodash'); const angular = require('angular'); -const isRunningInAsar = require('electron-is-running-in-asar'); -const errors = require('../../shared/errors'); -const os = require('os'); +const _ = require('lodash'); +const resinCorvus = require('resin-corvus/browser'); const packageJSON = require('../../../package.json'); -const arch = require('arch'); -const utils = require('../../shared/utils'); -// Force Mixpanel snippet to load Mixpanel locally -// instead of using a CDN for performance reasons -window.MIXPANEL_CUSTOM_LIB_URL = '../../bower_components/mixpanel/mixpanel.js'; - -require('../../../bower_components/mixpanel/mixpanel-jslib-snippet.js'); -require('../../../bower_components/angular-mixpanel/src/angular-mixpanel'); const MODULE_NAME = 'Etcher.Modules.Analytics'; const analytics = angular.module(MODULE_NAME, [ - 'analytics.mixpanel', require('../models/settings') ]); -/** - * @summary Get host architecture - * @function - * @private - * - * @description - * We need this because node's os.arch() returns the process architecture - * See: https://github.com/nodejs/node-v0.x-archive/issues/2862 - * - * @returns {String} Host architecture - * - * @example - * if (getHostArchitecture() === 'x64') { - * console.log('Host architecture is x64'); - * } - */ -const getHostArchitecture = () => { - return _.includes([ 'ia32', 'x64' ], process.arch) ? _.replace(arch(), 'x86', 'ia32') : process.arch; -}; - -// Mixpanel integration -// https://github.com/kuhnza/angular-mixpanel - -analytics.config(($mixpanelProvider) => { - $mixpanelProvider.apiKey('63e5fc4563e00928da67d1226364dd4c'); - - $mixpanelProvider.superProperties({ - electron: process.versions.electron, - node: process.version, - arch: process.arch, - version: packageJSON.version, - osPlatform: os.platform(), - hostArch: getHostArchitecture(), - osRelease: os.release(), - cpuCores: os.cpus().length, - totalMemory: os.totalmem(), - startFreeMemory: os.freemem() - }); -}); - -// TrackJS integration -// http://docs.trackjs.com/tracker/framework-integrations - -analytics.run(($window) => { - - // Don't configure TrackJS when - // running inside the test suite - if (window.mocha) { - return; - } - - $window.trackJs.configure({ - userId: os.userInfo().username, - version: packageJSON.version +analytics.run((SettingsModel) => { + resinCorvus.install({ + services: { + sentry: _.get(packageJSON, [ 'analytics', 'sentry', 'token' ]), + mixpanel: _.get(packageJSON, [ 'analytics', 'mixpanel', 'token' ]) + }, + options: { + release: packageJSON.version, + shouldReport: () => { + return SettingsModel.get('errorReporting'); + } + } }); }); -analytics.service('AnalyticsService', function($log, $window, $mixpanel, SettingsModel) { +analytics.service('AnalyticsService', function() { /** * @summary Log a debug message @@ -106,22 +53,14 @@ analytics.service('AnalyticsService', function($log, $window, $mixpanel, Setting * @public * * @description - * This function sends the debug message to TrackJS only. + * This function sends the debug message to error reporting services. * * @param {String} message - message * * @example * AnalyticsService.log('Hello World'); */ - this.logDebug = (message) => { - const debugMessage = `${new Date()} ${message}`; - - if (SettingsModel.get('errorReporting') && isRunningInAsar()) { - $window.trackJs.console.debug(debugMessage); - } - - $log.debug(debugMessage); - }; + this.logDebug = resinCorvus.logDebug; /** * @summary Log an event @@ -129,7 +68,7 @@ analytics.service('AnalyticsService', function($log, $window, $mixpanel, Setting * @public * * @description - * This function sends the debug message to TrackJS and Mixpanel. + * This function sends the debug message to product analytics services. * * @param {String} message - message * @param {Object} [data] - event data @@ -139,23 +78,7 @@ analytics.service('AnalyticsService', function($log, $window, $mixpanel, Setting * image: '/dev/disk2' * }); */ - this.logEvent = (message, data) => { - const debugData = utils.hideAbsolutePathsInObject(utils.makeFlatStartCaseObject(data)); - - if (SettingsModel.get('errorReporting') && isRunningInAsar()) { - $mixpanel.track(message, debugData); - } - - const debugMessage = _.attempt(() => { - if (debugData) { - return `${message} (${JSON.stringify(debugData)})`; - } - - return message; - }); - - this.logDebug(debugMessage); - }; + this.logEvent = resinCorvus.logEvent; /** * @summary Log an exception @@ -163,24 +86,14 @@ analytics.service('AnalyticsService', function($log, $window, $mixpanel, Setting * @public * * @description - * This function logs an exception in TrackJS. + * This function logs an exception to error reporting services. * * @param {Error} exception - exception * * @example * AnalyticsService.logException(new Error('Something happened')); */ - this.logException = (exception) => { - if (_.every([ - SettingsModel.get('errorReporting'), - isRunningInAsar(), - errors.shouldReport(exception) - ])) { - $window.trackJs.track(exception); - } - - $log.error(exception); - }; + this.logException = resinCorvus.logException; }); diff --git a/lib/shared/errors.js b/lib/shared/errors.js index 9ef7225625..24c3941489 100644 --- a/lib/shared/errors.js +++ b/lib/shared/errors.js @@ -122,29 +122,6 @@ const getUserFriendlyMessageProperty = (error, property) => { return _.invoke(exports.HUMAN_FRIENDLY, [ code, property ], error); }; -/** - * @summary Check whether an error should be reported to TrackJS - * @function - * @public - * - * @description - * In order to determine whether the error should be reported, we - * check a property called `report`. For backwards compatibility, and - * to properly handle errors that we don't control, an error without - * this property is reported automatically. - * - * @param {Error} error - error - * @returns {Boolean} whether the error should be reported - * - * @example - * if (errors.shouldReport(new Error('foo'))) { - * console.log('We should report this error'); - * } - */ -exports.shouldReport = (error) => { - return !_.has(error, [ 'report' ]) || Boolean(error.report); -}; - /** * @summary Check if a string is blank * @function diff --git a/lib/shared/utils.js b/lib/shared/utils.js deleted file mode 100644 index 726f0f37e4..0000000000 --- a/lib/shared/utils.js +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2017 resin.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -const _ = require('lodash'); -_.mixin(require('lodash-deep')); -const flatten = require('flat').flatten; -const deepMapKeys = require('deep-map-keys'); -const path = require('path'); - -/** - * @summary Create a flattened copy of the object with all keys transformed in start case - * @function - * @public - * - * @param {*} object - object to transform - * @returns {*} transformed object - * - * @example - * const object = makeFlatStartCaseObject({ - * image: { - * size: 10000000000, - * recommendedSize: 10000000000 - * } - * }) - * - * console.log(object) - * > { - * > 'Image Size': 10000000000, - * > 'Image Recommended Size': 10000000000 - * > } - */ -exports.makeFlatStartCaseObject = (object) => { - if (_.isUndefined(object)) { - return object; - } - - // Transform primitives to objects - if (!_.isObject(object)) { - return { - Value: object - }; - } - - if (_.isArray(object)) { - return _.map(object, (property) => { - if (_.isObject(property)) { - return exports.makeFlatStartCaseObject(property); - } - - return property; - }); - } - - const transformedKeysObject = deepMapKeys(object, (key) => { - - // Preserve environment variables - const regex = /^[A-Z_]+$/; - if (regex.test(key)) { - return key; - } - - return _.startCase(key); - }); - - return flatten(transformedKeysObject, { - delimiter: ' ', - safe: true - }); - -}; - -/** - * @summary Create an object clone with all absolute paths replaced with the path basename - * @function - * @public - * - * @param {Object} object - original object - * @returns {Object} transformed object - * - * @example - * const anonymized = utils.hideAbsolutePathsInObject({ - * path1: '/home/john/rpi.img', - * simpleProperty: null, - * nested: { - * path2: '/home/john/another-image.img', - * path3: 'yet-another-image.img', - * otherProperty: false - * } - * }); - * - * console.log(anonymized); - * > { - * > path1: 'rpi.img', - * > simpleProperty: null, - * > nested: { - * > path2: 'another-image.img', - * > path3: 'yet-another-image.img', - * > otherProperty: false - * > } - * > } - */ -exports.hideAbsolutePathsInObject = (object) => { - return _.deepMapValues(object, (value) => { - if (!_.isString(value)) { - return value; - } - - // Don't alter disk devices, even though they appear as full paths - if (_.some([ - _.startsWith(value, '/dev/'), - _.startsWith(value, '\\\\.\\') - ])) { - return value; - } - - return path.isAbsolute(value) ? path.basename(value) : value; - }); - -}; - diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 6da0e6bff9..4abdd52658 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -154,7 +154,7 @@ }, "arch": { "version": "2.1.0", - "from": "arch@2.1.0", + "from": "arch@>=2.1.0 <3.0.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.0.tgz" }, "archive-type": { @@ -1040,6 +1040,11 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", "dev": true }, + "cookie": { + "version": "0.3.1", + "from": "cookie@0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz" + }, "cookiejar": { "version": "2.0.1", "from": "cookiejar@2.0.1", @@ -1256,7 +1261,7 @@ }, "deep-map-keys": { "version": "1.2.0", - "from": "deep-map-keys@1.2.0", + "from": "deep-map-keys@>=1.2.0 <2.0.0", "resolved": "https://registry.npmjs.org/deep-map-keys/-/deep-map-keys-1.2.0.tgz" }, "defaults": { @@ -1386,6 +1391,16 @@ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", "dev": true }, + "detect-node": { + "version": "2.0.3", + "from": "detect-node@>=2.0.3 <3.0.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz" + }, + "detect-process": { + "version": "1.0.4", + "from": "detect-process@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/detect-process/-/detect-process-1.0.4.tgz" + }, "detective": { "version": "4.5.0", "from": "detective@>=4.0.0 <5.0.0", @@ -2514,7 +2529,7 @@ }, "flat": { "version": "2.0.1", - "from": "flat@2.0.1", + "from": "flat@>=2.0.1 <3.0.0", "resolved": "https://registry.npmjs.org/flat/-/flat-2.0.1.tgz" }, "flat-cache": { @@ -3355,6 +3370,11 @@ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz", "dev": true }, + "is-electron": { + "version": "2.0.0", + "from": "is-electron@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.0.0.tgz" + }, "is-electron-renderer": { "version": "2.0.1", "from": "is-electron-renderer@>=2.0.0 <3.0.0", @@ -3467,6 +3487,11 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", "dev": true }, + "is-phantom": { + "version": "1.0.1", + "from": "is-phantom@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/is-phantom/-/is-phantom-1.0.1.tgz" + }, "is-posix-bracket": { "version": "0.1.1", "from": "is-posix-bracket@>=0.1.0 <0.2.0", @@ -3555,7 +3580,8 @@ "isstream": { "version": "0.1.2", "from": "isstream@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "dev": true }, "jju": { "version": "1.3.0", @@ -3618,8 +3644,7 @@ "json-stringify-safe": { "version": "5.0.1", "from": "json-stringify-safe@>=5.0.0 <5.1.0", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "dev": true + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" }, "json3": { "version": "3.3.2", @@ -3743,7 +3768,7 @@ }, "lodash-deep": { "version": "2.0.0", - "from": "lodash-deep@2.0.0", + "from": "lodash-deep@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/lodash-deep/-/lodash-deep-2.0.0.tgz" }, "lodash-es": { @@ -3946,6 +3971,11 @@ "from": "lru-cache@>=4.0.0 <5.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.1.tgz" }, + "lsmod": { + "version": "1.0.0", + "from": "lsmod@1.0.0", + "resolved": "https://registry.npmjs.org/lsmod/-/lsmod-1.0.0.tgz" + }, "lzma-native": { "version": "1.5.2", "from": "lzma-native@>=1.1.0 <2.0.0", @@ -4682,6 +4712,16 @@ } } }, + "mixpanel": { + "version": "0.6.0", + "from": "mixpanel@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/mixpanel/-/mixpanel-0.6.0.tgz" + }, + "mixpanel-browser": { + "version": "2.11.0", + "from": "mixpanel-browser@>=2.11.0 <3.0.0", + "resolved": "https://registry.npmjs.org/mixpanel-browser/-/mixpanel-browser-2.11.0.tgz" + }, "mkdirp": { "version": "0.5.1", "from": "mkdirp@>=0.5.0 <0.6.0", @@ -5520,6 +5560,23 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz", "dev": true }, + "raven": { + "version": "1.2.0", + "from": "raven@>=1.1.4 <2.0.0", + "resolved": "https://registry.npmjs.org/raven/-/raven-1.2.0.tgz", + "dependencies": { + "uuid": { + "version": "3.0.0", + "from": "uuid@3.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz" + } + } + }, + "raven-js": { + "version": "3.14.0", + "from": "raven-js@>=3.12.1 <4.0.0", + "resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.14.0.tgz" + }, "rc": { "version": "1.1.7", "from": "rc@>=1.1.2 <2.0.0", @@ -5803,6 +5860,18 @@ } } }, + "resin-corvus": { + "version": "1.0.0-beta.20", + "from": "resin-corvus@latest", + "resolved": "https://registry.npmjs.org/resin-corvus/-/resin-corvus-1.0.0-beta.20.tgz", + "dependencies": { + "lodash": { + "version": "4.17.4", + "from": "lodash@>=4.17.4 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz" + } + } + }, "resolve": { "version": "1.3.2", "from": "resolve@>=1.1.4 <2.0.0", @@ -6231,8 +6300,7 @@ "stack-trace": { "version": "0.0.9", "from": "stack-trace@>=0.0.0 <0.1.0", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", - "dev": true + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz" }, "stream-browserify": { "version": "2.0.1", diff --git a/package.json b/package.json index 15049d4b16..f4b00cf60b 100644 --- a/package.json +++ b/package.json @@ -68,23 +68,19 @@ "angular-seconds-to-date": "^1.0.0", "angular-ui-bootstrap": "^2.5.0", "angular-ui-router": "^0.4.2", - "arch": "^2.1.0", "archive-type": "^3.2.0", "bluebird": "^3.0.5", "bootstrap-sass": "^3.3.5", "chalk": "^1.1.3", "command-join": "^2.0.0", - "deep-map-keys": "^1.2.0", "drivelist": "^5.0.16", "electron-is-running-in-asar": "^1.0.0", "etcher-image-write": "^9.0.1", "etcher-latest-version": "^1.0.0", - "flat": "^2.0.1", "flexboxgrid": "^6.3.0", "immutable": "^3.8.1", "is-elevated": "^2.0.1", "lodash": "^4.5.1", - "lodash-deep": "^2.0.0", "lzma-native": "^1.5.2", "mountutils": "^1.0.2", "node-ipc": "^8.9.2", @@ -94,6 +90,7 @@ "redux-localstorage": "^0.4.1", "resin-cli-form": "^1.4.1", "resin-cli-visuals": "^1.2.8", + "resin-corvus": "^1.0.0-beta.20", "rx": "^4.1.0", "semver": "^5.1.0", "sudo-prompt": "^6.1.0", diff --git a/scripts/build/docker/Dockerfile-i686 b/scripts/build/docker/Dockerfile-i686 index 5fc398b2d9..00ddbf5c53 100644 --- a/scripts/build/docker/Dockerfile-i686 +++ b/scripts/build/docker/Dockerfile-i686 @@ -26,7 +26,7 @@ RUN apt-get update && apt-get install -y \ RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - \ && apt-get install -y nodejs RUN npm config set spin=false -RUN npm install -g bower asar electron-installer-debian +RUN npm install -g asar electron-installer-debian # Python RUN pip install codespell==1.9.2 awscli diff --git a/scripts/build/docker/Dockerfile-x86_64 b/scripts/build/docker/Dockerfile-x86_64 index 130911aaa5..c472d98a35 100644 --- a/scripts/build/docker/Dockerfile-x86_64 +++ b/scripts/build/docker/Dockerfile-x86_64 @@ -26,7 +26,7 @@ RUN apt-get update && apt-get install -y \ RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - \ && apt-get install -y nodejs RUN npm config set spin=false -RUN npm install -g bower asar electron-installer-debian +RUN npm install -g asar electron-installer-debian # Python RUN pip install codespell==1.9.2 awscli diff --git a/scripts/build/docker/Dockerfile.template b/scripts/build/docker/Dockerfile.template index 0ca0b10f03..d3fbfaa3d9 100644 --- a/scripts/build/docker/Dockerfile.template +++ b/scripts/build/docker/Dockerfile.template @@ -26,7 +26,7 @@ RUN apt-get update && apt-get install -y \ RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - \ && apt-get install -y nodejs RUN npm config set spin=false -RUN npm install -g bower asar electron-installer-debian +RUN npm install -g asar electron-installer-debian # Python RUN pip install codespell==1.9.2 awscli diff --git a/scripts/build/dependencies-bower.sh b/scripts/build/jq-inplace.sh similarity index 56% rename from scripts/build/dependencies-bower.sh rename to scripts/build/jq-inplace.sh index 3194a1ea68..d357475c98 100755 --- a/scripts/build/dependencies-bower.sh +++ b/scripts/build/jq-inplace.sh @@ -19,42 +19,38 @@ set -u set -e -./scripts/build/check-dependency.sh bower +./scripts/build/check-dependency.sh jq function usage() { echo "Usage: $0" echo "" echo "Options" echo "" - echo " -x " - echo " -p production install" + echo " -c " + echo " -f " + echo " -t " exit 1 } -ARGV_PREFIX="" -ARGV_PRODUCTION=false +ARGV_COMMAND="" +ARGV_FILE="" +ARGV_TEMPORARY_DIRECTORY="" -while getopts ":x:p" option; do +while getopts ":c:f:t:" option; do case $option in - x) ARGV_PREFIX=$OPTARG ;; - p) ARGV_PRODUCTION=true ;; + c) ARGV_COMMAND=$OPTARG ;; + f) ARGV_FILE=$OPTARG ;; + t) ARGV_TEMPORARY_DIRECTORY="$OPTARG" ;; *) usage ;; esac done -INSTALL_OPTS="--allow-root" - -if [ "$ARGV_PRODUCTION" == "true" ]; then - INSTALL_OPTS="$INSTALL_OPTS --production" -fi - -if [ -n "$ARGV_PREFIX" ]; then - cp "$PWD/bower.json" "$ARGV_PREFIX/bower.json" - pushd "$ARGV_PREFIX" - bower install $INSTALL_OPTS - popd - rm "$ARGV_PREFIX/bower.json" -else - bower install $INSTALL_OPTS +if [ -z "$ARGV_COMMAND" ] || + [ -z "$ARGV_FILE" ] || + [ -z "$ARGV_TEMPORARY_DIRECTORY" ]; then + usage fi +TEMPORARY_FILE="$ARGV_TEMPORARY_DIRECTORY/$(basename $ARGV_FILE).TMP" +jq "$ARGV_COMMAND" "$ARGV_FILE" > "$TEMPORARY_FILE" +mv "$TEMPORARY_FILE" "$ARGV_FILE" diff --git a/tests/shared/errors.spec.js b/tests/shared/errors.spec.js index bb01d22384..cc79d8a85a 100644 --- a/tests/shared/errors.spec.js +++ b/tests/shared/errors.spec.js @@ -36,97 +36,6 @@ describe('Shared: Errors', function() { }); - describe('.shouldReport()', function() { - - it('should return true for a string error', function() { - const error = 'foo'; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return true for a number 0 error', function() { - const error = 0; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return true for a number 1 error', function() { - const error = 1; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return true for a number -1 error', function() { - const error = -1; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return true for an array error', function() { - const error = [ 1, 2, 3 ]; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return true for an undefined error', function() { - const error = undefined; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return true for a null error', function() { - const error = null; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return true for an empty object error', function() { - const error = {}; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return true for a basic error', function() { - const error = new Error('foo'); - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return true for an error with a report true property', function() { - const error = new Error('foo'); - error.report = true; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should return false for an error with a report false property', function() { - const error = new Error('foo'); - error.report = false; - m.chai.expect(errors.shouldReport(error)).to.be.false; - }); - - it('should return false for an error with a report undefined property', function() { - const error = new Error('foo'); - error.report = undefined; - m.chai.expect(errors.shouldReport(error)).to.be.false; - }); - - it('should return false for an error with a report null property', function() { - const error = new Error('foo'); - error.report = null; - m.chai.expect(errors.shouldReport(error)).to.be.false; - }); - - it('should return false for an error with a report 0 property', function() { - const error = new Error('foo'); - error.report = 0; - m.chai.expect(errors.shouldReport(error)).to.be.false; - }); - - it('should return true for an error with a report 1 property', function() { - const error = new Error('foo'); - error.report = 1; - m.chai.expect(errors.shouldReport(error)).to.be.true; - }); - - it('should cast the report property to boolean', function() { - const error = new Error('foo'); - error.report = ''; - m.chai.expect(errors.shouldReport(error)).to.be.false; - }); - - }); - describe('.getTitle()', function() { it('should accept a string', function() { @@ -480,25 +389,25 @@ describe('Shared: Errors', function() { describe('.createError()', function() { - it('should report the resulting error by default', function() { + it('should not set `error.report` by default', function() { const error = errors.createError('Foo', 'Something happened'); - m.chai.expect(errors.shouldReport(error)).to.be.true; + m.chai.expect(error.report).to.be.undefined; }); - it('should not report the error if report is false', function() { + it('should set `error.report` to false if `options.report` is false', function() { const error = errors.createError('Foo', 'Something happened', { report: false }); - m.chai.expect(errors.shouldReport(error)).to.be.false; + m.chai.expect(error.report).to.be.false; }); - it('should not report the error if report evaluates to false', function() { + it('should set `error.report` to false if `options.report` evaluates to false', function() { const error = errors.createError('Foo', 'Something happened', { report: 0 }); - m.chai.expect(errors.shouldReport(error)).to.be.false; + m.chai.expect(error.report).to.be.false; }); it('should be an instance of Error', function() { @@ -550,9 +459,9 @@ describe('Shared: Errors', function() { describe('.createUserError()', function() { - it('should not report the resulting error', function() { + it('should set the `report` flag to `false`', function() { const error = errors.createUserError('Foo', 'Something happened'); - m.chai.expect(errors.shouldReport(error)).to.be.false; + m.chai.expect(error.report).to.be.false; }); it('should be an instance of Error', function() { diff --git a/tests/shared/utils.spec.js b/tests/shared/utils.spec.js deleted file mode 100644 index 0ce52d6d1d..0000000000 --- a/tests/shared/utils.spec.js +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2017 resin.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -const m = require('mochainon'); -const utils = require('../../lib/shared/utils'); -const path = require('path'); - -describe('Shared: Utils', function() { - - describe('.makeFlatStartCaseObject()', function() { - - it('should return undefined if given undefined', function() { - m.chai.expect(utils.makeFlatStartCaseObject(undefined)).to.be.undefined; - }); - - it('should return flat object with start case keys if given nested object', function() { - const object = { - person: { - firstName: 'John', - lastName: 'Doe', - address: { - streetNumber: 13, - streetName: 'Elm' - } - } - }; - - m.chai.expect(utils.makeFlatStartCaseObject(object)).to.deep.equal({ - 'Person First Name': 'John', - 'Person Last Name': 'Doe', - 'Person Address Street Number': 13, - 'Person Address Street Name': 'Elm' - }); - - }); - - it('should return an object with the key `value` if given `false`', function() { - m.chai.expect(utils.makeFlatStartCaseObject(false)).to.deep.equal({ - Value: false - }); - }); - - it('should return an object with the key `value` if given `null`', function() { - m.chai.expect(utils.makeFlatStartCaseObject(null)).to.deep.equal({ - Value: null - }); - }); - - it('should preserve environment variable', function() { - m.chai.expect(utils.makeFlatStartCaseObject({ - ETCHER_DISABLE_UPDATES: true - })).to.deep.equal({ - ETCHER_DISABLE_UPDATES: true - }); - }); - - it('should preserve environment variables inside objects', function() { - m.chai.expect(utils.makeFlatStartCaseObject({ - foo: { - FOO_BAR_BAZ: 3 - } - })).to.deep.equal({ - 'Foo FOO_BAR_BAZ': 3 - }); - }); - - it('should insert space after key starting with number', function() { - m.chai.expect(utils.makeFlatStartCaseObject({ - foo: { - '1key': 1 - } - })).to.deep.equal({ - 'Foo 1 Key': 1 - }); - }); - - it('should not modify start case keys', function() { - m.chai.expect(utils.makeFlatStartCaseObject({ - Foo: { - 'Start Case Key': 42 - } - })).to.deep.equal({ - 'Foo Start Case Key': 42 - }); - }); - - it('should not modify arrays', function() { - m.chai.expect(utils.makeFlatStartCaseObject([ 1, 2, { - nested: 3 - } ])).to.deep.equal([ 1, 2, { - Nested: 3 - } ]); - }); - - it('should not modify nested arrays', function() { - m.chai.expect(utils.makeFlatStartCaseObject({ - values: [ 1, 2, { - nested: 3 - } ] - })).to.deep.equal({ - Values: [ 1, 2, { - Nested: 3 - } ] - }); - }); - - it('should leave nested arrays nested', function() { - m.chai.expect(utils.makeFlatStartCaseObject([ 1, 2, [ 3, 4 ] ])).to.deep.equal([ 1, 2, [ 3, 4 ] ]); - }); - - }); - - describe('.hideAbsolutePathsInObject()', function() { - - it('should return undefined if given undefined', function() { - m.chai.expect(utils.hideAbsolutePathsInObject(undefined)).to.be.undefined; - }); - - it('should return null if given null', function() { - m.chai.expect(utils.hideAbsolutePathsInObject(null)).to.be.null; - }); - - it('should return a clone of the object if there are no paths in the object', function() { - const object = { - numberProperty: 1, - nested: { - otherProperty: 'value' - } - }; - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.not.equal(object); - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.deep.equal(object); - }); - - describe('given UNIX paths', function() { - - beforeEach(function() { - this.isAbsolute = path.isAbsolute; - this.basename = path.basename; - path.isAbsolute = path.posix.isAbsolute; - path.basename = path.posix.basename; - }); - - afterEach(function() { - path.isAbsolute = this.isAbsolute; - path.basename = this.basename; - }); - - it('should replace absolute paths with the basename', function() { - const object = { - prop1: 'some value', - prop2: '/home/john/rpi.img' - }; - - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.deep.equal({ - prop1: 'some value', - prop2: 'rpi.img' - }); - }); - - it('should replace nested absolute paths with the basename', function() { - const object = { - nested: { - path: '/home/john/rpi.img' - } - }; - - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.deep.equal({ - nested: { - path: 'rpi.img' - } - }); - }); - - it('should not alter /dev/sdb', function() { - const object = { - nested: { - path: '/dev/sdb' - } - }; - - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.deep.equal({ - nested: { - path: '/dev/sdb' - } - }); - }); - - it('should not alter relative paths', function() { - const object = { - path: 'foo/bar' - }; - - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.deep.equal({ - path: 'foo/bar' - }); - }); - - it('should handle arrays', function() { - m.chai.expect(utils.hideAbsolutePathsInObject({ - foo: 'foo', - bar: [ - { - path: '/foo/bar/baz' - }, - { - path: '/foo/bar/baz' - }, - { - path: '/foo/bar/baz' - } - ] - })).to.deep.equal({ - foo: 'foo', - bar: [ - { - path: 'baz' - }, - { - path: 'baz' - }, - { - path: 'baz' - } - ] - }); - }); - - }); - - describe('given Windows paths', function() { - - beforeEach(function() { - this.isAbsolute = path.isAbsolute; - this.basename = path.basename; - path.isAbsolute = path.win32.isAbsolute; - path.basename = path.win32.basename; - }); - - afterEach(function() { - path.isAbsolute = this.isAbsolute; - path.basename = this.basename; - }); - - it('should replace absolute paths with the basename', function() { - const object = { - prop1: 'some value', - prop2: 'C:\\Users\\John\\rpi.img' - }; - - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.deep.equal({ - prop1: 'some value', - prop2: 'rpi.img' - }); - - }); - - it('should replace nested absolute paths with the basename', function() { - const object = { - nested: { - path: 'C:\\Users\\John\\rpi.img' - } - }; - - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.deep.equal({ - nested: { - path: 'rpi.img' - } - }); - }); - - it('should not alter \\\\.\\PHYSICALDRIVE1', function() { - const object = { - nested: { - path: '\\\\.\\PHYSICALDRIVE1' - } - }; - - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.deep.equal({ - nested: { - path: '\\\\.\\PHYSICALDRIVE1' - } - }); - }); - - it('should not alter relative paths', function() { - const object = { - path: 'foo\\bar' - }; - - m.chai.expect(utils.hideAbsolutePathsInObject(object)).to.deep.equal({ - path: 'foo\\bar' - }); - }); - - it('should handle arrays', function() { - m.chai.expect(utils.hideAbsolutePathsInObject({ - foo: 'foo', - bar: [ { - path: 'C:\\foo\\bar\\baz' - }, { - path: 'C:\\foo\\bar\\baz' - }, { - path: 'C:\\foo\\bar\\baz' - } ] - })).to.deep.equal({ - foo: 'foo', - bar: [ { - path: 'baz' - }, { - path: 'baz' - }, { - path: 'baz' - } ] - }); - }); - - }); - - }); - -});