Consider the following scenario:
- The user selects an image from an external drive
- The user selects a drive
- The user unmounts/ejects the external drive
- The user clicks flash
The application state will contain an image path that is no longer
accessible, causing an ENOENT error when spawning the CLI process.
Change-Type: patch
Changelog-Entry: Display a user error if the image is no longer accessible when the writer starts.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit implements our own version of the `is-elevated` module. The
reason behind this is that `is-elevated` relies on lots of unnecessary
modules, that eventually require `spawn-sync` and `try-thread-sleep`,
which conditionally require dependencies that are not even declared in
their `package.json`, causing issues when concatenating the Etcher CLI.
See: https://github.com/resin-io/etcher/pull/1235
See: https://github.com/resin-io/etcher/pull/1228
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
`image-stream` returns image objects that look like this:
```js
{
stream: <readable stream>,
transform: <transform stream>,
size: {
original: <number>,
final: {
value: <number>,
estimation: <boolean>
}
},
...
}
```
While the GUI handles image objects that look like this:
```sh
{
path: <string>,
size: <number>,
...
}
```
It looks like we should share a common structure between both, so we can
use `image-stream` images in `drive-constraints`, for example.
Turns out that we actually transform `image-stream` image objects to GUI
image objects when the user selects an image using the image selector
dialog, which is another indicator that we should normalise this
situation.
As a solution, this commit does the following:
- Add `path` to `image-stream` image object
- Reuse `image-stream` image objects in the GUI, given they are a
superset of GUI image objects
See: https://github.com/resin-io/etcher/pull/1223#discussion_r108165110
Fixes: https://github.com/resin-io/etcher/issues/1232
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
`mountutils` is a native C++ NodeJS addon the Etcher team has been
working on to solve several issues we've been having with third party
unmount programs.
We'll see how this little module behaves after some real world usage.
I'm confident that it will fix the issues linked in this commit.
This commit also upgrades `npm` to 4.4.4 in Appveyor, given there is a
known building issue on Windows that is solved in a recent version.
Change-Type: minor
Changelog-Entry: Fix several unmount related issues in all platforms.
See: https://github.com/resin-io-modules/mountutils
Fixes: https://github.com/resin-io/etcher/issues/1177
Fixes: https://github.com/resin-io/etcher/issues/985
Fixes: https://github.com/resin-io/etcher/issues/750
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
The CLI still happily let you flash an image that doesn't fit on the
drive. This commit prevents such scenario right before flashing, but we
should still implement a smarter CLI drive detection widget for when the
user runs the CLI interactively.
Change-Type: patch
Changelog-Entry: Prevent flashing an image that is larger than the drive with the CLI.
Fixes: https://github.com/resin-io/etcher/issues/858
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
Currently, the Etcher CLI will print scary stack traces for every single
error (e.g: if you forgot to pass an image to the tool), given that
`errors.getDescription()` will return a stack trace if no other
description could be found.
This commit introduces an `ETCHER_CLI_DEBUG` environment variable, which
when set, it will cause the Etcher CLI to output stack traces, plus a
boolean `userFriendlyDescriptionsOnly` option to
`errors.getDescription()`, so we can control whether
`errors.getDescription()` returns things like stack traces, or
stringified error objects.
Change-Type: minor
Changelog-Entry: Don't print stack traces by default in the CLI.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
The current error handling logic is a mess. We have code that tries to
fetch information about errors in different places throughout the
application, and its incredibly hard to ensure certain types of error
get decent human friendly error messages.
This commit groups, improves, and tests all error related functions in
`lib/shared/errors.js`.
Here's a summary of the changes, in more detail:
- Move the `HUMAN_FRIENDLY` object to `shared/errors.js`
- Extend `HUMAN_FRIENDLY` with error descriptions
- Add `ENOMEM` to `shared/errors.js`
- Group CLI and `OSDialogService` mechanisms for getting an error title
and an error description
- Move error serialisation routines from `robot` to `shared/errors.js`
- Create and use `createError()` and `createUserError()` utility
functions
- Add user friendly descriptions to many errors
- Don't report user errors to TrackJS
Fixes: https://github.com/resin-io/etcher/issues/1098
Change-Type: minor
Changelog-Entry: Make errors more user friendly throughout the application.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This is one step towards enforcing the linter until we barely have to
check for style issues on code reviews.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
There are a lot of new rules since the last time I revised the ESLint
rules documentation.
I've updated the main `.eslintrc.yml` to include some newer additions,
plus I added another ESLint configuration file inside `tests`, so we can
add some stricted rules to the production code while relaxing them for
the test suite (due to the fact that Mocha is not very ES6 friendly and
Angular tests require a bit of dark magic to setup).
This is a summary of the most important changes:
- Disallow "magic numbers"
These should now be extracted to constants, which forces us to think of
a good name for them, and thus make the code more self-documenting (I
had to Google up the meaning of some existing magic numbers, so I guess
this will be great for readability purposes).
- Require consistent `return` statements
Some functions relied on JavaScript relaxed casting mechanism to work,
which now have explicit return values. This flag also helped me detect
some promises that were not being returned, and therefore risked not
being caught by the exception handlers in case of errors.
- Disallow redefining function arguments
Immutability makes functions easier to reason about.
- Enforce JavaScript string templates instead of string concatenation
We were heavily mixing boths across the codebase.
There are some extra rules that I tweaked, however most of codebase
changes in this commit are related to the rules mentioned above.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
- The type in `@type` should be surrounded by curly braces
- We should use `@type` in some cases where we used `@property`
- `@module` descriptions should go above such tag
- Namespaces should not declare their access type
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
We currently attempt to read extra metadata from ZIP files, such as a
logo, image name, image url, etc. In order to simplify the metadata
story, we decided that this metadata will not live on the image itself,
but rather on a centralised repo, which greatly simplified our custom
archive extraction logic and allows us to make use of these nice
features even when streaming the image directly from the internet.
We'll be working on bringing back this functionality from a centralised
repo in subsequent commits.
Change-Type: major
Changelog-Entry: Remove extended archives metadata extraction logic.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
The `image-stream` module currently returns a readable stream, a
transform stream, a "size", and an optional "estimatedUncompressedSize".
Based on this information, its hard to say what "size" represents. Some
format handlers return the compressed size and provide a decompression
transform stream while others return the decompressed stream directly
and put the decompressed size in "size".
As a way to simplify this, every format handler now returns a "size"
object with the following properties:
- `original`: The original compressed size
- `final.estimated`: Whether the final size is an estimation or not
- `final.value`: The final uncompressed size
As a bonus, we extract the file size retrieval logic to
`imageStream.getFromFilePath()`, which is the onlt part where the
concept of a file should be referred to.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This is a long lasting task. The `etcher-image-stream` project takes
care of converting any kind of image input into a NodeJS readable
stream, handling things like decompression in betwee, however its a
module that, except for weird cases, there is no benefit on having
separate from the main repository.
In order to validate the assumption above, we've left the module
separate for almost a year, and no use case has emerged to keep it
like that.
This commit joins the code and tests of that module in the main
repository.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
The path `lib/cli/cli.js` is confusing. Rename to `options.js` which is
how we were already referencing the file in `lib/cli/etcher.js`.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
There are certain application messages that should be re-used between
the CLI and the GUI. In order to allow such re-usability, we extract out
the application messages used in JavaScript into
`lib/shared/messages.js` as a collection of Lodash `_.template`
templates.
Notice this file doesn't include application messages included in
Angular templates directly since it'd be hard to refactor all of them.
We plan to move to React soon, which will allow moving the remaining
messages very easily.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
- Inline dictionary of common error codes and friendly descriptions
We used to rely on `resin-cli-errors` for this, however the friendly
descriptions set there can be usually very Resin CLI specific, and thus
confusing to Etcher users.
The dictionary, along with other error related utilities live in
`lib/cli/errors.js`.
- Print error descriptions and codes if they are found
- Move `utils.printError()` to `errors.print()`
Change-Type: minor
Changelog-Entry: Improve Etcher CLI error messages.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
The `--robot` option of the CLI causes the program to output
machine-parseable strings, which can be easily consumed by the GUI to
update progress and other information.
The problem is that if the CLI fails to parse its command line arguments
when being called from the GUI for whatever reason, the `.fail()` Yargs
handler will be called, which doesn't output error information in the
usual "robot" format, causing the GUI to not understand the error
message.
Since the `.fail()` Yargs handler doesn't have access to the passed
options, we moved the "robot" functionality to an environment variable,
which we can easily check from there.
As a bonus, this PR refactors the whole robot logic into
`lib/shared/robot.js` and adds unit tests to it.
See: https://github.com/resin-io/etcher/issues/986
Change-Type: major
Changelog-Entry: Replace the `--robot` CLI option with an `ETCHER_CLI_ROBOT` environment variable.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
`SelectionStateModel`'s methods `isSystemDrive` and `isDriveLocked`
don't depend on application state. They have been extracted in a different
AngularJS service: `DriveConstraintsModel`. The new service's actual
implementation is in `lib/src`, in order to be reused by the CLI.
Miscellaneous changes:
- Rename `lib/src` to `lib/shared`
- Refactor `drive-constraints` to throw when image is undefined
The default behaviour was to pretend that we're all good if the if
the image is not specified. We're not using this "feature", and
it can be dangerous if we forget to pass in the image.
- Make `isSystemDrive` return `false` if `system` property is undefined
- Use `drive-constraints` in `store.js`
Change-Type: patch
This is a great simplification to the logic previously included in the
Yargs `.parse()` function on the Etcher CLI.
There is no scenario where the CLI script will be executed in a
standalone fashion (e.g: `etcher.js <options>`), so we can always safely
drop the first two elements from `process.argv`.
Change-Type: patch
Changelog-Entry: Fix command line arguments not interpreted correctly when running the CLI with a custom named NodeJS binary.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
The CLI requires elevation permissions to actually be able to write to
drives. For this reason, it makes sense that we introduce such a check
early on.
See: https://github.com/resin-io/etcher/issues/726
Change-Type: patch
Changelog-Entry: Check available permissions in the CLI early on.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
- Move UNIX unmount functionality to the CLI module
- Run `electron-mocha` for the CLI code
- Make unmount command templates that take a `drivelist` object as input
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
`yargs` wraps help output lines, causing the examples to be displayed
like this:
```
Examples:
/usr/bin/nodejs bin/etcher
raspberry-pi.img
/usr/bin/nodejs bin/etcher --no-check
raspberry-pi.img
/usr/bin/nodejs bin/etcher -d /dev/disk2
ubuntu.iso
/usr/bin/nodejs bin/etcher -d /dev/disk2
-y rpi.img
```
As a solution, we can set `.wrap(null)` to completely disable wrapping.
Fixes: https://github.com/resin-io/etcher/issues/810
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This PR makes use of `node-ipc` to emit progress information from the
child CLI to the GUI process rather than the tailing approach we've
been doing until now.
This change was motivated by the following Electron fix which landed in
v1.4.4: https://github.com/electron/electron/pull/7578. Before such fix,
Electron would not output anything to stdout/stderr if the Electron
process was running with `ELECTRON_RUN_AS_NODE` under Windows, which
forced us to implement `--log` option in the Etcher CLI to output state
information to a file.
Since this issue is fixed, we can consume the Etcher CLI output from
within `child_process.spawn`, which opens more interesting possibilities
for sharing information between both processes.
This coindentally fixes a Windows issue where the tailing module would
receive malformed JSON, causing Etcher to crash at `JSON.parse`. The
reason of this problem was a bug in the tailing module we were using.
Fixes: https://github.com/resin-io/etcher/issues/642
Change-Type: patch
Changelog-Entry: Fix "Unexpected end of JSON" error in Windows.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
The Etcher CLI displays a nice `Checksum: $checksum` message upon
completion. Since the addition of bmap support, a checksum for an image
might not be calculated, causing the CLI to display `Checksum:
undefined`.
This PR takes care of this small UX issue by only showing the checksum
message if one indeed exists.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This PR makes use of the `bytesToZeroOutFromTheBeginning` option
introduced in:
- https://github.com/resin-io-modules/etcher-image-stream/pull/34
- https://github.com/resin-io-modules/bmapflash/pull/6
The option, when set in `manifest.json`, causes a certain amount of
bytes to be zeroed out before the bmap-assisted write process starts, in
order to prevent issues on certain ROM bootloaders causing by
`bmap-tools` thinking certain parts of the initial sectors are holes.
The following components were upgraded:
- `etcher-image-stream` was upgraded to v4.1.0
- `etcher-image-write` was upgraded to v8.1.0
Changelog-Entry: Allow archive images to configure a certain amount of bytes to be zeroed out from the beginning of the drive when using bmaps.
Change-Type: minor
Fixes: https://github.com/resin-io/etcher/issues/673
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This new version stops sending a `passedValidation` boolean property
upon completion and still throws an `EVALIDATION` error when validation
fails.
Such small chance allows us to get rid of lot of complexity related to
handling the `passedValidation` value in the application state.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
In order to get the bmap file contents to the Etcher CLI, we were
handling extraction, writing to a temporary file, then reading again,
and all sorts of other mumbo-jumbo, without realising that
`etcher-image-stream` already has this information right where we need
it (in the CLI's writer module) and in the way we need it (as plain
text).
Re-using from there hugely simplifies things.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This PR integrates `.bmap` support recently added to
`etcher-image-write` into Etcher itself.
It does it in the following way:
- It adds a `--bmap` option to the Etcher CLI.
- It saves a potential `bmap` file contents to the
`SelectionStateModel`.
- In the GUI, at the time of writing, if there is a `bmap` file content
in `SelectionStateModel`, it gets written to a temporary file and such
path is passed as the `--bmap` option to the CLI.
Since validation checksums don't make sense anymore, the finish screen
doesn't show the checksum box in this case.
Change-Type: minor
Changelog-Entry: Add `.bmap` support.
Fixes: https://github.com/resin-io/etcher/issues/171
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
When using the `--robot` option, we write to `stdout`/`stderr` using
`WritableStream#write()`. This operation is asynchronous, however we're
not waiting for the data to be flushed before calling `process.exit()`
right after emitting the `done` event.
This causes a rance condition where sometimes `done` is never written to
the log file, and therefore the GUI remains waiting forever.
Change-Type: patch
Changelog-Entry: Fix application stuck at "Finishing".
See: https://github.com/resin-io/etcher/issues/613
See: https://github.com/resin-io/etcher/issues/609
See: https://github.com/resin-io/etcher/issues/573
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
We try our best to check that the images the user select are too big for
the selected drive as early as possible, but this probes to be
problematic with certain compressed formats, like bzip2, which doesn't
store any information about the uncompressed size, requiring a ~50s
intensive computation as a minimum to find it out.
For these kinds of formats, we don't perform an early check, but instead
gracefully handle the case where the drive doesn't have any more space.
This PR handles an `ENOSPC` error by displaying the alert orange ribbon,
and prompting the user to retry with a larger drive. This is a huge
improvement over the cryptic `EIO` error what was thrown before, and
over having Etcher freeze at a certain percentage point.
Change-Type: minor
Changelog-Entry: Display a nice alert ribbon if drive runs out of space.
See: https://github.com/resin-io/etcher/issues/571
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
The Etcher CLI doesn't care if the drive exists or not. The user will
eventually find out since the CLI will output an `ENOENT` when trying to
actually write data, however its nicer from a UX perspective to catch
this early on.
Change-Type: minor
Changelog-Entry: Validate the existence of the passed drive.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
JSCS has merged with ESLint. This is the perfect excuse to move to
ESLint and unify both JSHint and JSCS hints under ESLint.
This PR also deprecates `gulp lint` in favour of `npm run lint`.
See: https://medium.com/@markelog/jscs-end-of-the-line-bc9bf0b3fdb2#.zbuwvxa5y
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
ES6 fat arrows provide reasonable `this` behaviour, which protects us
from some subtle accidental bugs, and erradicates `const self = this`
from the codebase.
Far arrows were not applied in Mocha code and AngularJS
controllers/services constructors since these frameworks rely on
`.bind()` on those functions.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
The Etcher CLI `--robot` option outputs space separated lines including
useful information in a predefined order, for example:
```sh
progress write 50% 15s 65536
```
While this is very easy to parse, a stringified JSON line is much more
convenient since:
- We don't have to write any parsing logic.
- We don't have to guess the value types (string, number, boolean, etc).
- We don't have to hardcode property names.
- We don't have to extend the parsing code if we decide to send new
commands from the CLI, or make any change to the data we output.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
* Document `can-ignore` module.require annotation
This annotation was introduced in: 1872d1f
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
* Trigger CI build