Compare commits

...

93 Commits

Author SHA1 Message Date
Zane Hitchcox
de93d6ac78 Update BUILD.md 2021-07-23 18:44:24 -04:00
Zane Hitchcox
6a25c9cda3 Update BUILD.md 2021-07-23 18:22:32 -04:00
Zane Hitchcox
936afec1a5 Update BUILD.md 2021-07-23 16:04:08 -04:00
Zane Hitchcox
2be29e22c2 build instructions
Change-type: patch
2021-06-26 13:19:56 -04:00
Balena CI
ccb08a48f1 v1.5.120 2021-05-11 19:56:49 +03:00
bulldozer-balena[bot]
a8f3d45b12 Merge pull request #3514 from balena-io/add-cloudsmith-reference
Update README to reference Cloudsmith
2021-05-11 16:49:15 +00:00
Lorenzo Alberto Maria Ambrosi
7e333caaf9 Update README to reference Cloudsmith
Change-type: patch
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-05-11 17:59:17 +02:00
Balena CI
70229e8684 v1.5.119 2021-05-01 11:45:32 +03:00
bulldozer-balena[bot]
261700389b Merge pull request #3500 from balena-io/new-deb-rpm-ppa
Update readme for new PPA provider
2021-05-01 08:43:36 +00:00
Lorenzo Alberto Maria Ambrosi
250aed2eb1 Update readme for new PPA provider
Change-type: patch
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2021-04-30 23:30:08 +02:00
Balena CI
ed1f008fe2 v1.5.118 2021-04-29 11:47:01 +03:00
bulldozer-balena[bot]
e9ce270dab Merge pull request #3495 from balena-io/etcher-dev-server
Etcher dev server
2021-04-29 08:45:03 +00:00
Zane Hitchcox
1ee110bc95 patch: development environment
Add webpack dev server and hot module reloading to get live changes and reloads without reloading the whole electron app.

This patch also runs the development environment in development mode, which is much, much faster on builds and rebuilds.
2021-04-26 21:17:32 -04:00
Zane Hitchcox
33dd07c675 patch: watch files for electron 2021-04-20 22:30:05 -04:00
Balena CI
39ccbbeeda v1.5.117 2021-04-06 14:44:31 +03:00
bulldozer-balena[bot]
55d2400ac7 Merge pull request #3432 from balena-io/electron-11
Electron 11
2021-04-06 11:42:19 +00:00
Alexis Svinartchouk
0bdea5c54c Rename mac releases (keep old naming)
Change-type: patch
2021-04-02 15:52:33 +02:00
Alexis Svinartchouk
3be372d49f Disable spectron tests on macOS
Change-type: patch
2021-04-01 15:48:39 +02:00
Alexis Svinartchouk
d0c66b2c48 Update electron to v12.0.2
Change-type: patch
2021-04-01 12:13:34 +02:00
Alexis Svinartchouk
65082c4790 Update etcher-sdk from 6.1.1 to 6.2.1
Update etcher-sdk from 6.1.1 to 6.2.1

Change-type: patch
2021-03-29 14:11:44 +02:00
Alexis Svinartchouk
e87ed9beed Fix getAppPath() returning an asar file on macOS
Change-type: patch
2021-03-23 17:53:54 +01:00
Andrew Scheller
bc5563d9c2 Grammar fix
"flash directly" sounds odd

Change-type: patch
2021-03-23 14:32:30 +01:00
vlad doster
ad83ab5dcc (docs) update README.md
- fix spelling
- emphasize notes
- add link
- fix macOS to account for new homebrew API

Change-type: patch
2021-03-23 12:00:40 +01:00
Andrew Scheller
0dc1cf9701 Update copyright year in electron-builder.yml
Change-type: patch
2021-03-23 11:55:43 +01:00
Andrew Scheller
11489c6538 Update copyright year in .resinci.json
Change-type: patch
2021-03-23 11:55:29 +01:00
Dugan Chen
2619d4bc86 Separate the Yum and DNF instructions.
Change-type: patch
2021-03-23 11:55:04 +01:00
Alexis Svinartchouk
3730efd350 Set msvs_version to 2019 when rebuilding
Change-type: patch
2021-03-22 17:23:43 +01:00
Alexis Svinartchouk
6ece32c546 Use moduleIds: 'natural' in webpack config to keep js files in arm64 and x64 mac builds identical
Change-type: patch
2021-03-22 15:38:57 +01:00
Alexis Svinartchouk
fd9996a3cc Update electron-builder to 22.10.5
Change-type: patch
2021-03-22 15:38:57 +01:00
Alexis Svinartchouk
f06cc89152 Update spectron to v13
Change-type: patch
2021-03-22 15:38:57 +01:00
Alexis Svinartchouk
c1d7ab3fa9 Update dependencies, use aws4-axios@2.2.1 to avoid adding more dependiencies
Also filter out dmg-license dependencies from the shrinkwrap file
aws4-axios@2.3.0 brings in react-native, see aws/aws-sdk-js-v3#1797

Change-type: patch
2021-03-22 15:38:57 +01:00
Alexis Svinartchouk
b206483c7c Update scripts to build universal mac dmgs on the ci
Change-type: patch
2021-03-22 15:38:57 +01:00
Alexis Svinartchouk
c3eb8c7b56 Fix beforeBuild.js script to also work on mac
Change-type: patch
2021-03-15 19:26:49 +01:00
Alexis Svinartchouk
0849d4f435 Support building universal dmgs (x64 and arm64) for mac
Change-type: patch
2021-03-15 19:26:49 +01:00
Alexis Svinartchouk
1dba3ae19b Update electron-builder to 22.10.4
Change-type: patch
2021-02-16 15:49:18 +01:00
Alexis Svinartchouk
f33f2e3771 Fix titlebar z-index
Change-type: patch
2021-02-16 15:49:18 +01:00
Alexis Svinartchouk
e56aaed973 Explicitly set contextIsolation to false
Change-type: patch
2021-02-16 15:49:12 +01:00
Alexis Svinartchouk
a4659f038e Update electron from 9.4.1 to 11.2.3
Change-type: patch
2021-02-10 17:51:56 +01:00
Alexis Svinartchouk
cd462818da Update etcher-sdk from 6.1.0 to 6.1.1
Update etcher-sdk from 6.1.0 to 6.1.1

Change-type: patch
2021-02-10 17:50:47 +01:00
Balena CI
37769efbed v1.5.116 2021-02-03 17:56:40 +02:00
bulldozer-balena[bot]
0f70c4bbce Merge pull request #3414 from balena-io/116
116
2021-02-03 15:54:29 +00:00
Alexis Svinartchouk
48b5e8b9d9 Only cleanup temporary decompressed files in child-writer
Change-type: patch
2021-02-03 14:55:16 +01:00
Alexis Svinartchouk
1f138f0ecc Add .versionbot/CHANGELOG.yml
Change-type: patch
2021-02-03 14:55:16 +01:00
Alexis Svinartchouk
73f67e99ca Stop using node-tmp, use withTmpFile from etcher-sdk instead
Change-type: patch
2021-02-03 14:55:16 +01:00
Alexis Svinartchouk
9114da2445 Update etcher-sdk from 5.2.2 to 6.1.0
Update etcher-sdk from 5.2.2 to 6.1.0

Change-type: patch
2021-02-03 14:55:16 +01:00
Alexis Svinartchouk
554bbcc780 Revert "Change some border colors to have higher contrast"
This reverts commit 8c4edaabba.

Change-type: patch
2021-02-01 19:44:37 +01:00
Alexis Svinartchouk
4db2289cfd Update electron to v9.4.1
Change-type: patch
2021-02-01 19:44:37 +01:00
Alexis Svinartchouk
c15b56bc23 Update etcher-sdk from 5.2.1 to 5.2.2
Update etcher-sdk from 5.2.1 to 5.2.2

Change-type: patch
2021-01-19 18:44:19 +01:00
Balena CI
9f52dda6ae v1.5.115 2021-01-18 14:09:10 +02:00
bulldozer-balena[bot]
fadcefb11a Merge pull request #3413 from balena-io/115
Update etcher-sdk from 5.1.12 to 5.2.1
2021-01-18 12:07:11 +00:00
Alexis Svinartchouk
361c32913c Update etcher-sdk from 5.1.12 to 5.2.1
Update etcher-sdk from 5.1.12 to 5.2.1

Change-type: patch
2021-01-18 10:46:59 +01:00
Balena CI
5c2042198e v1.5.114 2021-01-15 14:30:49 +02:00
bulldozer-balena[bot]
99df53098c Merge pull request #3394 from balena-io/114
114
2021-01-15 12:28:31 +00:00
Alexis Svinartchouk
aa563c87bd Remove libappindicator1 debian dependency
Changelog-entry: Remove libappindicator1 debian dependency
Change-type: patch
2021-01-12 15:22:43 +01:00
Alexis Svinartchouk
1188888956 Update etcher-sdk from 5.1.11 to 5.1.12
Update etcher-sdk from 5.1.11 to 5.1.12

Change-type: patch
2021-01-12 15:22:43 +01:00
Alexis Svinartchouk
f9d7991dc8 Update rendition from 18.8.3 to 19.2.0
Update rendition from 18.8.3 to 19.2.0

Change-type: patch
2021-01-12 15:22:42 +01:00
Alexis Svinartchouk
53954e81fd Update dependencies
Change-type: patch
2021-01-12 15:22:42 +01:00
Alexis Svinartchouk
f82996bfd1 Update @balena/lint to 5.3.0
Change-type: patch
2021-01-12 15:22:42 +01:00
Alexis Svinartchouk
b74069eb41 Update webpack to v5
Changelog-entry: Update webpack to v5
Change-type: patch
2021-01-12 15:22:42 +01:00
Alexis Svinartchouk
e8c7591751 Fix typo in webpack.config.ts comment
Change-type: patch
2021-01-12 15:22:42 +01:00
Aaron Shaw
3521b61a81 docs: fix quote marks
Fix quote mark styling

Change-type: patch
Signed-off-by: Aaron Shaw <aaron@balena.io>
2021-01-12 15:22:42 +01:00
Alexis Svinartchouk
93db90c725 Disable screensaver while flashing (on balena-electron-env)
Change-type: patch
2021-01-12 15:22:42 +01:00
Balena CI
1dc56aed14 v1.5.113 2020-12-17 16:23:23 +02:00
bulldozer-balena[bot]
d814202424 Merge pull request #3377 from balena-io/113
113
2020-12-17 14:20:57 +00:00
Alexis Svinartchouk
c54856a616 Only store the first error for each target
Changelog-entry: Show the first error for each drive (not the last)
Change-type: patch
2020-12-16 12:33:17 +01:00
Alexis Svinartchouk
fc45df270a Fix red leds not showing for failed devices
Change-type: patch
2020-12-14 18:59:40 +01:00
Aaron Shaw
3cde2faed0 docs: add documentation links
add documentation and faq links

Change-Type: patch
Closes: https://github.com/balena-io/etcher/issues/3191
Signed-off-by: Aaron Shaw <aaron@balena.io>
2020-12-14 18:59:40 +01:00
Aaron Shaw
b4b8c89aad docs: update macOS version
Update macOS version as latest version of Electron is 10.10 compatible only (Yosemite)

Change-Type: patch
Signed-off-by: Aaron Shaw <aaron@balena.io>
2020-12-14 18:59:40 +01:00
Alexis Svinartchouk
36d05724c0 Improve hover message when the drive is too small
Changelog-entry: Improve hover message when the drive is too small
Change-type: patch
2020-12-14 18:59:40 +01:00
Alexis Svinartchouk
b1e4e681d1 Update electron to v9.4.0
Changelog-entry: Update electron to v9.4.0
Change-type: patch
2020-12-14 18:59:40 +01:00
Giovanni Garufi
3987078c11 Update npm to v6.14.8
Change-type: patch
2020-12-11 17:51:50 +01:00
Alexis Svinartchouk
de0010eb72 Update rgb leds colors
Change-type: patch
2020-12-10 17:18:54 +01:00
Alexis Svinartchouk
1f94f44b18 Remove unmountOnSuccess setting
Changelog-entry: Remove unmountOnSuccess setting
Change-type: patch
2020-12-10 15:36:19 +01:00
Alexis Svinartchouk
fe0b45cae6 Only show auto-updates setting on supported targets
Change-type: patch
2020-12-10 15:35:37 +01:00
Alexis Svinartchouk
c32e485f27 Remove dead code in settings modal
Change-type: patch
2020-12-10 14:05:08 +01:00
Alexis Svinartchouk
409b78fc21 Fix effective flashing speed calculation for compressed images
Changelog-entry: Fix effective flashing speed calculation for compressed images
Change-type: patch
2020-12-08 17:14:49 +01:00
bulldozer-balena[bot]
2f08142f5a Merge pull request #3379 from balena-io/high-contrast-lines
Change some border colors to have higher contrast
2020-12-08 13:54:20 +00:00
Lorenzo Alberto Maria Ambrosi
8c4edaabba Change some border colors to have higher contrast
Change-type: patch
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
2020-12-08 14:37:24 +01:00
Alexis Svinartchouk
05497ce85c Update etcher-sdk from 5.1.10 to 5.1.11
Update etcher-sdk from 5.1.10 to 5.1.11

Changelog-entry: Update etcher-sdk from 5.1.10 to 5.1.11
Change-type: patch
2020-12-07 19:31:41 +01:00
Alexis Svinartchouk
d3df2fe57e Update sys-class-rgb-led from 2.1.1 to 3.0.0
Update sys-class-rgb-led from 2.1.1 to 3.0.0

Changelog-entry: Update sys-class-rgb-led from 2.1.1 to 3.0.0
Change-type: patch
2020-12-04 14:11:51 +01:00
Balena CI
a0f07082f2 v1.5.112 2020-12-03 17:19:22 +02:00
bulldozer-balena[bot]
b7efa8e1f0 Merge pull request #3362 from balena-io/112
112
2020-12-03 15:17:28 +00:00
Alexis Svinartchouk
3647457bb5 Add rendition and sys-class-rgb-led to repo.yml
Change-type: patch
2020-12-02 20:23:04 +01:00
Alexis Svinartchouk
2e5a39dcd8 Update sys-class-rgb-led from 2.1.0 to 2.1.1
Update sys-class-rgb-led from 2.1.0 to 2.1.1

Changelog-entry: Update sys-class-rgb-led from 2.1.0 to 2.1.1
Change-type: patch
2020-12-02 20:23:04 +01:00
Alexis Svinartchouk
edabacfb3a Fix spectron test to work on Windows in all cases
Change-type: none
2020-12-02 20:23:04 +01:00
Alexis Svinartchouk
f46176fd10 Fix layout when the featured project is not showing
Changelog-entry: Fix layout when the featured project is not showing
Change-type: patch
2020-12-02 20:23:04 +01:00
Alexis Svinartchouk
2158e20380 Improve flashing error handling
Changelog-entry: Improve flashing error handling
Change-type: patch
2020-12-02 20:23:04 +01:00
Alexis Svinartchouk
fa593e33d1 Update repo.yml to enable nested changelogs
Change-type: none
2020-12-02 19:27:48 +01:00
Alexis Svinartchouk
50730bd3df Fix imports in child-writer.ts
Change-type: none
2020-12-02 19:27:48 +01:00
Alexis Svinartchouk
4e68955981 Target commit instead of branch name for sudo-prompt
Change-type: none
2020-12-02 19:27:48 +01:00
Alexis Svinartchouk
3c0084d012 Fix modal content height on Windows
Change-type: patch
2020-12-02 19:27:48 +01:00
Alexis Svinartchouk
8bd11a01ae Update etcher-sdk from 5.1.5 to 5.1.10
Update etcher-sdk from 5.1.5 to 5.1.10

Changelog-entry: Update etcher-sdk from 5.1.5 to 5.1.10
Change-type: patch
2020-12-02 19:27:48 +01:00
Alexis Svinartchouk
da3a22d0f6 Set useContentSize to true so the size is the same on all platforms
Changelog-entry: Set useContentSize to true so the size is the same on all platforms
Change-type: patch
2020-11-24 17:10:17 +01:00
43 changed files with 17829 additions and 6449 deletions

View File

@@ -15,7 +15,7 @@
},
"builder": {
"appId": "io.balena.etcher",
"copyright": "Copyright 2016-2020 Balena Ltd",
"copyright": "Copyright 2016-2021 Balena Ltd",
"productName": "balenaEtcher",
"nodeGypRebuild": false,
"afterPack": "./afterPack.js",
@@ -30,7 +30,8 @@
"category": "public.app-category.developer-tools",
"hardenedRuntime": true,
"entitlements": "entitlements.mac.plist",
"entitlementsInherit": "entitlements.mac.plist"
"entitlementsInherit": "entitlements.mac.plist",
"artifactName": "${productName}-${version}.${ext}"
},
"dmg": {
"iconSize": 110,

11237
.versionbot/CHANGELOG.yml Normal file

File diff suppressed because it is too large Load Diff

93
BUILD.md Normal file
View File

@@ -0,0 +1,93 @@
# Building etcher on Windows, Linux, and Mac
> How do you build etcher? On Windows, Linux, Mac
Its the same on all systems:
First clone the repository recursively:
`git clone --recursive https://github.com:balena-io/etcher`
```
rm -rf node_modules
make electron-develop
npm start
```
To build packages for distribution, run `make electron-build` after the steps above.
### Windows
> What version of mingw and visual studio are needed to build? Any other dependencies for windows? Instructions for how to install?
Visual studio 2019 with:
* MSVC v142 x86-64 build tools
* Windows 10 SDK
Also install Windows Driver Kit from https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk
- you might have to look under "previous versions" for the windows wdk to match your windows sdk
- all you need from this page is the WDK, you can ignore everything else, just download it
pip install -r requirements.txt
Mingw64, install it from https://www.msys2.org/
install choco: https://chocolatey.org/install
install jq: choco install jq -y
Add /c/msys64/usr/bin/ to path
> It appears youre supposed to use `npm i` and then `npm watch` and then `npm start` in order to build/run the electron app, but Im getting the error:
NODE_MODULE_VERSION 88. This version of Node.js requires
NODE_MODULE_VERSION 80. Please try re-compiling or re-installing
From the module `xxhash`
This error means that a module wasnt built for the correct runtime (node or electron) and version. In general it means that either you ran `npm i` instead of `make electron-develop` or you just updated the electron version.
Remove the node_modules folder and run `make electron-develop`, that should fix it.
If you want to use only npm, set up some env vars to target the correct runtime as in https://github.com/balena-io/EtcherProApplication/blob/v1.0.0/Dockerfile#L11-L13
Each time you change a js file, you need to run `npm webpack` again. This is quite slow. To make it faster leave `npm run watch` running. It actually just runs `webpack --watch`
https://github.com/electron/electron/blob/master/docs/tutorial/using-native-node-modules.md
### Mac OS X
Install XCode via the App Store
> I get the error: `gyp: No Xcode or CLT version detected!`
Fix with:
```
sudo xcodebuild -license accept
```
> I get the error: `xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance`
Fix with:
```
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
```
> I get the error: `[webpack-cli] Error: Could not find lzma_native binding`
Try removing node_modules and running `make electron-develop` again.
### Linux
Should work OOTB, please create issue if not.
* Note: Might have to downgrade to Node 14
### FreeBSD
Should work OOTB, please create issue if not.
* Note: Might have to downgrade to Node 14

View File

@@ -3,6 +3,677 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
# v1.5.120
## (2021-05-11)
* Update README to reference Cloudsmith [Lorenzo Alberto Maria Ambrosi]
# v1.5.119
## (2021-04-30)
* Update readme for new PPA provider [Lorenzo Alberto Maria Ambrosi]
# v1.5.118
## (2021-04-27)
* patch: development environment [Zane Hitchcox]
* patch: watch files for electron [Zane Hitchcox]
# v1.5.117
## (2021-04-02)
* Rename mac releases (keep old naming) [Alexis Svinartchouk]
* Disable spectron tests on macOS [Alexis Svinartchouk]
* Update electron to v12.0.2 [Alexis Svinartchouk]
<details>
<summary> Update etcher-sdk from 6.1.1 to 6.2.1 [Alexis Svinartchouk] </summary>
> ## etcher-sdk-6.2.1
> ### (2021-03-26)
>
>
> <details>
> <summary> Update node-raspberrypi-usbboot from 0.2.11 to 0.3.0 [Alexis Svinartchouk] </summary>
>
>> ### node-raspberrypi-usbboot-0.3.0
>> #### (2021-03-26)
>>
>> * Add support for compute module 4 [Alexis Svinartchouk]
>> * Fix size endianness of boot_message_t message [Alexis Svinartchouk]
>>
> </details>
>
>
> ## etcher-sdk-6.2.0
> ### (2021-02-18)
>
> * Added BeagleBone USB Boot example [Parthiban Gandhi]
> * Added BeagleBone USB Boot support [Parthiban Gandhi]
>
</details>
* Fix getAppPath() returning an asar file on macOS [Alexis Svinartchouk]
* Grammar fix [Andrew Scheller]
* (docs) update README.md [vlad doster]
* Update copyright year in electron-builder.yml [Andrew Scheller]
* Update copyright year in .resinci.json [Andrew Scheller]
* Separate the Yum and DNF instructions. [Dugan Chen]
* Set msvs_version to 2019 when rebuilding [Alexis Svinartchouk]
* Use moduleIds: 'natural' in webpack config to keep js files in arm64 and x64 mac builds identical [Alexis Svinartchouk]
* Update electron-builder to 22.10.5 [Alexis Svinartchouk]
* Update spectron to v13 [Alexis Svinartchouk]
* Update dependencies, use aws4-axios@2.2.1 to avoid adding more dependiencies [Alexis Svinartchouk]
* Update scripts to build universal mac dmgs on the ci [Alexis Svinartchouk]
* Fix beforeBuild.js script to also work on mac [Alexis Svinartchouk]
* Support building universal dmgs (x64 and arm64) for mac [Alexis Svinartchouk]
* Update electron-builder to 22.10.4 [Alexis Svinartchouk]
* Fix titlebar z-index [Alexis Svinartchouk]
* Explicitly set contextIsolation to false [Alexis Svinartchouk]
* Update electron from 9.4.1 to 11.2.3 [Alexis Svinartchouk]
<details>
<summary> Update etcher-sdk from 6.1.0 to 6.1.1 [Alexis Svinartchouk] </summary>
> ## etcher-sdk-6.1.1
> ### (2021-02-10)
>
>
> <details>
> <summary> Update node-raspberrypi-usbboot from 0.2.10 to 0.2.11 [Alexis Svinartchouk] </summary>
>
>> ### node-raspberrypi-usbboot-0.2.11
>> #### (2021-02-10)
>>
>> * Update @balena.io/usb from 1.3.12 to 1.3.14 [Alexis Svinartchouk]
>>
> </details>
>
>
</details>
# v1.5.116
## (2021-02-03)
* Only cleanup temporary decompressed files in child-writer [Alexis Svinartchouk]
* Add .versionbot/CHANGELOG.yml [Alexis Svinartchouk]
* Stop using node-tmp, use withTmpFile from etcher-sdk instead [Alexis Svinartchouk]
<details>
<summary> Update etcher-sdk from 5.2.2 to 6.1.0 [Alexis Svinartchouk] </summary>
> ## etcher-sdk-6.1.0
> ### (2021-02-03)
>
> * Prefix temporary decompressed images filenames [Alexis Svinartchouk]
>
> ## etcher-sdk-6.0.1
> ### (2021-02-02)
>
> * Ignore ENOENT errors on unlink in withTmpFile [Alexis Svinartchouk]
>
> ## etcher-sdk-6.0.0
> ### (2021-02-01)
>
> * Export tmp and add prefix and postfix options [Alexis Svinartchouk]
>
> ## etcher-sdk-5.2.3
> ### (2021-01-26)
>
> * upgrade lint [Zane Hitchcox]
>
</details>
* Revert "Change some border colors to have higher contrast" [Alexis Svinartchouk]
* Update electron to v9.4.1 [Alexis Svinartchouk]
<details>
<summary> Update etcher-sdk from 5.2.1 to 5.2.2 [Alexis Svinartchouk] </summary>
> ## etcher-sdk-5.2.2
> ### (2021-01-19)
>
>
> <details>
> <summary> Update drivelist from 9.2.2 to 9.2.4 [Alexis Svinartchouk] </summary>
>
>> ### drivelist-9.2.4
>> #### (2021-01-19)
>>
>> * Pass strings between methods as std::string instead of char * [Floris Bos]
>>
>> ### drivelist-9.2.3
>> #### (2021-01-19)
>>
>> * Support lsblk versions that do no support the pttype column [Alexis Svinartchouk]
>>
> </details>
>
>
</details>
# v1.5.115
## (2021-01-18)
<details>
<summary> Update etcher-sdk from 5.1.12 to 5.2.1 [Alexis Svinartchouk] </summary>
> ## etcher-sdk-5.2.1
> ### (2021-01-15)
>
> * Only run one diskpart at a time [Alexis Svinartchouk]
> * Ignore diskpart VDS_E_DISK_IS_OFFLINE errors [Alexis Svinartchouk]
>
> ## etcher-sdk-5.2.0
> ### (2021-01-06)
>
> * Store progress on usbboot devices [Alexis Svinartchouk]
>
</details>
# v1.5.114
## (2021-01-12)
* Remove libappindicator1 debian dependency [Alexis Svinartchouk]
<details>
<summary> Update etcher-sdk from 5.1.11 to 5.1.12 [Alexis Svinartchouk] </summary>
> ## etcher-sdk-5.1.12
> ### (2021-01-06)
>
> * Remove BlockDevice.mountpoints incorrect typing [Alexis Svinartchouk]
> * Update axios to 0.21.1 and aws4-axios to 2.0.1 [Alexis Svinartchouk]
>
</details>
<details>
<summary> Update rendition from 18.8.3 to 19.2.0 [Alexis Svinartchouk] </summary>
> ## rendition-19.2.0
> ### (2020-12-29)
>
> * Add truncate property to Txt component [JSReds]
>
> ## rendition-19.1.0
> ### (2020-12-29)
>
> * Add fallback image source to Img component [Stevche Radevski]
>
> ## rendition-19.0.0
> ### (2020-12-21)
>
> * Remove Arcslider component [Stevche Radevski]
>
> ## rendition-18.20.4
> ### (2020-12-17)
>
> * Upgrade rehype-raw to latest version [Kakhaber]
>
> ## rendition-18.20.3
> ### (2020-12-17)
>
> * Fix disabled button tooltip [JSReds]
>
> ## rendition-18.20.2
> ### (2020-12-16)
>
> * Turn keydown handler into an arrow function [Stevche Radevski]
>
> ## rendition-18.20.1
> ### (2020-12-14)
>
> * Fix form not getting the Enter key event when nested in a modal [Stevche Radevski]
>
> ## rendition-18.20.0
> ### (2020-12-14)
>
> * feat: Add new StatsBar component [Graham McCulloch]
>
> ## rendition-18.19.2
> ### (2020-12-14)
>
> * Update snapshots [Graham McCulloch]
> * Removed out-of-date documentation and template text [Graham McCulloch]
>
> ## rendition-18.19.1
> ### (2020-12-04)
>
> * Markdown: Fix line breaks [Kakhaber]
>
> ## rendition-18.19.0
> ### (2020-12-02)
>
> * Make card size responsive [Stevche Radevski]
>
> ## rendition-18.18.0
> ### (2020-12-02)
>
> * Allow passing responsive values to datagrid width props [Stevche Radevski]
>
> ## rendition-18.17.2
> ### (2020-12-01)
>
> * Update snapshots due to a Card change [JSReds]
>
> ## rendition-18.17.1
> ### (2020-12-01)
>
> * Card: make body to be full height [JSReds]
>
> ## rendition-18.17.0
> ### (2020-12-01)
>
> * Add star rating component [Kakhaber]
>
> ## rendition-18.16.0
> ### (2020-11-23)
>
> * Completely revamp the development setup for rendition [Stevche Radevski]
>
> ## rendition-18.15.1
> ### (2020-11-16)
>
> * Modal: Change the button margins to use the predefined spacing palette [Thodoris Greasidis]
>
> ## rendition-18.15.0
> ### (2020-11-16)
>
> * Modal: Move the cancel button first for dangerous & warning actions [Thodoris Greasidis]
>
> ## rendition-18.14.0
> ### (2020-11-16)
>
> * Allow passing checked items as a prop to Table [Stevche Radevski]
>
> ## rendition-18.13.4
> ### (2020-11-16)
>
> * Fix accidental complete lodash import [Thodoris Greasidis]
>
> ## rendition-18.13.3
> ### (2020-11-16)
>
> * Form: Remove the flaky Captcha sceenshot test [Thodoris Greasidis]
> * Update react-simplemde-editor & snapshots for upstream versions [Thodoris Greasidis]
>
> ## rendition-18.13.2
> ### (2020-10-29)
>
> * Updated snapshots [Graham McCulloch]
> * Fix: Confirm only depends on the files it needs [Graham McCulloch]
>
> ## rendition-18.13.1
> ### (2020-10-23)
>
> * Button: Preserve event during confirmation [Kakhaber]
>
> ## rendition-18.13.0
> ### (2020-10-22)
>
> * Button: Add confirmation property [Kakhaber]
>
> ## rendition-18.12.2
> ### (2020-10-21)
>
> * Tabs: changed interfaces and props [JSReds]
>
> ## rendition-18.12.1
> ### (2020-10-20)
>
> * Fix Tabs typings [Stevche Radevski]
>
> ## rendition-18.12.0
> ### (2020-10-19)
>
> * Add a Grid component [Stevche Radevski]
>
> ## rendition-18.11.3
> ### (2020-10-14)
>
> * Added more documentation for JsonSchemaRenderer [Graham McCulloch]
>
> ## rendition-18.11.2
> ### (2020-10-14)
>
> * fix: UI schema for JsonSchemaRenderer DropDownButton and ButtonGroup widgets [Graham McCulloch]
>
> ## rendition-18.11.1
> ### (2020-10-13)
>
> * Add dark mode to storybook [Stevche Radevski]
>
> ## rendition-18.11.0
> ### (2020-10-08)
>
> * Allow passing widget to extraFormats field [Stevche Radevski]
>
> ## rendition-18.10.2
> ### (2020-09-30)
>
> * Resolve module path not relying on node_moules dir [Kakhaber]
>
> ## rendition-18.10.1
> ### (2020-09-29)
>
> * Set tabpanel height so it stretches to full height [StefKors]
> * Specify tabs width to fix layout problems [StefKors]
>
> ## rendition-18.10.0
> ### (2020-09-24)
>
> * feat: Add ColorWidget for JsonSchemaRenderer [Graham McCulloch]
>
> ## rendition-18.9.2
> ### (2020-09-22)
>
> * Markdown: Ignore decorators inside a code block [Kakhaber]
>
> ## rendition-18.9.1
> ### (2020-09-21)
>
> * Add compact variation to tabs [StefKors]
>
> ## rendition-18.9.0
> ### (2020-09-18)
>
> * Improve spacing for Modal and Select components [Stevche Radevski]
>
> ## rendition-18.8.4
> ### (2020-09-17)
>
> * fix: Use widget's display name to reference the widget [Graham McCulloch]
>
</details>
* Update dependencies [Alexis Svinartchouk]
* Update @balena/lint to 5.3.0 [Alexis Svinartchouk]
* Update webpack to v5 [Alexis Svinartchouk]
* Fix typo in webpack.config.ts comment [Alexis Svinartchouk]
* docs: fix quote marks [Aaron Shaw]
* Disable screensaver while flashing (on balena-electron-env) [Alexis Svinartchouk]
# v1.5.113
## (2020-12-16)
* Show the first error for each drive (not the last) [Alexis Svinartchouk]
* Fix red leds not showing for failed devices [Alexis Svinartchouk]
* docs: add documentation links [Aaron Shaw]
* docs: update macOS version [Aaron Shaw]
* Improve hover message when the drive is too small [Alexis Svinartchouk]
* Update electron to v9.4.0 [Alexis Svinartchouk]
* Update npm to v6.14.8 [Giovanni Garufi]
* Update rgb leds colors [Alexis Svinartchouk]
* Remove unmountOnSuccess setting [Alexis Svinartchouk]
* Only show auto-updates setting on supported targets [Alexis Svinartchouk]
* Remove dead code in settings modal [Alexis Svinartchouk]
* Fix effective flashing speed calculation for compressed images [Alexis Svinartchouk]
* Change some border colors to have higher contrast [Lorenzo Alberto Maria Ambrosi]
<details>
<summary> Update etcher-sdk from 5.1.10 to 5.1.11 [Alexis Svinartchouk] </summary>
> ## etcher-sdk-5.1.11
> ### (2020-12-07)
>
> * Don't use the O_SYNC flag for block devices, only O_DIRECT [Alexis Svinartchouk]
>
</details>
<details>
<summary> Update sys-class-rgb-led from 2.1.1 to 3.0.0 [Alexis Svinartchouk] </summary>
> ## sys-class-rgb-led-3.0.0
> ### (2020-12-03)
>
> * Add example etcher-pro rainbow animation [Alexis Svinartchouk]
> * Use one setInterval instead of a loop for each led, t in seconds [Alexis Svinartchouk]
>
</details>
# v1.5.112
## (2020-12-02)
* Add rendition and sys-class-rgb-led to repo.yml [Alexis Svinartchouk]
<details>
<summary> Update sys-class-rgb-led from 2.1.0 to 2.1.1 [Alexis Svinartchouk] </summary>
> ## sys-class-rgb-led-2.1.1
> ### (2020-12-01)
>
> * Replace resin-lint with @balena/lint [Alexis Svinartchouk]
> * Update typescript to v4.1.2 [Alexis Svinartchouk]
> * Add versionbot changelog [Alexis Svinartchouk]
>
</details>
* Fix layout when the featured project is not showing [Alexis Svinartchouk]
* Improve flashing error handling [Alexis Svinartchouk]
* Fix modal content height on Windows [Alexis Svinartchouk]
<details>
<summary> Update etcher-sdk from 5.1.5 to 5.1.10 [Alexis Svinartchouk] </summary>
> ## etcher-sdk-5.1.10
> ### (2020-12-02)
>
>
> <details>
> <summary> Update balena-image-fs from 7.0.5 to 7.0.6 [Alexis Svinartchouk] </summary>
>
>> ### balena-image-fs-7.0.6
>> #### (2020-12-02)
>>
>>
>> <details>
>> <summary> Update ext2fs from 3.0.4 to 3.0.5 [Alexis Svinartchouk] </summary>
>>
>>> #### node-ext2fs-3.0.5
>>> ##### (2020-12-02)
>>>
>>> * Fix reading and discarding with offsets > 32 bits [Alexis Svinartchouk]
>>>
>> </details>
>>
>>
> </details>
>
>
> ## etcher-sdk-5.1.9
> ### (2020-12-01)
>
> * Add repo.yml file [Alexis Svinartchouk]
> * Update @balena/udif from 1.1.0 to 1.1.1 [Alexis Svinartchouk]
>
> <details>
> <summary> Update zip-part-stream from 1.0.2 to 1.0.3 [Alexis Svinartchouk] </summary>
>
>> ### zip-part-stream-1.0.3
>> #### (2020-11-30)
>>
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
> </details>
>
>
> <details>
> <summary> Update node-raspberrypi-usbboot from 0.2.9 to 0.2.10 [Alexis Svinartchouk] </summary>
>
>> ### node-raspberrypi-usbboot-0.2.10
>> #### (2020-11-30)
>>
>> * Update typescript to v4.1.2 [Alexis Svinartchouk]
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
> </details>
>
>
> <details>
> <summary> Update mountutils from 1.3.19 to 1.3.20 [Alexis Svinartchouk] </summary>
>
>> ### mountutils-1.3.20
>> #### (2020-11-30)
>>
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
> </details>
>
>
> <details>
> <summary> Update gzip-stream from 1.1.1 to 1.1.2 [Alexis Svinartchouk] </summary>
>
>> ### gzip-stream-1.1.2
>> #### (2020-11-30)
>>
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
> </details>
>
>
> <details>
> <summary> Update drivelist from 9.2.1 to 9.2.2 [Alexis Svinartchouk] </summary>
>
>> ### drivelist-9.2.2
>> #### (2020-11-30)
>>
>> * Update typescript to v4.1.2 [Alexis Svinartchouk]
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
> </details>
>
>
> <details>
> <summary> Update blockmap from 4.0.2 to 4.0.3 [Alexis Svinartchouk] </summary>
>
>> ### blockmap-4.0.3
>> #### (2020-11-30)
>>
>> * Update typescript to v4.1.2 [Alexis Svinartchouk]
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
> </details>
>
>
> <details>
> <summary> Update partitioninfo from 6.0.1 to 6.0.2 [Alexis Svinartchouk] </summary>
>
>> ### partitioninfo-6.0.2
>> #### (2020-11-27)
>>
>>
>> <details>
>> <summary> Update file-disk from 8.0.0 to 8.0.1 [Alexis Svinartchouk] </summary>
>>
>>> #### file-disk-8.0.1
>>> ##### (2020-11-26)
>>>
>>> * Add versionbot changelog [Alexis Svinartchouk]
>>>
>> </details>
>>
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
> </details>
>
>
> <details>
> <summary> Update file-disk from 8.0.0 to 8.0.1 [Alexis Svinartchouk] </summary>
>
>> ### file-disk-8.0.1
>> #### (2020-11-26)
>>
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
>> ### file-disk-8.0.1
>> #### (2020-11-26)
>>
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
> </details>
>
>
> <details>
> <summary> Update balena-image-fs from 7.0.4 to 7.0.5 [Alexis Svinartchouk] </summary>
>
>> ### balena-image-fs-7.0.5
>> #### (2020-11-27)
>>
>>
>> <details>
>> <summary> Update file-disk from 8.0.0 to 8.0.1 [Alexis Svinartchouk] </summary>
>>
>>> #### file-disk-8.0.1
>>> ##### (2020-11-26)
>>>
>>> * Add versionbot changelog [Alexis Svinartchouk]
>>>
>> </details>
>>
>>
>> <details>
>> <summary> Update ext2fs from 3.0.3 to 3.0.4 [Alexis Svinartchouk] </summary>
>>
>>> #### node-ext2fs-3.0.4
>>> ##### (2020-11-26)
>>>
>>> * Add versionbot changelog [Alexis Svinartchouk]
>>>
>> </details>
>>
>>
>> <details>
>> <summary> Update partitioninfo from 6.0.1 to 6.0.2 [Alexis Svinartchouk] </summary>
>>
>>> #### partitioninfo-6.0.2
>>> ##### (2020-11-27)
>>>
>>>
>>> <details>
>>> <summary> Update file-disk from 8.0.0 to 8.0.1 [Alexis Svinartchouk] </summary>
>>>
>>>> ##### file-disk-8.0.1
>>>> ###### (2020-11-26)
>>>>
>>>> * Add versionbot changelog [Alexis Svinartchouk]
>>>>
>>> </details>
>>>
>>> * Add versionbot changelog [Alexis Svinartchouk]
>>>
>> </details>
>>
>> * Add versionbot changelog [Alexis Svinartchouk]
>>
> </details>
>
>
> ## etcher-sdk-5.1.8
> ### (2020-11-26)
>
> * Add versionbot changelog [Alexis Svinartchouk]
>
> ## etcher-sdk-5.1.7
> ### (2020-11-25)
>
> * Don't start opening drives in advance to avoid unhandled rejections [Alexis Svinartchouk]
> * Update generated docs [Alexis Svinartchouk]
>
> ## etcher-sdk-5.1.6
> ### (2020-11-24)
>
> * Do not unmount source drives [Alexis Svinartchouk]
> * Factorize retrying transient errors [Alexis Svinartchouk]
> * Retry opening files & block devices on transient errors [Alexis Svinartchouk]
> * Update generated docs [Alexis Svinartchouk]
>
</details>
* Set useContentSize to true so the size is the same on all platforms [Alexis Svinartchouk]
# v1.5.111
## (2020-11-23)

4
FAQ.md
View File

@@ -37,10 +37,10 @@ modules=xwayland.so
Sometimes, things might go wrong, and you end up with a half-flashed drive that is unusable by your operating systems, and common graphical tools might even refuse to get it back to a normal state.
To solve these kinds of problems, we've collected [a list of fail-proof methods](https://github.com/balena-io/etcher/blob/master/docs/USER-DOCUMENTATION.md#recovering-broken-drives) to completely erase your drive in major operating systems.
## I receive No polkit authentication agent found error in GNU/Linux
## I receive "No polkit authentication agent found" error in GNU/Linux
Etcher requires an available [polkit authentication agent](https://wiki.archlinux.org/index.php/Polkit#Authentication_agents) in your system in order to show a secure password prompt dialog to perform elevation. Make sure you have one installed for the desktop environment of your choice.
## May I run Etcher in older macOS versions?
Etcher GUI is based on the [Electron](http://electron.atom.io/) framework, [which only supports macOS 10.9 and newer versions](https://github.com/electron/electron/blob/master/docs/tutorial/support.md#supported-platforms).
Etcher GUI is based on the [Electron](http://electron.atom.io/) framework, [which only supports macOS 10.10 and newer versions](https://github.com/electron/electron/blob/master/docs/tutorial/support.md#supported-platforms).

View File

@@ -3,7 +3,7 @@
# ---------------------------------------------------------------------
RESIN_SCRIPTS ?= ./scripts/resin
export NPM_VERSION ?= 6.14.5
export NPM_VERSION ?= 6.14.8
S3_BUCKET = artifacts.ci.balena-cloud.com
# This directory will be completely deleted by the `clean` rule

133
README.md
View File

@@ -5,16 +5,16 @@
Etcher is a powerful OS image flasher built with web technologies to ensure
flashing an SDCard or USB drive is a pleasant and safe experience. It protects
you from accidentally writing to your hard-drives, ensures every byte of data
was written correctly and much more. It can also flash directly Raspberry Pi devices that support the usbboot protocol
was written correctly, and much more. It can also directly flash Raspberry Pi devices that support [USB device boot mode](https://www.raspberrypi.org/documentation/hardware/raspberrypi/bootmodes/device.md).
[![Current Release](https://img.shields.io/github/release/balena-io/etcher.svg?style=flat-square)](https://balena.io/etcher)
[![License](https://img.shields.io/github/license/balena-io/etcher.svg?style=flat-square)](https://github.com/balena-io/etcher/blob/master/LICENSE)
[![Dependency status](https://img.shields.io/david/balena-io/etcher.svg?style=flat-square)](https://david-dm.org/balena-io/etcher)
[![Balena.io Forums](https://img.shields.io/discourse/https/forums.balena.io/topics.svg?style=flat-square&label=balena.io%20forums)](https://forums.balena.io/c/etcher)
***
---
[**Download**][etcher] | [**Support**][SUPPORT] | [**Documentation**][USER-DOCUMENTATION] | [**Contributing**][CONTRIBUTING] | [**Roadmap**][milestones]
[**Download**][etcher] | [**Support**][support] | [**Documentation**][user-documentation] | [**Contributing**][contributing] | [**Roadmap**][milestones]
## Supported Operating Systems
@@ -22,7 +22,7 @@ was written correctly and much more. It can also flash directly Raspberry Pi dev
- macOS 10.10 (Yosemite) and later
- Microsoft Windows 7 and later
Note that Etcher will run on any platform officially supported by
**Note**: Etcher will run on any platform officially supported by
[Electron][electron]. Read more in their
[documentation][electron-supported-platforms].
@@ -31,81 +31,99 @@ Note that Etcher will run on any platform officially supported by
Refer to the [downloads page][etcher] for the latest pre-made
installers for all supported operating systems.
> Note: Our deb and rpm packages are now hosted on [Cloudsmith](https://cloudsmith.com)!
#### Debian and Ubuntu based Package Repository (GNU/Linux x86/x64)
1. Add Etcher debian repository:
1. Add Etcher Debian repository:
```sh
echo "deb https://deb.etcher.io stable etcher" | sudo tee /etc/apt/sources.list.d/balena-etcher.list
```
```sh
curl -1sLf \
'https://dl.cloudsmith.io/public/balena/etcher/setup.deb.sh' \
| sudo -E bash
```
2. Trust Bintray.com's GPG key:
2. Update and install:
```sh
sudo apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv-keys 379CE192D401AB61
```
3. Update and install:
```sh
sudo apt-get update
sudo apt-get install balena-etcher-electron
```
```sh
sudo apt-get update
sudo apt-get install balena-etcher-electron
```
##### Uninstall
```sh
sudo apt-get remove balena-etcher-electron
sudo rm /etc/apt/sources.list.d/balena-etcher.list
sudo apt-get update
rm /etc/apt/sources.list.d/balena-etcher.list
apt-get clean
rm -rf /var/lib/apt/lists/*
apt-get update
```
##### OpenSUSE LEAP & Tumbleweed install
```sh
sudo zypper ar https://balena.io/etcher/static/etcher-rpm.repo
sudo zypper ref
sudo zypper in balena-etcher-electron
curl -1sLf \
'https://dl.cloudsmith.io/public/balena/etcher/setup.rpm.sh' \
| sudo -E bash
```
##### Uninstall
```sh
sudo zypper rm balena-etcher-electron
zypper rr balena-etcher
zypper rr balena-etcher-source
```
#### Redhat (RHEL) and Fedora based Package Repository (GNU/Linux x86/x64)
#### Redhat (RHEL) and Fedora-based Package Repository (GNU/Linux x86/x64)
##### DNF
1. Add Etcher rpm repository:
```sh
sudo wget https://balena.io/etcher/static/etcher-rpm.repo -O /etc/yum.repos.d/etcher-rpm.repo
```
```sh
curl -1sLf \
'https://dl.cloudsmith.io/public/balena/etcher/setup.rpm.sh' \
| sudo -E bash
```
2. Update and install:
```sh
sudo yum install -y balena-etcher-electron
```
or
```sh
sudo dnf install -y balena-etcher-electron
```
```sh
sudo dnf install -y balena-etcher-electron
rm /etc/yum.repos.d/balena-etcher.repo
rm /etc/yum.repos.d/balena-etcher-source.repo
```
##### Uninstall
###### Uninstall
```sh
rm /etc/yum.repos.d/balena-etcher.repo
rm /etc/yum.repos.d/balena-etcher-source.repo
```
##### Yum
1. Add Etcher rpm repository:
```sh
curl -1sLf \
'https://dl.cloudsmith.io/public/balena/etcher/setup.rpm.sh' \
| sudo -E bash
```
2. Update and install:
```sh
sudo yum install -y balena-etcher-electron
```
###### Uninstall
```sh
sudo yum remove -y balena-etcher-electron
sudo rm /etc/yum.repos.d/etcher-rpm.repo
sudo yum clean all
sudo yum makecache fast
```
or
```sh
sudo dnf remove -y balena-etcher-electron
sudo rm /etc/yum.repos.d/etcher-rpm.repo
sudo dnf clean all
sudo dnf makecache
rm /etc/yum.repos.d/balena-etcher.repo
rm /etc/yum.repos.d/balena-etcher-source.repo
```
#### Solus (GNU/Linux x64)
@@ -120,11 +138,10 @@ sudo eopkg it etcher
sudo eopkg rm etcher
```
#### Arch Linux / Manjaro (GNU/Linux x64)
#### Arch/Manjaro Linux (GNU/Linux x64)
Etcher is offered through the Arch User Repository and can be installed on both Manjaro and Arch systems. You can compile it from the source code in this repository using [`balena-etcher`](https://aur.archlinux.org/packages/balena-etcher/). The following example uses a common AUR helper to install the latest release:
```sh
yay -S balena-etcher
```
@@ -135,20 +152,20 @@ yay -S balena-etcher
yay -R balena-etcher
```
#### Brew Cask (macOS)
#### Brew (macOS)
Note that the Etcher Cask has to be updated manually to point to new versions,
**Note**: Etcher has to be updated manually to point to new versions,
so it might not refer to the latest version immediately after an Etcher
release.
```sh
brew cask install balenaetcher
brew install balenaetcher
```
##### Uninstall
```sh
brew cask uninstall balenaetcher
brew uninstall balenaetcher
```
#### Chocolatey (Windows)
@@ -168,20 +185,20 @@ choco uninstall etcher
## Support
If you're having any problem, please [raise an issue][newissue] on GitHub and
If you're having any problem, please [raise an issue][newissue] on GitHub, and
the balena.io team will be happy to help.
## License
Etcher is free software, and may be redistributed under the terms specified in
Etcher is free software and may be redistributed under the terms specified in
the [license].
[etcher]: https://balena.io/etcher
[electron]: https://electronjs.org/
[electron-supported-platforms]: https://electronjs.org/docs/tutorial/support#supported-platforms
[SUPPORT]: https://github.com/balena-io/etcher/blob/master/SUPPORT.md
[CONTRIBUTING]: https://github.com/balena-io/etcher/blob/master/docs/CONTRIBUTING.md
[USER-DOCUMENTATION]: https://github.com/balena-io/etcher/blob/master/docs/USER-DOCUMENTATION.md
[support]: https://github.com/balena-io/etcher/blob/master/SUPPORT.md
[contributing]: https://github.com/balena-io/etcher/blob/master/docs/CONTRIBUTING.md
[user-documentation]: https://github.com/balena-io/etcher/blob/master/docs/USER-DOCUMENTATION.md
[milestones]: https://github.com/balena-io/etcher/milestones
[newissue]: https://github.com/balena-io/etcher/issues/new
[license]: https://github.com/balena-io/etcher/blob/master/LICENSE

View File

@@ -4,6 +4,13 @@ Getting help with Etcher
There are various ways to get support for Etcher if you experience an issue or
have an idea you'd like to share with us.
Documentation
------
We have answers to a variety of frequently asked questions in the [user
documentation][documentation] and also in the [FAQs][faq] on the Etcher website.
Forums
------
@@ -32,3 +39,5 @@ one][new-issue].
[discourse]: https://forums.balena.io/c/etcher
[issues]: https://github.com/balena-io/etcher/issues
[new-issue]: https://github.com/balena-io/etcher/issues/new
[documentation]: https://github.com/balena-io/etcher/blob/master/docs/USER-DOCUMENTATION.md
[faq]: https://etcher.io

View File

@@ -6,21 +6,28 @@ const process = require('process');
// Rebuild native modules for ia32 and run webpack again for the ia32 part of windows packages
exports.default = function(context) {
if (context.platform.name === 'windows') {
cp.execFileSync(
'bash',
['./node_modules/.bin/electron-rebuild', '--types', 'dev', '--arch', context.arch],
);
if (['windows', 'mac'].includes(context.platform.name)) {
const run = context.platform.name === 'windows' ? 'sh' : 'node';
cp.execFileSync(
run,
['node_modules/.bin/electron-rebuild', '--types', 'dev', '--arch', context.arch],
{
env: {
...process.env,
npm_config_msvs_version: '2019',
},
},
);
rimraf.sync('generated');
cp.execFileSync(
'bash',
['./node_modules/.bin/webpack'],
cp.execFileSync(
run,
['node_modules/.bin/webpack'],
{
env: {
...process.env,
npm_config_target_arch: context.arch,
},
},
);
}
);
}
}

View File

@@ -1,5 +1,5 @@
appId: io.balena.etcher
copyright: Copyright 2016-2020 Balena Ltd
copyright: Copyright 2016-2021 Balena Ltd
productName: balenaEtcher
npmRebuild: true
nodeGypRebuild: false
@@ -16,6 +16,7 @@ mac:
hardenedRuntime: true
entitlements: "entitlements.mac.plist"
entitlementsInherit: "entitlements.mac.plist"
artifactName: "${productName}-${version}.${ext}"
dmg:
background: assets/dmg/background.tiff
icon: assets/icon.icns
@@ -54,7 +55,6 @@ deb:
depends:
- gconf2
- gconf-service
- libappindicator1
- libasound2
- libatk1.0-0
- libc6

View File

@@ -38,6 +38,7 @@ import * as exceptionReporter from './modules/exception-reporter';
import * as osDialog from './os/dialog';
import * as windowProgress from './os/window-progress';
import MainPage from './pages/main/MainPage';
import './css/main.css';
window.addEventListener(
'unhandledrejection',
@@ -339,7 +340,7 @@ window.addEventListener('beforeunload', async (event) => {
}
});
async function main() {
export async function main() {
await ledsInit();
ReactDOM.render(
React.createElement(MainPage),
@@ -356,5 +357,3 @@ async function main() {
},
);
}
main();

View File

@@ -303,9 +303,9 @@ export class DriveSelector extends React.Component<
case compatibility.system():
return warning.systemDrive();
case compatibility.tooSmall():
const recommendedDriveSize =
const size =
this.state.image?.recommendedDriveSize || this.state.image?.size || 0;
return warning.unrecommendedDriveSize({ recommendedDriveSize }, drive);
return warning.tooSmall({ size }, drive);
}
}

View File

@@ -17,7 +17,6 @@
import CircleSvg from '@fortawesome/fontawesome-free/svgs/solid/circle.svg';
import CheckCircleSvg from '@fortawesome/fontawesome-free/svgs/solid/check-circle.svg';
import TimesCircleSvg from '@fortawesome/fontawesome-free/svgs/solid/times-circle.svg';
import * as _ from 'lodash';
import outdent from 'outdent';
import * as React from 'react';
import { Flex, FlexProps, Link, TableColumn, Txt } from 'rendition';
@@ -104,6 +103,19 @@ const columns: Array<TableColumn<FlashError>> = [
},
];
function getEffectiveSpeed(results: {
sourceMetadata: {
size: number;
blockmappedSize?: number;
};
averageFlashingSpeed: number;
}) {
const flashedSize =
results.sourceMetadata.blockmappedSize ?? results.sourceMetadata.size;
const timeSpent = flashedSize / results.averageFlashingSpeed;
return results.sourceMetadata.size / timeSpent;
}
export function FlashResults({
goToMain,
image = '',
@@ -117,23 +129,18 @@ export function FlashResults({
errors: FlashError[];
skip: boolean;
results: {
bytesWritten: number;
sourceMetadata: {
size: number;
blockmappedSize: number;
blockmappedSize?: number;
};
averageFlashingSpeed: number;
devices: { failed: number; successful: number };
};
} & FlexProps) {
const [showErrorsInfo, setShowErrorsInfo] = React.useState(false);
const allFailed = results.devices.successful === 0;
const allFailed = !skip && results.devices.successful === 0;
const someFailed = results.devices.failed !== 0 || errors.length !== 0;
const effectiveSpeed = _.round(
bytesToMegabytes(
results.sourceMetadata.size /
(results.bytesWritten / results.averageFlashingSpeed),
),
const effectiveSpeed = bytesToMegabytes(getEffectiveSpeed(results)).toFixed(
1,
);
return (
@@ -155,7 +162,7 @@ export function FlashResults({
<Txt>{middleEllipsis(image, 24)}</Txt>
</Flex>
<Txt fontSize={24} color="#fff" mb="17px">
Flash Complete!
Flash {allFailed ? 'Failed' : 'Complete'}!
</Txt>
{skip ? <Txt color="#7e8085">Validation has been skipped</Txt> : null}
</Flex>

View File

@@ -23,7 +23,7 @@ import { StepButton } from '../../styled-components';
const FlashProgressBar = styled(ProgressBar)`
> div {
width: 220px;
width: 100%;
height: 12px;
color: white !important;
text-shadow: none !important;
@@ -33,7 +33,7 @@ const FlashProgressBar = styled(ProgressBar)`
}
}
width: 220px;
width: 100%;
height: 12px;
margin-bottom: 6px;
border-radius: 14px;

View File

@@ -31,9 +31,7 @@ interface ReducedFlashingInfosProps {
style?: React.CSSProperties;
}
export class ReducedFlashingInfos extends React.Component<
ReducedFlashingInfosProps
> {
export class ReducedFlashingInfos extends React.Component<ReducedFlashingInfosProps> {
constructor(props: ReducedFlashingInfosProps) {
super(props);
this.state = {};

View File

@@ -16,7 +16,6 @@
import GithubSvg from '@fortawesome/fontawesome-free/svgs/brands/github.svg';
import * as _ from 'lodash';
import * as os from 'os';
import * as React from 'react';
import { Flex, Checkbox, Txt } from 'rendition';
@@ -26,40 +25,25 @@ import * as analytics from '../../modules/analytics';
import { open as openExternal } from '../../os/open-external/services/open-external';
import { Modal } from '../../styled-components';
const platform = os.platform();
interface Setting {
name: string;
label: string | JSX.Element;
options?: {
description: string;
confirmLabel: string;
};
hide?: boolean;
}
async function getSettingsList(): Promise<Setting[]> {
return [
const list: Setting[] = [
{
name: 'errorReporting',
label: 'Anonymously report errors and usage statistics to balena.io',
},
{
name: 'unmountOnSuccess',
/**
* On Windows, "Unmounting" basically means "ejecting".
* On top of that, Windows users are usually not even
* familiar with the meaning of "unmount", which comes
* from the UNIX world.
*/
label: `${platform === 'win32' ? 'Eject' : 'Auto-unmount'} on success`,
},
{
];
if (['appimage', 'nsis', 'dmg'].includes(packageType)) {
list.push({
name: 'updatesEnabled',
label: 'Auto-updates enabled',
hide: ['rpm', 'deb'].includes(packageType),
},
];
});
}
return list;
}
interface SettingsModalProps {
@@ -86,25 +70,14 @@ export function SettingsModal({ toggleModal }: SettingsModalProps) {
})();
});
const toggleSetting = async (
setting: string,
options?: Setting['options'],
) => {
const toggleSetting = async (setting: string) => {
const value = currentSettings[setting];
const dangerous = options !== undefined;
analytics.logEvent('Toggle setting', {
setting,
value,
dangerous,
});
analytics.logEvent('Toggle setting', { setting, value });
await settings.set(setting, !value);
setCurrentSettings({
...currentSettings,
[setting]: !value,
});
return;
};
return (
@@ -118,14 +91,14 @@ export function SettingsModal({ toggleModal }: SettingsModalProps) {
>
<Flex flexDirection="column">
{settingsList.map((setting: Setting, i: number) => {
return setting.hide ? null : (
return (
<Flex key={setting.name} mb={14}>
<Checkbox
toggle
tabIndex={6 + i}
label={setting.label}
checked={currentSettings[setting.name]}
onChange={() => toggleSetting(setting.name, setting.options)}
onChange={() => toggleSetting(setting.name)}
/>
</Flex>
);

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Etcher</title>
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
<main id="main"></main>
<script src="http://localhost:3030/gui.js"></script>
</body>
</html>

View File

@@ -14,6 +14,7 @@
* limitations under the License.
*/
import * as electron from 'electron';
import * as sdk from 'etcher-sdk';
import * as _ from 'lodash';
@@ -45,6 +46,8 @@ export function isFlashing(): boolean {
* start a flash process.
*/
export function setFlashingFlag() {
// see https://github.com/balenablocks/balena-electron-env/blob/4fce9c461f294d4a768db8f247eea6f75d7b08b0/README.md#remote-methods
electron.ipcRenderer.send('disable-screensaver');
store.dispatch({
type: Actions.SET_FLASHING_FLAG,
data: {},
@@ -66,6 +69,8 @@ export function unsetFlashingFlag(results: {
type: Actions.UNSET_FLASHING_FLAG,
data: results,
});
// see https://github.com/balenablocks/balena-electron-env/blob/4fce9c461f294d4a768db8f247eea6f75d7b08b0/README.md#remote-methods
electron.ipcRenderer.send('enable-screensaver');
}
export function setDevicePaths(devicePaths: string[]) {
@@ -85,6 +90,10 @@ export function addFailedDeviceError({
const failedDeviceErrorsMap = new Map(
store.getState().toJS().failedDeviceErrors,
);
if (failedDeviceErrorsMap.has(device.device)) {
// Only store the first error
return;
}
failedDeviceErrorsMap.set(device.device, {
description: device.description,
device: device.device,

View File

@@ -15,7 +15,7 @@
*/
import * as _ from 'lodash';
import { AnimationFunction, Color, RGBLed } from 'sys-class-rgb-led';
import { Animator, AnimationFunction, Color, RGBLed } from 'sys-class-rgb-led';
import {
isSourceDrive,
@@ -25,30 +25,14 @@ import * as settings from './settings';
import { DEFAULT_STATE, observe } from './store';
const leds: Map<string, RGBLed> = new Map();
const animator = new Animator([], 10);
function setLeds(
drivesPaths: Set<string>,
colorOrAnimation: Color | AnimationFunction,
frequency?: number,
) {
for (const path of drivesPaths) {
const led = leds.get(path);
if (led) {
if (Array.isArray(colorOrAnimation)) {
led.setStaticColor(colorOrAnimation);
} else {
led.setAnimation(colorOrAnimation, frequency);
}
}
}
}
const red: Color = [1, 0, 0];
const green: Color = [0, 1, 0];
const blue: Color = [0, 0, 1];
const white: Color = [1, 1, 1];
const red: Color = [0.59, 0, 0];
const green: Color = [0, 0.59, 0];
const blue: Color = [0, 0, 0.59];
const white: Color = [0.04, 0.04, 0.04];
const black: Color = [0, 0, 0];
const purple: Color = [0.5, 0, 0.5];
const purple: Color = [0.117, 0, 0.196];
function createAnimationFunction(
intensityFunction: (t: number) => number,
@@ -61,16 +45,20 @@ function createAnimationFunction(
}
function blink(t: number) {
return Math.floor(t / 1000) % 2;
return Math.floor(t) % 2;
}
function breathe(t: number) {
return (1 + Math.sin(t / 1000)) / 2;
function one(_t: number) {
return 1;
}
const breatheBlue = createAnimationFunction(breathe, blue);
const blinkGreen = createAnimationFunction(blink, green);
const blinkPurple = createAnimationFunction(blink, purple);
const staticRed = createAnimationFunction(one, red);
const staticGreen = createAnimationFunction(one, green);
const staticBlue = createAnimationFunction(one, blue);
const staticWhite = createAnimationFunction(one, white);
const staticBlack = createAnimationFunction(one, black);
interface LedsState {
step: 'main' | 'flashing' | 'verifying' | 'finish';
@@ -80,6 +68,17 @@ interface LedsState {
failedDrives: string[];
}
function setLeds(animation: AnimationFunction, drivesPaths: Set<string>) {
const rgbLeds: RGBLed[] = [];
for (const path of drivesPaths) {
const led = leds.get(path);
if (led) {
rgbLeds.push(led);
}
}
return { animation, rgbLeds };
}
// Source slot (1st slot): behaves as a target unless it is chosen as source
// No drive: black
// Drive plugged: blue - on
@@ -110,6 +109,7 @@ export function updateLeds({
// Remove selected devices from plugged set
for (const d of selectedOk) {
plugged.delete(d);
unplugged.delete(d);
}
// Remove plugged devices from unplugged set
@@ -122,38 +122,42 @@ export function updateLeds({
selectedOk.delete(d);
}
const mapping: Array<{
animation: AnimationFunction;
rgbLeds: RGBLed[];
}> = [];
// Handle source slot
if (sourceDrive !== undefined) {
if (unplugged.has(sourceDrive)) {
unplugged.delete(sourceDrive);
// TODO
setLeds(new Set([sourceDrive]), breatheBlue, 2);
} else if (plugged.has(sourceDrive)) {
if (plugged.has(sourceDrive)) {
plugged.delete(sourceDrive);
setLeds(new Set([sourceDrive]), blue);
mapping.push(setLeds(staticBlue, new Set([sourceDrive])));
}
}
if (step === 'main') {
setLeds(unplugged, black);
setLeds(plugged, black);
setLeds(selectedOk, white);
setLeds(selectedFailed, white);
mapping.push(
setLeds(staticBlack, new Set([...unplugged, ...plugged])),
setLeds(staticWhite, new Set([...selectedOk, ...selectedFailed])),
);
} else if (step === 'flashing') {
setLeds(unplugged, black);
setLeds(plugged, black);
setLeds(selectedOk, blinkPurple, 2);
setLeds(selectedFailed, red);
mapping.push(
setLeds(staticBlack, new Set([...unplugged, ...plugged])),
setLeds(blinkPurple, selectedOk),
setLeds(staticRed, selectedFailed),
);
} else if (step === 'verifying') {
setLeds(unplugged, black);
setLeds(plugged, black);
setLeds(selectedOk, blinkGreen, 2);
setLeds(selectedFailed, red);
mapping.push(
setLeds(staticBlack, new Set([...unplugged, ...plugged])),
setLeds(blinkGreen, selectedOk),
setLeds(staticRed, selectedFailed),
);
} else if (step === 'finish') {
setLeds(unplugged, black);
setLeds(plugged, black);
setLeds(selectedOk, green);
setLeds(selectedFailed, red);
mapping.push(
setLeds(staticBlack, new Set([...unplugged, ...plugged])),
setLeds(staticGreen, selectedOk),
setLeds(staticRed, selectedFailed),
);
}
animator.mapping = mapping;
}
interface DeviceFromState {
@@ -189,7 +193,7 @@ function stateObserver(state: typeof DEFAULT_STATE) {
selectedDrivesPaths = s.devicePaths;
}
const failedDevicePaths = s.failedDeviceErrors.map(
([devicePath]: [string]) => devicePath,
([, { devicePath }]: [string, { devicePath: string }]) => devicePath,
);
const newLedsState = {
step,

View File

@@ -77,8 +77,7 @@ export async function writeConfigFile(
const DEFAULT_SETTINGS: _.Dictionary<any> = {
errorReporting: true,
unmountOnSuccess: true,
updatesEnabled: !_.includes(['rpm', 'deb'], packageJSON.packageType),
updatesEnabled: ['appimage', 'nsis', 'dmg'].includes(packageJSON.packageType),
desktopNotifications: true,
autoBlockmapping: true,
decompressFirst: true,

View File

@@ -15,9 +15,8 @@
*/
import { Drive as DrivelistDrive } from 'drivelist';
import * as electron from 'electron';
import * as sdk from 'etcher-sdk';
import * as _ from 'lodash';
import { Dictionary } from 'lodash';
import * as ipc from 'node-ipc';
import * as os from 'os';
import * as path from 'path';
@@ -25,6 +24,7 @@ import * as path from 'path';
import * as packageJSON from '../../../../package.json';
import * as errors from '../../../shared/errors';
import * as permissions from '../../../shared/permissions';
import { getAppPath } from '../../../shared/utils';
import { SourceMetadata } from '../components/source-selector/source-selector';
import * as flashState from '../models/flash-state';
import * as selectionState from '../models/selection-state';
@@ -93,11 +93,7 @@ function terminateServer() {
}
function writerArgv(): string[] {
let entryPoint = path.join(
electron.remote.app.getAppPath(),
'generated',
'child-writer.js',
);
let entryPoint = path.join(getAppPath(), 'generated', 'child-writer.js');
// AppImages run over FUSE, so the files inside the mount point
// can only be accessed by the user that mounted the AppImage.
// This means we can't re-spawn Etcher as root from the same
@@ -133,6 +129,14 @@ function writerEnv() {
interface FlashResults {
skip?: boolean;
cancelled?: boolean;
results?: {
bytesWritten: number;
devices: {
failed: number;
successful: number;
};
errors: Error[];
};
}
async function performWrite(
@@ -143,11 +147,7 @@ async function performWrite(
let cancelled = false;
let skip = false;
ipc.serve();
const {
unmountOnSuccess,
autoBlockmapping,
decompressFirst,
} = await settings.getAll();
const { autoBlockmapping, decompressFirst } = await settings.getAll();
return await new Promise((resolve, reject) => {
ipc.server.on('error', (error) => {
terminateServer();
@@ -166,7 +166,6 @@ async function performWrite(
driveCount: drives.length,
uuid: flashState.getFlashUuid(),
flashInstanceUuid: flashState.getFlashUuid(),
unmountOnSuccess,
};
ipc.server.on('fail', ({ device, error }) => {
@@ -177,10 +176,12 @@ async function performWrite(
});
ipc.server.on('done', (event) => {
event.results.errors = _.map(event.results.errors, (data) => {
return errors.fromJSON(data);
});
_.merge(flashResults, event);
event.results.errors = event.results.errors.map(
(data: Dictionary<any> & { message: string }) => {
return errors.fromJSON(data);
},
);
flashResults.results = event.results;
});
ipc.server.on('abort', () => {
@@ -201,7 +202,6 @@ async function performWrite(
destinations: drives,
SourceType: image.SourceType.name,
autoBlockmapping,
unmountOnSuccess,
decompressFirst,
});
});
@@ -209,7 +209,7 @@ async function performWrite(
const argv = writerArgv();
ipc.server.on('start', async () => {
console.log(`Elevating command: ${_.join(argv, ' ')}`);
console.log(`Elevating command: ${argv.join(' ')}`);
const env = writerEnv();
try {
const results = await permissions.elevateCommand(argv, {
@@ -231,11 +231,11 @@ async function performWrite(
}
console.log('Flash results', flashResults);
// This likely means the child died halfway through
// The flash wasn't cancelled and we didn't get a 'done' event
if (
!flashResults.cancelled &&
!flashResults.skip &&
!_.get(flashResults, ['results', 'bytesWritten'])
flashResults.results === undefined
) {
reject(
errors.createUserError({
@@ -268,7 +268,7 @@ export async function flash(
throw new Error('There is already a flash in progress');
}
flashState.setFlashingFlag();
await flashState.setFlashingFlag();
flashState.setDevicePaths(
drives.map((d) => d.devicePath).filter((p) => p != null) as string[],
);
@@ -280,16 +280,18 @@ export async function flash(
uuid: flashState.getFlashUuid(),
status: 'started',
flashInstanceUuid: flashState.getFlashUuid(),
unmountOnSuccess: await settings.get('unmountOnSuccess'),
};
analytics.logEvent('Flash', analyticsData);
try {
const result = await write(image, drives, flashState.setProgressState);
flashState.unsetFlashingFlag(result);
await flashState.unsetFlashingFlag(result);
} catch (error) {
flashState.unsetFlashingFlag({ cancelled: false, errorCode: error.code });
await flashState.unsetFlashingFlag({
cancelled: false,
errorCode: error.code,
});
windowProgress.clear();
const { results = {} } = flashState.getFlashResults();
const eventData = {
@@ -335,7 +337,6 @@ export async function cancel(type: string) {
driveCount: drives.length,
uuid: flashState.getFlashUuid(),
flashInstanceUuid: flashState.getFlashUuid(),
unmountOnSuccess: await settings.get('unmountOnSuccess'),
status,
};
analytics.logEvent('Cancel', analyticsData);

View File

@@ -15,6 +15,7 @@
*/
import { exec } from 'child_process';
import { withTmpFile } from 'etcher-sdk/build/tmp';
import { readFile } from 'fs';
import { chain, trim } from 'lodash';
import { platform } from 'os';
@@ -22,8 +23,6 @@ import { join } from 'path';
import { env } from 'process';
import { promisify } from 'util';
import { withTmpFile } from '../../../shared/tmp';
const readFileAsync = promisify(readFile);
const execAsync = promisify(exec);
@@ -41,11 +40,11 @@ async function getWmicNetworkDrivesOutput(): Promise<string> {
// So we just redirect to a file and read it afterwards as we know it will be ucs2 encoded.
const options = {
// Close the file once it's created
discardDescriptor: true,
keepOpen: false,
// Wmic fails with "Invalid global switch" when the "/output:" switch filename contains a dash ("-")
prefix: 'tmp',
};
return withTmpFile(options, async (path) => {
return withTmpFile(options, async ({ path }) => {
const command = [
join(env.SystemRoot as string, 'System32', 'Wbem', 'wmic'),
'path',

View File

@@ -59,6 +59,27 @@ const getErrorMessageFromCode = (errorCode: string) => {
return '';
};
function notifySuccess(
iconPath: string,
basename: string,
drives: any,
devices: { successful: number; failed: number },
) {
notification.send(
'Flash complete!',
messages.info.flashComplete(basename, drives, devices),
iconPath,
);
}
function notifyFailure(iconPath: string, basename: string, drives: any) {
notification.send(
'Oops! Looks like the flash failed.',
messages.error.flashFailure(basename, drives),
iconPath,
);
}
async function flashImageToDrive(
isFlashing: boolean,
goToSuccess: () => void,
@@ -84,20 +105,20 @@ async function flashImageToDrive(
if (!flashState.wasLastFlashCancelled()) {
const {
results = { devices: { successful: 0, failed: 0 } },
skip,
cancelled,
} = flashState.getFlashResults();
notification.send(
'Flash complete!',
messages.info.flashComplete(basename, drives as any, results.devices),
iconPath,
);
if (!skip && !cancelled) {
if (results.devices.successful > 0) {
notifySuccess(iconPath, basename, drives, results.devices);
} else {
notifyFailure(iconPath, basename, drives);
}
}
goToSuccess();
}
} catch (error) {
notification.send(
'Oops! Looks like the flash failed.',
messages.error.flashFailure(path.basename(image.path), drives),
iconPath,
);
notifyFailure(iconPath, basename, drives);
let errorMessage = getErrorMessageFromCode(error.code);
if (!errorMessage) {
error.image = basename;
@@ -135,6 +156,7 @@ interface FlashStepProps {
failed: number;
speed?: number;
eta?: number;
width: string;
}
export interface DriveWithWarnings extends constraints.DrivelistDrive {
@@ -241,6 +263,7 @@ export class FlashStep extends React.PureComponent<
<Flex
flexDirection="column"
alignItems="start"
width={this.props.width}
style={this.props.style}
>
<FlashSvg

View File

@@ -239,6 +239,7 @@ export class MainPage extends React.Component<
)}
<FlashStep
width={this.state.isWebviewShowing ? '220px' : '200px'}
goToSuccess={() => this.setState({ current: 'success' })}
shouldFlashStepBeDisabled={shouldFlashStepBeDisabled}
isFlashing={this.state.isFlashing}
@@ -277,7 +278,7 @@ export class MainPage extends React.Component<
// @ts-ignore
'-webkit-app-region': 'drag',
position: 'relative',
zIndex: 1,
zIndex: 2,
}}
>
<Flex width="100%" />

10
lib/gui/app/renderer.ts Normal file
View File

@@ -0,0 +1,10 @@
// @ts-nocheck
import { main } from './app';
if (module.hot) {
module.hot.accept('./app', () => {
main();
});
}
main();

View File

@@ -149,7 +149,7 @@ export const Modal = styled(({ style, children, ...props }) => {
})`
> div {
padding: 0;
height: 100%;
height: 99%;
> div:first-child {
height: 81%;

View File

@@ -100,6 +100,7 @@ export const theme = _.merge({}, Theme, {
font-size: 16px;
&& {
width: 200px;
height: 48px;
}

View File

@@ -133,7 +133,7 @@ async function createMainWindow() {
width,
height,
frame: !fullscreen,
useContentSize: false,
useContentSize: true,
show: false,
resizable: false,
maximizable: false,
@@ -147,6 +147,7 @@ async function createMainWindow() {
webPreferences: {
backgroundThrottling: false,
nodeIntegration: true,
contextIsolation: false,
webviewTag: true,
zoomFactor: width / defaultWidth,
enableRemoteModule: true,

View File

@@ -15,12 +15,24 @@
*/
import { Drive as DrivelistDrive } from 'drivelist';
import * as sdk from 'etcher-sdk';
import {
BlockDevice,
File,
Http,
Metadata,
SourceDestination,
} from 'etcher-sdk/build/source-destination';
import {
MultiDestinationProgress,
OnProgressFunction,
OnFailFunction,
decompressThenFlash,
DECOMPRESSED_IMAGE_PREFIX,
} from 'etcher-sdk/build/multi-write';
import { cleanupTmpFiles } from 'etcher-sdk/build/tmp';
import * as ipc from 'node-ipc';
import { totalmem } from 'os';
import { BlockDevice, File, Http } from 'etcher-sdk/build/source-destination';
import { toJSON } from '../../shared/errors';
import { GENERAL_ERROR, SUCCESS } from '../../shared/exit-codes';
import { delay } from '../../shared/utils';
@@ -57,7 +69,7 @@ function log(message: string) {
*/
async function terminate(exitCode: number) {
ipc.disconnect(IPC_SERVER_ID);
await cleanupTmpFiles(Date.now());
await cleanupTmpFiles(Date.now(), DECOMPRESSED_IMAGE_PREFIX);
process.nextTick(() => {
process.exit(exitCode || SUCCESS);
});
@@ -85,7 +97,7 @@ export interface WriteResult {
successful: number;
};
errors: FlashError[];
sourceMetadata?: sdk.sourceDestination.Metadata;
sourceMetadata?: Metadata;
}
export interface FlashResults extends WriteResult {
@@ -112,19 +124,15 @@ async function writeAndValidate({
onProgress,
onFail,
}: {
source: sdk.sourceDestination.SourceDestination;
destinations: sdk.sourceDestination.BlockDevice[];
source: SourceDestination;
destinations: BlockDevice[];
verify: boolean;
autoBlockmapping: boolean;
decompressFirst: boolean;
onProgress: sdk.multiWrite.OnProgressFunction;
onFail: sdk.multiWrite.OnFailFunction;
onProgress: OnProgressFunction;
onFail: OnFailFunction;
}): Promise<WriteResult> {
const {
sourceMetadata,
failures,
bytesWritten,
} = await sdk.multiWrite.decompressThenFlash({
const { sourceMetadata, failures, bytesWritten } = await decompressThenFlash({
source,
destinations,
onFail,
@@ -149,7 +157,7 @@ async function writeAndValidate({
};
for (const [destination, error] of failures) {
const err = error as FlashError;
const drive = destination as sdk.sourceDestination.BlockDevice;
const drive = destination as BlockDevice;
err.device = drive.device;
err.description = drive.description;
result.errors.push(err);
@@ -160,7 +168,6 @@ async function writeAndValidate({
interface WriteOptions {
image: SourceMetadata;
destinations: DrivelistDrive[];
unmountOnSuccess: boolean;
autoBlockmapping: boolean;
decompressFirst: boolean;
SourceType: string;
@@ -201,7 +208,7 @@ ipc.connectTo(IPC_SERVER_ID, () => {
* @example
* writer.on('progress', onProgress)
*/
const onProgress = (state: sdk.multiWrite.MultiDestinationProgress) => {
const onProgress = (state: MultiDestinationProgress) => {
ipc.of[IPC_SERVER_ID].emit('state', state);
};
@@ -237,10 +244,7 @@ ipc.connectTo(IPC_SERVER_ID, () => {
* @example
* writer.on('fail', onFail)
*/
const onFail = (
destination: sdk.sourceDestination.SourceDestination,
error: Error,
) => {
const onFail = (destination: SourceDestination, error: Error) => {
ipc.of[IPC_SERVER_ID].emit('fail', {
// TODO: device should be destination
// @ts-ignore (destination.drive is private)
@@ -253,13 +257,12 @@ ipc.connectTo(IPC_SERVER_ID, () => {
const imagePath = options.image.path;
log(`Image: ${imagePath}`);
log(`Devices: ${destinations.join(', ')}`);
log(`Umount on success: ${options.unmountOnSuccess}`);
log(`Auto blockmapping: ${options.autoBlockmapping}`);
log(`Decompress first: ${options.decompressFirst}`);
const dests = options.destinations.map((destination) => {
return new sdk.sourceDestination.BlockDevice({
return new BlockDevice({
drive: destination,
unmountOnSuccess: options.unmountOnSuccess,
unmountOnSuccess: true,
write: true,
direct: true,
});
@@ -298,7 +301,6 @@ ipc.connectTo(IPC_SERVER_ID, () => {
await delay(DISCONNECT_DELAY);
await terminate(exitCode);
} catch (error) {
log(`Error: ${error.message}`);
exitCode = GENERAL_ERROR;
ipc.of[IPC_SERVER_ID].emit('error', toJSON(error));
}

View File

@@ -15,11 +15,12 @@
*/
import { execFile } from 'child_process';
import { app, remote } from 'electron';
import { join } from 'path';
import { env } from 'process';
import { promisify } from 'util';
import { getAppPath } from '../utils';
const execFileAsync = promisify(execFile);
const SUCCESSFUL_AUTH_MARKER = 'AUTHENTICATION SUCCEEDED';
@@ -37,7 +38,7 @@ export async function sudo(
env: {
PATH: env.PATH,
SUDO_ASKPASS: join(
(app || remote.app).getAppPath(),
getAppPath(),
__dirname,
'sudo-askpass.osascript.js',
),

View File

@@ -81,13 +81,10 @@ export const compatibility = {
} as const;
export const warning = {
unrecommendedDriveSize: (
image: { recommendedDriveSize: number },
drive: { device: string; size: number },
) => {
tooSmall: (source: { size: number }, target: { size: number }) => {
return outdent({ newline: ' ' })`
This image recommends a ${prettyBytes(image.recommendedDriveSize)}
drive, however ${drive.device} is only ${prettyBytes(drive.size)}.
The selected source is ${prettyBytes(source.size - target.size)}
larger than this drive.
`;
},
@@ -126,7 +123,7 @@ export const warning = {
},
largeDriveSize: () => {
return 'This is a large drive! Make sure it doesn\'t contain files that you want to keep.';
return "This is a large drive! Make sure it doesn't contain files that you want to keep.";
},
systemDrive: () => {

View File

@@ -15,6 +15,7 @@
*/
import * as childProcess from 'child_process';
import { withTmpFile } from 'etcher-sdk/build/tmp';
import { promises as fs } from 'fs';
import * as _ from 'lodash';
import * as os from 'os';
@@ -24,7 +25,6 @@ import { promisify } from 'util';
import { sudo as catalinaSudo } from './catalina-sudo/sudo';
import * as errors from './errors';
import { withTmpFile } from './tmp';
const execAsync = promisify(childProcess.exec);
const execFileAsync = promisify(childProcess.execFile);
@@ -172,10 +172,11 @@ export async function elevateCommand(
);
return await withTmpFile(
{
keepOpen: false,
prefix: 'balena-etcher-electron-',
postfix: '.cmd',
},
async (path) => {
async ({ path }) => {
await fs.writeFile(path, launchScript);
if (isWindows) {
return elevateScriptWindows(path, options.applicationName);

View File

@@ -1,27 +0,0 @@
import * as tmp from 'tmp';
function tmpFileAsync(
options: tmp.FileOptions,
): Promise<{ path: string; cleanup: () => void }> {
return new Promise((resolve, reject) => {
tmp.file(options, (error, path, _fd, cleanup) => {
if (error) {
reject(error);
} else {
resolve({ path, cleanup });
}
});
});
}
export async function withTmpFile<T>(
options: tmp.FileOptions,
fn: (path: string) => Promise<T>,
): Promise<T> {
const { path, cleanup } = await tmpFileAsync(options);
try {
return await fn(path);
} finally {
cleanup();
}
}

View File

@@ -15,6 +15,7 @@
*/
import axios from 'axios';
import { app, remote } from 'electron';
import { Dictionary } from 'lodash';
import * as errors from './errors';
@@ -47,3 +48,16 @@ export async function delay(duration: number): Promise<void> {
setTimeout(resolve, duration);
});
}
export function getAppPath(): string {
return (
(app || remote.app)
.getAppPath()
// With macOS universal builds, getAppPath() returns the path to an app.asar file containing an index.js file which will
// include the app-x64 or app-arm64 folder depending on the arch.
// We don't care about the app.asar file, we want the actual folder.
.replace(/\.asar$/, () =>
process.platform === 'darwin' ? '-' + process.arch : '',
)
);
}

11299
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "balena-etcher",
"private": true,
"displayName": "balenaEtcher",
"version": "1.5.111",
"version": "1.5.120",
"packageType": "local",
"main": "generated/etcher.js",
"description": "Flash OS images to SD cards and USB drives, safely and easily.",
@@ -25,10 +25,10 @@
"start": "./node_modules/.bin/electron .",
"postshrinkwrap": "ts-node ./scripts/clean-shrinkwrap.ts",
"webpack": "webpack",
"watch": "webpack --watch",
"watch": "webpack serve --no-optimization-minimize --config ./webpack.dev.config.ts",
"concourse-build-electron": "npm run webpack",
"concourse-test": "npx npm@6.14.5 test",
"concourse-test-electron": "npx npm@6.14.5 test"
"concourse-test": "npx npm@6.14.8 test",
"concourse-test-electron": "npx npm@6.14.8 test"
},
"husky": {
"hooks": {
@@ -46,44 +46,53 @@
"author": "Balena Inc. <hello@etcher.io>",
"license": "Apache-2.0",
"platformSpecificDependencies": [
"xmlbuilder",
"xmldom",
"@types/plist",
"@types/verror",
"crc",
"iconv-corefoundation",
"plist",
"dmg-license",
"fsevents",
"winusb-driver-generator"
],
"devDependencies": {
"@balena/lint": "^5.0.4",
"@balena/lint": "^5.3.0",
"@fortawesome/fontawesome-free": "^5.13.1",
"@svgr/webpack": "^5.4.0",
"@svgr/webpack": "^5.5.0",
"@types/chai": "^4.2.7",
"@types/copy-webpack-plugin": "^6.0.0",
"@types/mime-types": "^2.1.0",
"@types/mini-css-extract-plugin": "^0.9.1",
"@types/mini-css-extract-plugin": "^1.2.2",
"@types/mocha": "^8.0.3",
"@types/node": "^12.12.39",
"@types/node": "^14.14.41",
"@types/node-ipc": "^9.1.2",
"@types/react-dom": "^16.8.4",
"@types/semver": "^7.1.0",
"@types/sinon": "^9.0.0",
"@types/terser-webpack-plugin": "^4.1.0",
"@types/terser-webpack-plugin": "^5.0.2",
"@types/tmp": "^0.2.0",
"@types/webpack-node-externals": "^2.5.0",
"aws4-axios": "2.2.1",
"chai": "^4.2.0",
"copy-webpack-plugin": "^6.0.1",
"css-loader": "^4.2.1",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^5.0.1",
"d3": "^4.13.0",
"debug": "^4.2.0",
"electron": "9.3.3",
"electron-builder": "^22.9.1",
"electron": "12.0.2",
"electron-builder": "^22.10.5",
"electron-mocha": "^9.3.2",
"electron-notarize": "^1.0.0",
"electron-rebuild": "^2.3.2",
"electron-updater": "^4.3.5",
"etcher-sdk": "^5.1.5",
"file-loader": "^6.0.0",
"etcher-sdk": "^6.2.1",
"file-loader": "^6.2.0",
"husky": "^4.2.5",
"immutable": "^3.8.1",
"lint-staged": "^10.2.2",
"lodash": "^4.17.10",
"mini-css-extract-plugin": "^0.10.0",
"mini-css-extract-plugin": "^1.3.3",
"mocha": "^8.0.1",
"native-addon-loader": "^2.0.1",
"node-ipc": "^9.1.1",
@@ -94,23 +103,25 @@
"react": "^16.8.5",
"react-dom": "^16.8.5",
"redux": "^4.0.5",
"rendition": "^18.8.3",
"rendition": "^19.2.0",
"resin-corvus": "^2.0.5",
"semver": "^7.3.2",
"simple-progress-webpack-plugin": "^1.1.2",
"sinon": "^9.0.2",
"spectron": "^11.0.0",
"string-replace-loader": "^2.3.0",
"spectron": "^14.0.0",
"string-replace-loader": "^3.0.1",
"style-loader": "^2.0.0",
"styled-components": "^5.1.0",
"sudo-prompt": "github:zvin/sudo-prompt#workaround-windows-amperstand-in-username",
"sys-class-rgb-led": "^2.1.0",
"tmp": "^0.2.1",
"ts-loader": "^8.0.0",
"ts-node": "^9.0.0",
"sudo-prompt": "github:zvin/sudo-prompt#7cdede2f0da28fbcc2db48402d7d935f3a825c91",
"sys-class-rgb-led": "^3.0.0",
"ts-loader": "^8.0.12",
"ts-node": "^9.1.1",
"tslib": "^2.0.0",
"typescript": "^4.1.2",
"typescript": "^4.2.2",
"url-loader": "^4.1.1",
"uuid": "^8.1.0",
"webpack": "^4.40.2",
"webpack-cli": "^3.3.9"
"webpack": "^5.11.0",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^3.11.2"
}
}

View File

@@ -8,4 +8,13 @@ sentry:
triggerNotification:
version: 1.5.81
stagingPercentage: 100
upstream:
- repo: etcher-sdk
url: https://github.com/balena-io-modules/etcher-sdk
module: 'etcher-sdk'
- repo: sys-class-rgb-led
url: https://github.com/balena-io-modules/sys-class-rgb-led
module: sys-class-rgb-led
- repo: rendition
url: https://github.com/balena-io-modules/rendition
module: rendition

View File

@@ -29,6 +29,10 @@ const SHRINKWRAP_FILENAME = path.join(__dirname, '..', 'npm-shrinkwrap.json');
async function main() {
try {
const cleaned = omit(shrinkwrap, packageInfo.platformSpecificDependencies);
for (const item of Object.values(cleaned.dependencies)) {
// @ts-ignore
item.dev = true;
}
await writeFileAsync(
SHRINKWRAP_FILENAME,
JSON.stringify(cleaned, null, JSON_INDENT),

View File

@@ -16,7 +16,6 @@
import { expect } from 'chai';
import * as settings from '../../../lib/gui/app/models/settings';
import * as progressStatus from '../../../lib/gui/app/modules/progress-status';
describe('Browser: progressStatus', function () {
@@ -30,8 +29,6 @@ describe('Browser: progressStatus', function () {
eta: 15,
speed: 100000000000000,
};
settings.set('unmountOnSuccess', true);
});
it('should report 0% if percentage == 0 but speed != 0', function () {
@@ -40,22 +37,14 @@ describe('Browser: progressStatus', function () {
);
});
it('should handle percentage == 0, flashing, unmountOnSuccess', function () {
it('should handle percentage == 0, flashing', function () {
this.state.speed = 0;
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
'0% Flashing...',
);
});
it('should handle percentage == 0, flashing, !unmountOnSuccess', function () {
this.state.speed = 0;
settings.set('unmountOnSuccess', false);
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
'0% Flashing...',
);
});
it('should handle percentage == 0, verifying, unmountOnSuccess', function () {
it('should handle percentage == 0, verifying', function () {
this.state.speed = 0;
this.state.type = 'verifying';
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
@@ -63,31 +52,14 @@ describe('Browser: progressStatus', function () {
);
});
it('should handle percentage == 0, verifying, !unmountOnSuccess', function () {
this.state.speed = 0;
this.state.type = 'verifying';
settings.set('unmountOnSuccess', false);
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
'0% Validating...',
);
});
it('should handle percentage == 50, flashing, unmountOnSuccess', function () {
it('should handle percentage == 50, flashing', function () {
this.state.percentage = 50;
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
'50% Flashing...',
);
});
it('should handle percentage == 50, flashing, !unmountOnSuccess', function () {
this.state.percentage = 50;
settings.set('unmountOnSuccess', false);
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
'50% Flashing...',
);
});
it('should handle percentage == 50, verifying, unmountOnSuccess', function () {
it('should handle percentage == 50, verifying', function () {
this.state.percentage = 50;
this.state.type = 'verifying';
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
@@ -95,31 +67,14 @@ describe('Browser: progressStatus', function () {
);
});
it('should handle percentage == 50, verifying, !unmountOnSuccess', function () {
this.state.percentage = 50;
this.state.type = 'verifying';
settings.set('unmountOnSuccess', false);
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
'50% Validating...',
);
});
it('should handle percentage == 100, flashing, unmountOnSuccess', function () {
it('should handle percentage == 100, flashing', function () {
this.state.percentage = 100;
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
'Finishing...',
);
});
it('should handle percentage == 100, flashing, !unmountOnSuccess', function () {
this.state.percentage = 100;
settings.set('unmountOnSuccess', false);
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
'Finishing...',
);
});
it('should handle percentage == 100, verifying, unmountOnSuccess', function () {
it('should handle percentage == 100, verifying', function () {
this.state.percentage = 100;
this.state.type = 'verifying';
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
@@ -127,9 +82,8 @@ describe('Browser: progressStatus', function () {
);
});
it('should handle percentage == 100, validatinf, !unmountOnSuccess', function () {
it('should handle percentage == 100, validating', function () {
this.state.percentage = 100;
settings.set('unmountOnSuccess', false);
expect(progressStatus.titleFromFlashState(this.state)).to.equal(
'Finishing...',
);

View File

@@ -15,43 +15,52 @@
*/
import { expect } from 'chai';
import { platform } from 'os';
import { Application } from 'spectron';
import * as electronPath from 'electron';
describe('Spectron', function () {
// Mainly for CI jobs
this.timeout(40000);
// TODO: spectron fails to start on the CI with:
// Error: Failed to create session.
// unknown error: Chrome failed to start: exited abnormally
if (platform() !== 'darwin') {
describe('Spectron', function () {
// Mainly for CI jobs
this.timeout(40000);
const app = new Application({
path: (electronPath as unknown) as string,
args: ['--no-sandbox', '.'],
});
before('app:start', async () => {
await app.start();
});
after('app:stop', async () => {
if (app && app.isRunning()) {
await app.stop();
}
});
describe('Browser Window', () => {
it('should open a browser window', async () => {
// We can't use `isVisible()` here as it won't work inside
// a Windows Docker container, but we can approximate it
// with these set of checks:
const bounds = await app.browserWindow.getBounds();
expect(bounds.height).to.be.above(0);
expect(bounds.width).to.be.above(0);
expect(await app.browserWindow.isMinimized()).to.be.false;
expect(await app.browserWindow.isVisible()).to.be.true;
const app = new Application({
path: (electronPath as unknown) as string,
args: ['--no-sandbox', '.'],
});
it('should set a proper title', async () => {
// @ts-ignore (SpectronClient.getTitle exists)
return expect(await app.client.getTitle()).to.equal('Etcher');
before('app:start', async () => {
await app.start();
});
after('app:stop', async () => {
if (app && app.isRunning()) {
await app.stop();
}
});
describe('Browser Window', () => {
it('should open a browser window', async () => {
// We can't use `isVisible()` here as it won't work inside
// a Windows Docker container, but we can approximate it
// with these set of checks:
const bounds = await app.browserWindow.getBounds();
expect(bounds.height).to.be.above(0);
expect(bounds.width).to.be.above(0);
expect(await app.browserWindow.isMinimized()).to.be.false;
expect(
(await app.browserWindow.isVisible()) ||
(await app.browserWindow.isFocused()),
).to.be.true;
});
it('should set a proper title', async () => {
// @ts-ignore (SpectronClient.getTitle exists)
return expect(await app.client.getTitle()).to.equal('Etcher');
});
});
});
});
}

View File

@@ -17,7 +17,6 @@
import * as CopyPlugin from 'copy-webpack-plugin';
import { readdirSync } from 'fs';
import * as _ from 'lodash';
import * as MiniCssExtractPlugin from 'mini-css-extract-plugin';
import * as os from 'os';
import outdent from 'outdent';
import * as path from 'path';
@@ -32,8 +31,7 @@ import { BannerPlugin, NormalModuleReplacementPlugin } from 'webpack';
*/
function externalPackageJson(packageJsonPath: string) {
return (
_context: string,
request: string,
{ request }: { context: string; request: string },
callback: (error?: Error | null, result?: string) => void,
) => {
if (_.endsWith(request, 'package.json')) {
@@ -50,8 +48,7 @@ function platformSpecificModule(
) {
// Resolves module on platform, otherwise resolves the replacement
return (
_context: string,
request: string,
{ request }: { context: string; request: string },
callback: (error?: Error, result?: string, type?: string) => void,
) => {
if (request === module && os.platform() !== platform) {
@@ -70,6 +67,8 @@ function renameNodeModules(resourcePath: string) {
path
.relative(__dirname, resourcePath)
.replace('node_modules', 'modules')
// use the same name on all architectures so electron-builder can build a universal dmg on mac
.replace(LZMA_BINDINGS_FOLDER, LZMA_BINDINGS_FOLDER_RENAMED)
// file-loader expects posix paths, even on Windows
.replace(/\\/g, '/')
);
@@ -89,6 +88,7 @@ function findLzmaNativeBindingsFolder(): string {
}
const LZMA_BINDINGS_FOLDER = findLzmaNativeBindingsFolder();
const LZMA_BINDINGS_FOLDER_RENAMED = 'binding';
interface ReplacementRule {
search: string;
@@ -119,7 +119,15 @@ function fetchWasm(...where: string[]) {
} catch {
}
function appPath() {
return Path.isAbsolute(__dirname) ? __dirname : Path.join(electron.remote.app.getAppPath(), 'generated');
return Path.isAbsolute(__dirname) ?
__dirname :
Path.join(
// With macOS universal builds, getAppPath() returns the path to an app.asar file containing an index.js file which will
// include the app-x64 or app-arm64 folder depending on the arch.
// We don't care about the app.asar file, we want the actual folder.
electron.remote.app.getAppPath().replace(/\\.asar$/, () => process.platform === 'darwin' ? '-' + process.arch : ''),
'generated'
);
}
scriptDirectory = Path.join(appPath(), 'modules', ${whereStr}, '/');
`;
@@ -128,6 +136,7 @@ function fetchWasm(...where: string[]) {
const commonConfig = {
mode: 'production',
optimization: {
moduleIds: 'natural',
minimize: true,
minimizer: [
new TerserPlugin({
@@ -148,7 +157,12 @@ const commonConfig = {
rules: [
{
test: /\.css$/,
use: 'css-loader',
use: ['style-loader', 'css-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: { name: renameNodeModules },
},
{
test: /\.svg$/,
@@ -192,12 +206,7 @@ const commonConfig = {
// remove node-pre-gyp magic from lzma-native
{
search: 'require(binding_path)',
replace: () => {
return `require('./${path.posix.join(
LZMA_BINDINGS_FOLDER,
'lzma_native.node',
)}')`;
},
replace: `require('./${LZMA_BINDINGS_FOLDER}/lzma_native.node')`,
},
// use regular stream module instead of readable-stream
{
@@ -241,7 +250,19 @@ const commonConfig = {
"return await readFile(Path.join(__dirname, '..', 'blobs', filename));",
replace: outdent`
const { app, remote } = require('electron');
return await readFile(Path.join((app || remote.app).getAppPath(), 'generated', __dirname.replace('node_modules', 'modules'), '..', 'blobs', filename));
return await readFile(
Path.join(
// With macOS universal builds, getAppPath() returns the path to an app.asar file containing an index.js file which will
// include the app-x64 or app-arm64 folder depending on the arch.
// We don't care about the app.asar file, we want the actual folder.
(app || remote.app).getAppPath().replace(/\\.asar$/, () => process.platform === 'darwin' ? '-' + process.arch : ''),
'generated',
__dirname.replace('node_modules', 'modules'),
'..',
'blobs',
filename
)
);
`,
}),
// Use the libext2fs.wasm file in the generated folder
@@ -276,7 +297,7 @@ const commonConfig = {
format: process.env.WEBPACK_PROGRESS || 'verbose',
}),
// Force axios to use http.js, not xhr.js as we need stream support
// (it's package.json file replaces http with xhr for browser targets).
// (its package.json file replaces http with xhr for browser targets).
new NormalModuleReplacementPlugin(
slashOrAntislash(/node_modules\/axios\/lib\/adapters\/xhr\.js/),
'./http.js',
@@ -319,7 +340,7 @@ if (os.platform() === 'win32') {
// liblzma.dll is required on Windows for lzma-native
guiConfigCopyPatterns.push({
from: `node_modules/lzma-native/${LZMA_BINDINGS_FOLDER}/liblzma.dll`,
to: `modules/lzma-native/${LZMA_BINDINGS_FOLDER}/liblzma.dll`,
to: `modules/lzma-native/${LZMA_BINDINGS_FOLDER_RENAMED}/liblzma.dll`,
});
}
@@ -331,10 +352,18 @@ const guiConfig = {
__filename: true,
},
entry: {
gui: path.join(__dirname, 'lib', 'gui', 'app', 'app.ts'),
gui: path.join(__dirname, 'lib', 'gui', 'app', 'renderer.ts'),
},
plugins: [
...commonConfig.plugins,
new CopyPlugin({
patterns: [
{ from: 'lib/gui/app/index.html', to: 'index.html' },
// electron-builder doesn't bundle folders named "assets"
// See https://github.com/electron-userland/electron-builder/issues/4545
{ from: 'assets/icon.png', to: 'media/icon.png' },
],
}),
// Remove "Download the React DevTools for a better development experience" message
new BannerPlugin({
banner: '__REACT_DEVTOOLS_GLOBAL_HOOK__ = { isDisabled: true };',
@@ -373,41 +402,4 @@ const childWriterConfig = {
},
};
const cssConfig = {
mode: 'production',
optimization: {
minimize: false,
},
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf|svg)$/,
loader: 'file-loader',
options: { name: renameNodeModules },
},
],
},
plugins: [
new MiniCssExtractPlugin({ filename: '[name].css' }),
new CopyPlugin({
patterns: [
{ from: 'lib/gui/app/index.html', to: 'index.html' },
// electron-builder doesn't bundle folders named "assets"
// See https://github.com/electron-userland/electron-builder/issues/4545
{ from: 'assets/icon.png', to: 'media/icon.png' },
],
}),
],
entry: {
index: path.join(__dirname, 'lib', 'gui', 'app', 'css', 'main.css'),
},
output: {
path: path.join(__dirname, 'generated'),
},
};
module.exports = [cssConfig, guiConfig, etcherConfig, childWriterConfig];
export default [guiConfig, etcherConfig, childWriterConfig];

22
webpack.dev.config.ts Normal file
View File

@@ -0,0 +1,22 @@
import configs from './webpack.config';
import { WebpackOptionsNormalized } from 'webpack';
import * as fs from 'fs';
const [
guiConfig,
etcherConfig,
childWriterConfig,
] = (configs as unknown) as WebpackOptionsNormalized[];
configs.forEach((config) => {
config.mode = 'development';
});
guiConfig.devServer = {
hot: true,
port: 3030,
};
fs.copyFileSync('./lib/gui/app/index.dev.html', './generated/index.html');
export default [guiConfig, etcherConfig, childWriterConfig];