chore: follow standardjs guidelines (#1664)

- Extend the `standard` ESLint configuration
- Remove ESLint rules that are defined in the `standard` configuration
- Get rid of semi-colons

See: https://github.com/resin-io/etcher/pull/1657
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
This commit is contained in:
Juan Cruz Viotti 2017-08-03 09:01:54 -04:00 committed by GitHub
parent 5c19b70e83
commit d8e31665a0
134 changed files with 5337 additions and 5391 deletions

View File

@ -7,7 +7,9 @@ env:
plugins:
- lodash
- jsdoc
extends: 'eslint:recommended'
extends: 'standard'
parserOptions:
sourceType: 'script'
settings:
jsdoc:
additionalTagNames:
@ -17,63 +19,16 @@ rules:
# Possible Errors
no-cond-assign:
- error
no-console:
- off
no-constant-condition:
- error
no-control-regex:
- error
no-debugger:
- error
no-dupe-args:
- error
no-dupe-keys:
- error
no-duplicate-case:
- error
no-empty:
- error
no-empty-character-class:
- error
no-ex-assign:
- error
no-extra-boolean-cast:
- error
no-extra-parens:
- error
no-extra-semi:
- error
no-func-assign:
- error
no-inner-declarations:
- error
- both
no-invalid-regexp:
- error
no-irregular-whitespace:
- error
no-negated-in-lhs:
- error
no-obj-calls:
- error
no-prototype-builtins:
- error
no-regex-spaces:
- error
no-sparse-arrays:
- error
no-template-curly-in-string:
- error
no-unexpected-multiline:
- error
no-unreachable:
- error
no-unsafe-finally:
- error
use-isnan:
- error
valid-jsdoc:
- error
- requireReturn: false
@ -89,13 +44,9 @@ rules:
prefer:
arg: "param"
return: "returns"
valid-typeof:
- error
# Best Practices
accessor-pairs:
- error
array-callback-return:
- error
block-scoped-var:
@ -110,19 +61,12 @@ rules:
- error
default-case:
- error
dot-location:
- error
- property
dot-notation:
- error
eqeqeq:
- error
guard-for-in:
- error
no-alert:
- error
no-caller:
- error
no-case-declarations:
- error
no-div-regex:
@ -131,106 +75,43 @@ rules:
- error
no-empty-function:
- error
no-empty-pattern:
- error
no-eq-null:
- error
no-eval:
- error
no-extend-native:
- error
no-extra-bind:
- error
no-extra-label:
- error
no-fallthrough:
- error
no-floating-decimal:
- error
no-global-assign:
- error
no-implicit-coercion:
- error
no-implicit-globals:
- error
no-implied-eval:
- error
no-iterator:
- error
no-labels:
- error
no-lone-blocks:
- error
no-loop-func:
- error
no-magic-numbers:
- error
no-multi-spaces:
- error
no-multi-str:
- error
no-native-reassign:
- error
no-new:
- error
no-new-func:
- error
no-new-wrappers:
- error
no-octal:
- error
no-octal-escape:
- error
no-param-reassign:
- error
no-proto:
- error
no-redeclare:
- error
no-restricted-properties:
- error
- property: __proto__
no-return-assign:
- error
no-return-await:
- error
no-script-url:
- error
no-self-assign:
- error
no-self-compare:
- error
no-sequences:
- error
no-throw-literal:
- error
no-unmodified-loop-condition:
- error
no-unused-expressions:
- error
no-unused-labels:
- error
no-useless-call:
- error
no-useless-concat:
- error
no-useless-escape:
- error
no-void:
- error
no-warning-comments:
- off
no-with:
- error
radix:
- error
vars-on-top:
- off
wrap-iife:
- error
- outside
yoda:
- error
# Strict mode
@ -245,21 +126,11 @@ rules:
- always
no-catch-shadow:
- error
no-delete-var:
- error
no-label-var:
- error
no-restricted-globals:
- error
- event
no-shadow:
- error
no-shadow-restricted-names:
- error
no-undef:
- error
no-undef-init:
- error
no-undefined:
- error
no-unused-vars:
@ -273,14 +144,8 @@ rules:
- error
global-require:
- off
handle-callback-err:
- error
no-mixed-requires:
- error
no-new-require:
- error
no-path-concat:
- error
no-process-env:
- off
no-process-exit:
@ -293,38 +158,20 @@ rules:
array-bracket-spacing:
- error
- always
block-spacing:
- error
brace-style:
- error
- 1tbs
camelcase:
- error
capitalized-comments:
- error
- always
- ignoreConsecutiveComments: true
comma-dangle:
- error
- never
comma-spacing:
- error
- before: false
after: true
comma-style:
- error
- last
computed-property-spacing:
- error
- never
consistent-this:
- error
- self
eol-last:
- error
func-call-spacing:
- error
- never
func-name-matching:
- error
- always
@ -341,19 +188,6 @@ rules:
- min: 2
exceptions:
- "_"
indent:
- error
- 2
- SwitchCase: 1
key-spacing:
- error
- beforeColon: false
afterColon: true
mode: strict
keyword-spacing:
- error
- before: true
after: true
line-comment-position:
- error
- position: above
@ -390,14 +224,8 @@ rules:
multiline-ternary:
- error
- never
new-cap:
- error
new-parens:
- error
newline-per-chained-call:
- off
no-array-constructor:
- error
no-bitwise:
- error
no-continue:
@ -408,21 +236,12 @@ rules:
- error
no-mixed-operators:
- error
no-mixed-spaces-and-tabs:
- error
no-multi-assign:
- error
no-multiple-empty-lines:
- error
- max: 1
maxEOF: 1
maxBOF: 0
no-negated-condition:
- error
no-nested-ternary:
- error
no-new-object:
- error
no-plusplus:
- error
no-restricted-syntax:
@ -431,46 +250,24 @@ rules:
- ForInStatement
no-spaced-func:
- error
no-tabs:
- error
no-trailing-spaces:
- error
no-underscore-dangle:
- error
- allowAfterThis: false
no-unneeded-ternary:
- error
no-whitespace-before-property:
- error
object-curly-newline:
- error
- minProperties: 1
object-curly-spacing:
- error
- always
object-property-newline:
- error
one-var-declaration-per-line:
- error
- always
one-var:
- error
- never
operator-assignment:
- error
- always
operator-linebreak:
- error
- after
padded-blocks:
- error
- never
quote-props:
- error
- as-needed
quotes:
- error
- single
require-jsdoc:
- error
- require:
@ -478,32 +275,11 @@ rules:
ClassDeclaration: true
MethodDefinition: true
ArrowFunctionExpression: true
semi:
- error
- always
semi-spacing:
- error
- before: false
after: true
space-before-blocks:
- error
space-before-function-paren:
- error
- anonymous: always
named: always
asyncArrow: never
space-in-parens:
- error
- never
space-infix-ops:
- error
space-unary-ops:
- error
- words: true
nonwords: false
spaced-comment:
- error
- always
template-tag-spacing:
- error
- always
@ -522,32 +298,12 @@ rules:
- error
- before: true
after: true
constructor-super:
- error
generator-star-spacing:
- error
- before: true
after: false
no-class-assign:
- error
no-confusing-arrow:
- error
no-const-assign:
- error
no-dupe-class-members:
- error
no-duplicate-imports:
- error
no-new-symbol:
- error
no-this-before-super:
- error
no-useless-computed-key:
- error
no-useless-constructor:
- error
no-useless-rename:
- error
no-var:
- error
object-shorthand:
@ -570,17 +326,8 @@ rules:
- allowNamedFunctions: false
require-yield:
- error
rest-spread-spacing:
- error
template-curly-spacing:
- error
- never
symbol-description:
- error
yield-star-spacing:
- error
- before: true
after: false
# Lodash

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const _ = require('lodash')
/**
* @summary Get the explicit boolean form of an argument
@ -44,19 +44,19 @@ const _ = require('lodash');
exports.getBooleanArgumentForm = (argumentName, value) => {
const prefix = _.attempt(() => {
if (!value) {
return '--no-';
return '--no-'
}
const SHORT_OPTION_LENGTH = 1;
const SHORT_OPTION_LENGTH = 1
if (_.size(argumentName) === SHORT_OPTION_LENGTH) {
return '-';
return '-'
}
return '--';
});
return '--'
})
return prefix + argumentName;
};
return prefix + argumentName
}
/**
* @summary Get CLI writer arguments
@ -94,7 +94,7 @@ exports.getArguments = (options) => {
exports.getBooleanArgumentForm('unmount', options.unmountOnSuccess),
exports.getBooleanArgumentForm('check', options.validateWriteOnSuccess)
];
]
return argv;
};
return argv
}

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const path = require('path');
const path = require('path')
/**
* @summary Child writer constants
@ -37,4 +37,4 @@ module.exports = {
*/
WRITER_PROXY_SCRIPT: path.join(__dirname, 'writer-proxy.js')
};
}

View File

@ -14,17 +14,17 @@
* limitations under the License.
*/
'use strict';
'use strict'
const EventEmitter = require('events').EventEmitter;
const _ = require('lodash');
const childProcess = require('child_process');
const ipc = require('node-ipc');
const rendererUtils = require('./renderer-utils');
const cli = require('./cli');
const CONSTANTS = require('./constants');
const EXIT_CODES = require('../shared/exit-codes');
const robot = require('../shared/robot');
const EventEmitter = require('events').EventEmitter
const _ = require('lodash')
const childProcess = require('child_process')
const ipc = require('node-ipc')
const rendererUtils = require('./renderer-utils')
const cli = require('./cli')
const CONSTANTS = require('./constants')
const EXIT_CODES = require('../shared/exit-codes')
const robot = require('../shared/robot')
/**
* @summary Perform a write
@ -57,7 +57,7 @@ const robot = require('../shared/robot');
* });
*/
exports.write = (image, drive, options) => {
const emitter = new EventEmitter();
const emitter = new EventEmitter()
const argv = cli.getArguments({
entryPoint: rendererUtils.getApplicationEntryPoint(),
@ -65,17 +65,17 @@ exports.write = (image, drive, options) => {
device: drive.device,
validateWriteOnSuccess: options.validateWriteOnSuccess,
unmountOnSuccess: options.unmountOnSuccess
});
})
// There might be multiple Etcher instances running at
// the same time, therefore we must ensure each IPC
// server/client has a different name.
process.env.IPC_SERVER_ID = `etcher-server-${process.pid}`;
process.env.IPC_CLIENT_ID = `etcher-client-${process.pid}`;
process.env.IPC_SERVER_ID = `etcher-server-${process.pid}`
process.env.IPC_CLIENT_ID = `etcher-client-${process.pid}`
ipc.config.id = process.env.IPC_SERVER_ID;
ipc.config.silent = true;
ipc.serve();
ipc.config.id = process.env.IPC_SERVER_ID
ipc.config.silent = true
ipc.serve()
/**
* @summary Safely terminate the IPC server
@ -91,11 +91,11 @@ exports.write = (image, drive, options) => {
// just stops receiving any further connections,
// but remains open if there are active ones.
_.each(ipc.server.sockets, (socket) => {
socket.destroy();
});
socket.destroy()
})
ipc.server.stop();
};
ipc.server.stop()
}
/**
* @summary Emit an error to the client
@ -108,9 +108,9 @@ exports.write = (image, drive, options) => {
* emitError(new Error('foo bar'));
*/
const emitError = (error) => {
terminateServer();
emitter.emit('error', error);
};
terminateServer()
emitter.emit('error', error)
}
/**
* @summary Bridge robot message to the child writer caller
@ -127,7 +127,7 @@ exports.write = (image, drive, options) => {
const bridgeRobotMessage = (message) => {
const parsedMessage = _.attempt(() => {
if (robot.isMessage(message)) {
return robot.parseMessage(message);
return robot.parseMessage(message)
}
// Don't be so strict. If a message doesn't look like
@ -135,83 +135,83 @@ exports.write = (image, drive, options) => {
// for debugging purposes.
return robot.parseMessage(robot.buildMessage(robot.COMMAND.LOG, {
message
}));
});
}))
})
if (_.isError(parsedMessage)) {
emitError(parsedMessage);
return;
emitError(parsedMessage)
return
}
try {
// These are lighweight accessor methods for
// the properties of the parsed message
const messageCommand = robot.getCommand(parsedMessage);
const messageData = robot.getData(parsedMessage);
const messageCommand = robot.getCommand(parsedMessage)
const messageData = robot.getData(parsedMessage)
// The error object is decomposed by the CLI for serialisation
// purposes. We compose it back to an `Error` here in order
// to provide better encapsulation.
if (messageCommand === robot.COMMAND.ERROR) {
emitError(robot.recomposeErrorMessage(parsedMessage));
emitError(robot.recomposeErrorMessage(parsedMessage))
} else if (messageCommand === robot.COMMAND.LOG) {
// If the message data is an object and it contains a
// message string then log the message string only.
if (_.isPlainObject(messageData) && _.isString(messageData.message)) {
console.log(messageData.message);
console.log(messageData.message)
} else {
console.log(messageData);
console.log(messageData)
}
} else {
emitter.emit(messageCommand, messageData);
emitter.emit(messageCommand, messageData)
}
} catch (error) {
emitError(error);
emitError(error)
}
};
}
ipc.server.on('error', emitError);
ipc.server.on('message', bridgeRobotMessage);
ipc.server.on('error', emitError)
ipc.server.on('message', bridgeRobotMessage)
ipc.server.on('start', () => {
const child = childProcess.fork(CONSTANTS.WRITER_PROXY_SCRIPT, argv, {
silent: true,
env: process.env
});
})
child.stdout.on('data', (data) => {
console.info(`WRITER: ${data.toString()}`);
});
console.info(`WRITER: ${data.toString()}`)
})
child.stderr.on('data', (data) => {
bridgeRobotMessage(data.toString());
bridgeRobotMessage(data.toString())
// This function causes the `close` event to be emitted
child.kill();
});
child.kill()
})
child.on('error', emitError);
child.on('error', emitError)
child.on('close', (code) => {
terminateServer();
terminateServer()
if (code === EXIT_CODES.CANCELLED) {
return emitter.emit('done', {
cancelled: true
});
})
}
// We shouldn't emit the `done` event manually here
// since the writer process will take care of it.
if (code === EXIT_CODES.SUCCESS || code === EXIT_CODES.VALIDATION_ERROR) {
return null;
return null
}
return emitError(new Error(`Child process exited with error code: ${code}`));
});
});
return emitError(new Error(`Child process exited with error code: ${code}`))
})
})
ipc.server.start();
ipc.server.start()
return emitter;
};
return emitter
}

View File

@ -14,16 +14,16 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* This file is only meant to be loaded by the renderer process.
*/
const path = require('path');
const isRunningInAsar = require('electron-is-running-in-asar');
const electron = require('electron');
const CONSTANTS = require('./constants');
const path = require('path')
const isRunningInAsar = require('electron-is-running-in-asar')
const electron = require('electron')
const CONSTANTS = require('./constants')
/**
* @summary Get application entry point
@ -37,14 +37,14 @@ const CONSTANTS = require('./constants');
*/
exports.getApplicationEntryPoint = () => {
if (isRunningInAsar()) {
return path.join(process.resourcesPath, 'app.asar');
return path.join(process.resourcesPath, 'app.asar')
}
const ENTRY_POINT_ARGV_INDEX = 1;
const relativeEntryPoint = electron.remote.process.argv[ENTRY_POINT_ARGV_INDEX];
const ENTRY_POINT_ARGV_INDEX = 1
const relativeEntryPoint = electron.remote.process.argv[ENTRY_POINT_ARGV_INDEX]
// On GNU/Linux, `pkexec` resolves relative paths
// from `/root`, therefore we pass an absolute path,
// in order to be on the safe side.
return path.join(CONSTANTS.PROJECT_ROOT, relativeEntryPoint);
};
return path.join(CONSTANTS.PROJECT_ROOT, relativeEntryPoint)
}

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const _ = require('lodash')
/**
* @summary Split stringified object lines
@ -41,5 +41,5 @@ exports.splitObjectLines = (lines) => {
.split(/((?:[^\n"']|"[^"]*"|'[^']*')+)/)
.map(_.trim)
.reject(_.isEmpty)
.value();
};
.value()
}

View File

@ -14,19 +14,19 @@
* limitations under the License.
*/
'use strict';
'use strict'
const Bluebird = require('bluebird');
const childProcess = require('child_process');
const ipc = require('node-ipc');
const _ = require('lodash');
const os = require('os');
const path = require('path');
const utils = require('./utils');
const EXIT_CODES = require('../shared/exit-codes');
const robot = require('../shared/robot');
const permissions = require('../shared/permissions');
const packageJSON = require('../../package.json');
const Bluebird = require('bluebird')
const childProcess = require('child_process')
const ipc = require('node-ipc')
const _ = require('lodash')
const os = require('os')
const path = require('path')
const utils = require('./utils')
const EXIT_CODES = require('../shared/exit-codes')
const robot = require('../shared/robot')
const permissions = require('../shared/permissions')
const packageJSON = require('../../package.json')
// This script is in charge of spawning the writer process and
// ensuring it has the necessary privileges. It might look a bit
@ -43,7 +43,7 @@ const packageJSON = require('../../package.json');
* @private
* @type {String}
*/
const executable = _.first(process.argv);
const executable = _.first(process.argv)
/**
* @summary The first index that represents an actual option argument
@ -54,7 +54,7 @@ const executable = _.first(process.argv);
* @description
* The first arguments are usually the program executable itself, etc.
*/
const OPTIONS_INDEX_START = 2;
const OPTIONS_INDEX_START = 2
/**
* @summary The list of Etcher argument options
@ -62,11 +62,11 @@ const OPTIONS_INDEX_START = 2;
* @private
* @type {String[]}
*/
const etcherArguments = process.argv.slice(OPTIONS_INDEX_START);
const etcherArguments = process.argv.slice(OPTIONS_INDEX_START)
permissions.isElevated().then((elevated) => {
if (!elevated) {
console.log('Attempting to elevate');
console.log('Attempting to elevate')
const commandArguments = _.attempt(() => {
if (os.platform() === 'linux' && process.env.APPIMAGE && process.env.APPDIR) {
@ -75,16 +75,16 @@ permissions.isElevated().then((elevated) => {
const translatedArguments = _.chain(process.argv)
.tail()
.invokeMap('replace', path.join(process.env.APPDIR, 'usr/'), '')
.value();
.value()
return _.concat([ process.env.APPIMAGE ], translatedArguments);
return _.concat([ process.env.APPIMAGE ], translatedArguments)
}
return process.argv;
});
return process.argv
})
// For debugging purposes
console.log(`Running: ${commandArguments.join(' ')}`);
console.log(`Running: ${commandArguments.join(' ')}`)
return permissions.elevateCommand(commandArguments, {
applicationName: packageJSON.displayName,
@ -101,16 +101,16 @@ permissions.isElevated().then((elevated) => {
}
}).then((results) => {
if (results.cancelled) {
process.exit(EXIT_CODES.CANCELLED);
process.exit(EXIT_CODES.CANCELLED)
}
});
})
}
console.log('Re-spawning with elevation');
console.log('Re-spawning with elevation')
return new Bluebird((resolve, reject) => {
ipc.config.id = process.env.IPC_CLIENT_ID;
ipc.config.silent = true;
ipc.config.id = process.env.IPC_CLIENT_ID
ipc.config.silent = true
// > If set to 0, the client will NOT try to reconnect.
// See https://github.com/RIAEvangelist/node-ipc/
@ -118,10 +118,10 @@ permissions.isElevated().then((elevated) => {
// The purpose behind this change is for this process
// to emit a "disconnect" event as soon as the GUI
// process is closed, so we can kill the CLI as well.
ipc.config.stopRetrying = 0;
ipc.config.stopRetrying = 0
ipc.connectTo(process.env.IPC_SERVER_ID, () => {
ipc.of[process.env.IPC_SERVER_ID].on('error', reject);
ipc.of[process.env.IPC_SERVER_ID].on('error', reject)
ipc.of[process.env.IPC_SERVER_ID].on('connect', () => {
const child = childProcess.spawn(executable, etcherArguments, {
env: {
@ -138,11 +138,11 @@ permissions.isElevated().then((elevated) => {
MOUNTUTILS_DEBUG: 1
}
});
})
ipc.of[process.env.IPC_SERVER_ID].on('disconnect', _.bind(child.kill, child));
child.on('error', reject);
child.on('close', resolve);
ipc.of[process.env.IPC_SERVER_ID].on('disconnect', _.bind(child.kill, child))
child.on('error', reject)
child.on('close', resolve)
/**
* @summary Emit an object message to the IPC server
@ -162,18 +162,18 @@ permissions.isElevated().then((elevated) => {
// Trying to parse multiple JSON objects separated by new lines will
// of course make the parser confused, causing errors later on.
_.each(utils.splitObjectLines(data.toString()), (object) => {
ipc.of[process.env.IPC_SERVER_ID].emit('message', object);
});
};
ipc.of[process.env.IPC_SERVER_ID].emit('message', object)
})
}
child.stdout.on('data', emitMessage);
child.stderr.on('data', emitMessage);
});
});
child.stdout.on('data', emitMessage)
child.stderr.on('data', emitMessage)
})
})
}).then((exitCode) => {
process.exit(exitCode);
});
process.exit(exitCode)
})
}).catch((error) => {
robot.printError(error);
process.exit(EXIT_CODES.GENERAL_ERROR);
});
robot.printError(error)
process.exit(EXIT_CODES.GENERAL_ERROR)
})

View File

@ -14,32 +14,32 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const path = require('path');
const Bluebird = require('bluebird');
const visuals = require('resin-cli-visuals');
const form = require('resin-cli-form');
const drivelist = Bluebird.promisifyAll(require('drivelist'));
const writer = require('./writer');
const utils = require('./utils');
const options = require('./options');
const robot = require('../shared/robot');
const messages = require('../shared/messages');
const EXIT_CODES = require('../shared/exit-codes');
const errors = require('../shared/errors');
const permissions = require('../shared/permissions');
const _ = require('lodash')
const path = require('path')
const Bluebird = require('bluebird')
const visuals = require('resin-cli-visuals')
const form = require('resin-cli-form')
const drivelist = Bluebird.promisifyAll(require('drivelist'))
const writer = require('./writer')
const utils = require('./utils')
const options = require('./options')
const robot = require('../shared/robot')
const messages = require('../shared/messages')
const EXIT_CODES = require('../shared/exit-codes')
const errors = require('../shared/errors')
const permissions = require('../shared/permissions')
const ARGV_IMAGE_PATH_INDEX = 0;
const imagePath = options._[ARGV_IMAGE_PATH_INDEX];
const ARGV_IMAGE_PATH_INDEX = 0
const imagePath = options._[ARGV_IMAGE_PATH_INDEX]
permissions.isElevated().then((elevated) => {
if (!elevated) {
throw errors.createUserError({
title: messages.error.elevationRequired(),
description: 'This tool requires special permissions to write to external drives'
});
})
}
return form.run([
@ -64,30 +64,30 @@ permissions.isElevated().then((elevated) => {
yes: robot.isEnabled(process.env) || options.yes || null
}
});
})
}).then((answers) => {
if (!answers.yes) {
throw errors.createUserError({
title: 'Aborted',
description: 'We can\'t proceed without confirmation'
});
})
}
const progressBars = {
write: new visuals.Progress('Flashing'),
check: new visuals.Progress('Validating')
};
}
return drivelist.listAsync().then((drives) => {
const selectedDrive = _.find(drives, {
device: answers.drive
});
})
if (!selectedDrive) {
throw errors.createUserError({
title: 'The selected drive was not found',
description: `We can't find ${answers.drive} in your system. Did you unplug the drive?`
});
})
}
return writer.writeImage(imagePath, selectedDrive, {
@ -100,52 +100,52 @@ permissions.isElevated().then((elevated) => {
percentage: Math.floor(state.percentage),
eta: state.eta,
speed: Math.floor(state.speed)
});
})
} else {
progressBars[state.type].update(state);
progressBars[state.type].update(state)
}
}).then((results) => {
return {
imagePath,
flash: results,
drive: selectedDrive
};
});
});
}
})
})
}).then((results) => {
return Bluebird.try(() => {
if (robot.isEnabled(process.env)) {
return robot.printMessage('done', {
sourceChecksum: results.flash.sourceChecksum
});
})
}
console.log(messages.info.flashComplete({
drive: results.drive,
imageBasename: path.basename(results.imagePath)
}));
}))
if (results.flash.sourceChecksum) {
console.log(`Checksum: ${results.flash.sourceChecksum}`);
console.log(`Checksum: ${results.flash.sourceChecksum}`)
}
return Bluebird.resolve();
return Bluebird.resolve()
}).then(() => {
process.exit(EXIT_CODES.SUCCESS);
});
process.exit(EXIT_CODES.SUCCESS)
})
}).catch((error) => {
return Bluebird.try(() => {
if (robot.isEnabled(process.env)) {
return robot.printError(error);
return robot.printError(error)
}
utils.printError(error);
return Bluebird.resolve();
utils.printError(error)
return Bluebird.resolve()
}).then(() => {
if (error.code === 'EVALIDATION') {
process.exit(EXIT_CODES.VALIDATION_ERROR);
process.exit(EXIT_CODES.VALIDATION_ERROR)
}
process.exit(EXIT_CODES.GENERAL_ERROR);
});
});
process.exit(EXIT_CODES.GENERAL_ERROR)
})
})

View File

@ -14,16 +14,16 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const fs = require('fs');
const yargs = require('yargs');
const utils = require('./utils');
const robot = require('../shared/robot');
const EXIT_CODES = require('../shared/exit-codes');
const errors = require('../shared/errors');
const packageJSON = require('../../package.json');
const _ = require('lodash')
const fs = require('fs')
const yargs = require('yargs')
const utils = require('./utils')
const robot = require('../shared/robot')
const EXIT_CODES = require('../shared/exit-codes')
const errors = require('../shared/errors')
const packageJSON = require('../../package.json')
/**
* @summary The minimum required number of CLI arguments
@ -31,7 +31,7 @@ const packageJSON = require('../../package.json');
* @private
* @type {Number}
*/
const MINIMUM_NUMBER_OF_ARGUMENTS = 1;
const MINIMUM_NUMBER_OF_ARGUMENTS = 1
/**
* @summary The index of the image argument
@ -39,7 +39,7 @@ const MINIMUM_NUMBER_OF_ARGUMENTS = 1;
* @private
* @type {Number}
*/
const IMAGE_PATH_ARGV_INDEX = 0;
const IMAGE_PATH_ARGV_INDEX = 0
/**
* @summary The first index that represents an actual option argument
@ -50,7 +50,7 @@ const IMAGE_PATH_ARGV_INDEX = 0;
* @description
* The first arguments are usually the program executable itself, etc.
*/
const OPTIONS_INDEX_START = 2;
const OPTIONS_INDEX_START = 2
/**
* @summary Parsed CLI options and arguments
@ -69,8 +69,8 @@ module.exports = yargs
.epilogue([
'Exit codes:',
_.map(EXIT_CODES, (value, key) => {
const reason = _.map(_.split(key, '_'), _.capitalize).join(' ');
return ` ${value} - ${reason}`;
const reason = _.map(_.split(key, '_'), _.capitalize).join(' ')
return ` ${value} - ${reason}`
}).join('\n'),
'',
'If you need help, don\'t hesitate in contacting us at:',
@ -95,32 +95,32 @@ module.exports = yargs
.fail((message, error) => {
const errorObject = error || errors.createUserError({
title: message
});
})
if (robot.isEnabled(process.env)) {
robot.printError(errorObject);
robot.printError(errorObject)
} else {
yargs.showHelp();
utils.printError(errorObject);
yargs.showHelp()
utils.printError(errorObject)
}
process.exit(EXIT_CODES.GENERAL_ERROR);
process.exit(EXIT_CODES.GENERAL_ERROR)
})
// Assert that image exists
.check((argv) => {
const imagePath = argv._[IMAGE_PATH_ARGV_INDEX];
const imagePath = argv._[IMAGE_PATH_ARGV_INDEX]
try {
fs.accessSync(imagePath);
fs.accessSync(imagePath)
} catch (error) {
throw errors.createUserError({
title: 'Unable to access file',
description: `The image ${imagePath} is not accessible`
});
})
}
return true;
return true
})
.check((argv) => {
@ -128,10 +128,10 @@ module.exports = yargs
throw errors.createUserError({
title: 'Missing drive',
description: 'You need to explicitly pass a drive when enabling robot mode'
});
})
}
return true;
return true
})
.options({
@ -168,4 +168,4 @@ module.exports = yargs
default: true
}
})
.parse(process.argv.slice(OPTIONS_INDEX_START));
.parse(process.argv.slice(OPTIONS_INDEX_START))

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const chalk = require('chalk');
const errors = require('../shared/errors');
const chalk = require('chalk')
const errors = require('../shared/errors')
/**
* @summary Print an error to stderr
@ -30,18 +30,18 @@ const errors = require('../shared/errors');
* utils.printError(new Error('Oops!'));
*/
exports.printError = (error) => {
const title = errors.getTitle(error);
const title = errors.getTitle(error)
const description = errors.getDescription(error, {
userFriendlyDescriptionsOnly: true
});
})
console.error(chalk.red(title));
console.error(chalk.red(title))
if (description) {
console.error(`\n${chalk.red(description)}`);
console.error(`\n${chalk.red(description)}`)
}
if (process.env.ETCHER_CLI_DEBUG && error.stack) {
console.error(`\n${chalk.red(error.stack)}`);
console.error(`\n${chalk.red(error.stack)}`)
}
};
}

View File

@ -14,23 +14,23 @@
* limitations under the License.
*/
'use strict';
'use strict'
const imageWrite = require('etcher-image-write');
const Bluebird = require('bluebird');
const fs = Bluebird.promisifyAll(require('fs'));
const mountutils = Bluebird.promisifyAll(require('mountutils'));
const os = require('os');
const imageStream = require('../image-stream');
const errors = require('../shared/errors');
const constraints = require('../shared/drive-constraints');
const imageWrite = require('etcher-image-write')
const Bluebird = require('bluebird')
const fs = Bluebird.promisifyAll(require('fs'))
const mountutils = Bluebird.promisifyAll(require('mountutils'))
const os = require('os')
const imageStream = require('../image-stream')
const errors = require('../shared/errors')
const constraints = require('../shared/drive-constraints')
/**
* @summary Timeout, in milliseconds, to wait before unmounting on success
* @constant
* @type {Number}
*/
const UNMOUNT_ON_SUCCESS_TIMEOUT_MS = 2000;
const UNMOUNT_ON_SUCCESS_TIMEOUT_MS = 2000
/**
* @summary Write an image to a disk drive
@ -67,19 +67,19 @@ exports.writeImage = (imagePath, drive, options, onProgress) => {
return Bluebird.try(() => {
// Unmounting a drive in Windows means we can't write to it anymore
if (os.platform() === 'win32') {
return Bluebird.resolve();
return Bluebird.resolve()
}
return mountutils.unmountDiskAsync(drive.device);
return mountutils.unmountDiskAsync(drive.device)
}).then(() => {
return fs.openAsync(drive.raw, 'rs+');
return fs.openAsync(drive.raw, 'rs+')
}).then((driveFileDescriptor) => {
return imageStream.getFromFilePath(imagePath).then((image) => {
if (!constraints.isDriveLargeEnough(drive, image)) {
throw errors.createUserError({
title: 'The image you selected is too big for this drive',
description: 'Please connect a bigger drive and try again'
});
})
}
return imageWrite.write({
@ -94,13 +94,13 @@ exports.writeImage = (imagePath, drive, options, onProgress) => {
transform: image.transform,
bmap: image.bmap,
bytesToZeroOutFromTheBeginning: image.bytesToZeroOutFromTheBeginning
});
})
}).then((writer) => {
return new Bluebird((resolve, reject) => {
writer.on('progress', onProgress);
writer.on('error', reject);
writer.on('done', resolve);
});
writer.on('progress', onProgress)
writer.on('error', reject)
writer.on('done', resolve)
})
}).tap(() => {
// Make sure the device stream file descriptor is closed
// before returning control the the caller. Not closing
@ -109,7 +109,7 @@ exports.writeImage = (imagePath, drive, options, onProgress) => {
// right afterwards in some Windows 7 systems.
return fs.closeAsync(driveFileDescriptor).then(() => {
if (!options.unmountOnSuccess) {
return Bluebird.resolve();
return Bluebird.resolve()
}
// Closing a file descriptor on a drive containing mountable
@ -118,8 +118,8 @@ exports.writeImage = (imagePath, drive, options, onProgress) => {
// right afterwards.
return Bluebird.delay(UNMOUNT_ON_SUCCESS_TIMEOUT_MS)
.return(drive.device)
.then(mountutils.unmountDiskAsync);
});
});
});
};
.then(mountutils.unmountDiskAsync)
})
})
})
}

View File

@ -18,33 +18,33 @@
* @module Etcher
*/
'use strict';
'use strict'
/* eslint-disable no-var */
var angular = require('angular');
var angular = require('angular')
/* eslint-enable no-var */
const electron = require('electron');
const Bluebird = require('bluebird');
const semver = require('semver');
const EXIT_CODES = require('../shared/exit-codes');
const messages = require('../shared/messages');
const s3Packages = require('../shared/s3-packages');
const release = require('../shared/release');
const store = require('../shared/store');
const packageJSON = require('../../package.json');
const flashState = require('../shared/models/flash-state');
const settings = require('./models/settings');
const windowProgress = require('./os/window-progress');
const analytics = require('./modules/analytics');
const updateNotifier = require('./components/update-notifier');
const availableDrives = require('../shared/models/available-drives');
const selectionState = require('../shared/models/selection-state');
const driveScanner = require('./modules/drive-scanner');
const osDialog = require('./os/dialog');
const exceptionReporter = require('./modules/exception-reporter');
const electron = require('electron')
const Bluebird = require('bluebird')
const semver = require('semver')
const EXIT_CODES = require('../shared/exit-codes')
const messages = require('../shared/messages')
const s3Packages = require('../shared/s3-packages')
const release = require('../shared/release')
const store = require('../shared/store')
const packageJSON = require('../../package.json')
const flashState = require('../shared/models/flash-state')
const settings = require('./models/settings')
const windowProgress = require('./os/window-progress')
const analytics = require('./modules/analytics')
const updateNotifier = require('./components/update-notifier')
const availableDrives = require('../shared/models/available-drives')
const selectionState = require('../shared/models/selection-state')
const driveScanner = require('./modules/drive-scanner')
const osDialog = require('./os/dialog')
const exceptionReporter = require('./modules/exception-reporter')
const app = angular.module('Etcher', [
require('angular-ui-router'),
@ -67,7 +67,7 @@ const app = angular.module('Etcher', [
// Utils
require('./utils/manifest-bind/manifest-bind')
]);
])
app.run(() => {
console.log([
@ -82,46 +82,46 @@ app.run(() => {
'Drop us a line at join+etcher@resin.io',
'',
`Version = ${packageJSON.version}, Type = ${packageJSON.packageType}`
].join('\n'));
});
].join('\n'))
})
app.run(() => {
const currentVersion = packageJSON.version;
const currentVersion = packageJSON.version
analytics.logEvent('Application start', {
packageType: packageJSON.packageType,
version: currentVersion
});
})
settings.load().then(() => {
const shouldCheckForUpdates = updateNotifier.shouldCheckForUpdates({
currentVersion,
lastSleptUpdateNotifier: settings.get('lastSleptUpdateNotifier'),
lastSleptUpdateNotifierVersion: settings.get('lastSleptUpdateNotifierVersion')
});
})
const currentReleaseType = release.getReleaseType(currentVersion);
const updatesEnabled = settings.get('updatesEnabled');
const currentReleaseType = release.getReleaseType(currentVersion)
const updatesEnabled = settings.get('updatesEnabled')
if (!shouldCheckForUpdates || !updatesEnabled) {
analytics.logEvent('Not checking for updates', {
shouldCheckForUpdates,
updatesEnabled,
releaseType: currentReleaseType
});
})
return Bluebird.resolve();
return Bluebird.resolve()
}
const updateSemverRange = packageJSON.updates.semverRange;
const includeUnstableChannel = settings.get('includeUnstableUpdateChannel');
const updateSemverRange = packageJSON.updates.semverRange
const includeUnstableChannel = settings.get('includeUnstableUpdateChannel')
analytics.logEvent('Checking for updates', {
currentVersion,
releaseType: currentReleaseType,
updateSemverRange,
includeUnstableChannel
});
})
return s3Packages.getLatestVersion(currentReleaseType, {
range: updateSemverRange,
@ -130,8 +130,8 @@ app.run(() => {
if (semver.gte(currentVersion, latestVersion || '0.0.0')) {
analytics.logEvent('Update notification skipped', {
reason: 'Latest version'
});
return Bluebird.resolve();
})
return Bluebird.resolve()
}
// In case the internet connection is not good and checking the
@ -142,24 +142,24 @@ app.run(() => {
if (selectionState.hasImage()) {
analytics.logEvent('Update notification skipped', {
reason: 'Image selected'
});
return Bluebird.resolve();
})
return Bluebird.resolve()
}
analytics.logEvent('Notifying update', {
latestVersion
});
})
return updateNotifier.notify(latestVersion, {
allowSleepUpdateCheck: currentReleaseType === release.RELEASE_TYPE.PRODUCTION
});
});
}).catch(exceptionReporter.report);
});
})
})
}).catch(exceptionReporter.report)
})
app.run(() => {
store.subscribe(() => {
const currentFlashState = flashState.getFlashState();
const currentFlashState = flashState.getFlashState()
// There is usually a short time period between the `isFlashing()`
// property being set, and the flashing actually starting, which
@ -169,18 +169,18 @@ app.run(() => {
// We use the presence of `.eta` to determine that the actual
// writing started.
if (!flashState.isFlashing() || !currentFlashState.eta) {
return;
return
}
analytics.logDebug([
`Progress (${currentFlashState.type}):`,
`${currentFlashState.percentage}% at ${currentFlashState.speed} MB/s`,
`(eta ${currentFlashState.eta}s)`
].join(' '));
].join(' '))
windowProgress.set(currentFlashState.percentage);
});
});
windowProgress.set(currentFlashState.percentage)
})
})
app.run(($timeout) => {
driveScanner.on('drives', (drives) => {
@ -189,41 +189,41 @@ app.run(($timeout) => {
// available drives list has changed, and incorrectly
// keeps asking the user to "Connect a drive".
$timeout(() => {
availableDrives.setDrives(drives);
});
});
availableDrives.setDrives(drives)
})
})
driveScanner.on('error', (error) => {
// Stop the drive scanning loop in case of errors,
// otherwise we risk presenting the same error over
// and over again to the user, while also heavily
// spamming our error reporting service.
driveScanner.stop();
driveScanner.stop()
return exceptionReporter.report(error);
});
return exceptionReporter.report(error)
})
driveScanner.start();
});
driveScanner.start()
})
app.run(($window) => {
let popupExists = false;
let popupExists = false
$window.addEventListener('beforeunload', (event) => {
if (!flashState.isFlashing() || popupExists) {
analytics.logEvent('Close application', {
isFlashing: flashState.isFlashing()
});
return;
})
return
}
// Don't close window while flashing
event.returnValue = false;
event.returnValue = false
// Don't open any more popups
popupExists = true;
popupExists = true
analytics.logEvent('Close attempt while flashing');
analytics.logEvent('Close attempt while flashing')
osDialog.showWarning({
confirmationLabel: 'Yes, quit',
@ -234,45 +234,45 @@ app.run(($window) => {
if (confirmed) {
analytics.logEvent('Close confirmed while flashing', {
uuid: flashState.getFlashUuid()
});
})
// This circumvents the 'beforeunload' event unlike
// electron.remote.app.quit() which does not.
electron.remote.process.exit(EXIT_CODES.SUCCESS);
electron.remote.process.exit(EXIT_CODES.SUCCESS)
}
analytics.logEvent('Close rejected while flashing');
popupExists = false;
}).catch(exceptionReporter.report);
});
});
analytics.logEvent('Close rejected while flashing')
popupExists = false
}).catch(exceptionReporter.report)
})
})
app.run(($rootScope) => {
$rootScope.$on('$stateChangeSuccess', (event, toState, toParams, fromState) => {
// Ignore first navigation
if (!fromState.name) {
return;
return
}
analytics.logEvent('Navigate', {
to: toState.name,
from: fromState.name
});
});
});
})
})
})
app.config(($urlRouterProvider) => {
$urlRouterProvider.otherwise('/main');
});
$urlRouterProvider.otherwise('/main')
})
app.config(($provide) => {
$provide.decorator('$exceptionHandler', ($delegate) => {
return (exception, cause) => {
exceptionReporter.report(exception);
$delegate(exception, cause);
};
});
});
exceptionReporter.report(exception)
$delegate(exception, cause)
}
})
})
app.controller('HeaderController', function (OSOpenExternalService) {
/**
@ -288,19 +288,19 @@ app.controller('HeaderController', function (OSOpenExternalService) {
* HeaderController.openHelpPage();
*/
this.openHelpPage = () => {
const DEFAULT_SUPPORT_URL = 'https://github.com/resin-io/etcher/blob/master/SUPPORT.md';
const supportUrl = selectionState.getImageSupportUrl() || DEFAULT_SUPPORT_URL;
OSOpenExternalService.open(supportUrl);
};
});
const DEFAULT_SUPPORT_URL = 'https://github.com/resin-io/etcher/blob/master/SUPPORT.md'
const supportUrl = selectionState.getImageSupportUrl() || DEFAULT_SUPPORT_URL
OSOpenExternalService.open(supportUrl)
}
})
app.controller('StateController', function ($rootScope, $scope) {
const unregisterStateChange = $rootScope.$on('$stateChangeSuccess', (event, toState, toParams, fromState) => {
this.previousName = fromState.name;
this.currentName = toState.name;
});
this.previousName = fromState.name
this.currentName = toState.name
})
$scope.$on('$destroy', unregisterStateChange);
$scope.$on('$destroy', unregisterStateChange)
/**
* @summary Get the previous state name
@ -314,7 +314,7 @@ app.controller('StateController', function ($rootScope, $scope) {
* console.log('We left the main screen!');
* }
*/
this.previousName = null;
this.previousName = null
/**
* @summary Get the current state name
@ -328,5 +328,5 @@ app.controller('StateController', function ($rootScope, $scope) {
* console.log('We are on the main screen!');
* }
*/
this.currentName = null;
});
this.currentName = null
})

View File

@ -14,15 +14,15 @@
* limitations under the License.
*/
'use strict';
'use strict'
const angular = require('angular');
const _ = require('lodash');
const messages = require('../../../../shared/messages');
const constraints = require('../../../../shared/drive-constraints');
const analytics = require('../../../modules/analytics');
const availableDrives = require('../../../../shared/models/available-drives');
const selectionState = require('../../../../shared/models/selection-state');
const angular = require('angular')
const _ = require('lodash')
const messages = require('../../../../shared/messages')
const constraints = require('../../../../shared/drive-constraints')
const analytics = require('../../../modules/analytics')
const availableDrives = require('../../../../shared/models/available-drives')
const selectionState = require('../../../../shared/models/selection-state')
module.exports = function (
$q,
@ -34,14 +34,14 @@ module.exports = function (
* @type {Object}
* @public
*/
this.state = selectionState;
this.state = selectionState
/**
* @summary Static methods to check a drive's properties
* @type {Object}
* @public
*/
this.constraints = constraints;
this.constraints = constraints
/**
* @summary The drives model
@ -54,7 +54,7 @@ module.exports = function (
* this allows the property to be automatically updated
* when `availableDrives` detects a change in the drives.
*/
this.drives = availableDrives;
this.drives = availableDrives
/**
* @summary Determine if we can change a drive's selection state
@ -72,11 +72,11 @@ module.exports = function (
*/
const shouldChangeDriveSelectionState = (drive) => {
if (!constraints.isDriveValid(drive, selectionState.getImage())) {
return $q.resolve(false);
return $q.resolve(false)
}
if (constraints.isDriveSizeRecommended(drive, selectionState.getImage())) {
return $q.resolve(true);
return $q.resolve(true)
}
return WarningModalService.display({
@ -88,8 +88,8 @@ module.exports = function (
}),
'Are you sure you want to continue?'
].join(' ')
});
};
})
}
/**
* @summary Toggle a drive selection
@ -110,14 +110,14 @@ module.exports = function (
analytics.logEvent('Toggle drive', {
drive,
previouslySelected: selectionState.isCurrentDrive(drive.device)
});
})
return shouldChangeDriveSelectionState(drive).then((canChangeDriveSelectionState) => {
if (canChangeDriveSelectionState) {
selectionState.toggleSetDrive(drive.device);
selectionState.toggleSetDrive(drive.device)
}
});
};
})
}
/**
* @summary Close the modal and resolve the selected drive
@ -128,17 +128,17 @@ module.exports = function (
* DriveSelectorController.closeModal();
*/
this.closeModal = () => {
const selectedDrive = selectionState.getDrive();
const selectedDrive = selectionState.getDrive()
// Sanity check to cover the case where a drive is selected,
// the drive is then unplugged from the computer and the modal
// is resolved with a non-existent drive.
if (!selectedDrive || !_.includes(this.drives.getDrives(), selectedDrive)) {
$uibModalInstance.close();
$uibModalInstance.close()
} else {
$uibModalInstance.close(selectedDrive);
$uibModalInstance.close(selectedDrive)
}
};
}
/**
* @summary Select a drive and close the modal
@ -158,14 +158,14 @@ module.exports = function (
this.selectDriveAndClose = (drive) => {
return shouldChangeDriveSelectionState(drive).then((canChangeDriveSelectionState) => {
if (canChangeDriveSelectionState) {
selectionState.setDrive(drive.device);
selectionState.setDrive(drive.device)
analytics.logEvent('Drive selected (double click)');
analytics.logEvent('Drive selected (double click)')
this.closeModal();
this.closeModal()
}
});
};
})
}
/**
* @summary Memoize ImmutableJS list reference
@ -193,41 +193,41 @@ module.exports = function (
* const memoizedFunction = memoizeImmutableListReference(getList);
*/
this.memoizeImmutableListReference = (func) => {
let previousTuples = [];
let previousTuples = []
return (...restArgs) => {
let areArgsInTuple = false;
let state = Reflect.apply(func, this, restArgs);
let areArgsInTuple = false
let state = Reflect.apply(func, this, restArgs)
previousTuples = _.map(previousTuples, ([ oldArgs, oldState ]) => {
if (angular.equals(oldArgs, restArgs)) {
areArgsInTuple = true;
areArgsInTuple = true
if (angular.equals(state, oldState)) {
// Use the previously memoized state for this argument
state = oldState;
state = oldState
}
// Update the tuple state
return [ oldArgs, state ];
return [ oldArgs, state ]
}
// Return the tuple unchanged
return [ oldArgs, oldState ];
});
return [ oldArgs, oldState ]
})
// Add the state associated with these args to be memoized
if (!areArgsInTuple) {
previousTuples.push([ restArgs, state ]);
previousTuples.push([ restArgs, state ])
}
return state;
};
};
return state
}
}
this.getDrives = this.memoizeImmutableListReference(() => {
return this.drives.getDrives();
});
return this.drives.getDrives()
})
/**
* @summary Get a drive's compatibility status object(s)
@ -249,6 +249,6 @@ module.exports = function (
* }
*/
this.getDriveStatuses = this.memoizeImmutableListReference((drive) => {
return this.constraints.getDriveImageCompatibilityStatuses(drive, this.state.getImage());
});
};
return this.constraints.getDriveImageCompatibilityStatuses(drive, this.state.getImage())
})
}

View File

@ -14,21 +14,21 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.Components.DriveSelector
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Components.DriveSelector';
const angular = require('angular')
const MODULE_NAME = 'Etcher.Components.DriveSelector'
const DriveSelector = angular.module(MODULE_NAME, [
require('../modal/modal'),
require('../warning-modal/warning-modal'),
require('../../utils/byte-size/byte-size')
]);
])
DriveSelector.controller('DriveSelectorController', require('./controllers/drive-selector'));
DriveSelector.service('DriveSelectorService', require('./services/drive-selector'));
DriveSelector.controller('DriveSelectorController', require('./controllers/drive-selector'))
DriveSelector.service('DriveSelectorService', require('./services/drive-selector'))
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
module.exports = function (ModalService, $q) {
let modal = null;
let modal = null
/**
* @summary Open the drive selector widget
@ -37,10 +37,10 @@ module.exports = function (ModalService, $q) {
template: './components/drive-selector/templates/drive-selector-modal.tpl.html',
controller: 'DriveSelectorController as modal',
size: 'drive-selector-modal'
});
})
return modal.result;
};
return modal.result
}
/**
* @summary Close the drive selector widget
@ -55,11 +55,11 @@ module.exports = function (ModalService, $q) {
*/
this.close = () => {
if (modal) {
return modal.close();
return modal.close()
}
// Resolve `undefined` if the modal
// was already closed for consistency
return $q.resolve();
};
};
return $q.resolve()
}
}

View File

@ -14,18 +14,18 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.Components.FlashErrorModal
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Components.FlashErrorModal';
const angular = require('angular')
const MODULE_NAME = 'Etcher.Components.FlashErrorModal'
const FlashErrorModal = angular.module(MODULE_NAME, [
require('../warning-modal/warning-modal')
]);
])
FlashErrorModal.service('FlashErrorModalService', require('./services/flash-error-modal'));
FlashErrorModal.service('FlashErrorModalService', require('./services/flash-error-modal'))
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,11 +14,11 @@
* limitations under the License.
*/
'use strict';
'use strict'
const flashState = require('../../../../shared/models/flash-state');
const selectionState = require('../../../../shared/models/selection-state');
const analytics = require('../../../modules/analytics');
const flashState = require('../../../../shared/models/flash-state')
const selectionState = require('../../../../shared/models/selection-state')
const analytics = require('../../../modules/analytics')
module.exports = function (WarningModalService) {
/**
@ -37,13 +37,13 @@ module.exports = function (WarningModalService) {
confirmationLabel: 'Retry',
description: message
}).then((confirmed) => {
flashState.resetState();
flashState.resetState()
if (confirmed) {
analytics.logEvent('Restart after failure');
analytics.logEvent('Restart after failure')
} else {
selectionState.clear();
selectionState.clear()
}
});
};
};
})
}
}

View File

@ -14,18 +14,18 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.Components.Modal
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Components.Modal';
const angular = require('angular')
const MODULE_NAME = 'Etcher.Components.Modal'
const Modal = angular.module(MODULE_NAME, [
require('angular-ui-bootstrap')
]);
])
Modal.service('ModalService', require('./services/modal'));
Modal.service('ModalService', require('./services/modal'))
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const analytics = require('../../../modules/analytics');
const _ = require('lodash')
const analytics = require('../../../modules/analytics')
module.exports = function ($uibModal, $q) {
/**
@ -41,11 +41,11 @@ module.exports = function ($uibModal, $q) {
this.open = (options = {}) => {
_.defaults(options, {
size: 'sm'
});
})
analytics.logEvent('Open modal', {
template: options.template
});
})
const modal = $uibModal.open({
animation: true,
@ -53,7 +53,7 @@ module.exports = function ($uibModal, $q) {
controller: options.controller,
size: options.size,
resolve: options.resolve
});
})
return {
close: modal.close,
@ -61,26 +61,26 @@ module.exports = function ($uibModal, $q) {
modal.result.then((value) => {
analytics.logEvent('Modal accepted', {
value
});
})
resolve(value);
resolve(value)
}).catch((error) => {
// Bootstrap doesn't 'resolve' these but cancels the dialog
if (error === 'escape key press' || error === 'backdrop click') {
analytics.logEvent('Modal rejected', {
method: error
});
})
return resolve();
return resolve()
}
analytics.logEvent('Modal rejected', {
value: error
});
})
return reject(error);
});
return reject(error)
})
})
};
};
};
}
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @summary ProgressButton directive
@ -40,5 +40,5 @@ module.exports = () => {
percentage: '=',
striped: '@'
}
};
};
}
}

View File

@ -14,15 +14,15 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.Components.ProgressButton
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Components.ProgressButton';
const ProgressButton = angular.module(MODULE_NAME, []);
ProgressButton.directive('progressButton', require('./directives/progress-button'));
const angular = require('angular')
const MODULE_NAME = 'Etcher.Components.ProgressButton'
const ProgressButton = angular.module(MODULE_NAME, [])
ProgressButton.directive('progressButton', require('./directives/progress-button'))
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,22 +14,22 @@
* limitations under the License.
*/
'use strict';
'use strict'
/* eslint-disable jsdoc/require-example */
const _ = require('lodash');
const electron = require('electron');
const angular = require('angular');
const react = require('react');
const propTypes = require('prop-types');
const react2angular = require('react2angular').react2angular;
const analytics = require('../modules/analytics');
const packageJSON = require('../../../package.json');
const robot = require('../../shared/robot');
const _ = require('lodash')
const electron = require('electron')
const angular = require('angular')
const react = require('react')
const propTypes = require('prop-types')
const react2angular = require('react2angular').react2angular
const analytics = require('../modules/analytics')
const packageJSON = require('../../../package.json')
const robot = require('../../shared/robot')
const MODULE_NAME = 'Etcher.Components.SafeWebview';
const angularSafeWebview = angular.module(MODULE_NAME, []);
const MODULE_NAME = 'Etcher.Components.SafeWebview'
const angularSafeWebview = angular.module(MODULE_NAME, [])
/**
* @summary Electron session identifier
@ -37,7 +37,7 @@ const angularSafeWebview = angular.module(MODULE_NAME, []);
* @private
* @type {String}
*/
const ELECTRON_SESSION = 'persist:success-banner';
const ELECTRON_SESSION = 'persist:success-banner'
/**
* @summary Etcher version search-parameter key
@ -45,7 +45,7 @@ const ELECTRON_SESSION = 'persist:success-banner';
* @private
* @type {String}
*/
const ETCHER_VERSION_PARAM = 'etcher-version';
const ETCHER_VERSION_PARAM = 'etcher-version'
/**
* @summary API version search-parameter key
@ -53,7 +53,7 @@ const ETCHER_VERSION_PARAM = 'etcher-version';
* @private
* @type {String}
*/
const API_VERSION_PARAM = 'api-version';
const API_VERSION_PARAM = 'api-version'
/**
* @summary Webview API version
@ -67,7 +67,7 @@ const API_VERSION_PARAM = 'api-version';
* This version number is exposed to the banner such that it can determine what
* features are safe to utilize.
*/
const API_VERSION = 1;
const API_VERSION = 1
/**
* @summary Webviews that hide/show depending on the HTTP status returned
@ -82,37 +82,37 @@ class SafeWebview extends react.PureComponent {
* @param {Object} props - React element properties
*/
constructor (props) {
super(props);
super(props)
this.state = {
shouldShow: true
};
}
const url = new window.URL(props.src);
const url = new window.URL(props.src)
// We set the version GET parameters here.
url.searchParams.set(ETCHER_VERSION_PARAM, packageJSON.version);
url.searchParams.set(API_VERSION_PARAM, API_VERSION);
url.searchParams.set(ETCHER_VERSION_PARAM, packageJSON.version)
url.searchParams.set(API_VERSION_PARAM, API_VERSION)
this.entryHref = url.href;
this.entryHref = url.href
// Events steal 'this'
this.didFailLoad = _.bind(this.didFailLoad, this);
this.didGetResponseDetails = _.bind(this.didGetResponseDetails, this);
this.didFailLoad = _.bind(this.didFailLoad, this)
this.didGetResponseDetails = _.bind(this.didGetResponseDetails, this)
this.eventTuples = [
[ 'did-fail-load', this.didFailLoad ],
[ 'did-get-response-details', this.didGetResponseDetails ],
[ 'new-window', this.constructor.newWindow ],
[ 'console-message', this.constructor.consoleMessage ]
];
]
// Make a persistent electron session for the webview
electron.remote.session.fromPartition(ELECTRON_SESSION, {
// Disable the cache for the session such that new content shows up when refreshing
cache: false
});
})
}
/**
@ -126,7 +126,7 @@ class SafeWebview extends react.PureComponent {
width: this.state.shouldShow ? null : '0',
height: this.state.shouldShow ? null : '0'
}
}, []);
}, [])
}
/**
@ -135,15 +135,15 @@ class SafeWebview extends react.PureComponent {
componentDidMount () {
// Events React is unaware of have to be handled manually
_.map(this.eventTuples, (tuple) => {
this.refs.webview.addEventListener(...tuple);
});
this.refs.webview.addEventListener(...tuple)
})
// Use the 'success-banner' session
this.refs.webview.partition = ELECTRON_SESSION;
this.refs.webview.partition = ELECTRON_SESSION
// It's important that this comes after the partition setting, otherwise it will
// use another session and we can't change it without destroying the element again
this.refs.webview.src = this.entryHref;
this.refs.webview.src = this.entryHref
}
/**
@ -152,8 +152,8 @@ class SafeWebview extends react.PureComponent {
componentWillUnmount () {
// Events that React is unaware of have to be handled manually
_.map(this.eventTuples, (tuple) => {
this.refs.webview.removeEventListener(...tuple);
});
this.refs.webview.removeEventListener(...tuple)
})
}
/**
@ -166,14 +166,14 @@ class SafeWebview extends react.PureComponent {
// because reload interferes with 'src' setting, resetting the 'src' attribute
// to what it was was just prior.
if (this.refs.webview.src === this.entryHref) {
this.refs.webview.reload();
this.refs.webview.reload()
} else {
this.refs.webview.src = this.entryHref;
this.refs.webview.src = this.entryHref
}
this.setState({
shouldShow: true
});
})
}
}
@ -183,7 +183,7 @@ class SafeWebview extends react.PureComponent {
didFailLoad () {
this.setState({
shouldShow: false
});
})
}
/**
@ -191,12 +191,12 @@ class SafeWebview extends react.PureComponent {
* @param {Event} event - Event object
*/
didGetResponseDetails (event) {
const HTTP_OK = 200;
const HTTP_ERR = 400;
const HTTP_OK = 200
const HTTP_ERR = 400
this.setState({
shouldShow: event.httpResponseCode >= HTTP_OK && event.httpResponseCode < HTTP_ERR
});
})
}
/**
@ -204,13 +204,13 @@ class SafeWebview extends react.PureComponent {
* @param {Event} event - event object
*/
static newWindow (event) {
const url = new window.URL(event.url);
const url = new window.URL(event.url)
if (_.every([
url.protocol === 'http:' || url.protocol === 'https:',
event.disposition === 'foreground-tab'
])) {
electron.shell.openExternal(url.href);
electron.shell.openExternal(url.href)
}
}
@ -233,15 +233,15 @@ class SafeWebview extends react.PureComponent {
*/
static consoleMessage (event) {
if (!robot.isMessage(event.message)) {
return;
return
}
const message = robot.parseMessage(event.message);
const message = robot.parseMessage(event.message)
if (robot.getCommand(message) === robot.COMMAND.LOG) {
analytics.logEvent(robot.getData(message));
analytics.logEvent(robot.getData(message))
} else if (robot.getCommand(message) === robot.COMMAND.ERROR) {
analytics.logException(robot.getData(message));
analytics.logException(robot.getData(message))
}
}
}
@ -258,8 +258,8 @@ SafeWebview.propTypes = {
*/
refreshNow: propTypes.bool
};
}
angularSafeWebview.component('safeWebview', react2angular(SafeWebview));
angularSafeWebview.component('safeWebview', react2angular(SafeWebview))
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/* eslint-disable jsdoc/require-example */
@ -22,18 +22,18 @@
* @module Etcher.Components.SVGIcon
*/
const _ = require('lodash');
const angular = require('angular');
const react = require('react');
const propTypes = require('prop-types');
const react2angular = require('react2angular').react2angular;
const path = require('path');
const fs = require('fs');
const _ = require('lodash')
const angular = require('angular')
const react = require('react')
const propTypes = require('prop-types')
const react2angular = require('react2angular').react2angular
const path = require('path')
const fs = require('fs')
const MODULE_NAME = 'Etcher.Components.SVGIcon';
const angularSVGIcon = angular.module(MODULE_NAME, []);
const MODULE_NAME = 'Etcher.Components.SVGIcon'
const angularSVGIcon = angular.module(MODULE_NAME, [])
const DEFAULT_SIZE = '40px';
const DEFAULT_SIZE = '40px'
/**
* @summary SVG element that takes both filepaths and file contents
@ -50,27 +50,27 @@ class SVGIcon extends react.Component {
// relative to *this directory*.
// TODO: There might be a way to compute the path
// relatively to the `index.html`.
const imagePath = path.join(__dirname, this.props.path);
const imagePath = path.join(__dirname, this.props.path)
let contents = '';
let contents = ''
if (_.startsWith(this.props.path, '<')) {
contents = this.props.path;
contents = this.props.path
} else {
contents = fs.readFileSync(imagePath, {
encoding: 'utf8'
});
})
}
const width = this.props.width || DEFAULT_SIZE;
const height = this.props.height || DEFAULT_SIZE;
const width = this.props.width || DEFAULT_SIZE
const height = this.props.height || DEFAULT_SIZE
const parser = new window.DOMParser();
const doc = parser.parseFromString(contents, 'image/svg+xml');
const svg = doc.querySelector('svg');
const parser = new window.DOMParser()
const doc = parser.parseFromString(contents, 'image/svg+xml')
const svg = doc.querySelector('svg')
const img = document.createElement('img');
img.src = `data:image/svg+xml,${encodeURIComponent(svg.outerHTML)}`;
const img = document.createElement('img')
img.src = `data:image/svg+xml,${encodeURIComponent(svg.outerHTML)}`
return react.createElement('div', {
className: 'svg-icon',
@ -84,7 +84,7 @@ class SVGIcon extends react.Component {
dangerouslySetInnerHTML: {
__html: img.outerHTML
}
});
})
}
/**
@ -93,7 +93,7 @@ class SVGIcon extends react.Component {
*/
componentWillReceiveProps (nextProps) {
// This will update the element if the properties change
this.setState(nextProps);
this.setState(nextProps)
}
}
@ -119,7 +119,7 @@ SVGIcon.propTypes = {
*/
disabled: propTypes.bool
};
}
angularSVGIcon.component('svgIcon', react2angular(SVGIcon));
module.exports = MODULE_NAME;
angularSVGIcon.component('svgIcon', react2angular(SVGIcon))
module.exports = MODULE_NAME

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
module.exports = function ($uibModalInstance, tooltipData) {
/**
@ -22,7 +22,7 @@ module.exports = function ($uibModalInstance, tooltipData) {
* @type {Object}
* @public
*/
this.data = tooltipData;
this.data = tooltipData
/**
* @summary Close the modal
@ -33,6 +33,6 @@ module.exports = function ($uibModalInstance, tooltipData) {
* TooltipModalController.closeModal();
*/
this.closeModal = () => {
$uibModalInstance.dismiss();
};
};
$uibModalInstance.dismiss()
}
}

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const _ = require('lodash')
module.exports = function (ModalService) {
/**
@ -43,6 +43,6 @@ module.exports = function (ModalService) {
resolve: {
tooltipData: _.constant(options)
}
}).result;
};
};
}).result
}
}

View File

@ -14,19 +14,19 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.Components.TooltipModal
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Components.TooltipModal';
const angular = require('angular')
const MODULE_NAME = 'Etcher.Components.TooltipModal'
const TooltipModal = angular.module(MODULE_NAME, [
require('../modal/modal')
]);
])
TooltipModal.controller('TooltipModalController', require('./controllers/tooltip-modal'));
TooltipModal.service('TooltipModalService', require('./services/tooltip-modal'));
TooltipModal.controller('TooltipModalController', require('./controllers/tooltip-modal'))
TooltipModal.service('TooltipModalService', require('./services/tooltip-modal'))
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,16 +14,16 @@
* limitations under the License.
*/
'use strict';
'use strict'
const electron = require('electron');
const Bluebird = require('bluebird');
const _ = require('lodash');
const settings = require('../models/settings');
const analytics = require('../modules/analytics');
const units = require('../../shared/units');
const release = require('../../shared/release');
const packageJSON = require('../../../package.json');
const electron = require('electron')
const Bluebird = require('bluebird')
const _ = require('lodash')
const settings = require('../models/settings')
const analytics = require('../modules/analytics')
const units = require('../../shared/units')
const release = require('../../shared/release')
const packageJSON = require('../../../package.json')
/**
* @summary The number of days the update notifier can be put to sleep
@ -31,7 +31,7 @@ const packageJSON = require('../../../package.json');
* @private
* @type {Number}
*/
exports.UPDATE_NOTIFIER_SLEEP_DAYS = packageJSON.updates.sleepDays;
exports.UPDATE_NOTIFIER_SLEEP_DAYS = packageJSON.updates.sleepDays
/**
* @summary The current Electron browser window
@ -39,7 +39,7 @@ exports.UPDATE_NOTIFIER_SLEEP_DAYS = packageJSON.updates.sleepDays;
* @private
* @type {Object}
*/
const currentWindow = electron.remote.getCurrentWindow();
const currentWindow = electron.remote.getCurrentWindow()
/**
* @summary Determine if it's time to check for updates
@ -64,18 +64,18 @@ const currentWindow = electron.remote.getCurrentWindow();
exports.shouldCheckForUpdates = (options) => {
_.defaults(options, {
lastSleptUpdateNotifierVersion: options.currentVersion
});
})
if (_.some([
!options.lastSleptUpdateNotifier,
release.getReleaseType(options.currentVersion) !== release.RELEASE_TYPE.PRODUCTION,
options.currentVersion !== options.lastSleptUpdateNotifierVersion
])) {
return true;
return true
}
return Date.now() - options.lastSleptUpdateNotifier > units.daysToMilliseconds(this.UPDATE_NOTIFIER_SLEEP_DAYS);
};
return Date.now() - options.lastSleptUpdateNotifier > units.daysToMilliseconds(this.UPDATE_NOTIFIER_SLEEP_DAYS)
}
/**
* @summary Open the update notifier widget
@ -96,10 +96,10 @@ exports.notify = (version, options = {}) => {
const BUTTONS = [
'Download',
'Skip'
];
]
const BUTTON_CONFIRMATION_INDEX = _.indexOf(BUTTONS, _.first(BUTTONS));
const BUTTON_REJECTION_INDEX = _.indexOf(BUTTONS, _.last(BUTTONS));
const BUTTON_CONFIRMATION_INDEX = _.indexOf(BUTTONS, _.first(BUTTONS))
const BUTTON_REJECTION_INDEX = _.indexOf(BUTTONS, _.last(BUTTONS))
const dialogOptions = {
type: 'info',
@ -108,13 +108,13 @@ exports.notify = (version, options = {}) => {
cancelId: BUTTON_REJECTION_INDEX,
title: 'New Update Available!',
message: `Etcher ${version} is available for download`
};
}
if (_.get(options, [ 'allowSleepUpdateCheck' ], true)) {
_.merge(dialogOptions, {
checkboxLabel: `Remind me again in ${this.UPDATE_NOTIFIER_SLEEP_DAYS} days`,
checkboxChecked: false
});
})
}
return new Bluebird((resolve) => {
@ -122,8 +122,8 @@ exports.notify = (version, options = {}) => {
return resolve({
agreed: response === BUTTON_CONFIRMATION_INDEX,
sleepUpdateCheck: checkboxChecked || false
});
});
})
})
}).tap((results) => {
// Only update the last slept update timestamp if the
// user ticked the "Remind me again in ..." checkbox,
@ -132,20 +132,20 @@ exports.notify = (version, options = {}) => {
return Bluebird.all([
settings.set('lastSleptUpdateNotifier', Date.now()),
settings.set('lastSleptUpdateNotifierVersion', packageJSON.version)
]);
])
}
return Bluebird.resolve();
return Bluebird.resolve()
}).then((results) => {
analytics.logEvent('Close update modal', {
sleepUpdateCheck: results.sleepUpdateCheck,
notifyVersion: version,
currentVersion: packageJSON.version,
agreed: results.agreed
});
})
if (results.agreed) {
electron.shell.openExternal('https://etcher.io?ref=etcher_update');
electron.shell.openExternal('https://etcher.io?ref=etcher_update')
}
});
};
})
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
module.exports = function ($uibModalInstance, options) {
/**
@ -22,7 +22,7 @@ module.exports = function ($uibModalInstance, options) {
* @type {Object}
* @public
*/
this.options = options;
this.options = options
/**
* @summary Reject the warning prompt
@ -33,8 +33,8 @@ module.exports = function ($uibModalInstance, options) {
* WarningModalController.reject();
*/
this.reject = () => {
$uibModalInstance.close(false);
};
$uibModalInstance.close(false)
}
/**
* @summary Accept the warning prompt
@ -45,6 +45,6 @@ module.exports = function ($uibModalInstance, options) {
* WarningModalController.accept();
*/
this.accept = () => {
$uibModalInstance.close(true);
};
};
$uibModalInstance.close(true)
}
}

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const _ = require('lodash')
module.exports = function ($sce, ModalService) {
/**
@ -38,7 +38,7 @@ module.exports = function ($sce, ModalService) {
* });
*/
this.display = (options = {}) => {
options.description = $sce.trustAsHtml(options.description);
options.description = $sce.trustAsHtml(options.description)
return ModalService.open({
template: './components/warning-modal/templates/warning-modal.tpl.html',
controller: 'WarningModalController as modal',
@ -46,6 +46,6 @@ module.exports = function ($sce, ModalService) {
resolve: {
options: _.constant(options)
}
}).result;
};
};
}).result
}
}

View File

@ -14,19 +14,19 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.Components.WarningModal
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Components.WarningModal';
const angular = require('angular')
const MODULE_NAME = 'Etcher.Components.WarningModal'
const WarningModal = angular.module(MODULE_NAME, [
require('../modal/modal')
]);
])
WarningModal.controller('WarningModalController', require('./controllers/warning-modal'));
WarningModal.service('WarningModalService', require('./services/warning-modal'));
WarningModal.controller('WarningModalController', require('./controllers/warning-modal'))
WarningModal.service('WarningModalService', require('./services/warning-modal'))
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,19 +14,19 @@
* limitations under the License.
*/
'use strict';
'use strict'
const electron = require('electron');
const _ = require('lodash');
const path = require('path');
const EXIT_CODES = require('../shared/exit-codes');
let mainWindow = null;
const electron = require('electron')
const _ = require('lodash')
const path = require('path')
const EXIT_CODES = require('../shared/exit-codes')
let mainWindow = null
// Enable drivelist debugging information
// See https://github.com/resin-io-modules/drivelist
process.env.DRIVELIST_DEBUG = 1;
process.env.DRIVELIST_DEBUG = 1
electron.app.on('window-all-closed', electron.app.quit);
electron.app.on('window-all-closed', electron.app.quit)
// Sending a `SIGINT` (e.g: Ctrl-C) to an Electron app that registers
// a `beforeunload` window event handler results in a disconnected white
@ -35,12 +35,12 @@ electron.app.on('window-all-closed', electron.app.quit);
// make use of it to ensure the browser window is completely destroyed.
// See https://github.com/electron/electron/issues/5273
electron.app.on('before-quit', () => {
process.exit(EXIT_CODES.SUCCESS);
});
process.exit(EXIT_CODES.SUCCESS)
})
electron.app.on('ready', () => {
// No menu bar
electron.Menu.setApplicationMenu(null);
electron.Menu.setApplicationMenu(null)
mainWindow = new electron.BrowserWindow({
width: 800,
@ -51,14 +51,14 @@ electron.app.on('ready', () => {
fullscreen: false,
titleBarStyle: 'hidden-inset',
icon: path.join(__dirname, '..', '..', 'assets', 'icon.png')
});
})
// Prevent flash of white when starting the application
mainWindow.on('ready-to-show', mainWindow.show);
mainWindow.on('ready-to-show', mainWindow.show)
mainWindow.on('closed', () => {
mainWindow = null;
});
mainWindow = null
})
// For some reason, Electron shortcuts are registered
// globally, which means that the app listers for shorcuts
@ -72,21 +72,21 @@ electron.app.on('ready', () => {
electron.globalShortcut.register('CmdOrCtrl+Alt+I', () => {
mainWindow.webContents.openDevTools({
mode: 'detach'
});
});
})
})
// Disable refreshing the browser window
// This is supposed to be handled by the `will-navigate`
// event, however there seems to be an issue where such
// event is not fired in macOS
// See: https://github.com/electron/electron/issues/8841
electron.globalShortcut.register('CmdOrCtrl+R', _.noop);
electron.globalShortcut.register('F5', _.noop);
});
electron.globalShortcut.register('CmdOrCtrl+R', _.noop)
electron.globalShortcut.register('F5', _.noop)
})
mainWindow.on('blur', () => {
electron.globalShortcut.unregisterAll();
});
electron.globalShortcut.unregisterAll()
})
// Prevent the user from being allowed to zoom-in the application.
//
@ -96,14 +96,14 @@ electron.app.on('ready', () => {
// electron desktop experience fixes in this file.
//
// See https://github.com/electron/electron/issues/3609
mainWindow.webContents.executeJavaScript('require(\'electron\').webFrame.setZoomLevelLimits(1, 1);');
mainWindow.webContents.executeJavaScript('require(\'electron\').webFrame.setZoomLevelLimits(1, 1);')
// Prevent external resources from being loaded (like images)
// when dropping them on the WebView.
// See https://github.com/electron/electron/issues/5919
mainWindow.webContents.on('will-navigate', (event) => {
event.preventDefault();
});
event.preventDefault()
})
mainWindow.loadURL(`file://${path.join(__dirname, 'index.html')}`);
});
mainWindow.loadURL(`file://${path.join(__dirname, 'index.html')}`)
})

View File

@ -14,16 +14,16 @@
* limitations under the License.
*/
'use strict';
'use strict'
const Bluebird = require('bluebird');
const Bluebird = require('bluebird')
/**
* @summary Local storage settings key
* @constant
* @type {String}
*/
const LOCAL_STORAGE_SETTINGS_KEY = 'etcher-settings';
const LOCAL_STORAGE_SETTINGS_KEY = 'etcher-settings'
/**
* @summary Read all local settings
@ -40,9 +40,9 @@ const LOCAL_STORAGE_SETTINGS_KEY = 'etcher-settings';
*/
exports.readAll = () => {
return Bluebird.try(() => {
return JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_SETTINGS_KEY)) || {};
});
};
return JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_SETTINGS_KEY)) || {}
})
}
/**
* @summary Write local settings
@ -60,11 +60,11 @@ exports.readAll = () => {
* });
*/
exports.writeAll = (settings) => {
const INDENTATION_SPACES = 2;
const INDENTATION_SPACES = 2
return Bluebird.try(() => {
window.localStorage.setItem(LOCAL_STORAGE_SETTINGS_KEY, JSON.stringify(settings, null, INDENTATION_SPACES));
});
};
window.localStorage.setItem(LOCAL_STORAGE_SETTINGS_KEY, JSON.stringify(settings, null, INDENTATION_SPACES))
})
}
/**
* @summary Clear the local settings
@ -83,6 +83,6 @@ exports.writeAll = (settings) => {
*/
exports.clear = () => {
return Bluebird.try(() => {
window.localStorage.removeItem(LOCAL_STORAGE_SETTINGS_KEY);
});
};
window.localStorage.removeItem(LOCAL_STORAGE_SETTINGS_KEY)
})
}

View File

@ -14,17 +14,17 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.Models.Settings
*/
const _ = require('lodash');
const Bluebird = require('bluebird');
const localSettings = require('./local-settings');
const store = require('../../shared/store');
const errors = require('../../shared/errors');
const _ = require('lodash')
const Bluebird = require('bluebird')
const localSettings = require('./local-settings')
const store = require('../../shared/store')
const errors = require('../../shared/errors')
/**
* @summary Set a settings object
@ -48,13 +48,13 @@ const errors = require('../../shared/errors');
* });
*/
const setSettingsObject = (settings) => {
const currentSettings = exports.getAll();
const currentSettings = exports.getAll()
return Bluebird.try(() => {
store.dispatch({
type: store.Actions.SET_SETTINGS,
data: settings
});
})
}).then(() => {
// Revert the application state if writing the data
// to the local machine was not successful
@ -62,19 +62,19 @@ const setSettingsObject = (settings) => {
store.dispatch({
type: store.Actions.SET_SETTINGS,
data: currentSettings
});
})
throw error;
});
});
};
throw error
})
})
}
/**
* @summary Default settings
* @constant
* @type {Object}
*/
const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS();
const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS()
/**
* @summary Reset settings to their default values
@ -89,8 +89,8 @@ const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS();
* });
*/
exports.reset = () => {
return setSettingsObject(DEFAULT_SETTINGS);
};
return setSettingsObject(DEFAULT_SETTINGS)
}
/**
* @summary Extend the current settings
@ -111,11 +111,11 @@ exports.assign = (settings) => {
if (_.isNil(settings)) {
return Bluebird.reject(errors.createError({
title: 'Missing settings'
}));
}))
}
return setSettingsObject(_.assign(exports.getAll(), settings));
};
return setSettingsObject(_.assign(exports.getAll(), settings))
}
/**
* @summary Extend the application state with the local settings
@ -130,8 +130,8 @@ exports.assign = (settings) => {
* });
*/
exports.load = () => {
return localSettings.readAll().then(exports.assign);
};
return localSettings.readAll().then(exports.assign)
}
/**
* @summary Set a setting value
@ -151,19 +151,19 @@ exports.set = (key, value) => {
if (_.isNil(key)) {
return Bluebird.reject(errors.createError({
title: 'Missing setting key'
}));
}))
}
if (!_.isString(key)) {
return Bluebird.reject(errors.createError({
title: `Invalid setting key: ${key}`
}));
}))
}
return exports.assign({
[key]: value
});
};
})
}
/**
* @summary Get a setting value
@ -177,8 +177,8 @@ exports.set = (key, value) => {
* const value = settings.get('unmountOnSuccess');
*/
exports.get = (key) => {
return _.get(exports.getAll(), [ key ]);
};
return _.get(exports.getAll(), [ key ])
}
/**
* @summary Get all setting values
@ -192,5 +192,5 @@ exports.get = (key) => {
* console.log(allSettings.unmountOnSuccess);
*/
exports.getAll = () => {
return store.getState().get('settings').toJS();
};
return store.getState().get('settings').toJS()
}

View File

@ -14,12 +14,12 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const resinCorvus = require('resin-corvus/browser');
const packageJSON = require('../../../package.json');
const settings = require('../models/settings');
const _ = require('lodash')
const resinCorvus = require('resin-corvus/browser')
const packageJSON = require('../../../package.json')
const settings = require('../models/settings')
resinCorvus.install({
services: {
@ -29,10 +29,10 @@ resinCorvus.install({
options: {
release: packageJSON.version,
shouldReport: () => {
return settings.get('errorReporting');
return settings.get('errorReporting')
}
}
});
})
/**
* @summary Log a debug message
@ -47,7 +47,7 @@ resinCorvus.install({
* @example
* analytics.log('Hello World');
*/
exports.logDebug = resinCorvus.logDebug;
exports.logDebug = resinCorvus.logDebug
/**
* @summary Log an event
@ -65,7 +65,7 @@ exports.logDebug = resinCorvus.logDebug;
* image: '/dev/disk2'
* });
*/
exports.logEvent = resinCorvus.logEvent;
exports.logEvent = resinCorvus.logEvent
/**
* @summary Log an exception
@ -80,4 +80,4 @@ exports.logEvent = resinCorvus.logEvent;
* @example
* analytics.logException(new Error('Something happened'));
*/
exports.logException = resinCorvus.logException;
exports.logException = resinCorvus.logException

View File

@ -14,17 +14,17 @@
* limitations under the License.
*/
'use strict';
'use strict'
const Rx = require('rx');
const _ = require('lodash');
const EventEmitter = require('events').EventEmitter;
const drivelist = require('drivelist');
const settings = require('../models/settings');
const Rx = require('rx')
const _ = require('lodash')
const EventEmitter = require('events').EventEmitter
const drivelist = require('drivelist')
const settings = require('../models/settings')
const DRIVE_SCANNER_INTERVAL_MS = 2000;
const DRIVE_SCANNER_FIRST_SCAN_DELAY_MS = 0;
const emitter = new EventEmitter();
const DRIVE_SCANNER_INTERVAL_MS = 2000
const DRIVE_SCANNER_FIRST_SCAN_DELAY_MS = 0
const emitter = new EventEmitter()
/* eslint-disable lodash/prefer-lodash-method */
@ -36,19 +36,19 @@ const availableDrives = Rx.Observable.timer(
/* eslint-enable lodash/prefer-lodash-method */
.flatMap(() => {
return Rx.Observable.fromNodeCallback(drivelist.list)();
return Rx.Observable.fromNodeCallback(drivelist.list)()
})
.map((drives) => {
if (settings.get('unsafeMode')) {
return drives;
return drives
}
return _.reject(drives, {
system: true
});
})
})
.pausable(new Rx.Subject());
.pausable(new Rx.Subject())
/*
* This service emits the following events:
@ -69,10 +69,10 @@ const availableDrives = Rx.Observable.timer(
* ```
*/
availableDrives.subscribe((drives) => {
emitter.emit('drives', drives);
emitter.emit('drives', drives)
}, (error) => {
emitter.emit('error', error);
});
emitter.emit('error', error)
})
/**
* @summary Start scanning drives
@ -83,8 +83,8 @@ availableDrives.subscribe((drives) => {
* driveScanner.start();
*/
emitter.start = () => {
availableDrives.resume();
};
availableDrives.resume()
}
/**
* @summary Stop scanning drives
@ -95,7 +95,7 @@ emitter.start = () => {
* driveScanner.stop();
*/
emitter.stop = () => {
availableDrives.pause();
};
availableDrives.pause()
}
module.exports = emitter;
module.exports = emitter

View File

@ -14,11 +14,11 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const analytics = require('../modules/analytics');
const osDialog = require('../os/dialog');
const _ = require('lodash')
const analytics = require('../modules/analytics')
const osDialog = require('../os/dialog')
/**
* @summary Report an exception
@ -32,9 +32,9 @@ const osDialog = require('../os/dialog');
*/
exports.report = (exception) => {
if (_.isUndefined(exception)) {
return;
return
}
osDialog.showError(exception);
analytics.logException(exception);
};
osDialog.showError(exception)
analytics.logException(exception)
}

View File

@ -14,23 +14,23 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.Modules.ImageWriter
*/
const angular = require('angular');
const _ = require('lodash');
const childWriter = require('../../child-writer');
const settings = require('../models/settings');
const flashState = require('../../shared/models/flash-state');
const errors = require('../../shared/errors');
const windowProgress = require('../os/window-progress');
const analytics = require('../modules/analytics');
const angular = require('angular')
const _ = require('lodash')
const childWriter = require('../../child-writer')
const settings = require('../models/settings')
const flashState = require('../../shared/models/flash-state')
const errors = require('../../shared/errors')
const windowProgress = require('../os/window-progress')
const analytics = require('../modules/analytics')
const MODULE_NAME = 'Etcher.Modules.ImageWriter';
const imageWriter = angular.module(MODULE_NAME, []);
const MODULE_NAME = 'Etcher.Modules.ImageWriter'
const imageWriter = angular.module(MODULE_NAME, [])
imageWriter.service('ImageWriterService', function ($q, $rootScope) {
/**
@ -60,12 +60,12 @@ imageWriter.service('ImageWriterService', function ($q, $rootScope) {
const child = childWriter.write(image, drive, {
validateWriteOnSuccess: settings.get('validateWriteOnSuccess'),
unmountOnSuccess: settings.get('unmountOnSuccess')
});
child.on('error', reject);
child.on('done', resolve);
child.on('progress', onProgress);
});
};
})
child.on('error', reject)
child.on('done', resolve)
child.on('progress', onProgress)
})
}
/**
* @summary Flash an image to a drive
@ -88,10 +88,10 @@ imageWriter.service('ImageWriterService', function ($q, $rootScope) {
*/
this.flash = (image, drive) => {
if (flashState.isFlashing()) {
return $q.reject(new Error('There is already a flash in progress'));
return $q.reject(new Error('There is already a flash in progress'))
}
flashState.setFlashingFlag();
flashState.setFlashingFlag()
const analyticsData = {
image,
@ -99,9 +99,9 @@ imageWriter.service('ImageWriterService', function ($q, $rootScope) {
uuid: flashState.getFlashUuid(),
unmountOnSuccess: settings.get('unmountOnSuccess'),
validateWriteOnSuccess: settings.get('validateWriteOnSuccess')
};
}
analytics.logEvent('Flash', analyticsData);
analytics.logEvent('Flash', analyticsData)
return this.performWrite(image, drive, (state) => {
// Bring this value to the world of angular.
@ -109,38 +109,38 @@ imageWriter.service('ImageWriterService', function ($q, $rootScope) {
// `.getFlashState()` will not return
// the latest updated progress state.
$rootScope.$apply(() => {
flashState.setProgressState(state);
});
flashState.setProgressState(state)
})
}).then(flashState.unsetFlashingFlag).then(() => {
if (flashState.wasLastFlashCancelled()) {
analytics.logEvent('Elevation cancelled', analyticsData);
analytics.logEvent('Elevation cancelled', analyticsData)
} else {
analytics.logEvent('Done', analyticsData);
analytics.logEvent('Done', analyticsData)
}
}).catch((error) => {
flashState.unsetFlashingFlag({
errorCode: error.code
});
})
if (error.code === 'EVALIDATION') {
analytics.logEvent('Validation error', analyticsData);
analytics.logEvent('Validation error', analyticsData)
} else if (error.code === 'EUNPLUGGED') {
analytics.logEvent('Drive unplugged', analyticsData);
analytics.logEvent('Drive unplugged', analyticsData)
} else if (error.code === 'EIO') {
analytics.logEvent('Input/output error', analyticsData);
analytics.logEvent('Input/output error', analyticsData)
} else if (error.code === 'ENOSPC') {
analytics.logEvent('Out of space', analyticsData);
analytics.logEvent('Out of space', analyticsData)
} else {
analytics.logEvent('Flash error', _.merge({
error: errors.toJSON(error)
}, analyticsData));
}, analyticsData))
}
return $q.reject(error);
return $q.reject(error)
}).finally(() => {
windowProgress.clear();
});
};
});
windowProgress.clear()
})
}
})
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,20 +14,20 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const electron = require('electron');
const Bluebird = require('bluebird');
const errors = require('../../shared/errors');
const supportedFormats = require('../../shared/supported-formats');
const _ = require('lodash')
const electron = require('electron')
const Bluebird = require('bluebird')
const errors = require('../../shared/errors')
const supportedFormats = require('../../shared/supported-formats')
/**
* @summary Current renderer BrowserWindow instance
* @type {Object}
* @private
*/
const currentWindow = electron.remote.getCurrentWindow();
const currentWindow = electron.remote.getCurrentWindow()
/**
* @summary Open an image selection dialog
@ -71,10 +71,10 @@ exports.selectImage = () => {
// `_.first` is smart enough to not throw and return `undefined`
// if we pass it an `undefined` value (e.g: when the selection
// dialog was cancelled).
return resolve(_.first(files));
});
});
};
return resolve(_.first(files))
})
})
}
/**
* @summary Open a warning dialog
@ -105,15 +105,15 @@ exports.showWarning = (options) => {
_.defaults(options, {
confirmationLabel: 'OK',
rejectionLabel: 'Cancel'
});
})
const BUTTONS = [
options.confirmationLabel,
options.rejectionLabel
];
]
const BUTTON_CONFIRMATION_INDEX = _.indexOf(BUTTONS, options.confirmationLabel);
const BUTTON_REJECTION_INDEX = _.indexOf(BUTTONS, options.rejectionLabel);
const BUTTON_CONFIRMATION_INDEX = _.indexOf(BUTTONS, options.confirmationLabel)
const BUTTON_REJECTION_INDEX = _.indexOf(BUTTONS, options.rejectionLabel)
return new Bluebird((resolve) => {
electron.remote.dialog.showMessageBox(currentWindow, {
@ -125,10 +125,10 @@ exports.showWarning = (options) => {
message: options.title,
detail: options.description
}, (response) => {
return resolve(response === BUTTON_CONFIRMATION_INDEX);
});
});
};
return resolve(response === BUTTON_CONFIRMATION_INDEX)
})
})
}
/**
* @summary Show error dialog for an Error instance
@ -141,7 +141,7 @@ exports.showWarning = (options) => {
* osDialog.showError(new Error('Foo Bar'));
*/
exports.showError = (error) => {
const title = errors.getTitle(error);
const message = errors.getDescription(error);
electron.remote.dialog.showErrorBox(title, message);
};
const title = errors.getTitle(error)
const message = errors.getDescription(error)
electron.remote.dialog.showErrorBox(title, message)
}

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const _ = require('lodash')
/**
* @summary Dropzone directive
@ -40,18 +40,18 @@ module.exports = ($timeout) => {
osDropzone: '&'
},
link: (scope, $element) => {
const domElement = _.first($element);
const domElement = _.first($element)
// See https://github.com/electron/electron/blob/master/docs/api/file-object.md
// We're not interested in these events
domElement.ondragover = _.constant(false);
domElement.ondragleave = _.constant(false);
domElement.ondragend = _.constant(false);
domElement.ondragover = _.constant(false)
domElement.ondragleave = _.constant(false)
domElement.ondragend = _.constant(false)
domElement.ondrop = (event) => {
event.preventDefault();
const filename = _.first(event.dataTransfer.files).path;
event.preventDefault()
const filename = _.first(event.dataTransfer.files).path
// Safely bring this to the word of Angular
$timeout(() => {
@ -61,11 +61,11 @@ module.exports = ($timeout) => {
// parameter called `$file`
$file: filename
});
});
})
})
return false;
};
return false
}
}
};
};
}
}

View File

@ -14,15 +14,15 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.OS.Dropzone
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.OS.Dropzone';
const OSDropzone = angular.module(MODULE_NAME, []);
OSDropzone.directive('osDropzone', require('./directives/dropzone'));
const angular = require('angular')
const MODULE_NAME = 'Etcher.OS.Dropzone'
const OSDropzone = angular.module(MODULE_NAME, [])
OSDropzone.directive('osDropzone', require('./directives/dropzone'))
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const electron = require('electron');
const electron = require('electron')
/**
* @summary Send a notification
@ -43,8 +43,8 @@ const electron = require('electron');
exports.send = (title, options) => {
// `app.dock` is only defined in OS X
if (electron.remote.app.dock) {
electron.remote.app.dock.bounce();
electron.remote.app.dock.bounce()
}
return new window.Notification(title, options);
};
return new window.Notification(title, options)
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @summary OsOpenExternal directive
@ -38,11 +38,11 @@ module.exports = (OSOpenExternalService) => {
link: (scope, element, attributes) => {
// This directive might be added to elements
// other than buttons.
element.css('cursor', 'pointer');
element.css('cursor', 'pointer')
element.on('click', () => {
OSOpenExternalService.open(attributes.osOpenExternal);
});
OSOpenExternalService.open(attributes.osOpenExternal)
})
}
};
};
}
}

View File

@ -14,33 +14,33 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.OS.OpenExternal
*/
const angular = require('angular');
const url = require('url');
const angular = require('angular')
const url = require('url')
const MODULE_NAME = 'Etcher.OS.OpenExternal';
const OSOpenExternal = angular.module(MODULE_NAME, []);
OSOpenExternal.service('OSOpenExternalService', require('./services/open-external'));
OSOpenExternal.directive('osOpenExternal', require('./directives/open-external'));
const MODULE_NAME = 'Etcher.OS.OpenExternal'
const OSOpenExternal = angular.module(MODULE_NAME, [])
OSOpenExternal.service('OSOpenExternalService', require('./services/open-external'))
OSOpenExternal.directive('osOpenExternal', require('./directives/open-external'))
OSOpenExternal.run((OSOpenExternalService) => {
document.addEventListener('click', (event) => {
const target = event.target;
const target = event.target
if (target.tagName === 'A' && angular.isDefined(target.href)) {
// Electron interprets relative URLs as being relative to the
// current loaded URL (with `webContents.loadURL`) and expands
// them to the corresponding absolute URL. If it's a `file://`
// URL, we don't want it opened in an external browser.
if (url.parse(target.href).protocol !== 'file:') {
OSOpenExternalService.open(target.href);
OSOpenExternalService.open(target.href)
}
}
});
});
})
})
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const electron = require('electron');
const analytics = require('../../../modules/analytics');
const electron = require('electron')
const analytics = require('../../../modules/analytics')
module.exports = function () {
/**
@ -33,10 +33,10 @@ module.exports = function () {
this.open = (url) => {
analytics.logEvent('Open external link', {
url
});
})
if (url) {
electron.shell.openExternal(url);
electron.shell.openExternal(url)
}
};
};
}
}

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const electron = require('electron');
const utils = require('../../shared/utils');
const electron = require('electron')
const utils = require('../../shared/utils')
/**
* @summary A reference to the current renderer Electron window
@ -27,7 +27,7 @@ const utils = require('../../shared/utils');
* @description
* We expose this property to `this` for testability purposes.
*/
exports.currentWindow = electron.remote.getCurrentWindow();
exports.currentWindow = electron.remote.getCurrentWindow()
/**
* @summary Set operating system window progress
@ -43,8 +43,8 @@ exports.currentWindow = electron.remote.getCurrentWindow();
* windowProgress.set(85);
*/
exports.set = (percentage) => {
exports.currentWindow.setProgressBar(utils.percentageToFloat(percentage));
};
exports.currentWindow.setProgressBar(utils.percentageToFloat(percentage))
}
/**
* @summary Clear the window progress bar
@ -56,7 +56,7 @@ exports.set = (percentage) => {
*/
exports.clear = () => {
// Passing 0 or null/undefined doesn't work.
const ELECTRON_PROGRESS_BAR_RESET_VALUE = -1;
const ELECTRON_PROGRESS_BAR_RESET_VALUE = -1
exports.currentWindow.setProgressBar(ELECTRON_PROGRESS_BAR_RESET_VALUE);
};
exports.currentWindow.setProgressBar(ELECTRON_PROGRESS_BAR_RESET_VALUE)
}

View File

@ -14,12 +14,12 @@
* limitations under the License.
*/
'use strict';
'use strict'
const settings = require('../../../models/settings');
const flashState = require('../../../../shared/models/flash-state');
const selectionState = require('../../../../shared/models/selection-state');
const analytics = require('../../../modules/analytics');
const settings = require('../../../models/settings')
const flashState = require('../../../../shared/models/flash-state')
const selectionState = require('../../../../shared/models/selection-state')
const analytics = require('../../../modules/analytics')
module.exports = function ($state) {
/**
@ -27,14 +27,14 @@ module.exports = function ($state) {
* @type {Object}
* @public
*/
this.settings = settings;
this.settings = settings
/**
* @summary Source checksum
* @type {String}
* @public
*/
this.checksum = flashState.getLastFlashSourceChecksum();
this.checksum = flashState.getLastFlashSourceChecksum()
/**
* @summary Restart the flashing process
@ -48,8 +48,8 @@ module.exports = function ($state) {
* FinishController.restart({ preserveImage: true });
*/
this.restart = (options) => {
selectionState.clear(options);
analytics.logEvent('Restart', options);
$state.go('main');
};
};
selectionState.clear(options)
analytics.logEvent('Restart', options)
$state.go('main')
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* The finish page represents the application state where
@ -26,13 +26,13 @@
* @module Etcher.Pages.Finish
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Pages.Finish';
const angular = require('angular')
const MODULE_NAME = 'Etcher.Pages.Finish'
const FinishPage = angular.module(MODULE_NAME, [
require('angular-ui-router')
]);
])
FinishPage.controller('FinishController', require('./controllers/finish'));
FinishPage.controller('FinishController', require('./controllers/finish'))
FinishPage.config(($stateProvider) => {
$stateProvider
@ -40,7 +40,7 @@ FinishPage.config(($stateProvider) => {
url: '/success',
controller: 'FinishController as finish',
templateUrl: './pages/finish/templates/success.tpl.html'
});
});
})
})
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,12 +14,12 @@
* limitations under the License.
*/
'use strict';
'use strict'
const settings = require('../../../models/settings');
const selectionState = require('../../../../shared/models/selection-state');
const analytics = require('../../../modules/analytics');
const exceptionReporter = require('../../../modules/exception-reporter');
const settings = require('../../../models/settings')
const selectionState = require('../../../../shared/models/selection-state')
const analytics = require('../../../modules/analytics')
const exceptionReporter = require('../../../modules/exception-reporter')
module.exports = function (DriveSelectorService) {
/**
@ -33,17 +33,17 @@ module.exports = function (DriveSelectorService) {
this.openDriveSelector = () => {
DriveSelectorService.open().then((drive) => {
if (!drive) {
return;
return
}
selectionState.setDrive(drive.device);
selectionState.setDrive(drive.device)
analytics.logEvent('Select drive', {
device: drive.device,
unsafeMode: settings.get('unsafeMode')
});
}).catch(exceptionReporter.report);
};
})
}).catch(exceptionReporter.report)
}
/**
* @summary Reselect a drive
@ -54,7 +54,7 @@ module.exports = function (DriveSelectorService) {
* DriveSelectionController.reselectDrive();
*/
this.reselectDrive = () => {
this.openDriveSelector();
analytics.logEvent('Reselect drive');
};
};
this.openDriveSelector()
analytics.logEvent('Reselect drive')
}
}

View File

@ -14,16 +14,16 @@
* limitations under the License.
*/
'use strict';
'use strict'
const messages = require('../../../../shared/messages');
const settings = require('../../../models/settings');
const flashState = require('../../../../shared/models/flash-state');
const driveScanner = require('../../../modules/drive-scanner');
const utils = require('../../../../shared/utils');
const notification = require('../../../os/notification');
const exceptionReporter = require('../../../modules/exception-reporter');
const path = require('path');
const messages = require('../../../../shared/messages')
const settings = require('../../../models/settings')
const flashState = require('../../../../shared/models/flash-state')
const driveScanner = require('../../../modules/drive-scanner')
const utils = require('../../../../shared/utils')
const notification = require('../../../os/notification')
const exceptionReporter = require('../../../modules/exception-reporter')
const path = require('path')
module.exports = function (
$state,
@ -52,14 +52,14 @@ module.exports = function (
*/
this.flashImageToDrive = (image, drive) => {
if (flashState.isFlashing()) {
return;
return
}
// Stop scanning drives when flashing
// otherwise Windows throws EPERM
driveScanner.stop();
driveScanner.stop()
const iconPath = '../../assets/icon.png';
const iconPath = '../../assets/icon.png'
ImageWriterService.flash(image.path, drive).then(() => {
if (!flashState.wasLastFlashCancelled()) {
@ -69,8 +69,8 @@ module.exports = function (
drive
}),
icon: iconPath
});
$state.go('success');
})
$state.go('success')
}
})
.catch((error) => {
@ -80,27 +80,27 @@ module.exports = function (
drive
}),
icon: iconPath
});
})
// TODO: All these error codes to messages translations
// should go away if the writer emitted user friendly
// messages on the first place.
if (error.code === 'EVALIDATION') {
FlashErrorModalService.show(messages.error.validation());
FlashErrorModalService.show(messages.error.validation())
} else if (error.code === 'EUNPLUGGED') {
FlashErrorModalService.show(messages.error.driveUnplugged());
FlashErrorModalService.show(messages.error.driveUnplugged())
} else if (error.code === 'EIO') {
FlashErrorModalService.show(messages.error.inputOutput());
FlashErrorModalService.show(messages.error.inputOutput())
} else if (error.code === 'ENOSPC') {
FlashErrorModalService.show(messages.error.notEnoughSpaceInDrive());
FlashErrorModalService.show(messages.error.notEnoughSpaceInDrive())
} else {
FlashErrorModalService.show(messages.error.genericFlashError());
exceptionReporter.report(error);
FlashErrorModalService.show(messages.error.genericFlashError())
exceptionReporter.report(error)
}
}).finally(() => {
driveScanner.start();
});
};
driveScanner.start()
})
}
/**
* @summary Get progress button label
@ -113,23 +113,23 @@ module.exports = function (
* const label = FlashController.getProgressButtonLabel();
*/
this.getProgressButtonLabel = () => {
const currentFlashState = flashState.getFlashState();
const isChecking = currentFlashState.type === 'check';
const currentFlashState = flashState.getFlashState()
const isChecking = currentFlashState.type === 'check'
if (!flashState.isFlashing()) {
return 'Flash!';
return 'Flash!'
} else if (currentFlashState.percentage === utils.PERCENTAGE_MINIMUM && !currentFlashState.speed) {
return 'Starting...';
return 'Starting...'
} else if (currentFlashState.percentage === utils.PERCENTAGE_MAXIMUM) {
if (isChecking && settings.get('unmountOnSuccess')) {
return 'Unmounting...';
return 'Unmounting...'
}
return 'Finishing...';
return 'Finishing...'
} else if (isChecking) {
return `${currentFlashState.percentage}% Validating...`;
return `${currentFlashState.percentage}% Validating...`
}
return `${currentFlashState.percentage}%`;
};
};
return `${currentFlashState.percentage}%`
}
}

View File

@ -14,19 +14,19 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const Bluebird = require('bluebird');
const path = require('path');
const messages = require('../../../../shared/messages');
const errors = require('../../../../shared/errors');
const imageStream = require('../../../../image-stream');
const supportedFormats = require('../../../../shared/supported-formats');
const analytics = require('../../../modules/analytics');
const selectionState = require('../../../../shared/models/selection-state');
const osDialog = require('../../../os/dialog');
const exceptionReporter = require('../../../modules/exception-reporter');
const _ = require('lodash')
const Bluebird = require('bluebird')
const path = require('path')
const messages = require('../../../../shared/messages')
const errors = require('../../../../shared/errors')
const imageStream = require('../../../../image-stream')
const supportedFormats = require('../../../../shared/supported-formats')
const analytics = require('../../../modules/analytics')
const selectionState = require('../../../../shared/models/selection-state')
const osDialog = require('../../../os/dialog')
const exceptionReporter = require('../../../modules/exception-reporter')
module.exports = function (
$timeout,
@ -42,7 +42,7 @@ module.exports = function (
'img',
'iso',
'zip'
], supportedFormats.getAllExtensions());
], supportedFormats.getAllExtensions())
/**
* @summary Extra supported extensions
@ -53,7 +53,7 @@ module.exports = function (
this.extraSupportedExtensions = _.difference(
supportedFormats.getAllExtensions(),
this.mainSupportedExtensions
).sort();
).sort()
/**
* @summary Select image
@ -73,22 +73,22 @@ module.exports = function (
description: messages.error.invalidImage({
image
})
});
})
osDialog.showError(invalidImageError);
analytics.logEvent('Invalid image', image);
return;
osDialog.showError(invalidImageError)
analytics.logEvent('Invalid image', image)
return
}
Bluebird.try(() => {
let message = null;
let message = null
if (supportedFormats.looksLikeWindowsImage(image.path)) {
analytics.logEvent('Possibly Windows image', image);
message = messages.warning.looksLikeWindowsImage();
analytics.logEvent('Possibly Windows image', image)
message = messages.warning.looksLikeWindowsImage()
} else if (!image.hasMBR) {
analytics.logEvent('Missing partition table', image);
message = messages.warning.missingPartitionTable();
analytics.logEvent('Missing partition table', image)
message = messages.warning.missingPartitionTable()
}
if (message) {
@ -98,25 +98,25 @@ module.exports = function (
confirmationLabel: 'Change',
rejectionLabel: 'Continue',
description: message
});
})
}
return false;
return false
}).then((shouldChange) => {
if (shouldChange) {
return this.reselectImage();
return this.reselectImage()
}
selectionState.setImage(image);
selectionState.setImage(image)
// An easy way so we can quickly identify if we're making use of
// certain features without printing pages of text to DevTools.
image.logo = Boolean(image.logo);
image.bmap = Boolean(image.bmap);
image.logo = Boolean(image.logo)
image.bmap = Boolean(image.bmap)
return analytics.logEvent('Select image', image);
}).catch(exceptionReporter.report);
};
return analytics.logEvent('Select image', image)
}).catch(exceptionReporter.report)
}
/**
* @summary Select an image by path
@ -132,8 +132,8 @@ module.exports = function (
imageStream.getImageMetadata(imagePath)
.then((imageMetadata) => {
$timeout(() => {
this.selectImage(imageMetadata);
});
this.selectImage(imageMetadata)
})
})
.catch((error) => {
const imageError = errors.createUserError({
@ -142,12 +142,12 @@ module.exports = function (
imageBasename: path.basename(imagePath),
errorMessage: error.message
})
});
})
osDialog.showError(imageError);
analytics.logException(error);
});
};
osDialog.showError(imageError)
analytics.logException(error)
})
}
/**
* @summary Open image selector
@ -158,19 +158,19 @@ module.exports = function (
* ImageSelectionController.openImageSelector();
*/
this.openImageSelector = () => {
analytics.logEvent('Open image selector');
analytics.logEvent('Open image selector')
osDialog.selectImage().then((imagePath) => {
// Avoid analytics and selection state changes
// if no file was resolved from the dialog.
if (!imagePath) {
analytics.logEvent('Image selector closed');
return;
analytics.logEvent('Image selector closed')
return
}
this.selectImageByPath(imagePath);
}).catch(exceptionReporter.report);
};
this.selectImageByPath(imagePath)
}).catch(exceptionReporter.report)
}
/**
* @summary Reselect image
@ -183,10 +183,10 @@ module.exports = function (
this.reselectImage = () => {
analytics.logEvent('Reselect image', {
previousImage: selectionState.getImage()
});
})
this.openImageSelector();
};
this.openImageSelector()
}
/**
* @summary Get the basename of the selected image
@ -200,9 +200,9 @@ module.exports = function (
*/
this.getImageBasename = () => {
if (!selectionState.hasImage()) {
return '';
return ''
}
return path.basename(selectionState.getImagePath());
};
};
return path.basename(selectionState.getImagePath())
}
}

View File

@ -14,25 +14,25 @@
* limitations under the License.
*/
'use strict';
'use strict'
const settings = require('../../../models/settings');
const flashState = require('../../../../shared/models/flash-state');
const analytics = require('../../../modules/analytics');
const exceptionReporter = require('../../../modules/exception-reporter');
const availableDrives = require('../../../../shared/models/available-drives');
const selectionState = require('../../../../shared/models/selection-state');
const settings = require('../../../models/settings')
const flashState = require('../../../../shared/models/flash-state')
const analytics = require('../../../modules/analytics')
const exceptionReporter = require('../../../modules/exception-reporter')
const availableDrives = require('../../../../shared/models/available-drives')
const selectionState = require('../../../../shared/models/selection-state')
module.exports = function (
TooltipModalService,
OSOpenExternalService
) {
// Expose several modules to the template for convenience
this.selection = selectionState;
this.drives = availableDrives;
this.state = flashState;
this.settings = settings;
this.external = OSOpenExternalService;
this.selection = selectionState
this.drives = availableDrives
this.state = flashState
this.settings = settings
this.external = OSOpenExternalService
/**
* @summary Determine if the drive step should be disabled
@ -47,8 +47,8 @@ module.exports = function (
* }
*/
this.shouldDriveStepBeDisabled = () => {
return !selectionState.hasImage();
};
return !selectionState.hasImage()
}
/**
* @summary Determine if the flash step should be disabled
@ -63,8 +63,8 @@ module.exports = function (
* }
*/
this.shouldFlashStepBeDisabled = () => {
return !selectionState.hasDrive() || this.shouldDriveStepBeDisabled();
};
return !selectionState.hasDrive() || this.shouldDriveStepBeDisabled()
}
/**
* @summary Display a tooltip with the selected image details
@ -79,11 +79,11 @@ module.exports = function (
this.showSelectedImageDetails = () => {
analytics.logEvent('Show selected image tooltip', {
imagePath: selectionState.getImagePath()
});
})
return TooltipModalService.show({
title: 'Image File Name',
message: selectionState.getImagePath()
}).catch(exceptionReporter.report);
};
};
}).catch(exceptionReporter.report)
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* This page represents the application main page.
@ -22,10 +22,10 @@
* @module Etcher.Pages.Main
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Pages.Main';
const angular = require('angular')
const MODULE_NAME = 'Etcher.Pages.Main'
require('angular-moment');
require('angular-moment')
const MainPage = angular.module(MODULE_NAME, [
'angularMoment',
@ -45,12 +45,12 @@ const MainPage = angular.module(MODULE_NAME, [
require('../../modules/image-writer'),
require('../../utils/byte-size/byte-size')
]);
])
MainPage.controller('MainController', require('./controllers/main'));
MainPage.controller('ImageSelectionController', require('./controllers/image-selection'));
MainPage.controller('DriveSelectionController', require('./controllers/drive-selection'));
MainPage.controller('FlashController', require('./controllers/flash'));
MainPage.controller('MainController', require('./controllers/main'))
MainPage.controller('ImageSelectionController', require('./controllers/image-selection'))
MainPage.controller('DriveSelectionController', require('./controllers/drive-selection'))
MainPage.controller('FlashController', require('./controllers/flash'))
MainPage.config(($stateProvider) => {
$stateProvider
@ -58,7 +58,7 @@ MainPage.config(($stateProvider) => {
url: '/main',
controller: 'MainController as main',
templateUrl: './pages/main/templates/main.tpl.html'
});
});
})
})
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
'use strict';
'use strict'
const os = require('os');
const _ = require('lodash');
const settings = require('../../../models/settings');
const analytics = require('../../../modules/analytics');
const exceptionReporter = require('../../../modules/exception-reporter');
const os = require('os')
const _ = require('lodash')
const settings = require('../../../models/settings')
const analytics = require('../../../modules/analytics')
const exceptionReporter = require('../../../modules/exception-reporter')
module.exports = function (WarningModalService) {
/**
@ -29,7 +29,7 @@ module.exports = function (WarningModalService) {
* @constant
* @public
*/
this.platform = os.platform();
this.platform = os.platform()
/**
* @summary Refresh current settings
@ -40,23 +40,23 @@ module.exports = function (WarningModalService) {
* SettingsController.refreshSettings();
*/
this.refreshSettings = () => {
this.currentData = settings.getAll();
};
this.currentData = settings.getAll()
}
/**
* @summary Current settings value
* @type {Object}
* @public
*/
this.currentData = {};
this.refreshSettings();
this.currentData = {}
this.refreshSettings()
/**
* @summary Settings model
* @type {Object}
* @public
*/
this.model = settings;
this.model = settings
/**
* @summary Toggle setting
@ -81,27 +81,27 @@ module.exports = function (WarningModalService) {
* });
*/
this.toggle = (setting, options) => {
const value = this.currentData[setting];
const dangerous = !_.isUndefined(options);
const value = this.currentData[setting]
const dangerous = !_.isUndefined(options)
analytics.logEvent('Toggle setting', {
setting,
value,
dangerous
});
})
if (!value || !dangerous) {
return this.model.set(setting, value);
return this.model.set(setting, value)
}
// Keep the checkbox unchecked until the user confirms
this.currentData[setting] = false;
this.currentData[setting] = false
return WarningModalService.display(options).then((userAccepted) => {
if (userAccepted) {
this.model.set(setting, true);
this.refreshSettings();
this.model.set(setting, true)
this.refreshSettings()
}
}).catch(exceptionReporter.report);
};
};
}).catch(exceptionReporter.report)
}
}

View File

@ -14,20 +14,20 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @module Etcher.Pages.Settings
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Pages.Settings';
const angular = require('angular')
const MODULE_NAME = 'Etcher.Pages.Settings'
const SettingsPage = angular.module(MODULE_NAME, [
require('angular-ui-router'),
require('../../components/warning-modal/warning-modal')
]);
])
SettingsPage.controller('SettingsController', require('./controllers/settings'));
SettingsPage.controller('SettingsController', require('./controllers/settings'))
SettingsPage.config(($stateProvider) => {
$stateProvider
@ -35,7 +35,7 @@ SettingsPage.config(($stateProvider) => {
url: '/settings',
controller: 'SettingsController as settings',
templateUrl: './pages/settings/templates/settings.tpl.html'
});
});
})
})
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* The purpose of this module is to provide utilities
@ -23,14 +23,14 @@
* @module Etcher.Utils.ByteSize
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Utils.ByteSize';
const ByteSize = angular.module(MODULE_NAME, []);
const angular = require('angular')
const MODULE_NAME = 'Etcher.Utils.ByteSize'
const ByteSize = angular.module(MODULE_NAME, [])
/* eslint-disable lodash/prefer-lodash-method */
ByteSize.filter('closestUnit', require('./filter.js'));
ByteSize.filter('closestUnit', require('./filter.js'))
/* eslint-enable lodash/prefer-lodash-method */
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const units = require('../../../shared/units');
const units = require('../../../shared/units')
module.exports = () => {
/**
@ -30,5 +30,5 @@ module.exports = () => {
* @example
* {{ 7801405440 | closestUnit }}
*/
return units.bytesToClosestUnit;
};
return units.bytesToClosestUnit
}

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const errors = require('../../../../shared/errors');
const errors = require('../../../../shared/errors')
/**
* @summary ManifestBind directive
@ -38,15 +38,15 @@ module.exports = (ManifestBindService) => {
restrict: 'A',
scope: false,
link: (scope, element, attributes) => {
const value = ManifestBindService.get(attributes.manifestBind);
const value = ManifestBindService.get(attributes.manifestBind)
if (!value) {
throw errors.createError({
title: `ManifestBind: Unknown property \`${attributes.manifestBind}\``
});
})
}
element.html(value);
element.html(value)
}
};
};
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* The purpose of this module is to provide an attribute
@ -24,10 +24,10 @@
* @module Etcher.Utils.ManifestBind
*/
const angular = require('angular');
const MODULE_NAME = 'Etcher.Utils.ManifestBind';
const ManifestBind = angular.module(MODULE_NAME, []);
ManifestBind.service('ManifestBindService', require('./services/manifest-bind'));
ManifestBind.directive('manifestBind', require('./directives/manifest-bind'));
const angular = require('angular')
const MODULE_NAME = 'Etcher.Utils.ManifestBind'
const ManifestBind = angular.module(MODULE_NAME, [])
ManifestBind.service('ManifestBindService', require('./services/manifest-bind'))
ManifestBind.directive('manifestBind', require('./directives/manifest-bind'))
module.exports = MODULE_NAME;
module.exports = MODULE_NAME

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const packageJSON = require('../../../../../package.json');
const _ = require('lodash')
const packageJSON = require('../../../../../package.json')
module.exports = function () {
/**
@ -32,6 +32,6 @@ module.exports = function () {
* const version = ManifestBindService.get('version');
*/
this.get = (attribute) => {
return _.get(packageJSON, attribute);
};
};
return _.get(packageJSON, attribute)
}
}

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
'use strict';
'use strict'
const Bluebird = require('bluebird');
const _ = require('lodash');
const StreamZip = require('node-stream-zip');
const yauzl = Bluebird.promisifyAll(require('yauzl'));
const errors = require('../../shared/errors');
const Bluebird = require('bluebird')
const _ = require('lodash')
const StreamZip = require('node-stream-zip')
const yauzl = Bluebird.promisifyAll(require('yauzl'))
const errors = require('../../shared/errors')
/**
* @summary Get all archive entries
@ -44,12 +44,12 @@ exports.getEntries = (archive) => {
const zip = new StreamZip({
file: archive,
storeEntries: true
});
})
zip.on('error', reject);
zip.on('error', reject)
zip.on('ready', () => {
const EMPTY_ENTRY_SIZE = 0;
const EMPTY_ENTRY_SIZE = 0
return resolve(_.chain(zip.entries())
.omitBy({
@ -59,12 +59,12 @@ exports.getEntries = (archive) => {
return {
name: metadata.name,
size: metadata.size
};
}
})
.value());
});
});
};
.value())
})
})
}
/**
* @summary Extract a file from an archive
@ -91,27 +91,27 @@ exports.extractFile = (archive, entries, file) => {
})) {
throw errors.createError({
title: `Invalid entry: ${file}`
});
})
}
yauzl.openAsync(archive, {
lazyEntries: true
}).then((zipfile) => {
zipfile.readEntry();
zipfile.readEntry()
zipfile.on('entry', (entry) => {
if (entry.fileName !== file) {
return zipfile.readEntry();
return zipfile.readEntry()
}
return zipfile.openReadStream(entry, (error, readStream) => {
if (error) {
return reject(error);
return reject(error)
}
return resolve(readStream);
});
});
}).catch(reject);
});
};
return resolve(readStream)
})
})
}).catch(reject)
})
}

View File

@ -14,15 +14,15 @@
* limitations under the License.
*/
'use strict';
'use strict'
const Bluebird = require('bluebird');
const _ = require('lodash');
const PassThroughStream = require('stream').PassThrough;
const supportedFileTypes = require('./supported');
const utils = require('./utils');
const errors = require('../shared/errors');
const fileExtensions = require('../shared/file-extensions');
const Bluebird = require('bluebird')
const _ = require('lodash')
const PassThroughStream = require('stream').PassThrough
const supportedFileTypes = require('./supported')
const utils = require('./utils')
const errors = require('../shared/errors')
const fileExtensions = require('../shared/file-extensions')
/**
* @summary Archive metadata base path
@ -30,7 +30,7 @@ const fileExtensions = require('../shared/file-extensions');
* @private
* @type {String}
*/
const ARCHIVE_METADATA_BASE_PATH = '.meta';
const ARCHIVE_METADATA_BASE_PATH = '.meta'
/**
* @summary Image extensions
@ -40,11 +40,11 @@ const ARCHIVE_METADATA_BASE_PATH = '.meta';
*/
const IMAGE_EXTENSIONS = _.reduce(supportedFileTypes, (accumulator, file) => {
if (file.type === 'image') {
accumulator.push(file.extension);
accumulator.push(file.extension)
}
return accumulator;
}, []);
return accumulator
}, [])
/**
* @summary Extract entry by path
@ -75,16 +75,16 @@ const extractEntryByPath = (archive, filePath, options) => {
.split('/')
.tail()
.join('/')
.value() === filePath;
});
.value() === filePath
})
if (!fileEntry) {
return Bluebird.resolve(options.default);
return Bluebird.resolve(options.default)
}
return options.hooks.extractFile(archive, options.entries, fileEntry.name)
.then(utils.extractStream);
};
.then(utils.extractStream)
}
/**
* @summary Extract archive metadata
@ -119,14 +119,14 @@ const extractArchiveMetadata = (archive, basePath, options) => {
default: '{}'
}).then((manifest) => {
try {
return JSON.parse(manifest);
return JSON.parse(manifest)
} catch (parseError) {
throw errors.createUserError({
title: 'Invalid archive manifest.json',
description: 'The archive manifest.json file is not valid JSON'
});
})
}
});
})
})
}).then((results) => {
return {
@ -142,9 +142,9 @@ const extractArchiveMetadata = (archive, basePath, options) => {
logo: _.invoke(results.logo, [ 'toString' ]),
bmap: _.invoke(results.bmap, [ 'toString' ]),
instructions: _.invoke(results.instructions, [ 'toString' ])
};
});
};
}
})
}
/**
* @summary Extract image from archive
@ -173,18 +173,18 @@ const extractArchiveMetadata = (archive, basePath, options) => {
exports.extractImage = (archive, hooks) => {
return hooks.getEntries(archive).then((entries) => {
const imageEntries = _.filter(entries, (entry) => {
return _.includes(IMAGE_EXTENSIONS, fileExtensions.getLastFileExtension(entry.name));
});
return _.includes(IMAGE_EXTENSIONS, fileExtensions.getLastFileExtension(entry.name))
})
const VALID_NUMBER_OF_IMAGE_ENTRIES = 1;
const VALID_NUMBER_OF_IMAGE_ENTRIES = 1
if (imageEntries.length !== VALID_NUMBER_OF_IMAGE_ENTRIES) {
throw errors.createUserError({
title: 'Invalid archive image',
description: 'The archive image should contain one and only one top image file'
});
})
}
const imageEntry = _.first(imageEntries);
const imageEntry = _.first(imageEntries)
return Bluebird.props({
imageStream: hooks.extractFile(archive, entries, imageEntry.name),
@ -193,9 +193,9 @@ exports.extractImage = (archive, hooks) => {
hooks
})
}).then((results) => {
results.metadata.stream = results.imageStream;
results.metadata.transform = new PassThroughStream();
results.metadata.path = archive;
results.metadata.stream = results.imageStream
results.metadata.transform = new PassThroughStream()
results.metadata.path = archive
results.metadata.size = {
original: imageEntry.size,
@ -203,12 +203,12 @@ exports.extractImage = (archive, hooks) => {
estimation: false,
value: imageEntry.size
}
};
}
results.metadata.extension = fileExtensions.getLastFileExtension(imageEntry.name);
results.metadata.archiveExtension = fileExtensions.getLastFileExtension(archive);
results.metadata.extension = fileExtensions.getLastFileExtension(imageEntry.name)
results.metadata.archiveExtension = fileExtensions.getLastFileExtension(archive)
return results.metadata;
});
});
};
return results.metadata
})
})
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @summary The byte length of ISIZE
@ -23,7 +23,7 @@
* @description
* See https://tools.ietf.org/html/rfc1952
*/
const ISIZE_LENGTH = 4;
const ISIZE_LENGTH = 4
/**
* @summary Get the estimated uncompressed size of a gzip file
@ -64,9 +64,9 @@ const ISIZE_LENGTH = 4;
* });
*/
exports.getUncompressedSize = (options) => {
const ISIZE_BUFFER_START = 0;
const ISIZE_POSITION = options.size - ISIZE_LENGTH;
const ISIZE_BUFFER_START = 0
const ISIZE_POSITION = options.size - ISIZE_LENGTH
return options.read(ISIZE_POSITION, ISIZE_LENGTH).then((buffer) => {
return buffer.readUInt32LE(ISIZE_BUFFER_START);
});
};
return buffer.readUInt32LE(ISIZE_BUFFER_START)
})
}

View File

@ -14,24 +14,24 @@
* limitations under the License.
*/
'use strict';
'use strict'
/* eslint-disable jsdoc/require-example */
const Bluebird = require('bluebird');
const fs = Bluebird.promisifyAll(require('fs'));
const PassThroughStream = require('stream').PassThrough;
const lzma = Bluebird.promisifyAll(require('lzma-native'));
const zlib = require('zlib');
const unbzip2Stream = require('unbzip2-stream');
const gzip = require('./gzip');
const udif = Bluebird.promisifyAll(require('udif'));
const archive = require('./archive');
const utils = require('./utils');
const zipArchiveHooks = require('./archive-hooks/zip');
const fileExtensions = require('../shared/file-extensions');
const path = require('path');
const errors = require('../shared/errors');
const Bluebird = require('bluebird')
const fs = Bluebird.promisifyAll(require('fs'))
const PassThroughStream = require('stream').PassThrough
const lzma = Bluebird.promisifyAll(require('lzma-native'))
const zlib = require('zlib')
const unbzip2Stream = require('unbzip2-stream')
const gzip = require('./gzip')
const udif = Bluebird.promisifyAll(require('udif'))
const archive = require('./archive')
const utils = require('./utils')
const zipArchiveHooks = require('./archive-hooks/zip')
const fileExtensions = require('../shared/file-extensions')
const path = require('path')
const errors = require('../shared/errors')
/**
* @summary Image handlers
@ -67,7 +67,7 @@ module.exports = {
}
},
transform: unbzip2Stream()
});
})
},
/**
@ -85,14 +85,14 @@ module.exports = {
*/
'application/gzip': (imagePath, options) => {
return Bluebird.using(fs.openAsync(imagePath, 'r').disposer((fileDescriptor) => {
return fs.closeAsync(fileDescriptor);
return fs.closeAsync(fileDescriptor)
}), (fileDescriptor) => {
return gzip.getUncompressedSize({
size: options.size,
read: (position, count) => {
return utils.readBufferFromImageFileDescriptor(fileDescriptor, position, count);
return utils.readBufferFromImageFileDescriptor(fileDescriptor, position, count)
}
});
})
}).then((uncompressedSize) => {
return Bluebird.props({
path: imagePath,
@ -107,8 +107,8 @@ module.exports = {
}
},
transform: zlib.createGunzip()
});
});
})
})
},
/**
@ -126,14 +126,14 @@ module.exports = {
*/
'application/x-xz': (imagePath, options) => {
return Bluebird.using(fs.openAsync(imagePath, 'r').disposer((fileDescriptor) => {
return fs.closeAsync(fileDescriptor);
return fs.closeAsync(fileDescriptor)
}), (fileDescriptor) => {
return lzma.parseFileIndexAsync({
fileSize: options.size,
read: (count, position, callback) => {
utils.readBufferFromImageFileDescriptor(fileDescriptor, position, count).asCallback(callback);
utils.readBufferFromImageFileDescriptor(fileDescriptor, position, count).asCallback(callback)
}
});
})
}).then((metadata) => {
return {
path: imagePath,
@ -148,8 +148,8 @@ module.exports = {
}
},
transform: lzma.createDecompressor()
};
});
}
})
},
/**
@ -181,7 +181,7 @@ module.exports = {
}
},
transform: new PassThroughStream()
};
}
}).catch((error) => {
if (/invalid footer/i.test(error.message)) {
throw errors.createUserError({
@ -189,10 +189,10 @@ module.exports = {
description: `There was an error reading "${path.basename(imagePath)}". ` +
'The image does not appear to be a valid Apple Disk Image (dmg), or may have the wrong filename extension.\n\n' +
`Error: ${error.description || error.message}`
});
})
}
throw error;
});
throw error
})
},
/**
@ -206,7 +206,7 @@ module.exports = {
* @returns {Promise}
*/
'application/zip': (imagePath) => {
return archive.extractImage(imagePath, zipArchiveHooks);
return archive.extractImage(imagePath, zipArchiveHooks)
},
/**
@ -235,7 +235,7 @@ module.exports = {
}
},
transform: new PassThroughStream()
});
})
}
};
}

View File

@ -14,17 +14,17 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const Bluebird = require('bluebird');
const fs = Bluebird.promisifyAll(require('fs'));
const stream = require('stream');
const mime = require('./mime');
const handlers = require('./handlers');
const supportedFileTypes = require('./supported');
const errors = require('../shared/errors');
const parsePartitions = require('./parse-partitions');
const _ = require('lodash')
const Bluebird = require('bluebird')
const fs = Bluebird.promisifyAll(require('fs'))
const stream = require('stream')
const mime = require('./mime')
const handlers = require('./handlers')
const supportedFileTypes = require('./supported')
const errors = require('../shared/errors')
const parsePartitions = require('./parse-partitions')
/**
* @summary Get an image stream from a file
@ -73,19 +73,19 @@ exports.getFromFilePath = (file) => {
throw errors.createUserError({
title: 'Invalid image',
description: 'The image must be a file'
});
})
}
return mime.getMimeTypeFromFileName(file).then((type) => {
const mimeType = _.has(handlers, type) ? type : mime.DEFAULT_MIME_TYPE;
const mimeType = _.has(handlers, type) ? type : mime.DEFAULT_MIME_TYPE
return _.invoke(handlers, mimeType, file, {
size: fileStats.size
});
});
})
})
}).then((image) => {
return _.omitBy(image, _.isUndefined);
});
};
return _.omitBy(image, _.isUndefined)
})
}
/**
* @summary Get image metadata
@ -120,10 +120,10 @@ exports.getImageMetadata = (file) => {
.then(parsePartitions)
.then((image) => {
return _.omitBy(image, (property) => {
return property instanceof stream.Stream || _.isNil(property);
});
});
};
return property instanceof stream.Stream || _.isNil(property)
})
})
}
/**
* @summary Supported file types
@ -137,4 +137,4 @@ exports.getImageMetadata = (file) => {
* console.log('Supported file type: ' + fileType.extension);
* });
*/
exports.supportedFileTypes = supportedFileTypes;
exports.supportedFileTypes = supportedFileTypes

View File

@ -14,21 +14,21 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const Bluebird = require('bluebird');
const fs = Bluebird.promisifyAll(require('fs'));
const fileType = require('file-type');
const mime = require('mime-types');
const utils = require('./utils');
const _ = require('lodash')
const Bluebird = require('bluebird')
const fs = Bluebird.promisifyAll(require('fs'))
const fileType = require('file-type')
const mime = require('mime-types')
const utils = require('./utils')
/**
* @summary The default MIME type
* @type {String}
* @constant
*/
exports.DEFAULT_MIME_TYPE = 'application/octet-stream';
exports.DEFAULT_MIME_TYPE = 'application/octet-stream'
/**
* @summary Get file's mime type, by reading the initial 262 bytes if necessary
@ -45,20 +45,20 @@ exports.DEFAULT_MIME_TYPE = 'application/octet-stream';
* });
*/
exports.getMimeTypeFromFileName = (filename) => {
const mimeType = mime.lookup(filename);
const mimeType = mime.lookup(filename)
if (mimeType) {
return Bluebird.resolve(mimeType);
return Bluebird.resolve(mimeType)
}
const FILE_TYPE_ID_START = 0;
const FILE_TYPE_ID_BYTES = 262;
const FILE_TYPE_ID_START = 0
const FILE_TYPE_ID_BYTES = 262
return Bluebird.using(fs.openAsync(filename, 'r').disposer((fileDescriptor) => {
return fs.closeAsync(fileDescriptor);
return fs.closeAsync(fileDescriptor)
}), (fileDescriptor) => {
return utils.readBufferFromImageFileDescriptor(fileDescriptor, FILE_TYPE_ID_START, FILE_TYPE_ID_BYTES).then((buffer) => {
return _.get(fileType(buffer), [ 'mime' ], exports.DEFAULT_MIME_TYPE);
});
});
};
return _.get(fileType(buffer), [ 'mime' ], exports.DEFAULT_MIME_TYPE)
})
})
}

View File

@ -14,40 +14,40 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const Bluebird = require('bluebird');
const MBR = require('mbr');
const GPT = require('gpt');
const _ = require('lodash')
const Bluebird = require('bluebird')
const MBR = require('mbr')
const GPT = require('gpt')
/**
* @summary Maximum number of bytes to read from the stream
* @type {Number}
* @constant
*/
const MAX_STREAM_BYTES = 65536;
const MAX_STREAM_BYTES = 65536
/**
* @summary Initial number of bytes read
* @type {Number}
* @constant
*/
const INITIAL_LENGTH = 0;
const INITIAL_LENGTH = 0
/**
* @summary Initial block size
* @type {Number}
* @constant
*/
const INITIAL_BLOCK_SIZE = 512;
const INITIAL_BLOCK_SIZE = 512
/**
* @summary Maximum block size to check for
* @type {Number}
* @constant
*/
const MAX_BLOCK_SIZE = 4096;
const MAX_BLOCK_SIZE = 4096
/**
* @summary Attempt to parse the GPT from various block sizes
@ -66,23 +66,23 @@ const MAX_BLOCK_SIZE = 4096;
* }
*/
const detectGPT = (buffer) => {
let blockSize = INITIAL_BLOCK_SIZE;
let gpt = null;
let blockSize = INITIAL_BLOCK_SIZE
let gpt = null
// Attempt to parse the GPT from several offsets,
// as the block size of the image may vary (512,1024,2048,4096);
// For example, ISOs will usually have a block size of 4096,
// but raw images a block size of 512 bytes
while (blockSize <= MAX_BLOCK_SIZE) {
gpt = _.attempt(GPT.parse, buffer.slice(blockSize));
gpt = _.attempt(GPT.parse, buffer.slice(blockSize))
if (!_.isError(gpt)) {
return gpt;
return gpt
}
blockSize += blockSize;
blockSize += blockSize
}
return null;
};
return null
}
/**
* @summary Attempt to parse the MBR & GPT from a given buffer
@ -100,13 +100,13 @@ const detectGPT = (buffer) => {
* }
*/
const parsePartitionTables = (image, buffer) => {
const mbr = _.attempt(MBR.parse, buffer);
let gpt = null;
const mbr = _.attempt(MBR.parse, buffer)
let gpt = null
if (!_.isError(mbr)) {
image.hasMBR = true;
gpt = detectGPT(buffer);
image.hasGPT = !_.isNil(gpt);
image.hasMBR = true
gpt = detectGPT(buffer)
image.hasGPT = !_.isNil(gpt)
}
// As MBR and GPT partition entries have a different structure,
@ -121,8 +121,8 @@ const parsePartitionTables = (image, buffer) => {
firstLBA: partition.firstLBA,
lastLBA: partition.lastLBA,
extended: false
};
});
}
})
} else if (image.hasMBR) {
image.partitions = _.map(mbr.partitions, (partition) => {
return {
@ -132,10 +132,10 @@ const parsePartitionTables = (image, buffer) => {
firstLBA: partition.firstLBA,
lastLBA: partition.lastLBA,
extended: partition.extended
};
});
}
})
}
};
}
/**
* @summary Attempt to read the MBR and GPT from an imagestream
@ -159,44 +159,44 @@ const parsePartitionTables = (image, buffer) => {
*/
module.exports = (image) => {
return new Bluebird((resolve, reject) => {
const chunks = [];
let length = INITIAL_LENGTH;
let destroyed = false;
const chunks = []
let length = INITIAL_LENGTH
let destroyed = false
image.hasMBR = false;
image.hasGPT = false;
image.hasMBR = false
image.hasGPT = false
let stream = image.stream.pipe(image.transform);
let stream = image.stream.pipe(image.transform)
stream.on('error', reject);
stream.on('error', reject)
// We need to use the "old" flowing mode here,
// as some dependencies don't implement the "readable"
// mode properly (i.e. bzip2)
stream.on('data', (chunk) => {
chunks.push(chunk);
length += chunk.length;
chunks.push(chunk)
length += chunk.length
// Once we've read enough bytes, terminate the stream
if (length >= MAX_STREAM_BYTES && !destroyed) {
// Prefer close() over destroy(), as some streams
// from dependencies exhibit quirky behavior when destroyed
if (image.stream.close) {
image.stream.close();
image.stream.close()
} else {
image.stream.destroy();
image.stream.destroy()
}
// Remove references to stream to allow them being GCed
image.stream = null;
image.transform = null;
stream = null;
destroyed = true;
image.stream = null
image.transform = null
stream = null
destroyed = true
// Parse the MBR, GPT and partitions from the obtained buffer
parsePartitionTables(image, Buffer.concat(chunks));
resolve(image);
parsePartitionTables(image, Buffer.concat(chunks))
resolve(image)
}
});
});
};
})
})
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @summary Supported filename extensions
@ -77,4 +77,4 @@ module.exports = [
extension: 'rpi-sdimg',
type: 'image'
}
];
]

View File

@ -14,11 +14,11 @@
* limitations under the License.
*/
'use strict';
'use strict'
const Bluebird = require('bluebird');
const fs = Bluebird.promisifyAll(require('fs'));
const errors = require('../shared/errors');
const Bluebird = require('bluebird')
const fs = Bluebird.promisifyAll(require('fs'))
const errors = require('../shared/errors')
/**
* @summary Read a buffer from an image file descriptor
@ -39,19 +39,19 @@ const errors = require('../shared/errors');
* });
*/
exports.readBufferFromImageFileDescriptor = (fileDescriptor, position, count) => {
const BUFFER_FILL_VALUE = 0;
const BUFFER_START_POSITION = 0;
const buffer = Buffer.alloc(count, BUFFER_FILL_VALUE);
const BUFFER_FILL_VALUE = 0
const BUFFER_START_POSITION = 0
const buffer = Buffer.alloc(count, BUFFER_FILL_VALUE)
return fs.readAsync(fileDescriptor, buffer, BUFFER_START_POSITION, count, position).tap((bytesRead) => {
if (bytesRead !== count) {
throw errors.createUserError({
title: 'Looks like the image is truncated',
description: `We tried to read ${count} bytes at ${position}, but got ${bytesRead} bytes instead`
});
})
}
}).return(buffer);
};
}).return(buffer)
}
/**
* @summary Extract the data of a readable stream
@ -75,15 +75,15 @@ exports.readBufferFromImageFileDescriptor = (fileDescriptor, position, count) =>
*/
exports.extractStream = (stream) => {
return new Bluebird((resolve, reject) => {
const chunks = [];
const chunks = []
stream.on('data', (chunk) => {
chunks.push(chunk);
});
chunks.push(chunk)
})
stream.on('error', reject);
stream.on('error', reject)
stream.on('end', () => {
resolve(Buffer.concat(chunks));
});
});
};
resolve(Buffer.concat(chunks))
})
})
}

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const pathIsInside = require('path-is-inside');
const _ = require('lodash')
const pathIsInside = require('path-is-inside')
/**
* @summary The default unknown size for things such as images and drives
@ -25,7 +25,7 @@ const pathIsInside = require('path-is-inside');
* @private
* @type {Number}
*/
const UNKNOWN_SIZE = 0;
const UNKNOWN_SIZE = 0
/**
* @summary Check if a drive is locked
@ -49,8 +49,8 @@ const UNKNOWN_SIZE = 0;
* }
*/
exports.isDriveLocked = (drive) => {
return Boolean(_.get(drive, [ 'protected' ], false));
};
return Boolean(_.get(drive, [ 'protected' ], false))
}
/**
* @summary Check if a drive is a system drive
@ -71,8 +71,8 @@ exports.isDriveLocked = (drive) => {
* }
*/
exports.isSystemDrive = (drive) => {
return Boolean(_.get(drive, [ 'system' ], false));
};
return Boolean(_.get(drive, [ 'system' ], false))
}
/**
* @summary Check if a drive is source drive
@ -108,17 +108,17 @@ exports.isSystemDrive = (drive) => {
* }
*/
exports.isSourceDrive = (drive, image) => {
const mountpoints = _.get(drive, [ 'mountpoints' ], []);
const imagePath = _.get(image, [ 'path' ]);
const mountpoints = _.get(drive, [ 'mountpoints' ], [])
const imagePath = _.get(image, [ 'path' ])
if (!imagePath || _.isEmpty(mountpoints)) {
return false;
return false
}
return _.some(_.map(mountpoints, (mountpoint) => {
return pathIsInside(imagePath, mountpoint.path);
}));
};
return pathIsInside(imagePath, mountpoint.path)
}))
}
/**
* @summary Check if a drive is large enough for an image
@ -142,7 +142,7 @@ exports.isSourceDrive = (drive, image) => {
* }
*/
exports.isDriveLargeEnough = (drive, image) => {
const driveSize = _.get(drive, [ 'size' ], UNKNOWN_SIZE);
const driveSize = _.get(drive, [ 'size' ], UNKNOWN_SIZE)
if (_.get(image, [ 'size', 'final', 'estimation' ])) {
// If the drive size is smaller than the original image size, and
@ -150,22 +150,22 @@ exports.isDriveLargeEnough = (drive, image) => {
// here, based on the assumption that the final size will never
// be less than the original size.
if (driveSize < _.get(image, [ 'size', 'original' ], UNKNOWN_SIZE)) {
return false;
return false
}
// If the final image size is just an estimation then consider it
// large enough. In the worst case, the user gets an error saying
// the drive has ran out of space, instead of prohibiting the flash
// at all, when the estimation may be wrong.
return true;
return true
}
return driveSize >= _.get(image, [
'size',
'final',
'value'
], UNKNOWN_SIZE);
};
], UNKNOWN_SIZE)
}
/**
* @summary Check if a drive is is valid, i.e. not locked and large enough for an image
@ -195,8 +195,8 @@ exports.isDriveValid = (drive, image) => {
!this.isDriveLocked(drive),
this.isDriveLargeEnough(drive, image),
!this.isSourceDrive(drive, image)
]);
};
])
}
/**
* @summary Check if a drive meets the recommended drive size suggestion
@ -228,8 +228,8 @@ exports.isDriveValid = (drive, image) => {
* }
*/
exports.isDriveSizeRecommended = (drive, image) => {
return _.get(drive, [ 'size' ], UNKNOWN_SIZE) >= _.get(image, [ 'recommendedDriveSize' ], UNKNOWN_SIZE);
};
return _.get(drive, [ 'size' ], UNKNOWN_SIZE) >= _.get(image, [ 'recommendedDriveSize' ], UNKNOWN_SIZE)
}
/**
* @summary Drive/image compatibility status messages.
@ -286,7 +286,7 @@ exports.COMPATIBILITY_STATUS_MESSAGES = {
* The drive contains the image and therefore cannot be written to.
*/
CONTAINS_IMAGE: 'Drive Contains Image'
};
}
/**
* @summary Drive/image compatibility status types.
@ -299,7 +299,7 @@ exports.COMPATIBILITY_STATUS_MESSAGES = {
exports.COMPATIBILITY_STATUS_TYPES = {
WARNING: 1,
ERROR: 2
};
}
/**
* @summary Get drive/image compatibility in an object
@ -339,39 +339,39 @@ exports.COMPATIBILITY_STATUS_TYPES = {
* }
*/
exports.getDriveImageCompatibilityStatuses = (drive, image) => {
const statusList = [];
const statusList = []
// Mind the order of the if-statements if you modify.
if (exports.isSourceDrive(drive, image)) {
statusList.push({
type: exports.COMPATIBILITY_STATUS_TYPES.ERROR,
message: exports.COMPATIBILITY_STATUS_MESSAGES.CONTAINS_IMAGE
});
})
} else if (exports.isDriveLocked(drive)) {
statusList.push({
type: exports.COMPATIBILITY_STATUS_TYPES.ERROR,
message: exports.COMPATIBILITY_STATUS_MESSAGES.LOCKED
});
})
} else if (!_.isNil(drive) && !exports.isDriveLargeEnough(drive, image)) {
statusList.push({
type: exports.COMPATIBILITY_STATUS_TYPES.ERROR,
message: exports.COMPATIBILITY_STATUS_MESSAGES.TOO_SMALL
});
})
} else {
if (exports.isSystemDrive(drive)) {
statusList.push({
type: exports.COMPATIBILITY_STATUS_TYPES.WARNING,
message: exports.COMPATIBILITY_STATUS_MESSAGES.SYSTEM
});
})
}
if (!_.isNil(drive) && !exports.isDriveSizeRecommended(drive, image)) {
statusList.push({
type: exports.COMPATIBILITY_STATUS_TYPES.WARNING,
message: exports.COMPATIBILITY_STATUS_MESSAGES.SIZE_NOT_RECOMMENDED
});
})
}
}
return statusList;
};
return statusList
}

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const _ = require('lodash')
/**
* @summary Create an error details object
@ -38,9 +38,9 @@ const _ = require('lodash');
*/
const createErrorDetails = (options) => {
return _.pick(_.mapValues(options, (value) => {
return _.isFunction(value) ? value : _.constant(value);
}), [ 'title', 'description' ]);
};
return _.isFunction(value) ? value : _.constant(value)
}), [ 'title', 'description' ])
}
/**
* @summary Human-friendly error messages
@ -57,7 +57,7 @@ exports.HUMAN_FRIENDLY = {
*/
ENOENT: createErrorDetails({
title: (error) => {
return `No such file or directory: ${error.path}`;
return `No such file or directory: ${error.path}`
},
description: 'The file you\'re trying to access doesn\'t exist'
}),
@ -91,7 +91,7 @@ exports.HUMAN_FRIENDLY = {
/* eslint-enable new-cap */
};
}
/**
* @summary Get user friendly property from an error
@ -113,14 +113,14 @@ exports.HUMAN_FRIENDLY = {
* }
*/
const getUserFriendlyMessageProperty = (error, property) => {
const code = _.get(error, [ 'code' ]);
const code = _.get(error, [ 'code' ])
if (_.isNil(code) || !_.isString(code)) {
return null;
return null
}
return _.invoke(exports.HUMAN_FRIENDLY, [ code, property ], error);
};
return _.invoke(exports.HUMAN_FRIENDLY, [ code, property ], error)
}
/**
* @summary Check if a string is blank
@ -135,7 +135,7 @@ const getUserFriendlyMessageProperty = (error, property) => {
* console.log('The string is blank');
* }
*/
const isBlank = _.flow([ _.trim, _.isEmpty ]);
const isBlank = _.flow([ _.trim, _.isEmpty ])
/**
* @summary Get the title of an error
@ -156,26 +156,26 @@ const isBlank = _.flow([ _.trim, _.isEmpty ]);
*/
exports.getTitle = (error) => {
if (!_.isError(error) && !_.isPlainObject(error) && !_.isNil(error)) {
return _.toString(error);
return _.toString(error)
}
const codeTitle = getUserFriendlyMessageProperty(error, 'title');
const codeTitle = getUserFriendlyMessageProperty(error, 'title')
if (!_.isNil(codeTitle)) {
return codeTitle;
return codeTitle
}
const message = _.get(error, [ 'message' ]);
const message = _.get(error, [ 'message' ])
if (!isBlank(message)) {
return message;
return message
}
const code = _.get(error, [ 'code' ]);
const code = _.get(error, [ 'code' ])
if (!_.isNil(code) && !isBlank(code)) {
return `Error code: ${code}`;
return `Error code: ${code}`
}
return 'An error ocurred';
};
return 'An error ocurred'
}
/**
* @summary Get the description of an error
@ -195,36 +195,36 @@ exports.getTitle = (error) => {
exports.getDescription = (error, options = {}) => {
_.defaults(options, {
userFriendlyDescriptionsOnly: false
});
})
if (!_.isError(error) && !_.isPlainObject(error)) {
return '';
return ''
}
if (!isBlank(error.description)) {
return error.description;
return error.description
}
const codeDescription = getUserFriendlyMessageProperty(error, 'description');
const codeDescription = getUserFriendlyMessageProperty(error, 'description')
if (!_.isNil(codeDescription)) {
return codeDescription;
return codeDescription
}
if (options.userFriendlyDescriptionsOnly) {
return '';
return ''
}
if (error.stack) {
return error.stack;
return error.stack
}
if (_.isEmpty(error)) {
return '';
return ''
}
const INDENTATION_SPACES = 2;
return JSON.stringify(error, null, INDENTATION_SPACES);
};
const INDENTATION_SPACES = 2
return JSON.stringify(error, null, INDENTATION_SPACES)
}
/**
* @summary Create an error
@ -247,18 +247,18 @@ exports.getDescription = (error, options = {}) => {
*/
exports.createError = (options) => {
if (isBlank(options.title)) {
throw new Error(`Invalid error title: ${options.title}`);
throw new Error(`Invalid error title: ${options.title}`)
}
const error = new Error(options.title);
error.description = options.description;
const error = new Error(options.title)
error.description = options.description
if (!_.isNil(options.report) && !options.report) {
error.report = false;
error.report = false
}
return error;
};
return error
}
/**
* @summary Create a user error
@ -289,8 +289,8 @@ exports.createUserError = (options) => {
title: options.title,
description: options.description,
report: false
});
};
})
}
/**
* @summary Check if an error is an user error
@ -308,8 +308,8 @@ exports.createUserError = (options) => {
* }
*/
exports.isUserError = (error) => {
return _.isNil(error.report) ? false : !error.report;
};
return _.isNil(error.report) ? false : !error.report
}
/**
* @summary Convert an Error object to a JSON object
@ -327,8 +327,8 @@ exports.isUserError = (error) => {
*/
exports.toJSON = (error) => {
// Handle string error objects to be on the safe side
const isErrorLike = _.isError(error) || _.isPlainObject(error);
const errorObject = isErrorLike ? error : new Error(error);
const isErrorLike = _.isError(error) || _.isPlainObject(error)
const errorObject = isErrorLike ? error : new Error(error)
return {
message: errorObject.message,
@ -336,8 +336,8 @@ exports.toJSON = (error) => {
stack: errorObject.stack,
report: errorObject.report,
code: errorObject.code
};
};
}
}
/**
* @summary Convert a JSON object to an Error object
@ -354,5 +354,5 @@ exports.toJSON = (error) => {
* > 'foo'
*/
exports.fromJSON = (json) => {
return _.assign(new Error(json.message), json);
};
return _.assign(new Error(json.message), json)
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
'use strict'
/**
* @summary Etcher exit codes
@ -63,4 +63,4 @@ module.exports = {
*/
CANCELLED: 3
};
}

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const _ = require('lodash')
/**
* @summary Get the extensions of a file
@ -36,8 +36,8 @@ exports.getFileExtensions = _.memoize((filePath) => {
.split('.')
.tail()
.map(_.toLower)
.value();
});
.value()
})
/**
* @summary Get the last file extension
@ -53,8 +53,8 @@ exports.getFileExtensions = _.memoize((filePath) => {
* > [ 'gz' ]
*/
exports.getLastFileExtension = (filePath) => {
return _.last(exports.getFileExtensions(filePath));
};
return _.last(exports.getFileExtensions(filePath))
}
/**
* @summary Get the penultimate file extension
@ -70,5 +70,5 @@ exports.getLastFileExtension = (filePath) => {
* > [ 'img' ]
*/
exports.getPenultimateFileExtension = (filePath) => {
return _.last(_.initial(exports.getFileExtensions(filePath)));
};
return _.last(_.initial(exports.getFileExtensions(filePath)))
}

View File

@ -14,9 +14,9 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const _ = require('lodash')
/**
* @summary Application messages
@ -119,4 +119,4 @@ module.exports = {
}
};
}

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const store = require('../store');
const _ = require('lodash')
const store = require('../store')
/**
* @summary Check if there are available drives
@ -32,8 +32,8 @@ const store = require('../store');
* }
*/
exports.hasAvailableDrives = () => {
return !_.isEmpty(exports.getDrives());
};
return !_.isEmpty(exports.getDrives())
}
/**
* @summary Set a list of drives
@ -52,8 +52,8 @@ exports.setDrives = (drives) => {
store.dispatch({
type: store.Actions.SET_AVAILABLE_DRIVES,
data: drives
});
};
})
}
/**
* @summary Get detected drives
@ -66,5 +66,5 @@ exports.setDrives = (drives) => {
* const drives = availableDrives.getDrives();
*/
exports.getDrives = () => {
return store.getState().toJS().availableDrives;
};
return store.getState().toJS().availableDrives
}

View File

@ -14,11 +14,11 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const store = require('../store');
const units = require('../units');
const _ = require('lodash')
const store = require('../store')
const units = require('../units')
/**
* @summary Reset flash state
@ -31,8 +31,8 @@ const units = require('../units');
exports.resetState = () => {
store.dispatch({
type: store.Actions.RESET_FLASH_STATE
});
};
})
}
/**
* @summary Check if currently flashing
@ -47,8 +47,8 @@ exports.resetState = () => {
* }
*/
exports.isFlashing = () => {
return store.getState().toJS().isFlashing;
};
return store.getState().toJS().isFlashing
}
/**
* @summary Set the flashing flag
@ -67,8 +67,8 @@ exports.isFlashing = () => {
exports.setFlashingFlag = () => {
store.dispatch({
type: store.Actions.SET_FLASHING_FLAG
});
};
})
}
/**
* @summary Unset the flashing flag
@ -92,8 +92,8 @@ exports.unsetFlashingFlag = (results) => {
store.dispatch({
type: store.Actions.UNSET_FLASHING_FLAG,
data: results
});
};
})
}
/**
* @summary Set the flashing state
@ -124,15 +124,15 @@ exports.setProgressState = (state) => {
speed: _.attempt(() => {
if (_.isNumber(state.speed) && !_.isNaN(state.speed)) {
// Preserve only two decimal places
const PRECISION = 2;
return _.round(units.bytesToMegabytes(state.speed), PRECISION);
const PRECISION = 2
return _.round(units.bytesToMegabytes(state.speed), PRECISION)
}
return null;
return null
})
}
});
};
})
}
/**
* @summary Get the flash results
@ -145,8 +145,8 @@ exports.setProgressState = (state) => {
* const results = flashState.getFlashResults();
*/
exports.getFlashResults = () => {
return store.getState().toJS().flashResults;
};
return store.getState().toJS().flashResults
}
/**
* @summary Get the current flash state
@ -159,8 +159,8 @@ exports.getFlashResults = () => {
* const flashState = flashState.getFlashState();
*/
exports.getFlashState = () => {
return store.getState().get('flashState').toJS();
};
return store.getState().get('flashState').toJS()
}
/**
* @summary Determine if the last flash was cancelled
@ -178,8 +178,8 @@ exports.getFlashState = () => {
* }
*/
exports.wasLastFlashCancelled = () => {
return _.get(exports.getFlashResults(), [ 'cancelled' ], false);
};
return _.get(exports.getFlashResults(), [ 'cancelled' ], false)
}
/**
* @summary Get last flash source checksum
@ -195,8 +195,8 @@ exports.wasLastFlashCancelled = () => {
* const checksum = flashState.getLastFlashSourceChecksum();
*/
exports.getLastFlashSourceChecksum = () => {
return exports.getFlashResults().sourceChecksum;
};
return exports.getFlashResults().sourceChecksum
}
/**
* @summary Get last flash error code
@ -212,8 +212,8 @@ exports.getLastFlashSourceChecksum = () => {
* const errorCode = flashState.getLastFlashErrorCode();
*/
exports.getLastFlashErrorCode = () => {
return exports.getFlashResults().errorCode;
};
return exports.getFlashResults().errorCode
}
/**
* @summary Get current (or last) flash uuid
@ -229,5 +229,5 @@ exports.getLastFlashErrorCode = () => {
* const uuid = flashState.getFlashUuid();
*/
exports.getFlashUuid = () => {
return store.getState().toJS().flashUuid;
};
return store.getState().toJS().flashUuid
}

View File

@ -14,11 +14,11 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const store = require('../store');
const availableDrives = require('./available-drives');
const _ = require('lodash')
const store = require('../store')
const availableDrives = require('./available-drives')
/**
* @summary Set a drive
@ -34,8 +34,8 @@ exports.setDrive = (drive) => {
store.dispatch({
type: store.Actions.SELECT_DRIVE,
data: drive
});
};
})
}
/**
* @summary Toggle set drive
@ -49,11 +49,11 @@ exports.setDrive = (drive) => {
*/
exports.toggleSetDrive = (drive) => {
if (exports.isCurrentDrive(drive)) {
exports.removeDrive();
exports.removeDrive()
} else {
exports.setDrive(drive);
exports.setDrive(drive)
}
};
}
/**
* @summary Set a image
@ -71,8 +71,8 @@ exports.setImage = (image) => {
store.dispatch({
type: store.Actions.SELECT_IMAGE,
data: image
});
};
})
}
/**
* @summary Get drive
@ -87,8 +87,8 @@ exports.setImage = (image) => {
exports.getDrive = () => {
return _.find(availableDrives.getDrives(), {
device: store.getState().getIn([ 'selection', 'drive' ])
});
};
})
}
/**
* @summary Get the selected image
@ -101,8 +101,8 @@ exports.getDrive = () => {
* const image = selectionState.getImage();
*/
exports.getImage = () => {
return _.get(store.getState().toJS(), [ 'selection', 'image' ]);
};
return _.get(store.getState().toJS(), [ 'selection', 'image' ])
}
/**
* @summary Get image path
@ -119,8 +119,8 @@ exports.getImagePath = () => {
'selection',
'image',
'path'
]);
};
])
}
/**
* @summary Get image size
@ -139,8 +139,8 @@ exports.getImageSize = () => {
'size',
'final',
'value'
]);
};
])
}
/**
* @summary Get image url
@ -157,8 +157,8 @@ exports.getImageUrl = () => {
'selection',
'image',
'url'
]);
};
])
}
/**
* @summary Get image name
@ -175,8 +175,8 @@ exports.getImageName = () => {
'selection',
'image',
'name'
]);
};
])
}
/**
* @summary Get image logo
@ -193,8 +193,8 @@ exports.getImageLogo = () => {
'selection',
'image',
'logo'
]);
};
])
}
/**
* @summary Get image support url
@ -211,8 +211,8 @@ exports.getImageSupportUrl = () => {
'selection',
'image',
'supportUrl'
]);
};
])
}
/**
* @summary Get image recommended drive size
@ -229,8 +229,8 @@ exports.getImageRecommendedDriveSize = () => {
'selection',
'image',
'recommendedDriveSize'
]);
};
])
}
/**
* @summary Check if there is a selected drive
@ -245,8 +245,8 @@ exports.getImageRecommendedDriveSize = () => {
* }
*/
exports.hasDrive = () => {
return Boolean(exports.getDrive());
};
return Boolean(exports.getDrive())
}
/**
* @summary Check if there is a selected image
@ -261,8 +261,8 @@ exports.hasDrive = () => {
* }
*/
exports.hasImage = () => {
return Boolean(exports.getImage());
};
return Boolean(exports.getImage())
}
/**
* @summary Remove drive
@ -275,8 +275,8 @@ exports.hasImage = () => {
exports.removeDrive = () => {
store.dispatch({
type: store.Actions.REMOVE_DRIVE
});
};
})
}
/**
* @summary Remove image
@ -289,8 +289,8 @@ exports.removeDrive = () => {
exports.removeImage = () => {
store.dispatch({
type: store.Actions.REMOVE_IMAGE
});
};
})
}
/**
* @summary Clear selections
@ -310,13 +310,13 @@ exports.clear = (options = {}) => {
if (!options.preserveImage) {
store.dispatch({
type: store.Actions.REMOVE_IMAGE
});
})
}
store.dispatch({
type: store.Actions.REMOVE_DRIVE
});
};
})
}
/**
* @summary Check if a drive is the current drive
@ -333,8 +333,8 @@ exports.clear = (options = {}) => {
*/
exports.isCurrentDrive = (drive) => {
if (!drive) {
return false;
return false
}
return drive === _.get(exports.getDrive(), [ 'device' ]);
};
return drive === _.get(exports.getDrive(), [ 'device' ])
}

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const path = require('path');
const bindings = require('bindings');
const path = require('path')
const bindings = require('bindings')
/**
* @summary Load a native module
@ -40,5 +40,5 @@ exports.load = (moduleName) => {
/* eslint-enable camelcase */
});
};
})
}

View File

@ -14,23 +14,23 @@
* limitations under the License.
*/
'use strict';
'use strict'
const os = require('os');
const nativeModule = require('./native-module');
const Bluebird = require('bluebird');
const childProcess = Bluebird.promisifyAll(require('child_process'));
const sudoPrompt = Bluebird.promisifyAll(require('sudo-prompt'));
const commandJoin = require('command-join');
const _ = require('lodash');
const errors = require('./errors');
const os = require('os')
const nativeModule = require('./native-module')
const Bluebird = require('bluebird')
const childProcess = Bluebird.promisifyAll(require('child_process'))
const sudoPrompt = Bluebird.promisifyAll(require('sudo-prompt'))
const commandJoin = require('command-join')
const _ = require('lodash')
const errors = require('./errors')
/**
* @summary The user id of the UNIX "superuser"
* @constant
* @type {Number}
*/
const UNIX_SUPERUSER_USER_ID = 0;
const UNIX_SUPERUSER_USER_ID = 0
/**
* @summary Check if the current process is running with elevated permissions
@ -64,11 +64,11 @@ exports.isElevated = () => {
.then(_.constant(true))
.catch({
code: os.constants.errno.EPERM
}, _.constant(false));
}, _.constant(false))
}
return Bluebird.resolve(process.geteuid() === UNIX_SUPERUSER_USER_ID);
};
return Bluebird.resolve(process.geteuid() === UNIX_SUPERUSER_USER_ID)
}
/**
* @summary Get environment command prefix
@ -87,32 +87,32 @@ exports.isElevated = () => {
* childProcess.execSync(_.join(_.concat(commandPrefix, [ 'mycommand' ]), ' '));
*/
exports.getEnvironmentCommandPrefix = (environment) => {
const isWindows = os.platform() === 'win32';
const isWindows = os.platform() === 'win32'
if (_.isEmpty(environment)) {
return [];
return []
}
const argv = _.flatMap(environment, (value, key) => {
if (_.isNil(value)) {
return [];
return []
}
if (isWindows) {
return [ 'set', `${key}=${value}`, '&&' ];
return [ 'set', `${key}=${value}`, '&&' ]
}
return [ `${key}=${value}` ];
});
return [ `${key}=${value}` ]
})
if (isWindows) {
// This is a trick to make the binary afterwards catch
// the environment variables set just previously.
return _.concat(argv, [ 'call' ]);
return _.concat(argv, [ 'call' ])
}
return _.concat([ 'env' ], argv);
};
return _.concat([ 'env' ], argv)
}
/**
* @summary Quote a string
@ -126,8 +126,8 @@ exports.getEnvironmentCommandPrefix = (environment) => {
* const result = quote('foo');
*/
const quoteString = (string) => {
return `"${string}"`;
};
return `"${string}"`
}
/**
* @summary Elevate a command
@ -154,17 +154,17 @@ const quoteString = (string) => {
* });
*/
exports.elevateCommand = (command, options) => {
const isWindows = os.platform() === 'win32';
const isWindows = os.platform() === 'win32'
const prefixedCommand = _.concat(
exports.getEnvironmentCommandPrefix(options.environment),
_.map(command, (string) => {
return isWindows ? quoteString(string) : string;
return isWindows ? quoteString(string) : string
})
);
)
if (isWindows) {
const elevator = Bluebird.promisifyAll(nativeModule.load('elevator'));
const elevator = Bluebird.promisifyAll(nativeModule.load('elevator'))
return elevator.elevateAsync([
'cmd.exe',
'/c',
@ -172,8 +172,8 @@ exports.elevateCommand = (command, options) => {
]).then((results) => {
return {
cancelled: results.cancelled
};
});
}
})
}
return sudoPrompt.execAsync(commandJoin(prefixedCommand), {
@ -182,36 +182,36 @@ exports.elevateCommand = (command, options) => {
if (!_.isEmpty(stderr)) {
throw errors.createError({
title: stderr
});
})
}
return {
cancelled: false
};
}
// We're hardcoding internal error messages declared by `sudo-prompt`.
// There doesn't seem to be a better way to handle these errors, so
// for now, we should make sure we double check if the error messages
// have changed every time we upgrade `sudo-prompt`.
}).catch((error) => {
return _.includes(error.message, 'is not in the sudoers file');
return _.includes(error.message, 'is not in the sudoers file')
}, () => {
throw errors.createUserError({
title: 'Your user doesn\'t have enough privileges to proceed',
description: 'This application requires sudo privileges to be able to write to drives'
});
})
}).catch({
message: 'User did not grant permission.'
}, () => {
return {
cancelled: true
};
}
}).catch({
message: 'No polkit authentication agent found.'
}, () => {
throw errors.createUserError({
title: 'No polkit authentication agent found',
description: 'Please install a polkit authentication agent for your desktop environment of choice to continue'
});
});
};
})
})
}

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const semver = require('semver');
const _ = require('lodash')
const semver = require('semver')
/**
* @summary Application release types
@ -50,7 +50,7 @@ exports.RELEASE_TYPE = {
*/
UNKNOWN: 'UNKNOWN'
};
}
/**
* @summary Get the release type from a version string
@ -69,21 +69,21 @@ exports.RELEASE_TYPE = {
* }
*/
exports.getReleaseType = (version) => {
const GIT_HASH_REGEX = /^[0-9a-f]{7,40}$/;
const buildNumber = _.get(semver.parse(version), [ 'build' ]);
const GIT_HASH_REGEX = /^[0-9a-f]{7,40}$/
const buildNumber = _.get(semver.parse(version), [ 'build' ])
if (!_.isNil(buildNumber)) {
if (_.isEmpty(buildNumber)) {
return exports.RELEASE_TYPE.PRODUCTION;
return exports.RELEASE_TYPE.PRODUCTION
}
if (GIT_HASH_REGEX.test(_.first(buildNumber))) {
return exports.RELEASE_TYPE.SNAPSHOT;
return exports.RELEASE_TYPE.SNAPSHOT
}
}
return exports.RELEASE_TYPE.UNKNOWN;
};
return exports.RELEASE_TYPE.UNKNOWN
}
/**
* @summary Check if a version is a stable release
@ -99,5 +99,5 @@ exports.getReleaseType = (version) => {
* }
*/
exports.isStableRelease = (version) => {
return _.isEmpty(_.get(semver.parse(version), [ 'prerelease' ]));
};
return _.isEmpty(_.get(semver.parse(version), [ 'prerelease' ]))
}

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const errors = require('../errors');
const _ = require('lodash')
const errors = require('../errors')
/**
* @summary Robot commands
@ -44,7 +44,7 @@ exports.COMMAND = {
*/
LOG: 'log'
};
}
/**
* @summary Check whether we should emit parseable output
@ -60,9 +60,9 @@ exports.COMMAND = {
* }
*/
exports.isEnabled = (environment) => {
const value = _.get(environment, [ 'ETCHER_CLI_ROBOT' ], false);
return Boolean(value === 'false' ? false : value);
};
const value = _.get(environment, [ 'ETCHER_CLI_ROBOT' ], false)
return Boolean(value === 'false' ? false : value)
}
/**
* @summary Build a machine-parseable message
@ -85,14 +85,14 @@ exports.buildMessage = (title, data = {}) => {
if (!_.isPlainObject(data)) {
throw errors.createError({
title: `Invalid data: ${data}`
});
})
}
return JSON.stringify({
command: title,
data
});
};
})
}
/**
* @summary Check whether a string is a robot message
@ -116,11 +116,11 @@ exports.buildMessage = (title, data = {}) => {
*/
exports.isMessage = (string) => {
try {
return _.isPlainObject(JSON.parse(string));
return _.isPlainObject(JSON.parse(string))
} catch (error) {
return false;
return false
}
};
}
/**
* @summary Parse a machine-parseable message
@ -141,26 +141,26 @@ exports.isMessage = (string) => {
* > }
*/
exports.parseMessage = (string) => {
let output = null;
let output = null
try {
output = JSON.parse(string);
output = JSON.parse(string)
} catch (error) {
throw errors.createError({
title: 'Invalid message',
description: `${string}, ${error.message}`
});
})
}
if (!output.command || !output.data) {
throw errors.createError({
title: 'Invalid message',
description: `No command or data: ${string}`
});
})
}
return output;
};
return output
}
/**
* @summary Build a machine-parseable error message
@ -181,8 +181,8 @@ exports.parseMessage = (string) => {
* > 'foo'
*/
exports.buildErrorMessage = (error) => {
return exports.buildMessage(exports.COMMAND.ERROR, errors.toJSON(error));
};
return exports.buildMessage(exports.COMMAND.ERROR, errors.toJSON(error))
}
/**
* @summary Recompose an error message
@ -203,8 +203,8 @@ exports.buildErrorMessage = (error) => {
* > 'foo'
*/
exports.recomposeErrorMessage = (message) => {
return errors.fromJSON(message.data);
};
return errors.fromJSON(message.data)
}
/**
* @summary Get message command
@ -224,8 +224,8 @@ exports.recomposeErrorMessage = (message) => {
* > 'foo'
*/
exports.getCommand = (message) => {
return _.get(message, [ 'command' ]);
};
return _.get(message, [ 'command' ])
}
/**
* @summary Get message data
@ -247,8 +247,8 @@ exports.getCommand = (message) => {
* > { foo: 1 }
*/
exports.getData = (message) => {
return _.get(message, [ 'data' ], {});
};
return _.get(message, [ 'data' ], {})
}
/**
* @summary Print an error in a machine-friendly way
@ -261,8 +261,8 @@ exports.getData = (message) => {
* robot.printError(new Error('This is an error'));
*/
exports.printError = (error) => {
console.error(exports.buildErrorMessage(error));
};
console.error(exports.buildErrorMessage(error))
}
/**
* @summary Print a message in a machine-friendly way
@ -276,8 +276,8 @@ exports.printError = (error) => {
* robot.printMessage('progress', { percentage: 50 });
*/
exports.printMessage = (message, data) => {
console.log(exports.buildMessage(message, data));
};
console.log(exports.buildMessage(message, data))
}
/**
* @summary Log a message to the host's console
@ -290,5 +290,5 @@ exports.printMessage = (message, data) => {
* robot.log({ example: 'data' });
*/
exports.log = (data) => {
exports.printMessage(exports.COMMAND.LOG, data);
};
exports.printMessage(exports.COMMAND.LOG, data)
}

View File

@ -14,14 +14,14 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const semver = require('semver');
const Bluebird = require('bluebird');
const request = Bluebird.promisifyAll(require('request'));
const xml = Bluebird.promisifyAll(require('xml2js'));
const release = require('./release');
const _ = require('lodash')
const semver = require('semver')
const Bluebird = require('bluebird')
const request = Bluebird.promisifyAll(require('request'))
const xml = Bluebird.promisifyAll(require('xml2js'))
const release = require('./release')
/**
* @summary Etcher S3 bucket URLs
@ -46,7 +46,7 @@ exports.BUCKET_URL = {
*/
SNAPSHOT: 'https://resin-nightly-downloads.s3.amazonaws.com'
};
}
/**
* @summary Etcher S3 package name
@ -54,7 +54,7 @@ exports.BUCKET_URL = {
* @private
* @type {String}
*/
const S3_PACKAGE_NAME = 'etcher';
const S3_PACKAGE_NAME = 'etcher'
/**
* @summary Number of packages per Etcher version
@ -62,7 +62,7 @@ const S3_PACKAGE_NAME = 'etcher';
* @private
* @type {Number}
*/
const NUMBER_OF_PACKAGES = 8;
const NUMBER_OF_PACKAGES = 8
/**
* @summary Get the correct S3 bucket url from a release type
@ -81,15 +81,15 @@ const NUMBER_OF_PACKAGES = 8;
*/
exports.getBucketUrlFromReleaseType = (releaseType) => {
if (releaseType === release.RELEASE_TYPE.PRODUCTION) {
return exports.BUCKET_URL.PRODUCTION;
return exports.BUCKET_URL.PRODUCTION
}
if (releaseType === release.RELEASE_TYPE.SNAPSHOT) {
return exports.BUCKET_URL.SNAPSHOT;
return exports.BUCKET_URL.SNAPSHOT
}
return null;
};
return null
}
/**
* @summary Get all remote versions from an S3 bucket
@ -113,7 +113,7 @@ exports.getBucketUrlFromReleaseType = (releaseType) => {
*/
exports.getRemoteVersions = _.memoize((bucketUrl) => {
if (_.isNil(bucketUrl)) {
return Bluebird.reject(new Error(`Invalid bucket url: ${bucketUrl}`));
return Bluebird.reject(new Error(`Invalid bucket url: ${bucketUrl}`))
}
/* eslint-disable lodash/prefer-lodash-method */
@ -126,25 +126,25 @@ exports.getRemoteVersions = _.memoize((bucketUrl) => {
.then(xml.parseStringAsync)
.get('ListBucketResult')
.then((bucketResult) => {
return _.get(bucketResult, [ 'Contents' ], []);
return _.get(bucketResult, [ 'Contents' ], [])
})
.reduce((accumulator, entry) => {
const [ name, version ] = _.split(_.first(entry.Key), '/');
const [ name, version ] = _.split(_.first(entry.Key), '/')
if (name === S3_PACKAGE_NAME) {
if (_.isNil(accumulator[version])) {
accumulator[version] = 1;
accumulator[version] = 1
} else {
accumulator[version] += 1;
accumulator[version] += 1
}
}
return accumulator;
return accumulator
}, [])
.then((versions) => {
return _.keys(_.pickBy(versions, (occurrences) => {
return occurrences >= NUMBER_OF_PACKAGES;
}));
return occurrences >= NUMBER_OF_PACKAGES
}))
})
.catch({
code: 'ENOTFOUND'
@ -164,9 +164,9 @@ exports.getRemoteVersions = _.memoize((bucketUrl) => {
code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
}, () => {
return [];
});
});
return []
})
})
/**
* @summary Check if a version satisfies a semver range
@ -191,10 +191,10 @@ const semverSatisfies = (version, range) => {
// As a workaround, we drop the prerelease tags, if any, apply the range
// on that, and keep using the prerelease tag from then on.
// See https://github.com/npm/node-semver#prerelease-tags
const strippedVersion = `${semver.major(version)}.${semver.minor(version)}.${semver.patch(version)}`;
const strippedVersion = `${semver.major(version)}.${semver.minor(version)}.${semver.patch(version)}`
return semver.satisfies(strippedVersion, range);
};
return semver.satisfies(strippedVersion, range)
}
/**
* @summary Get the latest available version for a given release type
@ -218,18 +218,18 @@ const semverSatisfies = (version, range) => {
*/
exports.getLatestVersion = (releaseType, options = {}) => {
// For manual testing purposes
const ETCHER_FAKE_S3_LATEST_VERSION = process.env.ETCHER_FAKE_S3_LATEST_VERSION;
const ETCHER_FAKE_S3_LATEST_VERSION = process.env.ETCHER_FAKE_S3_LATEST_VERSION
if (!_.isNil(ETCHER_FAKE_S3_LATEST_VERSION)) {
if (release.getReleaseType(ETCHER_FAKE_S3_LATEST_VERSION) === releaseType) {
return Bluebird.resolve(ETCHER_FAKE_S3_LATEST_VERSION);
return Bluebird.resolve(ETCHER_FAKE_S3_LATEST_VERSION)
}
return Bluebird.resolve();
return Bluebird.resolve()
}
const bucketUrl = exports.getBucketUrlFromReleaseType(releaseType);
const bucketUrl = exports.getBucketUrlFromReleaseType(releaseType)
if (_.isNil(bucketUrl)) {
return Bluebird.reject(new Error(`No bucket URL found for release type: ${releaseType}`));
return Bluebird.reject(new Error(`No bucket URL found for release type: ${releaseType}`))
}
/* eslint-disable lodash/prefer-lodash-method */
@ -243,11 +243,11 @@ exports.getLatestVersion = (releaseType, options = {}) => {
!release.isStableRelease(version) && !options.includeUnstableChannel
])) {
return false;
return false
}
return semverSatisfies(version, options.range || '*');
return semverSatisfies(version, options.range || '*')
}).then((versions) => {
return _.last(versions.sort(semver.compare));
});
};
return _.last(versions.sort(semver.compare))
})
}

View File

@ -14,19 +14,19 @@
* limitations under the License.
*/
'use strict';
'use strict'
const Immutable = require('immutable');
const _ = require('lodash');
const redux = require('redux');
const uuidV4 = require('uuid/v4');
const constraints = require('./drive-constraints');
const supportedFormats = require('./supported-formats');
const errors = require('./errors');
const release = require('./release');
const fileExtensions = require('./file-extensions');
const utils = require('./utils');
const packageJSON = require('../../package.json');
const Immutable = require('immutable')
const _ = require('lodash')
const redux = require('redux')
const uuidV4 = require('uuid/v4')
const constraints = require('./drive-constraints')
const supportedFormats = require('./supported-formats')
const errors = require('./errors')
const release = require('./release')
const fileExtensions = require('./file-extensions')
const utils = require('./utils')
const packageJSON = require('../../package.json')
/**
* @summary Application default state
@ -53,7 +53,7 @@ const DEFAULT_STATE = Immutable.fromJS({
lastSleptUpdateNotifier: null,
lastSleptUpdateNotifierVersion: null
}
});
})
/**
* @summary Application supported action messages
@ -72,8 +72,8 @@ const ACTIONS = _.fromPairs(_.map([
'REMOVE_IMAGE',
'SET_SETTINGS'
], (message) => {
return [ message, message ];
}));
return [ message, message ]
}))
/**
* @summary Find a drive from the list of available drives
@ -91,11 +91,11 @@ const findDrive = (state, device) => {
/* eslint-disable lodash/prefer-lodash-method */
return state.get('availableDrives').find((drive) => {
return drive.get('device') === device;
});
return drive.get('device') === device
})
/* eslint-enable lodash/prefer-lodash-method */
};
}
/**
* @summary The redux store reducer
@ -117,25 +117,25 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
if (!action.data) {
throw errors.createError({
title: 'Missing drives'
});
})
}
if (!_.isArray(action.data) || !_.every(action.data, _.isPlainObject)) {
throw errors.createError({
title: `Invalid drives: ${action.data}`
});
})
}
const newState = state.set('availableDrives', Immutable.fromJS(action.data));
const newState = state.set('availableDrives', Immutable.fromJS(action.data))
const AUTOSELECT_DRIVE_COUNT = 1;
const numberOfDrives = action.data.length;
const AUTOSELECT_DRIVE_COUNT = 1
const numberOfDrives = action.data.length
if (numberOfDrives === AUTOSELECT_DRIVE_COUNT) {
const drive = _.first(action.data);
const drive = _.first(action.data)
// Even if there's no image selected, we need to call several
// drive/image related checks, and `{}` works fine with them
const image = state.getIn([ 'selection', 'image' ], Immutable.fromJS({})).toJS();
const image = state.getIn([ 'selection', 'image' ], Immutable.fromJS({})).toJS()
if (_.every([
constraints.isDriveValid(drive, image),
@ -149,73 +149,73 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
return storeReducer(newState, {
type: ACTIONS.SELECT_DRIVE,
data: drive.device
});
})
}
}
const selectedDevice = newState.getIn([ 'selection', 'drive' ]);
const selectedDevice = newState.getIn([ 'selection', 'drive' ])
if (selectedDevice && !_.find(action.data, {
device: selectedDevice
})) {
return storeReducer(newState, {
type: ACTIONS.REMOVE_DRIVE
});
})
}
return newState;
return newState
}
case ACTIONS.SET_FLASH_STATE: {
if (!state.get('isFlashing')) {
throw errors.createError({
title: 'Can\'t set the flashing state when not flashing'
});
})
}
if (!action.data.type) {
throw errors.createError({
title: 'Missing state type'
});
})
}
if (!_.isString(action.data.type)) {
throw errors.createError({
title: `Invalid state type: ${action.data.type}`
});
})
}
if (_.isNil(action.data.percentage)) {
throw errors.createError({
title: 'Missing state percentage'
});
})
}
if (!utils.isValidPercentage(action.data.percentage)) {
throw errors.createError({
title: `Invalid state percentage: ${action.data.percentage}`
});
})
}
if (_.isNil(action.data.eta)) {
throw errors.createError({
title: 'Missing state eta'
});
})
}
if (!_.isNumber(action.data.eta)) {
throw errors.createError({
title: `Invalid state eta: ${action.data.eta}`
});
})
}
if (_.isNil(action.data.speed)) {
throw errors.createError({
title: 'Missing state speed'
});
})
}
return state.set('flashState', Immutable.fromJS(action.data));
return state.set('flashState', Immutable.fromJS(action.data))
}
case ACTIONS.RESET_FLASH_STATE: {
@ -223,111 +223,111 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
.set('isFlashing', false)
.set('flashState', DEFAULT_STATE.get('flashState'))
.set('flashResults', DEFAULT_STATE.get('flashResults'))
.delete('flashUuid');
.delete('flashUuid')
}
case ACTIONS.SET_FLASHING_FLAG: {
return state
.set('isFlashing', true)
.set('flashUuid', uuidV4())
.set('flashResults', DEFAULT_STATE.get('flashResults'));
.set('flashResults', DEFAULT_STATE.get('flashResults'))
}
case ACTIONS.UNSET_FLASHING_FLAG: {
if (!action.data) {
throw errors.createError({
title: 'Missing results'
});
})
}
_.defaults(action.data, {
cancelled: false
});
})
if (!_.isBoolean(action.data.cancelled)) {
throw errors.createError({
title: `Invalid results cancelled: ${action.data.cancelled}`
});
})
}
if (action.data.cancelled && action.data.sourceChecksum) {
throw errors.createError({
title: 'The sourceChecksum value can\'t exist if the flashing was cancelled'
});
})
}
if (action.data.sourceChecksum && !_.isString(action.data.sourceChecksum)) {
throw errors.createError({
title: `Invalid results sourceChecksum: ${action.data.sourceChecksum}`
});
})
}
if (action.data.errorCode && !_.isString(action.data.errorCode) && !_.isNumber(action.data.errorCode)) {
throw errors.createError({
title: `Invalid results errorCode: ${action.data.errorCode}`
});
})
}
return state
.set('isFlashing', false)
.set('flashResults', Immutable.fromJS(action.data))
.set('flashState', DEFAULT_STATE.get('flashState'));
.set('flashState', DEFAULT_STATE.get('flashState'))
}
case ACTIONS.SELECT_DRIVE: {
if (!action.data) {
throw errors.createError({
title: 'Missing drive'
});
})
}
if (!_.isString(action.data)) {
throw errors.createError({
title: `Invalid drive: ${action.data}`
});
})
}
const selectedDrive = findDrive(state, action.data);
const selectedDrive = findDrive(state, action.data)
if (!selectedDrive) {
throw errors.createError({
title: `The drive is not available: ${action.data}`
});
})
}
if (selectedDrive.get('protected')) {
throw errors.createError({
title: 'The drive is write-protected'
});
})
}
const image = state.getIn([ 'selection', 'image' ]);
const image = state.getIn([ 'selection', 'image' ])
if (image && !constraints.isDriveLargeEnough(selectedDrive.toJS(), image.toJS())) {
throw errors.createError({
title: 'The drive is not large enough'
});
})
}
return state.setIn([ 'selection', 'drive' ], Immutable.fromJS(action.data));
return state.setIn([ 'selection', 'drive' ], Immutable.fromJS(action.data))
}
case ACTIONS.SELECT_IMAGE: {
if (!action.data.path) {
throw errors.createError({
title: 'Missing image path'
});
})
}
if (!_.isString(action.data.path)) {
throw errors.createError({
title: `Invalid image path: ${action.data.path}`
});
})
}
if (!action.data.extension) {
throw errors.createError({
title: 'Missing image extension'
});
})
}
if (_.some([
@ -336,16 +336,16 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
])) {
throw errors.createError({
title: `Invalid image extension: ${action.data.extension}`
});
})
}
const lastImageExtension = fileExtensions.getLastFileExtension(action.data.path);
const lastImageExtension = fileExtensions.getLastFileExtension(action.data.path)
if (lastImageExtension !== action.data.extension) {
if (!action.data.archiveExtension) {
throw errors.createError({
title: 'Missing image archive extension'
});
})
}
if (_.some([
@ -354,67 +354,67 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
])) {
throw errors.createError({
title: `Invalid image archive extension: ${action.data.archiveExtension}`
});
})
}
if (lastImageExtension !== action.data.archiveExtension) {
throw errors.createError({
title: `Image archive extension mismatch: ${action.data.archiveExtension} and ${lastImageExtension}`
});
})
}
}
if (!action.data.size) {
throw errors.createError({
title: 'Missing image size'
});
})
}
if (!_.isPlainObject(action.data.size)) {
throw errors.createError({
title: `Invalid image size: ${action.data.size}`
});
})
}
const MINIMUM_IMAGE_SIZE = 0;
const MINIMUM_IMAGE_SIZE = 0
if (!_.isInteger(action.data.size.original) || action.data.size.original < MINIMUM_IMAGE_SIZE) {
throw errors.createError({
title: `Invalid original image size: ${action.data.size.original}`
});
})
}
if (!_.isInteger(action.data.size.final.value) || action.data.size.final.value < MINIMUM_IMAGE_SIZE) {
throw errors.createError({
title: `Invalid final image size: ${action.data.size.final.value}`
});
})
}
if (!_.isBoolean(action.data.size.final.estimation)) {
throw errors.createError({
title: `Invalid final image size estimation flag: ${action.data.size.final.estimation}`
});
})
}
if (action.data.url && !_.isString(action.data.url)) {
throw errors.createError({
title: `Invalid image url: ${action.data.url}`
});
})
}
if (action.data.name && !_.isString(action.data.name)) {
throw errors.createError({
title: `Invalid image name: ${action.data.name}`
});
})
}
if (action.data.logo && !_.isString(action.data.logo)) {
throw errors.createError({
title: `Invalid image logo: ${action.data.logo}`
});
})
}
const selectedDrive = findDrive(state, state.getIn([ 'selection', 'drive' ]));
const selectedDrive = findDrive(state, state.getIn([ 'selection', 'drive' ]))
return _.attempt(() => {
if (selectedDrive && !_.every([
@ -423,64 +423,64 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
])) {
return storeReducer(state, {
type: ACTIONS.REMOVE_DRIVE
});
})
}
return state;
}).setIn([ 'selection', 'image' ], Immutable.fromJS(action.data));
return state
}).setIn([ 'selection', 'image' ], Immutable.fromJS(action.data))
}
case ACTIONS.REMOVE_DRIVE: {
return state.deleteIn([ 'selection', 'drive' ]);
return state.deleteIn([ 'selection', 'drive' ])
}
case ACTIONS.REMOVE_IMAGE: {
return state.deleteIn([ 'selection', 'image' ]);
return state.deleteIn([ 'selection', 'image' ])
}
case ACTIONS.SET_SETTINGS: {
if (!action.data) {
throw errors.createError({
title: 'Missing settings'
});
})
}
if (!_.isPlainObject(action.data)) {
throw errors.createError({
title: `Invalid settings: ${action.data}`
});
})
}
const invalidKey = _.find(_.keys(action.data), (key) => {
return !_.isString(key);
});
return !_.isString(key)
})
if (!_.isNil(invalidKey)) {
throw errors.createError({
title: `Invalid setting key: ${invalidKey}`
});
})
}
const invalidPair = _.find(_.toPairs(action.data), (pair) => {
return _.isObject(_.last(pair));
});
return _.isObject(_.last(pair))
})
if (!_.isNil(invalidPair)) {
throw errors.createError({
title: `Invalid setting value: ${_.last(invalidPair)} for ${_.first(invalidPair)}`
});
})
}
return state.setIn([ 'settings' ], Immutable.fromJS(action.data));
return state.setIn([ 'settings' ], Immutable.fromJS(action.data))
}
default: {
return state;
return state
}
}
};
}
module.exports = _.merge(redux.createStore(storeReducer, DEFAULT_STATE), {
Actions: ACTIONS,
Defaults: DEFAULT_STATE
});
})

View File

@ -14,12 +14,12 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const path = require('path');
const imageStream = require('../image-stream');
const fileExtensions = require('./file-extensions');
const _ = require('lodash')
const path = require('path')
const imageStream = require('../image-stream')
const fileExtensions = require('./file-extensions')
/**
* @summary Build an extension list getter from a type
@ -36,9 +36,9 @@ const getExtensionsFromTypeGetter = (type) => {
return () => {
return _.map(_.filter(imageStream.supportedFileTypes, {
type
}), 'extension');
};
};
}), 'extension')
}
}
/**
* @summary Get compressed extensions
@ -52,7 +52,7 @@ const getExtensionsFromTypeGetter = (type) => {
* console.log('We support the ' + extension + ' compressed file format');
* });
*/
exports.getCompressedExtensions = getExtensionsFromTypeGetter('compressed');
exports.getCompressedExtensions = getExtensionsFromTypeGetter('compressed')
/**
* @summary Get non compressed extensions
@ -66,7 +66,7 @@ exports.getCompressedExtensions = getExtensionsFromTypeGetter('compressed');
* console.log('We support the ' + extension + ' file format');
* });
*/
exports.getNonCompressedExtensions = getExtensionsFromTypeGetter('image');
exports.getNonCompressedExtensions = getExtensionsFromTypeGetter('image')
/**
* @summary Get archive extensions
@ -80,7 +80,7 @@ exports.getNonCompressedExtensions = getExtensionsFromTypeGetter('image');
* console.log('We support the ' + extension + ' file format');
* });
*/
exports.getArchiveExtensions = getExtensionsFromTypeGetter('archive');
exports.getArchiveExtensions = getExtensionsFromTypeGetter('archive')
/**
* @summary Get all supported extensions
@ -95,8 +95,8 @@ exports.getArchiveExtensions = getExtensionsFromTypeGetter('archive');
* });
*/
exports.getAllExtensions = () => {
return _.map(imageStream.supportedFileTypes, 'extension');
};
return _.map(imageStream.supportedFileTypes, 'extension')
}
/**
* @summary Check if an image is supported
@ -112,21 +112,21 @@ exports.getAllExtensions = () => {
* }
*/
exports.isSupportedImage = (imagePath) => {
const lastExtension = fileExtensions.getLastFileExtension(imagePath);
const penultimateExtension = fileExtensions.getPenultimateFileExtension(imagePath);
const lastExtension = fileExtensions.getLastFileExtension(imagePath)
const penultimateExtension = fileExtensions.getPenultimateFileExtension(imagePath)
if (_.some([
_.includes(exports.getNonCompressedExtensions(), lastExtension),
_.includes(exports.getArchiveExtensions(), lastExtension)
])) {
return true;
return true
}
return _.every([
_.includes(exports.getCompressedExtensions(), lastExtension),
_.includes(exports.getNonCompressedExtensions(), penultimateExtension)
]);
};
])
}
/**
* @summary Check if an image seems to be a Windows image
@ -142,6 +142,6 @@ exports.isSupportedImage = (imagePath) => {
* }
*/
exports.looksLikeWindowsImage = (imagePath) => {
const regex = /windows|win7|win8|win10|winxp/i;
return regex.test(path.basename(imagePath));
};
const regex = /windows|win7|win8|win10|winxp/i
return regex.test(path.basename(imagePath))
}

View File

@ -14,11 +14,11 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const _ = require('lodash')
const prettyBytes = require('pretty-bytes');
const prettyBytes = require('pretty-bytes')
/**
* @summary Megabyte to byte ratio
@ -29,7 +29,7 @@ const prettyBytes = require('pretty-bytes');
* @description
* 1 MB = 1e+6 B
*/
const MEGABYTE_TO_BYTE_RATIO = 1e+6;
const MEGABYTE_TO_BYTE_RATIO = 1e+6
/**
* @summary Milliseconds in a day
@ -40,7 +40,7 @@ const MEGABYTE_TO_BYTE_RATIO = 1e+6;
* @description
* From 24 * 60 * 60 * 1000
*/
const MILLISECONDS_IN_A_DAY = 86400000;
const MILLISECONDS_IN_A_DAY = 86400000
/**
* @summary Convert bytes to megabytes
@ -54,8 +54,8 @@ const MILLISECONDS_IN_A_DAY = 86400000;
* const result = units.bytesToMegabytes(7801405440);
*/
exports.bytesToMegabytes = (bytes) => {
return bytes / MEGABYTE_TO_BYTE_RATIO;
};
return bytes / MEGABYTE_TO_BYTE_RATIO
}
/**
* @summary Convert bytes to most appropriate unit string
@ -71,11 +71,11 @@ exports.bytesToMegabytes = (bytes) => {
*/
exports.bytesToClosestUnit = (bytes) => {
if (_.isNumber(bytes)) {
return prettyBytes(bytes);
return prettyBytes(bytes)
}
return null;
};
return null
}
/**
* @summary Convert days to milliseconds
@ -89,5 +89,5 @@ exports.bytesToClosestUnit = (bytes) => {
* const result = units.daysToMilliseconds(2);
*/
exports.daysToMilliseconds = (days) => {
return days * MILLISECONDS_IN_A_DAY;
};
return days * MILLISECONDS_IN_A_DAY
}

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const errors = require('./errors');
const _ = require('lodash')
const errors = require('./errors')
/**
* @summary Minimum percentage value
@ -25,7 +25,7 @@ const errors = require('./errors');
* @public
* @type {Number}
*/
exports.PERCENTAGE_MINIMUM = 0;
exports.PERCENTAGE_MINIMUM = 0
/**
* @summary Maximum percentage value
@ -33,7 +33,7 @@ exports.PERCENTAGE_MINIMUM = 0;
* @public
* @type {Number}
*/
exports.PERCENTAGE_MAXIMUM = 100;
exports.PERCENTAGE_MAXIMUM = 100
/**
* @summary Check if a percentage is valid
@ -53,8 +53,8 @@ exports.isValidPercentage = (percentage) => {
_.isNumber(percentage),
percentage >= exports.PERCENTAGE_MINIMUM,
percentage <= exports.PERCENTAGE_MAXIMUM
]);
};
])
}
/**
* @summary Convert a percentage to a float
@ -73,8 +73,8 @@ exports.percentageToFloat = (percentage) => {
if (!exports.isValidPercentage(percentage)) {
throw errors.createError({
title: `Invalid percentage: ${percentage}`
});
})
}
return percentage / exports.PERCENTAGE_MAXIMUM;
};
return percentage / exports.PERCENTAGE_MAXIMUM
}

View File

@ -14,11 +14,11 @@
* limitations under the License.
*/
'use strict';
'use strict'
// Enable debug information from all modules that use `debug`
// See https://github.com/visionmedia/debug#browser-support
process.env.DEBUG = '*';
process.env.DEBUG = '*'
// See http://electron.atom.io/docs/v0.37.7/api/environment-variables/#electronrunasnode
//
@ -31,7 +31,7 @@ process.env.DEBUG = '*';
// an older equivalent of `ELECTRON_RUN_AS_NODE` that still gets set when
// using `child_process.fork()`.
if (process.env.ELECTRON_RUN_AS_NODE || process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE) {
require('./cli/etcher');
require('./cli/etcher')
} else {
require('./gui/etcher');
require('./gui/etcher')
}

226
npm-shrinkwrap.json generated
View File

@ -423,9 +423,9 @@
"dev": true,
"dependencies": {
"js-tokens": {
"version": "3.0.1",
"version": "3.0.2",
"from": "js-tokens@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"dev": true
}
}
@ -954,6 +954,12 @@
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"dev": true
},
"contains-path": {
"version": "0.1.0",
"from": "contains-path@>=0.1.0 <0.2.0",
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
"dev": true
},
"cookie": {
"version": "0.3.1",
"from": "cookie@0.3.1",
@ -1880,9 +1886,9 @@
"dev": true
},
"eslint": {
"version": "3.18.0",
"from": "eslint@3.18.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-3.18.0.tgz",
"version": "3.19.0",
"from": "eslint@3.19.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz",
"dev": true,
"dependencies": {
"cli-width": {
@ -1897,10 +1903,118 @@
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
"dev": true
},
"json-stable-stringify": {
"version": "1.0.1",
"from": "json-stable-stringify@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"strip-bom": {
"version": "3.0.0",
"from": "strip-bom@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"dev": true
}
}
},
"eslint-config-standard": {
"version": "10.2.1",
"from": "eslint-config-standard@latest",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz",
"dev": true
},
"eslint-import-resolver-node": {
"version": "0.3.1",
"from": "eslint-import-resolver-node@>=0.3.1 <0.4.0",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz",
"dev": true,
"dependencies": {
"debug": {
"version": "2.6.8",
"from": "debug@^2.6.8",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
"dev": true
},
"ms": {
"version": "2.0.0",
"from": "ms@2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"dev": true
}
}
},
"eslint-module-utils": {
"version": "2.1.1",
"from": "eslint-module-utils@>=2.1.1 <3.0.0",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz",
"dev": true,
"dependencies": {
"debug": {
"version": "2.6.8",
"from": "debug@^2.6.8",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
"dev": true
},
"ms": {
"version": "2.0.0",
"from": "ms@2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"dev": true
}
}
},
"eslint-plugin-import": {
"version": "2.7.0",
"from": "eslint-plugin-import@latest",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.7.0.tgz",
"dev": true,
"dependencies": {
"debug": {
"version": "2.6.8",
"from": "debug@>=2.6.8 <3.0.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
"dev": true
},
"doctrine": {
"version": "1.5.0",
"from": "doctrine@1.5.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
"dev": true
},
"find-up": {
"version": "2.1.0",
"from": "find-up@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"dev": true
},
"isarray": {
"version": "1.0.0",
"from": "isarray@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"dev": true
},
"load-json-file": {
"version": "2.0.0",
"from": "load-json-file@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"dev": true
},
"ms": {
"version": "2.0.0",
"from": "ms@2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"dev": true
},
"path-type": {
"version": "2.0.0",
"from": "path-type@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
"dev": true
},
"read-pkg": {
"version": "2.0.0",
"from": "read-pkg@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
"dev": true
},
"read-pkg-up": {
"version": "2.0.0",
"from": "read-pkg-up@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
"dev": true
},
"strip-bom": {
@ -1923,6 +2037,56 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-lodash/-/eslint-plugin-lodash-2.3.6.tgz",
"dev": true
},
"eslint-plugin-node": {
"version": "5.1.1",
"from": "eslint-plugin-node@latest",
"resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.1.1.tgz",
"dev": true,
"dependencies": {
"balanced-match": {
"version": "1.0.0",
"from": "balanced-match@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"dev": true
},
"brace-expansion": {
"version": "1.1.8",
"from": "brace-expansion@>=1.1.7 <2.0.0",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
"dev": true
},
"ignore": {
"version": "3.3.3",
"from": "ignore@>=3.3.3 <4.0.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz",
"dev": true
},
"minimatch": {
"version": "3.0.4",
"from": "minimatch@>=3.0.4 <4.0.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"dev": true
},
"semver": {
"version": "5.3.0",
"from": "semver@5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"dev": true
}
}
},
"eslint-plugin-promise": {
"version": "3.5.0",
"from": "eslint-plugin-promise@latest",
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz",
"dev": true
},
"eslint-plugin-standard": {
"version": "3.0.1",
"from": "eslint-plugin-standard@latest",
"resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz",
"dev": true
},
"espree": {
"version": "3.4.0",
"from": "espree@>=3.4.0 <4.0.0",
@ -2451,6 +2615,12 @@
}
}
},
"function-bind": {
"version": "1.1.0",
"from": "function-bind@>=1.0.2 <2.0.0",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz",
"dev": true
},
"gauge": {
"version": "2.7.3",
"from": "gauge@>=2.7.1 <2.8.0",
@ -2724,6 +2894,12 @@
"from": "har-validator@>=4.2.1 <4.3.0",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz"
},
"has": {
"version": "1.0.1",
"from": "has@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz",
"dev": true
},
"has-ansi": {
"version": "2.0.0",
"from": "has-ansi@>=2.0.0 <3.0.0",
@ -2954,9 +3130,9 @@
}
},
"interpret": {
"version": "1.0.1",
"version": "1.0.3",
"from": "interpret@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz",
"dev": true
},
"invert-kv": {
@ -3324,6 +3500,12 @@
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"dev": true
},
"json-stable-stringify": {
"version": "1.0.1",
"from": "json-stable-stringify@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"dev": true
},
"json-stringify-safe": {
"version": "5.0.1",
"from": "json-stringify-safe@>=5.0.0 <5.1.0",
@ -3507,6 +3689,12 @@
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"dev": true
},
"lodash.cond": {
"version": "4.5.2",
"from": "lodash.cond@>=4.3.0 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz",
"dev": true
},
"lodash.create": {
"version": "3.1.1",
"from": "lodash.create@3.1.1",
@ -8237,6 +8425,12 @@
"from": "pkg-conf@>=1.1.2 <2.0.0",
"resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-1.1.3.tgz"
},
"pkg-dir": {
"version": "1.0.0",
"from": "pkg-dir@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
"dev": true
},
"pkg-fetch": {
"version": "2.3.3",
"from": "pkg-fetch@2.3.3",
@ -8762,9 +8956,9 @@
}
},
"resolve": {
"version": "1.3.2",
"from": "resolve@>=1.1.4 <2.0.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.2.tgz",
"version": "1.4.0",
"from": "resolve@>=1.1.6 <2.0.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz",
"dev": true
},
"resolve-dir": {
@ -9000,9 +9194,9 @@
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz"
},
"shelljs": {
"version": "0.7.7",
"version": "0.7.8",
"from": "shelljs@>=0.7.5 <0.8.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.7.tgz",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
"dev": true
},
"sigmund": {

View File

@ -94,9 +94,14 @@
"electron": "1.6.6",
"electron-builder": "19.9.1",
"electron-mocha": "3.3.0",
"eslint": "3.18.0",
"eslint-plugin-jsdoc": "^3.1.1",
"eslint": "3.19.0",
"eslint-config-standard": "10.2.1",
"eslint-plugin-import": "2.7.0",
"eslint-plugin-jsdoc": "3.1.1",
"eslint-plugin-lodash": "2.3.6",
"eslint-plugin-node": "5.1.1",
"eslint-plugin-promise": "3.5.0",
"eslint-plugin-standard": "3.0.1",
"file-exists": "1.0.0",
"html-angular-validate": "0.1.9",
"mochainon": "1.0.0",

View File

@ -14,19 +14,19 @@
* limitations under the License.
*/
'use strict';
'use strict'
// This script generates Dockerfiles based on a template containing all
// the necessary dependencies/ to run and build Etcher in multiple platforms.
const _ = require('lodash');
const fs = require('fs');
const path = require('path');
const currentDirectory = __dirname;
const _ = require('lodash')
const fs = require('fs')
const path = require('path')
const currentDirectory = __dirname
const template = fs.readFileSync(path.join(currentDirectory, 'Dockerfile.template'), {
encoding: 'utf8'
});
})
_.each([
{
@ -38,7 +38,7 @@ _.each([
image: 'ubuntu:12.04'
}
], (options) => {
const result = _.template(template)(options);
const filename = path.join(currentDirectory, `Dockerfile-${options.architecture}`);
fs.writeFileSync(filename, result);
});
const result = _.template(template)(options)
const filename = path.join(currentDirectory, `Dockerfile-${options.architecture}`)
fs.writeFileSync(filename, result)
})

View File

@ -13,18 +13,18 @@
* See: https://github.com/npm/npm/issues/2679
*/
'use strict';
'use strict'
const _ = require('lodash');
const fs = require('fs');
const path = require('path');
const packageJSON = require('../package.json');
const NPM_SHRINKWRAP_FILE_PATH = path.join(__dirname, '..', 'npm-shrinkwrap.json');
const shrinkwrapFile = require(NPM_SHRINKWRAP_FILE_PATH);
const platformSpecificDependencies = packageJSON.platformSpecificDependencies;
const JSON_INDENTATION_SPACES = 2;
const _ = require('lodash')
const fs = require('fs')
const path = require('path')
const packageJSON = require('../package.json')
const NPM_SHRINKWRAP_FILE_PATH = path.join(__dirname, '..', 'npm-shrinkwrap.json')
const shrinkwrapFile = require(NPM_SHRINKWRAP_FILE_PATH)
const platformSpecificDependencies = packageJSON.platformSpecificDependencies
const JSON_INDENTATION_SPACES = 2
console.log('Removing:', platformSpecificDependencies.join(', '));
console.log('Removing:', platformSpecificDependencies.join(', '))
/**
* @summary Get a shrinkwrap dependency object
@ -46,9 +46,9 @@ console.log('Removing:', platformSpecificDependencies.join(', '));
*/
const getShrinkwrapDependencyObject = (shrinkwrap, shrinkwrapPath) => {
return _.reduce(shrinkwrapPath, (accumulator, dependency) => {
return _.get(accumulator, [ 'dependencies', dependency ], {});
}, shrinkwrap);
};
return _.get(accumulator, [ 'dependencies', dependency ], {})
}, shrinkwrap)
}
/**
* @summary Get a cleaned shrinkwrap dependency object
@ -74,10 +74,10 @@ const getShrinkwrapDependencyObject = (shrinkwrap, shrinkwrapPath) => {
* console.log(object.version);
*/
const getPrettyShrinkwrapDependencyObject = (shrinkwrap, shrinkwrapPath) => {
const object = getShrinkwrapDependencyObject(shrinkwrap, shrinkwrapPath);
const object = getShrinkwrapDependencyObject(shrinkwrap, shrinkwrapPath)
if (_.isEmpty(object)) {
return null;
return null
}
return {
@ -86,8 +86,8 @@ const getPrettyShrinkwrapDependencyObject = (shrinkwrap, shrinkwrapPath) => {
version: object.version,
development: Boolean(object.dev),
optional: Boolean(object.optional)
};
};
}
}
/**
* @summary Get the manifest (package.json) of a shrinkwrap dependency
@ -104,26 +104,26 @@ const getPrettyShrinkwrapDependencyObject = (shrinkwrap, shrinkwrapPath) => {
const getShrinkwrapDependencyManifest = (shrinkwrapPath) => {
const manifestPath = _.chain(shrinkwrapPath)
.flatMap((dependency) => {
return [ 'node_modules', dependency ];
return [ 'node_modules', dependency ]
})
.concat([ 'package.json' ])
.reduce((accumulator, file) => {
return path.join(accumulator, file);
return path.join(accumulator, file)
}, '.')
.value();
.value()
try {
// For example
// ./node_modules/drivelist/node_modules/lodash/package.json
return require(`.${path.sep}${manifestPath}`);
return require(`.${path.sep}${manifestPath}`)
} catch (error) {
if (error.code === 'MODULE_NOT_FOUND') {
return null;
return null
}
throw error;
throw error
}
};
}
/**
* @summary Get the top level dependencies of a shrinkwrap object
@ -141,8 +141,8 @@ const getShrinkwrapDependencyManifest = (shrinkwrapPath) => {
* > }
*/
const getTopLevelDependenciesForShrinkwrapPath = (shrinkwrapPath) => {
return _.get(getShrinkwrapDependencyManifest(shrinkwrapPath), [ 'dependencies' ], {});
};
return _.get(getShrinkwrapDependencyManifest(shrinkwrapPath), [ 'dependencies' ], {})
}
/**
* @summary Get the dependency tree of a shrinkwrap dependency
@ -163,22 +163,22 @@ const getTopLevelDependenciesForShrinkwrapPath = (shrinkwrapPath) => {
* })
*/
const getDependencyTree = (shrinkwrap, shrinkwrapPath) => {
const dependencies = getTopLevelDependenciesForShrinkwrapPath(shrinkwrapPath);
const dependencies = getTopLevelDependenciesForShrinkwrapPath(shrinkwrapPath)
if (_.isEmpty(dependencies)) {
return [];
return []
}
const object = getShrinkwrapDependencyObject(shrinkwrap, shrinkwrapPath);
const object = getShrinkwrapDependencyObject(shrinkwrap, shrinkwrapPath)
const result = _.map(dependencies, (version, name) => {
const dependencyPath = _.has(object.dependencies, name) ? _.concat(shrinkwrapPath, [ name ]) : [ name ];
return getPrettyShrinkwrapDependencyObject(shrinkwrap, dependencyPath);
});
const dependencyPath = _.has(object.dependencies, name) ? _.concat(shrinkwrapPath, [ name ]) : [ name ]
return getPrettyShrinkwrapDependencyObject(shrinkwrap, dependencyPath)
})
return _.concat(result, _.flatMapDeep(result, (dependency) => {
return getDependencyTree(shrinkwrap, dependency.path);
}));
};
return getDependencyTree(shrinkwrap, dependency.path)
}))
}
/**
* @summary Remove certain development optional dependencies from a shrinkwrap file
@ -224,16 +224,16 @@ const removeOptionalDevelopmentDependencies = (shrinkwrap, blacklist) => {
}),
dependency.dev,
dependency.optional
]);
])
})
.mapValues((dependency) => {
return removeOptionalDevelopmentDependencies(dependency, blacklist);
return removeOptionalDevelopmentDependencies(dependency, blacklist)
})
.value();
.value()
}
return shrinkwrap;
};
return shrinkwrap
}
/**
* @summary Get the dependency tree of a dependency plus the dependency itself
@ -256,15 +256,15 @@ const removeOptionalDevelopmentDependencies = (shrinkwrap, blacklist) => {
const getTree = (shrinkwrap, shrinkwrapPath) => {
return _.compact(_.concat([
getPrettyShrinkwrapDependencyObject(shrinkwrap, shrinkwrapPath)
], getDependencyTree(shrinkwrap, shrinkwrapPath)));
};
], getDependencyTree(shrinkwrap, shrinkwrapPath)))
}
const blacklist = _.reduce(platformSpecificDependencies, (accumulator, dependencyPath) => {
return _.concat(accumulator, getTree(shrinkwrapFile, dependencyPath));
}, []);
return _.concat(accumulator, getTree(shrinkwrapFile, dependencyPath))
}, [])
const filteredShrinkwrap = removeOptionalDevelopmentDependencies(shrinkwrapFile, blacklist);
const result = JSON.stringify(filteredShrinkwrap, null, JSON_INDENTATION_SPACES);
const filteredShrinkwrap = removeOptionalDevelopmentDependencies(shrinkwrapFile, blacklist)
const result = JSON.stringify(filteredShrinkwrap, null, JSON_INDENTATION_SPACES)
fs.writeFileSync(NPM_SHRINKWRAP_FILE_PATH, `${result}\n`);
console.log('Done');
fs.writeFileSync(NPM_SHRINKWRAP_FILE_PATH, `${result}\n`)
console.log('Done')

View File

@ -8,17 +8,17 @@
* node scripts/html-lint.js
*/
'use strict';
'use strict'
const chalk = require('chalk');
const path = require('path');
const _ = require('lodash');
const angularValidate = require('html-angular-validate');
const EXIT_CODES = require('../lib/shared/exit-codes');
const PROJECT_ROOT = path.join(__dirname, '..');
const FILENAME = path.relative(PROJECT_ROOT, __filename);
const chalk = require('chalk')
const path = require('path')
const _ = require('lodash')
const angularValidate = require('html-angular-validate')
const EXIT_CODES = require('../lib/shared/exit-codes')
const PROJECT_ROOT = path.join(__dirname, '..')
const FILENAME = path.relative(PROJECT_ROOT, __filename)
console.log('Scanning...');
console.log('Scanning...')
angularValidate.validate(
[
@ -48,36 +48,36 @@ angularValidate.validate(
).then((result) => {
_.each(result.failed, (failure) => {
// The module has a typo in the "numbers" property
console.error(chalk.red(`${failure.numerrs} errors at ${path.relative(PROJECT_ROOT, failure.filepath)}`));
console.error(chalk.red(`${failure.numerrs} errors at ${path.relative(PROJECT_ROOT, failure.filepath)}`))
_.each(failure.errors, (error) => {
const errorPosition = `[${error.line}:${error.col}]`;
console.error(` ${chalk.yellow(errorPosition)} ${error.msg}`);
const errorPosition = `[${error.line}:${error.col}]`
console.error(` ${chalk.yellow(errorPosition)} ${error.msg}`)
if (/^Attribute (.*) not allowed on/.test(error.msg)) {
console.error(chalk.dim(` If this is a valid directive attribute, add it to the whitelist at ${FILENAME}`));
console.error(chalk.dim(` If this is a valid directive attribute, add it to the whitelist at ${FILENAME}`))
}
});
})
console.error('');
});
console.error('')
})
if (result.filessucceeded === result.fileschecked) {
console.log(chalk.green('Passed'));
console.log(chalk.green('Passed'))
} else {
console.error(chalk.red(`Total: ${result.filessucceeded}/${result.fileschecked}`));
console.error(chalk.red(`Total: ${result.filessucceeded}/${result.fileschecked}`))
}
if (!result.allpassed) {
const EXIT_TIMEOUT_MS = 500;
const EXIT_TIMEOUT_MS = 500
// Add a small timeout, otherwise the scripts exits
// before every string was printed on the screen.
setTimeout(() => {
process.exit(EXIT_CODES.GENERAL_ERROR);
}, EXIT_TIMEOUT_MS);
process.exit(EXIT_CODES.GENERAL_ERROR)
}, EXIT_TIMEOUT_MS)
}
}, (error) => {
console.error(error);
process.exit(EXIT_CODES.GENERAL_ERROR);
});
console.error(error)
process.exit(EXIT_CODES.GENERAL_ERROR)
})

View File

@ -14,29 +14,29 @@
* limitations under the License.
*/
'use strict';
'use strict'
const m = require('mochainon');
const cli = require('../../lib/child-writer/cli');
const m = require('mochainon')
const cli = require('../../lib/child-writer/cli')
describe('ChildWriter CLI', function () {
describe('.getBooleanArgumentForm()', function () {
it('should prepend --no if the value is false and option is long', function () {
m.chai.expect(cli.getBooleanArgumentForm('foo', false)).to.equal('--no-foo');
});
m.chai.expect(cli.getBooleanArgumentForm('foo', false)).to.equal('--no-foo')
})
it('should prepend -- if the value is true and option is long', function () {
m.chai.expect(cli.getBooleanArgumentForm('foo', true)).to.equal('--foo');
});
m.chai.expect(cli.getBooleanArgumentForm('foo', true)).to.equal('--foo')
})
it('should prepend --no if the value is false and option is short', function () {
m.chai.expect(cli.getBooleanArgumentForm('x', false)).to.equal('--no-x');
});
m.chai.expect(cli.getBooleanArgumentForm('x', false)).to.equal('--no-x')
})
it('should prepend - if the value is true and option is short', function () {
m.chai.expect(cli.getBooleanArgumentForm('x', true)).to.equal('-x');
});
});
m.chai.expect(cli.getBooleanArgumentForm('x', true)).to.equal('-x')
})
})
describe('.getArguments()', function () {
it('should return a list of arguments given validate = false, unmount = false', function () {
@ -53,8 +53,8 @@ describe('ChildWriter CLI', function () {
'/dev/disk2',
'--no-unmount',
'--no-check'
]);
});
])
})
it('should return a list of arguments given validate = false, unmount = true', function () {
m.chai.expect(cli.getArguments({
@ -70,8 +70,8 @@ describe('ChildWriter CLI', function () {
'/dev/disk2',
'--unmount',
'--no-check'
]);
});
])
})
it('should return a list of arguments given validate = true, unmount = false', function () {
m.chai.expect(cli.getArguments({
@ -87,8 +87,8 @@ describe('ChildWriter CLI', function () {
'/dev/disk2',
'--no-unmount',
'--check'
]);
});
])
})
it('should return a list of arguments given validate = true, unmount = true', function () {
m.chai.expect(cli.getArguments({
@ -104,7 +104,7 @@ describe('ChildWriter CLI', function () {
'/dev/disk2',
'--unmount',
'--check'
]);
});
});
});
])
})
})
})

View File

@ -14,64 +14,64 @@
* limitations under the License.
*/
'use strict';
'use strict'
const m = require('mochainon');
const utils = require('../../lib/child-writer/utils');
const m = require('mochainon')
const utils = require('../../lib/child-writer/utils')
describe('ChildWriter Utils', function () {
describe('.splitObjectLines()', function () {
it('should split multiple object lines', function () {
const input = '{"id":"foo"}\n{"id":"bar"}\n{"id":"baz"}';
const input = '{"id":"foo"}\n{"id":"bar"}\n{"id":"baz"}'
m.chai.expect(utils.splitObjectLines(input)).to.deep.equal([
'{"id":"foo"}',
'{"id":"bar"}',
'{"id":"baz"}'
]);
});
])
})
it('should ignore spaces in between', function () {
const input = '{"id":"foo"} \n {"id":"bar"}\n {"id":"baz"}';
const input = '{"id":"foo"} \n {"id":"bar"}\n {"id":"baz"}'
m.chai.expect(utils.splitObjectLines(input)).to.deep.equal([
'{"id":"foo"}',
'{"id":"bar"}',
'{"id":"baz"}'
]);
});
])
})
it('should ignore multiple new lines', function () {
const input = '{"id":"foo"}\n\n\n\n{"id":"bar"}\n\n{"id":"baz"}';
const input = '{"id":"foo"}\n\n\n\n{"id":"bar"}\n\n{"id":"baz"}'
m.chai.expect(utils.splitObjectLines(input)).to.deep.equal([
'{"id":"foo"}',
'{"id":"bar"}',
'{"id":"baz"}'
]);
});
])
})
it('should ignore new lines inside properties', function () {
const input = '{"id":"foo\nbar"}\n{"id":"\nhello\n"}';
const input = '{"id":"foo\nbar"}\n{"id":"\nhello\n"}'
m.chai.expect(utils.splitObjectLines(input)).to.deep.equal([
'{"id":"foo\nbar"}',
'{"id":"\nhello\n"}'
]);
});
])
})
it('should handle carriage returns', function () {
const input = '{"id":"foo"}\r\n{"id":"bar"}\r\n{"id":"baz"}';
const input = '{"id":"foo"}\r\n{"id":"bar"}\r\n{"id":"baz"}'
m.chai.expect(utils.splitObjectLines(input)).to.deep.equal([
'{"id":"foo"}',
'{"id":"bar"}',
'{"id":"baz"}'
]);
});
])
})
it('should ignore multiple carriage returns', function () {
const input = '{"id":"foo"}\r\n\r\n{"id":"bar"}\r\n\r\n\r\n{"id":"baz"}';
const input = '{"id":"foo"}\r\n\r\n{"id":"bar"}\r\n\r\n\r\n{"id":"baz"}'
m.chai.expect(utils.splitObjectLines(input)).to.deep.equal([
'{"id":"foo"}',
'{"id":"bar"}',
'{"id":"baz"}'
]);
});
});
});
])
})
})
})

View File

@ -14,26 +14,26 @@
* limitations under the License.
*/
'use strict';
'use strict'
const _ = require('lodash');
const m = require('mochainon');
const angular = require('angular');
require('angular-mocks');
const _ = require('lodash')
const m = require('mochainon')
const angular = require('angular')
require('angular-mocks')
describe('Browser: DriveSelector', function () {
beforeEach(angular.mock.module(
require('../../../lib/gui/components/drive-selector/drive-selector')
));
))
describe('DriveSelectorController', function () {
let $controller;
let $rootScope;
let $q;
let $uibModalInstance;
let WarningModalService;
let $controller
let $rootScope
let $q
let $uibModalInstance
let WarningModalService
let controller;
let controller
beforeEach(angular.mock.inject(function (
_$controller_,
@ -41,12 +41,12 @@ describe('Browser: DriveSelector', function () {
_$q_,
_WarningModalService_
) {
$controller = _$controller_;
$rootScope = _$rootScope_;
$q = _$q_;
$uibModalInstance = {};
WarningModalService = _WarningModalService_;
}));
$controller = _$controller_
$rootScope = _$rootScope_
$q = _$q_
$uibModalInstance = {}
WarningModalService = _WarningModalService_
}))
beforeEach(() => {
controller = $controller('DriveSelectorController', {
@ -54,49 +54,49 @@ describe('Browser: DriveSelector', function () {
$q,
$uibModalInstance,
WarningModalService
});
});
})
})
describe('.memoizeImmutableListReference()', function () {
it('constant true should return memoized true', function () {
const memoizedConstTrue = controller.memoizeImmutableListReference(_.constant(true));
m.chai.expect(memoizedConstTrue()).to.be.true;
});
const memoizedConstTrue = controller.memoizeImmutableListReference(_.constant(true))
m.chai.expect(memoizedConstTrue()).to.be.true
})
it('should reflect state changes', function () {
let stateA = false;
let stateA = false
const memoizedStateA = controller.memoizeImmutableListReference(() => {
return stateA;
});
return stateA
})
m.chai.expect(memoizedStateA()).to.be.false;
m.chai.expect(memoizedStateA()).to.be.false
stateA = true;
stateA = true
m.chai.expect(memoizedStateA()).to.be.true;
});
m.chai.expect(memoizedStateA()).to.be.true
})
it('should reflect different arguments', function () {
const memoizedParameter = controller.memoizeImmutableListReference(_.identity);
const memoizedParameter = controller.memoizeImmutableListReference(_.identity)
m.chai.expect(memoizedParameter(false)).to.be.false;
m.chai.expect(memoizedParameter(true)).to.be.true;
});
m.chai.expect(memoizedParameter(false)).to.be.false
m.chai.expect(memoizedParameter(true)).to.be.true
})
it('should handle equal angular objects with different hashes', function () {
const memoizedParameter = controller.memoizeImmutableListReference(_.identity);
const memoizedParameter = controller.memoizeImmutableListReference(_.identity)
const angularObjectA = {
$$hashKey: 1,
keyA: true
};
}
const angularObjectB = {
$$hashKey: 2,
keyA: true
};
}
m.chai.expect(memoizedParameter(angularObjectA)).to.equal(angularObjectA);
m.chai.expect(memoizedParameter(angularObjectB)).to.equal(angularObjectA);
});
});
});
});
m.chai.expect(memoizedParameter(angularObjectA)).to.equal(angularObjectA)
m.chai.expect(memoizedParameter(angularObjectB)).to.equal(angularObjectA)
})
})
})
})

View File

@ -14,86 +14,86 @@
* limitations under the License.
*/
'use strict';
'use strict'
const m = require('mochainon');
const _ = require('lodash');
const fs = require('fs');
const path = require('path');
const angular = require('angular');
require('angular-mocks');
const m = require('mochainon')
const _ = require('lodash')
const fs = require('fs')
const path = require('path')
const angular = require('angular')
require('angular-mocks')
describe('Browser: SVGIcon', function () {
beforeEach(angular.mock.module(
require('../../../lib/gui/components/svg-icon')
));
))
describe('svgIcon', function () {
let $compile;
let $rootScope;
let $compile
let $rootScope
beforeEach(angular.mock.inject(function (_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
}));
$compile = _$compile_
$rootScope = _$rootScope_
}))
it('should inline the svg contents in the element', function () {
const icon = '../../../lib/gui/assets/etcher.svg';
const icon = '../../../lib/gui/assets/etcher.svg'
let iconContents = _.split(fs.readFileSync(path.join(__dirname, '../../../lib/gui/assets/etcher.svg'), {
encoding: 'utf8'
}), /\r?\n/);
}), /\r?\n/)
// Injecting XML as HTML causes the XML header to be commented out.
// Modify here to ease assertions later on.
iconContents[0] = `<!--${iconContents[0].slice(1, iconContents[0].length - 1)}-->`;
iconContents = iconContents.join('\n');
iconContents[0] = `<!--${iconContents[0].slice(1, iconContents[0].length - 1)}-->`
iconContents = iconContents.join('\n')
const element = $compile(`<svg-icon path="'${icon}'">Resin.io</svg-icon>`)($rootScope);
$rootScope.$digest();
const element = $compile(`<svg-icon path="'${icon}'">Resin.io</svg-icon>`)($rootScope)
$rootScope.$digest()
// We parse the SVGs to get rid of discrepancies caused by string differences
// in the outputs; the XML trees are still equal, as proven here.
const originalSVGParser = new DOMParser();
const originalDoc = originalSVGParser.parseFromString(iconContents, 'image/svg+xml');
const compiledSVGParser = new DOMParser();
const compiledContents = decodeURIComponent(element.children()[0].children[0].src.substr(19));
const compiledDoc = compiledSVGParser.parseFromString(compiledContents, 'image/svg+xml');
const originalSVGParser = new DOMParser()
const originalDoc = originalSVGParser.parseFromString(iconContents, 'image/svg+xml')
const compiledSVGParser = new DOMParser()
const compiledContents = decodeURIComponent(element.children()[0].children[0].src.substr(19))
const compiledDoc = compiledSVGParser.parseFromString(compiledContents, 'image/svg+xml')
m.chai.expect(compiledDoc.outerHTML).to.equal(originalDoc.outerHTML);
});
m.chai.expect(compiledDoc.outerHTML).to.equal(originalDoc.outerHTML)
})
it('should accept an SVG in the path attribute', function () {
const iconContents = '<svg><rect x="10" y="10" height="100" width="100" style="stroke:red;fill:blue;"/></svg>';
const img = `<img src="data:image/svg+xml,${encodeURIComponent(iconContents)}">`;
$rootScope.iconContents = iconContents;
const iconContents = '<svg><rect x="10" y="10" height="100" width="100" style="stroke:red;fill:blue;"/></svg>'
const img = `<img src="data:image/svg+xml,${encodeURIComponent(iconContents)}">`
$rootScope.iconContents = iconContents
const element = $compile('<svg-icon path="iconContents">Resin.io</svg-icon>')($rootScope);
$rootScope.$digest();
m.chai.expect(element.children().html()).to.equal(img);
});
const element = $compile('<svg-icon path="iconContents">Resin.io</svg-icon>')($rootScope)
$rootScope.$digest()
m.chai.expect(element.children().html()).to.equal(img)
})
it('should default the size to 40x40 pixels', function () {
const icon = '../../../lib/gui/assets/etcher.svg';
const element = $compile(`<svg-icon path="'${icon}'">Resin.io</svg-icon>`)($rootScope);
$rootScope.$digest();
m.chai.expect(element.children().css('width')).to.equal('40px');
m.chai.expect(element.children().css('height')).to.equal('40px');
});
const icon = '../../../lib/gui/assets/etcher.svg'
const element = $compile(`<svg-icon path="'${icon}'">Resin.io</svg-icon>`)($rootScope)
$rootScope.$digest()
m.chai.expect(element.children().css('width')).to.equal('40px')
m.chai.expect(element.children().css('height')).to.equal('40px')
})
it('should be able to set a custom width', function () {
const icon = '../../../lib/gui/assets/etcher.svg';
const element = $compile(`<svg-icon path="'${icon}'" width="'20px'">Resin.io</svg-icon>`)($rootScope);
$rootScope.$digest();
m.chai.expect(element.children().css('width')).to.equal('20px');
m.chai.expect(element.children().css('height')).to.equal('40px');
});
const icon = '../../../lib/gui/assets/etcher.svg'
const element = $compile(`<svg-icon path="'${icon}'" width="'20px'">Resin.io</svg-icon>`)($rootScope)
$rootScope.$digest()
m.chai.expect(element.children().css('width')).to.equal('20px')
m.chai.expect(element.children().css('height')).to.equal('40px')
})
it('should be able to set a custom height', function () {
const icon = '../../../lib/gui/assets/etcher.svg';
const element = $compile(`<svg-icon path="'${icon}'" height="'20px'">Resin.io</svg-icon>`)($rootScope);
$rootScope.$digest();
m.chai.expect(element.children().css('width')).to.equal('40px');
m.chai.expect(element.children().css('height')).to.equal('20px');
});
});
});
const icon = '../../../lib/gui/assets/etcher.svg'
const element = $compile(`<svg-icon path="'${icon}'" height="'20px'">Resin.io</svg-icon>`)($rootScope)
$rootScope.$digest()
m.chai.expect(element.children().css('width')).to.equal('40px')
m.chai.expect(element.children().css('height')).to.equal('20px')
})
})
})

View File

@ -14,26 +14,26 @@
* limitations under the License.
*/
'use strict';
'use strict'
const m = require('mochainon');
const _ = require('lodash');
const units = require('../../../lib/shared/units');
const updateNotifier = require('../../../lib/gui/components/update-notifier');
const m = require('mochainon')
const _ = require('lodash')
const units = require('../../../lib/shared/units')
const updateNotifier = require('../../../lib/gui/components/update-notifier')
describe('Browser: updateNotifier', function () {
describe('.UPDATE_NOTIFIER_SLEEP_DAYS', function () {
it('should be an integer', function () {
m.chai.expect(_.isInteger(updateNotifier.UPDATE_NOTIFIER_SLEEP_DAYS)).to.be.true;
});
m.chai.expect(_.isInteger(updateNotifier.UPDATE_NOTIFIER_SLEEP_DAYS)).to.be.true
})
it('should be greater than 0', function () {
m.chai.expect(updateNotifier.UPDATE_NOTIFIER_SLEEP_DAYS > 0).to.be.true;
});
});
m.chai.expect(updateNotifier.UPDATE_NOTIFIER_SLEEP_DAYS > 0).to.be.true
})
})
describe('.shouldCheckForUpdates()', function () {
const UPDATE_NOTIFIER_SLEEP_MS = units.daysToMilliseconds(updateNotifier.UPDATE_NOTIFIER_SLEEP_DAYS);
const UPDATE_NOTIFIER_SLEEP_MS = units.daysToMilliseconds(updateNotifier.UPDATE_NOTIFIER_SLEEP_DAYS)
_.each([
@ -443,8 +443,8 @@ describe('Browser: updateNotifier', function () {
`lastSleptUpdateNotifierVersion=${testCase.options.lastSleptUpdateNotifierVersion}, and`,
`currentVersion=${testCase.options.currentVersion}`
], ' '), function () {
m.chai.expect(updateNotifier.shouldCheckForUpdates(testCase.options)).to.equal(testCase.expected);
});
});
});
});
m.chai.expect(updateNotifier.shouldCheckForUpdates(testCase.options)).to.equal(testCase.expected)
})
})
})
})

View File

@ -14,84 +14,84 @@
* limitations under the License.
*/
'use strict';
'use strict'
const m = require('mochainon');
const _ = require('lodash');
const Bluebird = require('bluebird');
const store = require('../../../lib/shared/store');
const settings = require('../../../lib/gui/models/settings');
const localSettings = require('../../../lib/gui/models/local-settings');
const m = require('mochainon')
const _ = require('lodash')
const Bluebird = require('bluebird')
const store = require('../../../lib/shared/store')
const settings = require('../../../lib/gui/models/settings')
const localSettings = require('../../../lib/gui/models/local-settings')
describe('Browser: settings', function () {
beforeEach(function () {
return settings.reset();
});
return settings.reset()
})
const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS();
const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS()
it('should be able to set and read values', function () {
m.chai.expect(settings.get('foo')).to.be.undefined;
m.chai.expect(settings.get('foo')).to.be.undefined
return settings.set('foo', true).then(() => {
m.chai.expect(settings.get('foo')).to.be.true;
return settings.set('foo', false);
m.chai.expect(settings.get('foo')).to.be.true
return settings.set('foo', false)
}).then(() => {
m.chai.expect(settings.get('foo')).to.be.false;
});
});
m.chai.expect(settings.get('foo')).to.be.false
})
})
describe('.reset()', function () {
it('should reset the settings to their default values', function () {
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS)
return settings.set('foo', 1234).then(() => {
m.chai.expect(settings.getAll()).to.not.deep.equal(DEFAULT_SETTINGS);
return settings.reset();
m.chai.expect(settings.getAll()).to.not.deep.equal(DEFAULT_SETTINGS)
return settings.reset()
}).then(() => {
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
});
});
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS)
})
})
it('should reset the local settings to their default values', function () {
return settings.set('foo', 1234).then(localSettings.readAll).then((data) => {
m.chai.expect(data).to.not.deep.equal(DEFAULT_SETTINGS);
return settings.reset();
m.chai.expect(data).to.not.deep.equal(DEFAULT_SETTINGS)
return settings.reset()
}).then(localSettings.readAll).then((data) => {
m.chai.expect(data).to.deep.equal(DEFAULT_SETTINGS);
});
});
m.chai.expect(data).to.deep.equal(DEFAULT_SETTINGS)
})
})
describe('given the local settings are cleared', function () {
beforeEach(function () {
return localSettings.clear();
});
return localSettings.clear()
})
it('should set the local settings to their default values', function () {
return settings.reset().then(localSettings.readAll).then((data) => {
m.chai.expect(data).to.deep.equal(DEFAULT_SETTINGS);
});
});
});
});
m.chai.expect(data).to.deep.equal(DEFAULT_SETTINGS)
})
})
})
})
describe('.assign()', function () {
it('should throw if no settings', function (done) {
settings.assign().asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Missing settings');
done();
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('Missing settings')
done()
})
})
it('should throw if setting an array', function (done) {
settings.assign({
foo: 'bar',
bar: [ 1, 2, 3 ]
}).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for bar');
done();
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for bar')
done()
})
})
it('should not override all settings', function () {
return settings.assign({
@ -101,184 +101,184 @@ describe('Browser: settings', function () {
m.chai.expect(settings.getAll()).to.deep.equal(_.assign({}, DEFAULT_SETTINGS, {
foo: 'bar',
bar: 'baz'
}));
});
});
}))
})
})
it('should not store invalid settings to the local machine', function () {
return localSettings.readAll().then((data) => {
m.chai.expect(data.foo).to.be.undefined;
m.chai.expect(data.foo).to.be.undefined
return new Bluebird((resolve) => {
settings.assign({
foo: [ 1, 2, 3 ]
}).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo');
return resolve();
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo')
return resolve()
})
})
}).then(localSettings.readAll).then((data) => {
m.chai.expect(data.foo).to.be.undefined;
});
});
m.chai.expect(data.foo).to.be.undefined
})
})
it('should store the settings to the local machine', function () {
return localSettings.readAll().then((data) => {
m.chai.expect(data.foo).to.be.undefined;
m.chai.expect(data.bar).to.be.undefined;
m.chai.expect(data.foo).to.be.undefined
m.chai.expect(data.bar).to.be.undefined
return settings.assign({
foo: 'bar',
bar: 'baz'
});
})
}).then(localSettings.readAll).then((data) => {
m.chai.expect(data.foo).to.equal('bar');
m.chai.expect(data.bar).to.equal('baz');
});
});
m.chai.expect(data.foo).to.equal('bar')
m.chai.expect(data.bar).to.equal('baz')
})
})
it('should not change the application state if storing to the local machine results in an error', function (done) {
settings.set('foo', 'bar').then(() => {
m.chai.expect(settings.get('foo')).to.equal('bar');
m.chai.expect(settings.get('foo')).to.equal('bar')
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll');
localSettingsWriteAllStub.returns(Bluebird.reject(new Error('localSettings error')));
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll')
localSettingsWriteAllStub.returns(Bluebird.reject(new Error('localSettings error')))
settings.assign({
foo: 'baz'
}).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('localSettings error');
localSettingsWriteAllStub.restore();
m.chai.expect(settings.get('foo')).to.equal('bar');
done();
});
}).catch(done);
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('localSettings error')
localSettingsWriteAllStub.restore()
m.chai.expect(settings.get('foo')).to.equal('bar')
done()
})
}).catch(done)
})
})
describe('.load()', function () {
it('should extend the application state with the local settings content', function () {
const object = {
foo: 'bar'
};
}
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS)
return localSettings.writeAll(object).then(() => {
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
return settings.load();
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS)
return settings.load()
}).then(() => {
m.chai.expect(settings.getAll()).to.deep.equal(_.assign({}, DEFAULT_SETTINGS, object));
});
});
m.chai.expect(settings.getAll()).to.deep.equal(_.assign({}, DEFAULT_SETTINGS, object))
})
})
it('should keep the application state intact if there are no local settings', function () {
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS)
return localSettings.clear().then(settings.load).then(() => {
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
});
});
});
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS)
})
})
})
describe('.set()', function () {
it('should set an unknown key', function () {
m.chai.expect(settings.get('foobar')).to.be.undefined;
m.chai.expect(settings.get('foobar')).to.be.undefined
return settings.set('foobar', true).then(() => {
m.chai.expect(settings.get('foobar')).to.be.true;
});
});
m.chai.expect(settings.get('foobar')).to.be.true
})
})
it('should reject if no key', function (done) {
settings.set(null, true).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Missing setting key');
done();
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('Missing setting key')
done()
})
})
it('should throw if key is not a string', function (done) {
settings.set(1234, true).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Invalid setting key: 1234');
done();
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('Invalid setting key: 1234')
done()
})
})
it('should throw if setting an object', function (done) {
settings.set('foo', {
setting: 1
}).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Invalid setting value: [object Object] for foo');
done();
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('Invalid setting value: [object Object] for foo')
done()
})
})
it('should throw if setting an array', function (done) {
settings.set('foo', [ 1, 2, 3 ]).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo');
done();
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo')
done()
})
})
it('should set the key to undefined if no value', function () {
return settings.set('foo', 'bar').then(() => {
m.chai.expect(settings.get('foo')).to.equal('bar');
return settings.set('foo');
m.chai.expect(settings.get('foo')).to.equal('bar')
return settings.set('foo')
}).then(() => {
m.chai.expect(settings.get('foo')).to.be.undefined;
});
});
m.chai.expect(settings.get('foo')).to.be.undefined
})
})
it('should store the setting to the local machine', function () {
return localSettings.readAll().then((data) => {
m.chai.expect(data.foo).to.be.undefined;
return settings.set('foo', 'bar');
m.chai.expect(data.foo).to.be.undefined
return settings.set('foo', 'bar')
}).then(localSettings.readAll).then((data) => {
m.chai.expect(data.foo).to.equal('bar');
});
});
m.chai.expect(data.foo).to.equal('bar')
})
})
it('should not store invalid settings to the local machine', function () {
return localSettings.readAll().then((data) => {
m.chai.expect(data.foo).to.be.undefined;
m.chai.expect(data.foo).to.be.undefined
return new Bluebird((resolve) => {
settings.set('foo', [ 1, 2, 3 ]).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo');
return resolve();
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo')
return resolve()
})
})
}).then(localSettings.readAll).then((data) => {
m.chai.expect(data.foo).to.be.undefined;
});
});
m.chai.expect(data.foo).to.be.undefined
})
})
it('should not change the application state if storing to the local machine results in an error', function (done) {
settings.set('foo', 'bar').then(() => {
m.chai.expect(settings.get('foo')).to.equal('bar');
m.chai.expect(settings.get('foo')).to.equal('bar')
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll');
localSettingsWriteAllStub.returns(Bluebird.reject(new Error('localSettings error')));
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll')
localSettingsWriteAllStub.returns(Bluebird.reject(new Error('localSettings error')))
settings.set('foo', 'baz').asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('localSettings error');
localSettingsWriteAllStub.restore();
m.chai.expect(settings.get('foo')).to.equal('bar');
done();
});
}).catch(done);
});
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('localSettings error')
localSettingsWriteAllStub.restore()
m.chai.expect(settings.get('foo')).to.equal('bar')
done()
})
}).catch(done)
})
})
describe('.getAll()', function () {
it('should initial return all default values', function () {
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
});
});
});
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS)
})
})
})

View File

@ -14,38 +14,38 @@
* limitations under the License.
*/
'use strict';
'use strict'
const m = require('mochainon');
const os = require('os');
const drivelist = require('drivelist');
const driveScanner = require('../../../lib/gui/modules/drive-scanner');
const m = require('mochainon')
const os = require('os')
const drivelist = require('drivelist')
const driveScanner = require('../../../lib/gui/modules/drive-scanner')
describe('Browser: driveScanner', function () {
describe('given no available drives', function () {
beforeEach(function () {
this.drivelistStub = m.sinon.stub(drivelist, 'list');
this.drivelistStub.yields(null, []);
});
this.drivelistStub = m.sinon.stub(drivelist, 'list')
this.drivelistStub.yields(null, [])
})
afterEach(function () {
this.drivelistStub.restore();
});
this.drivelistStub.restore()
})
it('should emit an empty array', function (done) {
driveScanner.once('drives', function (drives) {
m.chai.expect(drives).to.deep.equal([]);
driveScanner.stop();
done();
});
m.chai.expect(drives).to.deep.equal([])
driveScanner.stop()
done()
})
driveScanner.start();
});
});
driveScanner.start()
})
})
describe('given only system available drives', function () {
beforeEach(function () {
this.drivelistStub = m.sinon.stub(drivelist, 'list');
this.drivelistStub = m.sinon.stub(drivelist, 'list')
this.drivelistStub.yields(null, [ {
device: '/dev/sda',
description: 'WDC WD10JPVX-75J',
@ -56,37 +56,37 @@ describe('Browser: driveScanner', function () {
}
],
system: true
} ]);
});
} ])
})
afterEach(function () {
this.drivelistStub.restore();
});
this.drivelistStub.restore()
})
it('should emit an empty array', function (done) {
driveScanner.once('drives', function (drives) {
m.chai.expect(drives).to.deep.equal([]);
driveScanner.stop();
done();
});
m.chai.expect(drives).to.deep.equal([])
driveScanner.stop()
done()
})
driveScanner.start();
});
});
driveScanner.start()
})
})
describe('given linux', function () {
beforeEach(function () {
this.osPlatformStub = m.sinon.stub(os, 'platform');
this.osPlatformStub.returns('linux');
});
this.osPlatformStub = m.sinon.stub(os, 'platform')
this.osPlatformStub.returns('linux')
})
afterEach(function () {
this.osPlatformStub.restore();
});
this.osPlatformStub.restore()
})
describe('given available drives', function () {
beforeEach(function () {
this.drivelistStub = m.sinon.stub(drivelist, 'list');
this.drivelistStub = m.sinon.stub(drivelist, 'list')
this.drivelistStub.yields(null, [
{
device: '/dev/sda',
@ -124,12 +124,12 @@ describe('Browser: driveScanner', function () {
],
system: false
}
]);
});
])
})
afterEach(function () {
this.drivelistStub.restore();
});
this.drivelistStub.restore()
})
it('should emit the non removable drives', function (done) {
driveScanner.once('drives', function (drives) {
@ -158,30 +158,30 @@ describe('Browser: driveScanner', function () {
],
system: false
}
]);
])
driveScanner.stop();
done();
});
driveScanner.stop()
done()
})
driveScanner.start();
});
});
});
driveScanner.start()
})
})
})
describe('given windows', function () {
beforeEach(function () {
this.osPlatformStub = m.sinon.stub(os, 'platform');
this.osPlatformStub.returns('win32');
});
this.osPlatformStub = m.sinon.stub(os, 'platform')
this.osPlatformStub.returns('win32')
})
afterEach(function () {
this.osPlatformStub.restore();
});
this.osPlatformStub.restore()
})
describe('given available drives', function () {
beforeEach(function () {
this.drivelistStub = m.sinon.stub(drivelist, 'list');
this.drivelistStub = m.sinon.stub(drivelist, 'list')
this.drivelistStub.yields(null, [
{
device: '\\\\.\\PHYSICALDRIVE1',
@ -215,12 +215,12 @@ describe('Browser: driveScanner', function () {
],
system: false
}
]);
});
])
})
afterEach(function () {
this.drivelistStub.restore();
});
this.drivelistStub.restore()
})
it('should emit the non removable drives', function (done) {
driveScanner.once('drives', function (drives) {
@ -245,19 +245,19 @@ describe('Browser: driveScanner', function () {
],
system: false
}
]);
])
driveScanner.stop();
done();
});
driveScanner.stop()
done()
})
driveScanner.start();
});
});
driveScanner.start()
})
})
describe('given a drive with a single drive letters', function () {
beforeEach(function () {
this.drivelistStub = m.sinon.stub(drivelist, 'list');
this.drivelistStub = m.sinon.stub(drivelist, 'list')
this.drivelistStub.yields(null, [
{
device: '\\\\.\\PHYSICALDRIVE3',
@ -271,28 +271,28 @@ describe('Browser: driveScanner', function () {
],
system: false
}
]);
});
])
})
afterEach(function () {
this.drivelistStub.restore();
});
this.drivelistStub.restore()
})
it('should use the drive letter as the name', function (done) {
driveScanner.once('drives', function (drives) {
m.chai.expect(drives).to.have.length(1);
m.chai.expect(drives[0].displayName).to.equal('F:');
driveScanner.stop();
done();
});
m.chai.expect(drives).to.have.length(1)
m.chai.expect(drives[0].displayName).to.equal('F:')
driveScanner.stop()
done()
})
driveScanner.start();
});
});
driveScanner.start()
})
})
describe('given a drive with multiple drive letters', function () {
beforeEach(function () {
this.drivesListStub = m.sinon.stub(drivelist, 'list');
this.drivesListStub = m.sinon.stub(drivelist, 'list')
this.drivesListStub.yields(null, [
{
device: '\\\\.\\PHYSICALDRIVE3',
@ -312,45 +312,45 @@ describe('Browser: driveScanner', function () {
],
system: false
}
]);
});
])
})
afterEach(function () {
this.drivesListStub.restore();
});
this.drivesListStub.restore()
})
it('should join all the mountpoints in `name`', function (done) {
driveScanner.once('drives', function (drives) {
m.chai.expect(drives).to.have.length(1);
m.chai.expect(drives[0].displayName).to.equal('F:, G:, H:');
driveScanner.stop();
done();
});
m.chai.expect(drives).to.have.length(1)
m.chai.expect(drives[0].displayName).to.equal('F:, G:, H:')
driveScanner.stop()
done()
})
driveScanner.start();
});
});
});
driveScanner.start()
})
})
})
describe('given an error when listing the drives', function () {
beforeEach(function () {
this.drivesListStub = m.sinon.stub(drivelist, 'list');
this.drivesListStub.yields(new Error('scan error'));
});
this.drivesListStub = m.sinon.stub(drivelist, 'list')
this.drivesListStub.yields(new Error('scan error'))
})
afterEach(function () {
this.drivesListStub.restore();
});
this.drivesListStub.restore()
})
it('should emit the error', function (done) {
driveScanner.on('error', function (error) {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('scan error');
driveScanner.stop();
done();
});
m.chai.expect(error).to.be.an.instanceof(Error)
m.chai.expect(error.message).to.equal('scan error')
driveScanner.stop()
done()
})
driveScanner.start();
});
});
});
driveScanner.start()
})
})
})

View File

@ -14,123 +14,123 @@
* limitations under the License.
*/
'use strict';
'use strict'
const m = require('mochainon');
const angular = require('angular');
const flashState = require('../../../lib/shared/models/flash-state');
require('angular-mocks');
const m = require('mochainon')
const angular = require('angular')
const flashState = require('../../../lib/shared/models/flash-state')
require('angular-mocks')
describe('Browser: ImageWriter', function () {
beforeEach(angular.mock.module(
require('../../../lib/gui/modules/image-writer')
));
))
describe('ImageWriterService', function () {
let $q;
let $rootScope;
let ImageWriterService;
let $q
let $rootScope
let ImageWriterService
beforeEach(angular.mock.inject(function (_$q_, _$rootScope_, _ImageWriterService_) {
$q = _$q_;
$rootScope = _$rootScope_;
ImageWriterService = _ImageWriterService_;
}));
$q = _$q_
$rootScope = _$rootScope_
ImageWriterService = _ImageWriterService_
}))
describe('.flash()', function () {
describe('given a successful write', function () {
beforeEach(function () {
this.performWriteStub = m.sinon.stub(ImageWriterService, 'performWrite');
this.performWriteStub = m.sinon.stub(ImageWriterService, 'performWrite')
this.performWriteStub.returns($q.resolve({
cancelled: false,
sourceChecksum: '1234'
}));
});
}))
})
afterEach(function () {
this.performWriteStub.restore();
});
this.performWriteStub.restore()
})
it('should set flashing to false when done', function () {
flashState.unsetFlashingFlag({
cancelled: false,
sourceChecksum: '1234'
});
})
ImageWriterService.flash('foo.img', '/dev/disk2');
$rootScope.$apply();
m.chai.expect(flashState.isFlashing()).to.be.false;
});
ImageWriterService.flash('foo.img', '/dev/disk2')
$rootScope.$apply()
m.chai.expect(flashState.isFlashing()).to.be.false
})
it('should prevent writing more than once', function () {
flashState.unsetFlashingFlag({
cancelled: false,
sourceChecksum: '1234'
});
})
ImageWriterService.flash('foo.img', '/dev/disk2');
ImageWriterService.flash('foo.img', '/dev/disk2').catch(angular.noop);
$rootScope.$apply();
m.chai.expect(this.performWriteStub).to.have.been.calledOnce;
});
ImageWriterService.flash('foo.img', '/dev/disk2')
ImageWriterService.flash('foo.img', '/dev/disk2').catch(angular.noop)
$rootScope.$apply()
m.chai.expect(this.performWriteStub).to.have.been.calledOnce
})
it('should reject the second flash attempt', function () {
ImageWriterService.flash('foo.img', '/dev/disk2');
ImageWriterService.flash('foo.img', '/dev/disk2')
let rejectError = null;
let rejectError = null
ImageWriterService.flash('foo.img', '/dev/disk2').catch(function (error) {
rejectError = error;
});
rejectError = error
})
$rootScope.$apply();
$rootScope.$apply()
m.chai.expect(rejectError).to.be.an.instanceof(Error);
m.chai.expect(rejectError.message).to.equal('There is already a flash in progress');
});
});
m.chai.expect(rejectError).to.be.an.instanceof(Error)
m.chai.expect(rejectError.message).to.equal('There is already a flash in progress')
})
})
describe('given an unsuccessful write', function () {
beforeEach(function () {
this.performWriteStub = m.sinon.stub(ImageWriterService, 'performWrite');
this.error = new Error('write error');
this.error.code = 'FOO';
this.performWriteStub.returns($q.reject(this.error));
});
this.performWriteStub = m.sinon.stub(ImageWriterService, 'performWrite')
this.error = new Error('write error')
this.error.code = 'FOO'
this.performWriteStub.returns($q.reject(this.error))
})
afterEach(function () {
this.performWriteStub.restore();
});
this.performWriteStub.restore()
})
it('should set flashing to false when done', function () {
ImageWriterService.flash('foo.img', '/dev/disk2').catch(angular.noop);
$rootScope.$apply();
m.chai.expect(flashState.isFlashing()).to.be.false;
});
ImageWriterService.flash('foo.img', '/dev/disk2').catch(angular.noop)
$rootScope.$apply()
m.chai.expect(flashState.isFlashing()).to.be.false
})
it('should set the error code in the flash results', function () {
ImageWriterService.flash('foo.img', '/dev/disk2').catch(angular.noop);
$rootScope.$apply();
const flashResults = flashState.getFlashResults();
m.chai.expect(flashResults.errorCode).to.equal('FOO');
});
ImageWriterService.flash('foo.img', '/dev/disk2').catch(angular.noop)
$rootScope.$apply()
const flashResults = flashState.getFlashResults()
m.chai.expect(flashResults.errorCode).to.equal('FOO')
})
it('should be rejected with the error', function () {
flashState.unsetFlashingFlag({
cancelled: false,
sourceChecksum: '1234'
});
})
let rejection;
let rejection
ImageWriterService.flash('foo.img', '/dev/disk2').catch(function (error) {
rejection = error;
});
rejection = error
})
$rootScope.$apply();
$rootScope.$apply()
m.chai.expect(rejection).to.be.an.instanceof(Error);
m.chai.expect(rejection.message).to.equal('write error');
});
});
});
});
});
m.chai.expect(rejection).to.be.an.instanceof(Error)
m.chai.expect(rejection.message).to.equal('write error')
})
})
})
})
})

View File

@ -14,36 +14,36 @@
* limitations under the License.
*/
'use strict';
'use strict'
const m = require('mochainon');
const angular = require('angular');
require('angular-mocks');
const m = require('mochainon')
const angular = require('angular')
require('angular-mocks')
describe('Browser: OSDropzone', function () {
beforeEach(angular.mock.module(
require('../../../lib/gui/os/dropzone/dropzone')
));
))
describe('osDropzone', function () {
let $compile;
let $rootScope;
let $timeout;
let $compile
let $rootScope
let $timeout
beforeEach(angular.mock.inject(function (_$compile_, _$rootScope_, _$timeout_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$timeout = _$timeout_;
}));
$compile = _$compile_
$rootScope = _$rootScope_
$timeout = _$timeout_
}))
it('should pass the file back to the callback as $file', function (done) {
$rootScope.onDropZone = function (file) {
m.chai.expect(file).to.deep.equal('/foo/bar');
done();
};
m.chai.expect(file).to.deep.equal('/foo/bar')
done()
}
const element = $compile('<div os-dropzone="onDropZone($file)">Drop a file here</div>')($rootScope);
$rootScope.$digest();
const element = $compile('<div os-dropzone="onDropZone($file)">Drop a file here</div>')($rootScope)
$rootScope.$digest()
element[0].ondrop({
preventDefault: angular.noop,
@ -54,20 +54,20 @@ describe('Browser: OSDropzone', function () {
}
]
}
});
})
$rootScope.$digest();
$timeout.flush();
});
$rootScope.$digest()
$timeout.flush()
})
it('should pass undefined to the callback if not passing $file', function (done) {
$rootScope.onDropZone = function (file) {
m.chai.expect(file).to.be.undefined;
done();
};
m.chai.expect(file).to.be.undefined
done()
}
const element = $compile('<div os-dropzone="onDropZone()">Drop a file here</div>')($rootScope);
$rootScope.$digest();
const element = $compile('<div os-dropzone="onDropZone()">Drop a file here</div>')($rootScope)
$rootScope.$digest()
element[0].ondrop({
preventDefault: angular.noop,
@ -78,10 +78,10 @@ describe('Browser: OSDropzone', function () {
}
]
}
});
})
$rootScope.$digest();
$timeout.flush();
});
});
});
$rootScope.$digest()
$timeout.flush()
})
})
})

Some files were not shown because too many files have changed in this diff Show More