mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-24 03:36:36 +00:00
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:
parent
5c19b70e83
commit
d8e31665a0
259
.eslintrc.yml
259
.eslintrc.yml
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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')
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
@ -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))
|
||||
|
@ -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)}`)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
186
lib/gui/app.js
186
lib/gui/app.js
@ -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
|
||||
})
|
||||
|
@ -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())
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* @summary ProgressButton directive
|
||||
@ -40,5 +40,5 @@ module.exports = () => {
|
||||
percentage: '=',
|
||||
striped: '@'
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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')}`)
|
||||
})
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
@ -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}%`
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
@ -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()
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -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'
|
||||
}
|
||||
];
|
||||
]
|
||||
|
@ -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))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* @summary Etcher exit codes
|
||||
@ -63,4 +63,4 @@ module.exports = {
|
||||
*/
|
||||
CANCELLED: 3
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -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)))
|
||||
}
|
||||
|
@ -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 = {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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' ])
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
@ -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'
|
||||
});
|
||||
});
|
||||
};
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -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' ]))
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
});
|
||||
})
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
226
npm-shrinkwrap.json
generated
@ -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": {
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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')
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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'
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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"}'
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user