Currently, we were taking care of resetting the flashing state manually
across several controllers. Now that data mutations live in a single
place, we trigger a flash state reset whenever the flashing flag is set
to false, which reliably handles every case and allows us to forget
about it.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Currently, the update check runs every single time the main application
controller is instantiated, meaning that the update check would run
again when you visit the settings screen and go back to the main page,
or return to the main page after finishing a flash.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Now that we have a central source of truth for state mutations, the
auto-select feature fits really well in the redux store, particularly
inside the `SET_AVAILABLE_DRIVES` action.
This also has the great benefit that we can unit test the auto-selection
logic, which was not particularly trivial before, when such code lived
in the controller instead.
The only downside of this approach is that we lose the nice "Auto-select
drive" analytics event, which will be re-added very soon in a future PR.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
The addition of `ImmutableJS` caused some issues with Angular's digest
loop. Since `Immutable#toJS()` returns a new object/array every time
(that is, different references), it caused AngularJS to get stuck in an
infinite digest loop when using `ngRepeat` over a function that called
`Immutable#toJS()`.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
We were duplicating the remove drive logic in the `SET_AVAILABLE_DRIVES`
case when the currently selected drive didn't exist anymore.
A better way to handle this without coding repetition is to recursively
apply the reduced with the new state.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
If the user has a selected drive, but a new scan shows that such drive
is no longer available, then the selected drive should be de-selected.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
We shouldn't allow a write-protected drive from being selected, since
users will get confusing `EPERM` errors later on.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This document explains what the Etcher CLI is, how can be used, and some
peculiarities, like `--robot` and exit codes.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Currently, Etcher's application state is stored among various models,
making it a bit hard to mentually visualise the application state at a
certain point of execution. This also means that some quirky bugs
appear, and we have to take non-elegant measures to mitigate them, for
example:
- The current drive selection might be invalid if the current available
drive list doesn't contain it anymore.
- The progress state might be modified while there is no flashing in
process.
- We have to rely on event emission to propagate the current state to
the application progress bar.
- The validity of a selected drive might depend on the currently
selected image.
While all these issues can be addressed with common programming
techniques, Redux introduces a new way of thinking about the application
state that make the above problems non-existent, or trivial to fix.
This PR creates a Redux store containing the logic used to mutate state
from:
- `SelectionStateModel`.
- `DrivesMode`.
- `ImageWriterService`.
We are also making extra effort to preserve the public APIs from the
models, which we will be simplifying in later commits.
There is still much to be done, but we're happy to be taking the first
steo towards a much cleaner architecture.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
The concept of a drive scanner lends itself very well to the concept of
"reactive programming", since the "available drives" make perfect sense
as an "Observable".
For this reason, the module was re-implemented using RxJS, which greatly
simplifies things and erradicates certain edge cases we were protecting
ourselves from automatically.
Other changes made in this PR:
- `DriveScannerService` no longer requires `DrivesModel`. The
`DriveScannerService` is the one in charge of populating the model.
- `DriveScannerService.scan()` no longer returns an `EventEmitter`. The
service itself is now an `EventEmitter`.
- `DriveScannerService` now emits a `drives`, not a `scan` event.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
If for some reason either the error title or message are not strings,
the user gets a very obscure error that looks something like this:
```
Error: Could not call remote function ''.
Check that the function signature is correct.
Underlying error:
Error processing argument at index 0, conversion failure
```
What's even worse is that the above error is thrown when we attempt to
display an `Error` object, therefore completely hiding the real error.
In this commit, we make sure both parameters to `showErrorBox()` are
strings, as a safety measure to prevent this from happening again.
See: https://github.com/resin-io/etcher/issues/127
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This PR documents the process to upgrade the Electron version correctly,
in order to prevent any potential compatibility issue when building
native dependencies.
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>
Currently we had AppImage scripts and other resources in various
different places in the code base.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
If you run an `npm install` and then run `npm shrinkwrap`, the resulting
shrinkwrap file will contain the installed optional dependencies, making
them "required". If such optional dependency is platform dependent, `npm
install` will fail on different platform.
This is a known `shrinkwrap` limitation whose only workaround seems to
be manually filtering out platform specific dependencies from
`npm-shrinkwrap.json`.
For this purpose, we introduced the following changes:
- A custom `shrinkwrapIgnore` property in `package.json`, where we can
list specific modules that need to be filtered out from
`npm-shrinkwrap.json`.
- A NodeJS script to generate `npm-shrinkwrap.json` and omit modules
specified in `shrinkwrapIgnore` automatically.
- An NPM script called `shrinkwrap`, for convenience.
- Add `macos-alias` and `fs-xattr` to `shrinkwrapIgnore`.
- Regenerate `npm-shrinkwrap.json` based on newer dependencies from PRs
created before we introduced `npm-shrinkwrap.json` but merged after that
file was in place.
See: https://github.com/npm/npm/issues/2679
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
We will be generating shrinkwrap files in every release for the
following purposes:
- Be able to run an `npm install` containing the exact package versions
used at the time of publishing.
- Auto-generate dependency updates CHANGELOG entries by comparing
shrinkwrap files between versions.
See: https://docs.npmjs.com/cli/shrinkwrap
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Etcher will start following Angular's commit guidelines, enforced by a
neat tool called `commitizer`, with the main purpose of being able to
auto-generate the CHANGELOG file.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Currently, we extract all the extensions from an image path and report
back that the image is invalid if *any* of the extensions is not a
valida extension, however this can cause trouble with images including
information between dots that are not strictly extensions.
For example:
```
elementaryos-0.3.2-stable-i386.20151209.iso
```
Etcher will consider `20151209` to be an invalid extension and therefore
will prevent such image from being selected.
As a way to allow these corner cases but will make use of our enforced
check controls, the validation routine will only consider extensions
starting from the first non compressed extension.
This PR also includes logic to show a nice GUI dialog saying that the
image is invalid in order to provide a much better experience than just
silently failing.
Fixes: https://github.com/resin-io/etcher/issues/492
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Otherwise, DevTools gets opened inside the Etcher window, causing the
GUI to get completely messed up.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Currently, when the AppImage was being ran as `root` we would attempt to
run `./usr/bin/etcher`, assuming we were inside the AppDir already and
the relative path would resolve correctly.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Consider the case where a previously elevated mount was not unmounted
correctly. `mount | grep $(basename $APPIMAGE)` would evaluate to a
multi-line string, and therefore `awk` will perform its work on *each*
line separately, usually returning something like:
```
/tmp/.mountXXXX
/tmp/.mountYYYY-elevated
```
We then pass `$mountpoint` to `mkdir -p`, which evaluates to:
```
mkdir -p /tmp/.mountXXXX
/tmp/.mountYYYY-elevated
```
Therefore `/tmp/.mountXXXX` gets created, and
`/tmp/.mountYYYY-elevated` is ran as an executable, causing all sort of
cryptic errors to come out. This can be even worse, since the third
column of a `mount` line is not always a path, so the errors make even
less sense.
Fixes: https://github.com/resin-io/etcher/issues/482
Fixes: https://github.com/resin-io/etcher/issues/459
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Currently, the modal style style used in this component was declared in
`components/_modal.scss`, however since this srule is very specific to
the update notifier component, its better declared in
`update-notifier/styles`.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This dependency is not used directly by our build scripts, but its used
by `node-gyp` when building native modules, and its much nicer to show a
warning early on than having to halt the build script in the middle for
missing this dependency (specially on Windows systems).
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Currently we have logic in the drive selector dialog to prevent invalid
drives (too small, locked, etc) from being selected, however we are not
protecting auto-selection from these invalid devices.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This PR introduces two changes to mitigate this problem and overall
provide a better UX:
- Show ellipses in the middle of the image name in the first step if
needed.
- Add a tooltip below the image selection label in the first step to
show a little modal displaying the full path to the image.
Fixes: https://github.com/resin-io/etcher/issues/418
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
In older versions of Electron, the application would display a quick
flash of white before running caused by the WebView loading up.
This workaround doesn't seem necessary anymore.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
* Upgrade etcher-image-write to v5.0.1
The new version contains an important fix to prevent `EPERM` errors on
Windows with certain drives.
Fixes: https://github.com/resin-io/etcher/issues/334
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
* Upgrade NPM to fix newer package versions not available in Appveyor
See: https://github.com/npm/npm/issues/4984
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
We rely on a millisecond to determine the state of the update notifier
logic, which can fail at least once per 50 builds or so.
We increase the time difference to account for this little room for
error.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
* Implement SelectionStateModel.isDriveLocked()
Notice we also increase the maximum number of lines JSCS check, since
the `SelectionStateModel` test suite already met that limit.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
* Show a "Locked" label if the drive is write-protected
Fixes: https://github.com/resin-io/etcher/issues/458
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This is a huge improvement over our current approach, which was simply
to cross out the drive without further explanation.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
We want to re-use the `label` component without big paddings in other
areas of the application, therefore we move the custom padding to a
separate label modifier.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This is by no means a complete CSS refactoring. There still a lot to be
done. This encompasses mostly:
- Move "Finish page" specific styles to that module.
- Remove unused CSS rules.
- Move generic Bootstrap rules to `_bootstrap.scss`.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Currently, we detect the extensions of an image path by finding the
first dot, and splitting everything afterwards, however this will fail
with image paths containing dots, like `foo.1.2.3-bar.iso.gz`.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
Currently, `DriveScannerService` is in charge of both scanning the
available drives and maintaining the state of the currently detected
drives.
To honour the single responsibility principle, we split this service
into a `DrivesModel`, which is incharge of maintaining the state without
caring how they are detected, and `DriveScannerService`, which only
scans the available drives and modified `DrivesModel` accordingly.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
The user might attempt to select an invalid image by dropping on the
first step, which would cause Etcher to blindly select it, possibly
causing errors later on the process.
This PR makes use of the list of supported extensions provided by
`SupportedFormatsModel` and prevents the selection if necessary, logging
an event that might help us determine which unsupported image types
users try to burn most often.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
If the error object is not well-formed, try to get as most information
about it as we can instead of just realying on generic error messages.
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
* Show speed during check
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
* Display ETA during flash and check
Fixes: https://github.com/resin-io/etcher/issues/256
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>