mirror of
https://github.com/balena-io/etcher.git
synced 2025-11-09 18:38:32 +00:00
Compare commits
1 Commits
aethernet-
...
aethernet/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec7e0b745e |
65
.github/actions/publish/action.yml
vendored
65
.github/actions/publish/action.yml
vendored
@@ -15,7 +15,7 @@ inputs:
|
|||||||
default: "accounts+apple@balena.io"
|
default: "accounts+apple@balena.io"
|
||||||
NODE_VERSION:
|
NODE_VERSION:
|
||||||
type: string
|
type: string
|
||||||
default: "16.x"
|
default: "14.x"
|
||||||
VERBOSE:
|
VERBOSE:
|
||||||
type: string
|
type: string
|
||||||
default: "true"
|
default: "true"
|
||||||
@@ -46,6 +46,55 @@ runs:
|
|||||||
run: choco install yq
|
run: choco install yq
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
|
|
||||||
|
# FIXME: resinci-deploy is not actively maintained
|
||||||
|
# https://github.com/product-os/resinci-deploy
|
||||||
|
- name: Checkout resinci-deploy
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: product-os/resinci-deploy
|
||||||
|
token: ${{ fromJSON(inputs.secrets).FLOWZONE_TOKEN }}
|
||||||
|
path: resinci-deploy
|
||||||
|
|
||||||
|
- name: Build and install resinci-deploy
|
||||||
|
shell: bash --noprofile --norc -eo pipefail -x {0}
|
||||||
|
run: |
|
||||||
|
set -ea
|
||||||
|
|
||||||
|
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
|
||||||
|
|
||||||
|
runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
|
||||||
|
rm -rf ../resinci-deploy && mv resinci-deploy ..
|
||||||
|
|
||||||
|
pushd ../resinci-deploy && npm ci && npm link && popd
|
||||||
|
|
||||||
|
if [[ $runner_os =~ linux|macos ]]; then
|
||||||
|
chmod +x "$(dirname "$(which node)")/resinci-deploy" && which resinci-deploy
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Upload sourcemaps to sentry
|
||||||
|
- name: Generate Sentry DSN
|
||||||
|
id: sentry
|
||||||
|
shell: bash --noprofile --norc -eo pipefail -x {0}
|
||||||
|
run: |
|
||||||
|
set -ea
|
||||||
|
|
||||||
|
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
|
||||||
|
|
||||||
|
branch="$(echo '${{ github.event.pull_request.head.ref }}' | sed 's/[^[:alnum:]]/-/g')"
|
||||||
|
|
||||||
|
stdout="$(resinci-deploy store sentry \
|
||||||
|
--branch="${branch}" \
|
||||||
|
--name="$(jq -r '.name' package.json)" \
|
||||||
|
--team="$(yq e '.sentry.team' repo.yml)" \
|
||||||
|
--org="$(yq e '.sentry.org' repo.yml)" \
|
||||||
|
--type="$(yq e '.sentry.type' repo.yml)")"
|
||||||
|
|
||||||
|
echo "dsn=$(echo "${stdout}" | tail -n 1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
env:
|
||||||
|
SENTRY_TOKEN: ${{ fromJSON(inputs.secrets).SENTRY_AUTH_TOKEN }}
|
||||||
|
|
||||||
# https://www.electron.build/code-signing.html
|
# https://www.electron.build/code-signing.html
|
||||||
# https://github.com/Apple-Actions/import-codesign-certs
|
# https://github.com/Apple-Actions/import-codesign-certs
|
||||||
- name: Import Apple code signing certificate
|
- name: Import Apple code signing certificate
|
||||||
@@ -119,8 +168,8 @@ runs:
|
|||||||
|
|
||||||
for target in ${TARGETS}; do
|
for target in ${TARGETS}; do
|
||||||
electron-builder ${ELECTRON_BUILDER_OS} ${target} ${ARCHITECTURE_FLAGS} \
|
electron-builder ${ELECTRON_BUILDER_OS} ${target} ${ARCHITECTURE_FLAGS} \
|
||||||
--c.extraMetadata.analytics.sentry.token='https://739bbcfc0ba4481481138d3fc831136d@o95242.ingest.sentry.io/4504451487301632' \
|
--c.extraMetadata.analytics.sentry.token='${{ steps.sentry.outputs.dsn }}' \
|
||||||
--c.extraMetadata.analytics.amplitude.token='balena-etcher' \
|
--c.extraMetadata.analytics.mixpanel.token='balena-etcher' \
|
||||||
--c.extraMetadata.packageType="${target}"
|
--c.extraMetadata.packageType="${target}"
|
||||||
|
|
||||||
find dist -type f -maxdepth 1
|
find dist -type f -maxdepth 1
|
||||||
@@ -154,6 +203,16 @@ runs:
|
|||||||
-name "latest*.yml" \
|
-name "latest*.yml" \
|
||||||
-exec yq -i e .stagingPercentage=\"$percentage\" {} \;
|
-exec yq -i e .stagingPercentage=\"$percentage\" {} \;
|
||||||
|
|
||||||
|
- name: Upload sourcemap to Sentry
|
||||||
|
shell: bash --noprofile --norc -eo pipefail -x {0}
|
||||||
|
run: |
|
||||||
|
VERSION=${{ steps.package_release.outputs.version }} npm run uploadSourcemap
|
||||||
|
env:
|
||||||
|
SENTRY_AUTH_TOKEN: ${{ fromJSON(inputs.secrets).SENTRY_AUTH_TOKEN }}
|
||||||
|
npm_config_SENTRY_ORG: balenaEtcher
|
||||||
|
npm_config_SENTRY_PROJECT: balenaetcher
|
||||||
|
npm_config_SENTRY_VERSION: ${{ steps.package_release.outputs.version }}
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.github/actions/test/action.yml
vendored
2
.github/actions/test/action.yml
vendored
@@ -12,7 +12,7 @@ inputs:
|
|||||||
# --- custom environment
|
# --- custom environment
|
||||||
NODE_VERSION:
|
NODE_VERSION:
|
||||||
type: string
|
type: string
|
||||||
default: "16.x"
|
default: "14.x"
|
||||||
VERBOSE:
|
VERBOSE:
|
||||||
type: string
|
type: string
|
||||||
default: "true"
|
default: "true"
|
||||||
|
|||||||
1
.github/workflows/flowzone.yml
vendored
1
.github/workflows/flowzone.yml
vendored
@@ -27,4 +27,3 @@ jobs:
|
|||||||
repo_description: "Flash OS images to SD cards & USB drives, safely and easily."
|
repo_description: "Flash OS images to SD cards & USB drives, safely and easily."
|
||||||
repo_homepage: https://etcher.io/
|
repo_homepage: https://etcher.io/
|
||||||
repo_enable_wiki: true
|
repo_enable_wiki: true
|
||||||
cloudflare_website: "etcher"
|
|
||||||
|
|||||||
@@ -1,377 +1,3 @@
|
|||||||
- commits:
|
|
||||||
- subject: add-flash-with-etcher-to-docs
|
|
||||||
hash: 856b426dc98925f5e339976a5cac144f4bb4ea59
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Lizzie Epton
|
|
||||||
nested: []
|
|
||||||
version: 1.18.6
|
|
||||||
title: ""
|
|
||||||
date: 2023-03-21T13:24:18.265Z
|
|
||||||
- commits:
|
|
||||||
- subject: "patch: add apt-get update in flowzone preinstall"
|
|
||||||
hash: 0d9ac710880e6b9413b09e4c35a505034d1e9d51
|
|
||||||
body: libudev package has changed and cannot be installed if we not update apt
|
|
||||||
cache
|
|
||||||
footer: {}
|
|
||||||
author: Edwin Joassart
|
|
||||||
nested: []
|
|
||||||
version: 1.18.5
|
|
||||||
title: ""
|
|
||||||
date: 2023-03-09T11:30:34.540Z
|
|
||||||
- commits:
|
|
||||||
- subject: "patch: bump etcher-sdk to 8.3.1"
|
|
||||||
hash: bf0360e7f46ac620f95021e0c48a3a04d302e725
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: JOASSART Edwin
|
|
||||||
nested: []
|
|
||||||
version: 1.18.4
|
|
||||||
title: ""
|
|
||||||
date: 2023-03-02T17:31:31.788Z
|
|
||||||
- commits:
|
|
||||||
- subject: fix-typo
|
|
||||||
hash: 496f131c4b024dfcd17fde5173016f70c0d0599c
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Lizzie Epton
|
|
||||||
nested: []
|
|
||||||
- subject: edits-to-info-about-efp
|
|
||||||
hash: f582b0215c2cf66acf652afdaa47353e1a7eac07
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Lizzie Epton
|
|
||||||
nested: []
|
|
||||||
- subject: Add reference to etcher-efp in publishing.md
|
|
||||||
hash: 4c3c4babea5efdadbed7ba0df85f08b68a7b6f20
|
|
||||||
body: |
|
|
||||||
Add reference to etcher-efp in publishing.md
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Edwin Joassart
|
|
||||||
nested: []
|
|
||||||
version: 1.18.3
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-22T12:12:40.270Z
|
|
||||||
- commits:
|
|
||||||
- subject: "patch: organize docs"
|
|
||||||
hash: e479b95d72bed6a50ae6a971598a18d8a7562f0d
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: mcraa
|
|
||||||
nested: []
|
|
||||||
- subject: "patch: actualized develop guide"
|
|
||||||
hash: 926ff2b7549d8b187b18ee452ce48c62f6cd3531
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: mcraa
|
|
||||||
nested: []
|
|
||||||
- subject: "patch: updated commit message guide"
|
|
||||||
hash: 394b64319de11b1010b8acfe160de13a6f3851cd
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: mcraa
|
|
||||||
nested: []
|
|
||||||
- subject: add-item-from-FAQs
|
|
||||||
hash: 96fa53b6ee4ec7a29522df488b927074c0f301ca
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Lizzie Epton
|
|
||||||
nested: []
|
|
||||||
- subject: "patch: removed gt characters from contributing guide"
|
|
||||||
hash: 9b54e2af0b9356bb73e197cccbcc2ff89673361f
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: mcraa
|
|
||||||
nested: []
|
|
||||||
- subject: "patch: added docosaurus site name"
|
|
||||||
hash: b01cf3c2e1c3a7a234c8b957bd570ecdca81e0c1
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: mcraa
|
|
||||||
nested: []
|
|
||||||
version: 1.18.2
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-21T13:17:09.606Z
|
|
||||||
- commits:
|
|
||||||
- subject: "patch: use @electron/remote for locating rpiboot files"
|
|
||||||
hash: 04fa3dcd8c619dce927221cef5799b5210354d2e
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: mcraa
|
|
||||||
nested: []
|
|
||||||
version: 1.18.1
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-15T14:54:45.951Z
|
|
||||||
- commits:
|
|
||||||
- subject: Update to Electron 19
|
|
||||||
hash: c11db0a2797a6b1093dd3fa6f55bee5f100c6da4
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: minor
|
|
||||||
change-type: minor
|
|
||||||
author: Akis Kesoglou
|
|
||||||
nested: []
|
|
||||||
- subject: Remove Spectron and related (low-value) tests
|
|
||||||
hash: 6f7570d265e4b457afe832d00e5f45e0bf5a8a53
|
|
||||||
body: >
|
|
||||||
Spectron is long deprecated and abandoned and the browser tests are so
|
|
||||||
rudimentary that it’s no longer worth having them around. We will
|
|
||||||
introduce a proper browser-based test suite in the short term — it’s a
|
|
||||||
project in progress.
|
|
||||||
footer:
|
|
||||||
Change-type: minor
|
|
||||||
change-type: minor
|
|
||||||
author: Akis Kesoglou
|
|
||||||
nested: []
|
|
||||||
version: 1.18.0
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-14T18:07:05.870Z
|
|
||||||
- commits:
|
|
||||||
- subject: Update to Electron 17 and Node 16
|
|
||||||
hash: 3c1dd6ce29ddf43ef35e58236d25713fa2026c10
|
|
||||||
body: |
|
|
||||||
This is the latest Electron version officially supported by Spectron.
|
|
||||||
footer:
|
|
||||||
Change-type: minor
|
|
||||||
change-type: minor
|
|
||||||
author: Akis Kesoglou
|
|
||||||
nested: []
|
|
||||||
version: 1.17.0
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-14T16:18:54.834Z
|
|
||||||
- commits:
|
|
||||||
- subject: Update to Electron 14
|
|
||||||
hash: df7854111a901b620e3284edf10768d308ce7755
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: minor
|
|
||||||
change-type: minor
|
|
||||||
author: Akis Kesoglou
|
|
||||||
nested: []
|
|
||||||
version: 1.16.0
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-14T12:40:40.820Z
|
|
||||||
- commits:
|
|
||||||
- subject: "patch: app: i18n: Translation: Update zh-TW strings * Improve
|
|
||||||
translate. * Sync layout with English strings ts file."
|
|
||||||
hash: b51418814f5ef48d09e3157c92bda5eab173dbd5
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Signed-off-by: Edward Wu <bluehome.wu@gmail.com>
|
|
||||||
signed-off-by: Edward Wu <bluehome.wu@gmail.com>
|
|
||||||
author: Edward Wu
|
|
||||||
nested: []
|
|
||||||
version: 1.15.6
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-13T11:23:13.079Z
|
|
||||||
- commits:
|
|
||||||
- subject: revert auto-update feature
|
|
||||||
hash: e6d33eda2b8f767679a43f8056e20098b0f2f6d9
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: JOASSART Edwin
|
|
||||||
nested: []
|
|
||||||
version: 1.15.5
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-03T14:25:19.611Z
|
|
||||||
- commits:
|
|
||||||
- subject: Switch to `@electron/remote`
|
|
||||||
hash: 7ee174edcecbfc2d7370db6d4185b3ee4eedbe28
|
|
||||||
body: >
|
|
||||||
Electron 12 deprecated `electron.remote` and the functionality was removed
|
|
||||||
in Electron 14, but became available as a separate `@electron/remote`
|
|
||||||
module. This commit makes the transition to the external module as an
|
|
||||||
intermediary step to enable updating to a newer Electron version.
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Akis Kesoglou
|
|
||||||
nested: []
|
|
||||||
version: 1.15.4
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-02T18:26:45.877Z
|
|
||||||
- commits:
|
|
||||||
- subject: move EFP & success-banner to efp.balena.io
|
|
||||||
hash: a140faaebe087a96387604f12c3510ee22374d92
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Edwin Joassart
|
|
||||||
nested: []
|
|
||||||
version: 1.15.3
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-02T17:23:16.454Z
|
|
||||||
- commits:
|
|
||||||
- subject: Remove configuration remote update
|
|
||||||
hash: 85a49a221fa7fc9b1943dc8ed43b29995f9d8260
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Edwin Joassart
|
|
||||||
nested: []
|
|
||||||
version: 1.15.2
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-02T13:05:01.310Z
|
|
||||||
- commits:
|
|
||||||
- subject: Remove redundant resinci-deploy build step
|
|
||||||
hash: 48ddafd120cc9cd4fb94c0d6f7530a14be46f28d
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Akis Kesoglou
|
|
||||||
nested: []
|
|
||||||
- subject: Lazily import Electron from child-writer process
|
|
||||||
hash: 851219f835ed037d9fd970f538095e4b339c5342
|
|
||||||
body: >
|
|
||||||
No idea how this *used* to work, but it doesn’t since 887ec428 and this is
|
|
||||||
fixing it properly.
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Akis Kesoglou
|
|
||||||
nested: []
|
|
||||||
version: 1.15.1
|
|
||||||
title: ""
|
|
||||||
date: 2023-02-01T12:18:55.922Z
|
|
||||||
- commits:
|
|
||||||
- subject: Add support for Node 18
|
|
||||||
hash: 887ec42847acbd4a935b4e9ed6abb2b8d87058ce
|
|
||||||
body: >
|
|
||||||
The Electron version we’re currently using is on Node 14 but this is a
|
|
||||||
step forward to upgrading to a newer Electron and Node version.
|
|
||||||
|
|
||||||
|
|
||||||
Updates etcher-sdk and switches the redundant aws4-axios dependency to just axios.
|
|
||||||
|
|
||||||
|
|
||||||
Also changed bundler to stop trying to bundle wasm files — they must be included inline with JS code as data — and removed some now redundant code.
|
|
||||||
|
|
||||||
|
|
||||||
The crucial changes that enable support are:
|
|
||||||
|
|
||||||
|
|
||||||
1. The update to etcher-sdk@8 where some dependency fixes and updates took place
|
|
||||||
|
|
||||||
2. The downgrade and pinning of "electron-rebuild" to v3.2.3 until we’re able to update to Electron >= 14.2. The patch we need to avoid is https://github.com/electron/rebuild/pull/907. Also see: https://github.com/nodejs/node-gyp/issues/2673 and https://github.com/electron/rebuild/issues/913
|
|
||||||
|
|
||||||
3. A rule in webpack.config to ignore `aws-crt` which is a dependency of (ultimately) `aws4-axios` which is used by etcher-sdk and does a runtime check to its availability. We’re not currently using the “assume role” functionality (AFAIU) of aws4-axios and we don’t care that it’s not found, so force webpack to ignore the import. See https://github.com/aws/aws-sdk-js-v3/issues/3025
|
|
||||||
footer:
|
|
||||||
Change-type: minor
|
|
||||||
change-type: minor
|
|
||||||
author: Akis Kesoglou
|
|
||||||
nested: []
|
|
||||||
version: 1.15.0
|
|
||||||
title: ""
|
|
||||||
date: 2023-01-27T11:36:32.980Z
|
|
||||||
- commits:
|
|
||||||
- subject: "patch: fixed mac sudo on other languages"
|
|
||||||
hash: 19d1e093fc2b1588492c9868f7604ee15ab3fd5b
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: Peter Makra
|
|
||||||
nested: []
|
|
||||||
version: 1.14.3
|
|
||||||
title: ""
|
|
||||||
date: 2023-01-19T12:21:02.651Z
|
|
||||||
- commits:
|
|
||||||
- subject: "patch: revert to lockfile v1"
|
|
||||||
hash: 72af77860bee3685635c9f4db602c2a07e825037
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: Peter Makra
|
|
||||||
nested: []
|
|
||||||
- subject: "patch: update etcher-sdk for cm4v5"
|
|
||||||
hash: 8e63be2efecada2ad6abd9d9d7728859e2c30ebc
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: builder555
|
|
||||||
nested: []
|
|
||||||
version: 1.14.2
|
|
||||||
title: ""
|
|
||||||
date: 2023-01-17T14:37:41.555Z
|
|
||||||
- commits:
|
|
||||||
- subject: fix disabled-screensaver unhandled exception outside balena-electron env
|
|
||||||
hash: 46c406e8c1e3b5e41890aff7f65b1711e4426782
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Edwin Joassart
|
|
||||||
nested: []
|
|
||||||
version: 1.14.1
|
|
||||||
title: ""
|
|
||||||
date: 2023-01-16T13:22:36.972Z
|
|
||||||
- commits:
|
|
||||||
- subject: Anonymizes all paths before sending
|
|
||||||
hash: 86d43a536f7c9aa6b450a9f2f90341e07364208e
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Otávio Jacobi
|
|
||||||
nested: []
|
|
||||||
- subject: "patch: Sentry fix path"
|
|
||||||
hash: 6c417e35a13873cd95d25f42a819de3750cdf65d
|
|
||||||
body: ""
|
|
||||||
footer: {}
|
|
||||||
author: Edwin Joassart
|
|
||||||
nested: []
|
|
||||||
- subject: Remove personal path on etcher
|
|
||||||
hash: 2b728d3c521b76177a2c019b4891627272f35aac
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: minor
|
|
||||||
change-type: minor
|
|
||||||
author: Otávio Jacobi
|
|
||||||
nested: []
|
|
||||||
- subject: Unifying sentry reports in a single project
|
|
||||||
hash: f3f7ecb852503d4d97dbe6a78bf920ca177bddd1
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
author: Edwin Joassart
|
|
||||||
nested: []
|
|
||||||
- subject: Removes corvus in favor of sentry and analytics client
|
|
||||||
hash: 41fca03c98d4a72bd8c3842d7e6b9d41f65336f9
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
Signed-off-by: Otavio Jacobi
|
|
||||||
signed-off-by: Otavio Jacobi
|
|
||||||
author: Otávio Jacobi
|
|
||||||
nested: []
|
|
||||||
- subject: Removes corvus in favor of sentry and analytics client
|
|
||||||
hash: 10caf8f1b6a174762192b13ce7bb4eaa71e90fcc
|
|
||||||
body: ""
|
|
||||||
footer:
|
|
||||||
Change-type: patch
|
|
||||||
change-type: patch
|
|
||||||
Signed-off-by: Otavio Jacobi
|
|
||||||
signed-off-by: Otavio Jacobi
|
|
||||||
author: Otávio Jacobi
|
|
||||||
nested: []
|
|
||||||
version: 1.14.0
|
|
||||||
title: ""
|
|
||||||
date: 2023-01-16T11:23:54.866Z
|
|
||||||
- commits:
|
- commits:
|
||||||
- subject: Adding EtcherPro device serial number to the Settings modal
|
- subject: Adding EtcherPro device serial number to the Settings modal
|
||||||
hash: d25eda9a7d6bf89284b630b2d55cbb0a7e3a9432
|
hash: d25eda9a7d6bf89284b630b2d55cbb0a7e3a9432
|
||||||
|
|||||||
115
CHANGELOG.md
115
CHANGELOG.md
@@ -3,121 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
# v1.18.6
|
|
||||||
## (2023-03-21)
|
|
||||||
|
|
||||||
* add-flash-with-etcher-to-docs [Lizzie Epton]
|
|
||||||
|
|
||||||
# v1.18.5
|
|
||||||
## (2023-03-09)
|
|
||||||
|
|
||||||
* patch: add apt-get update in flowzone preinstall [Edwin Joassart]
|
|
||||||
|
|
||||||
# v1.18.4
|
|
||||||
## (2023-03-02)
|
|
||||||
|
|
||||||
* patch: bump etcher-sdk to 8.3.1 [JOASSART Edwin]
|
|
||||||
|
|
||||||
# v1.18.3
|
|
||||||
## (2023-02-22)
|
|
||||||
|
|
||||||
* fix-typo [Lizzie Epton]
|
|
||||||
* edits-to-info-about-efp [Lizzie Epton]
|
|
||||||
* Add reference to etcher-efp in publishing.md [Edwin Joassart]
|
|
||||||
|
|
||||||
# v1.18.2
|
|
||||||
## (2023-02-21)
|
|
||||||
|
|
||||||
* patch: organize docs [mcraa]
|
|
||||||
* patch: actualized develop guide [mcraa]
|
|
||||||
* patch: updated commit message guide [mcraa]
|
|
||||||
* add-item-from-FAQs [Lizzie Epton]
|
|
||||||
* patch: removed gt characters from contributing guide [mcraa]
|
|
||||||
* patch: added docosaurus site name [mcraa]
|
|
||||||
|
|
||||||
# v1.18.1
|
|
||||||
## (2023-02-15)
|
|
||||||
|
|
||||||
* patch: use @electron/remote for locating rpiboot files [mcraa]
|
|
||||||
|
|
||||||
# v1.18.0
|
|
||||||
## (2023-02-14)
|
|
||||||
|
|
||||||
* Update to Electron 19 [Akis Kesoglou]
|
|
||||||
* Remove Spectron and related (low-value) tests [Akis Kesoglou]
|
|
||||||
|
|
||||||
# v1.17.0
|
|
||||||
## (2023-02-14)
|
|
||||||
|
|
||||||
* Update to Electron 17 and Node 16 [Akis Kesoglou]
|
|
||||||
|
|
||||||
# v1.16.0
|
|
||||||
## (2023-02-14)
|
|
||||||
|
|
||||||
* Update to Electron 14 [Akis Kesoglou]
|
|
||||||
|
|
||||||
# v1.15.6
|
|
||||||
## (2023-02-13)
|
|
||||||
|
|
||||||
* patch: app: i18n: Translation: Update zh-TW strings * Improve translate. * Sync layout with English strings ts file. [Edward Wu]
|
|
||||||
|
|
||||||
# v1.15.5
|
|
||||||
## (2023-02-03)
|
|
||||||
|
|
||||||
* revert auto-update feature [JOASSART Edwin]
|
|
||||||
|
|
||||||
# v1.15.4
|
|
||||||
## (2023-02-02)
|
|
||||||
|
|
||||||
* Switch to `@electron/remote` [Akis Kesoglou]
|
|
||||||
|
|
||||||
# v1.15.3
|
|
||||||
## (2023-02-02)
|
|
||||||
|
|
||||||
* move EFP & success-banner to efp.balena.io [Edwin Joassart]
|
|
||||||
|
|
||||||
# v1.15.2
|
|
||||||
## (2023-02-02)
|
|
||||||
|
|
||||||
* Remove configuration remote update [Edwin Joassart]
|
|
||||||
|
|
||||||
# v1.15.1
|
|
||||||
## (2023-02-01)
|
|
||||||
|
|
||||||
* Remove redundant resinci-deploy build step [Akis Kesoglou]
|
|
||||||
* Lazily import Electron from child-writer process [Akis Kesoglou]
|
|
||||||
|
|
||||||
# v1.15.0
|
|
||||||
## (2023-01-27)
|
|
||||||
|
|
||||||
* Add support for Node 18 [Akis Kesoglou]
|
|
||||||
|
|
||||||
# v1.14.3
|
|
||||||
## (2023-01-19)
|
|
||||||
|
|
||||||
* patch: fixed mac sudo on other languages [Peter Makra]
|
|
||||||
|
|
||||||
# v1.14.2
|
|
||||||
## (2023-01-17)
|
|
||||||
|
|
||||||
* patch: revert to lockfile v1 [Peter Makra]
|
|
||||||
* patch: update etcher-sdk for cm4v5 [builder555]
|
|
||||||
|
|
||||||
# v1.14.1
|
|
||||||
## (2023-01-16)
|
|
||||||
|
|
||||||
* fix disabled-screensaver unhandled exception outside balena-electron env [Edwin Joassart]
|
|
||||||
|
|
||||||
# v1.14.0
|
|
||||||
## (2023-01-16)
|
|
||||||
|
|
||||||
* Anonymizes all paths before sending [Otávio Jacobi]
|
|
||||||
* patch: Sentry fix path [Edwin Joassart]
|
|
||||||
* Remove personal path on etcher [Otávio Jacobi]
|
|
||||||
* Unifying sentry reports in a single project [Edwin Joassart]
|
|
||||||
* Removes corvus in favor of sentry and analytics client [Otávio Jacobi]
|
|
||||||
* Removes corvus in favor of sentry and analytics client [Otávio Jacobi]
|
|
||||||
|
|
||||||
# v1.13.4
|
# v1.13.4
|
||||||
## (2023-01-12)
|
## (2023-01-12)
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,3 @@ Etcher requires an available [polkit authentication agent](https://wiki.archlinu
|
|||||||
## May I run Etcher in older macOS versions?
|
## 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.10 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).
|
||||||
|
|
||||||
## Can I use the Flash With Etcher button on my site?
|
|
||||||
|
|
||||||
You can use the Flash with Etcher button on your site or blog, if you have an OS that you want your users to be able to easily flash using Etcher, add the following code where you want to button to be:
|
|
||||||
|
|
||||||
`<a href="https://efp.balena.io/open-image-url?imageUrl=<your image URL>"><img src="http://balena.io/flash-with-etcher.png" /></a>`
|
|
||||||
33
README.md
33
README.md
@@ -53,15 +53,14 @@ confidence.
|
|||||||
2. Update and install:
|
2. Update and install:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt-get update #you can use apt instead of apt-get as well
|
sudo apt-get update
|
||||||
sudo apt-get install balena-etcher
|
sudo apt-get install balena-etcher-electron
|
||||||
```
|
```
|
||||||
>Note: for version v1.7.9 and below the package name was to `balena-etcher-electron`
|
|
||||||
|
|
||||||
##### Uninstall
|
##### Uninstall
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt-get remove balena-etcher
|
sudo apt-get remove balena-etcher-electron
|
||||||
rm /etc/apt/sources.list.d/balena-etcher.list
|
rm /etc/apt/sources.list.d/balena-etcher.list
|
||||||
apt-get clean
|
apt-get clean
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
@@ -86,9 +85,8 @@ apt-get update
|
|||||||
2. Update and install:
|
2. Update and install:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo dnf install -y balena-etcher
|
sudo dnf install -y balena-etcher-electron
|
||||||
```
|
```
|
||||||
>Note: for v1.7.9 and below the package name was `balena-etcher-electron`
|
|
||||||
|
|
||||||
###### Uninstall
|
###### Uninstall
|
||||||
|
|
||||||
@@ -110,14 +108,13 @@ rm /etc/yum.repos.d/balena-etcher-source.repo
|
|||||||
2. Update and install:
|
2. Update and install:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo yum install -y balena-etcher
|
sudo yum install -y balena-etcher-electron
|
||||||
```
|
```
|
||||||
>Note: for version v1.7.9 and below the package name was `balena-etcher-electron`
|
|
||||||
|
|
||||||
###### Uninstall
|
###### Uninstall
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo yum remove -y balena-etcher
|
sudo yum remove -y balena-etcher-electron
|
||||||
rm /etc/yum.repos.d/balena-etcher.repo
|
rm /etc/yum.repos.d/balena-etcher.repo
|
||||||
rm /etc/yum.repos.d/balena-etcher-source.repo
|
rm /etc/yum.repos.d/balena-etcher-source.repo
|
||||||
```
|
```
|
||||||
@@ -135,14 +132,13 @@ rm /etc/yum.repos.d/balena-etcher-source.repo
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo zypper up
|
sudo zypper up
|
||||||
sudo zypper install balena-etcher
|
sudo zypper install balena-etcher-electron
|
||||||
```
|
```
|
||||||
>Note: for version v1.7.9 and below the package name was `balena-etcher-electron`
|
|
||||||
|
|
||||||
##### Uninstall
|
##### Uninstall
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo zypper rm balena-etcher
|
sudo zypper rm balena-etcher-electron
|
||||||
# remove the repo
|
# remove the repo
|
||||||
sudo zypper rr balena-etcher
|
sudo zypper rr balena-etcher
|
||||||
sudo zypper rr balena-etcher-source
|
sudo zypper rr balena-etcher-source
|
||||||
@@ -173,19 +169,6 @@ yay -S balena-etcher
|
|||||||
```sh
|
```sh
|
||||||
yay -R balena-etcher
|
yay -R balena-etcher
|
||||||
```
|
```
|
||||||
#### WinGet (Windows)
|
|
||||||
|
|
||||||
This package is updated by [gh-action](https://github.com/vedantmgoyal2009/winget-releaser), and is kept up to date automatically.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
winget install balenaEtcher #or Balena.Etcher
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Uninstall
|
|
||||||
|
|
||||||
```sh
|
|
||||||
winget uninstall balenaEtcher
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Chocolatey (Windows)
|
#### Chocolatey (Windows)
|
||||||
|
|
||||||
|
|||||||
@@ -12,29 +12,67 @@ over the commit history.
|
|||||||
- Be able to automatically reference relevant changes from a dependency
|
- Be able to automatically reference relevant changes from a dependency
|
||||||
upgrade.
|
upgrade.
|
||||||
|
|
||||||
|
The guidelines are inspired by the [AngularJS git commit
|
||||||
|
guidelines][angular-commit-guidelines].
|
||||||
|
|
||||||
Commit structure
|
Commit structure
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
Each commit message needs to specify the semver-type. Which can be `patch|minor|major`.
|
Each commit message consists of a header, a body and a footer. The header has a
|
||||||
See the [Semantic Versioning][semver] specification for a more detailed explanation of the meaning of these types.
|
special format that includes a type, a scope and a subject.
|
||||||
See balena commit guidelines for more info about the whole commit structure.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
<semver-type>: <subject>
|
<type>(<scope>): <subject>
|
||||||
```
|
|
||||||
or
|
|
||||||
```
|
|
||||||
<subject>
|
|
||||||
<BLANK LINE>
|
<BLANK LINE>
|
||||||
<details>
|
<body>
|
||||||
<BLANK LINE>
|
<BLANK LINE>
|
||||||
Change-Type: <semver-type>
|
<footer>
|
||||||
```
|
```
|
||||||
|
|
||||||
The subject should not contain more than 70 characters, including the type and
|
The subject should not contain more than 70 characters, including the type and
|
||||||
scope, and the body should be wrapped at 72 characters.
|
scope, and the body should be wrapped at 72 characters.
|
||||||
|
|
||||||
|
Type
|
||||||
|
----
|
||||||
|
|
||||||
|
Must be one of the following:
|
||||||
|
|
||||||
|
- `feat`: A new feature.
|
||||||
|
- `fix`: A bug fix.
|
||||||
|
- `minifix`: A minimal fix that doesn't warrant an entry in the CHANGELOG.
|
||||||
|
- `docs`: Documentation only changes.
|
||||||
|
- `style`: Changes that do not affect the meaning of the code (white-space,
|
||||||
|
formatting, missing semi-colons, JSDoc annotations, comments, etc).
|
||||||
|
- `refactor`: A code change that neither fixes a bug nor adds a feature.
|
||||||
|
- `perf`: A code change that improves performance.
|
||||||
|
- `test`: Adding missing tests.
|
||||||
|
- `chore`: Changes to the build process or auxiliary tools and libraries.
|
||||||
|
- `upgrade`: A version upgrade of a project dependency.
|
||||||
|
|
||||||
|
Scope
|
||||||
|
-----
|
||||||
|
|
||||||
|
The scope is required for types that make sense, such as `feat`, `fix`,
|
||||||
|
`test`, etc. Certain commit types, such as `chore` might not have a clearly
|
||||||
|
defined scope, in which case its better to omit it.
|
||||||
|
|
||||||
|
Subject
|
||||||
|
-------
|
||||||
|
|
||||||
|
The subject should contain a short description of the change:
|
||||||
|
|
||||||
|
- Use the imperative, present tense.
|
||||||
|
- Don't capitalize the first letter.
|
||||||
|
- No dot (.) at the end.
|
||||||
|
|
||||||
|
Footer
|
||||||
|
------
|
||||||
|
|
||||||
|
The footer contains extra information about the commit, such as tags.
|
||||||
|
|
||||||
|
**Breaking Changes** should start with the word BREAKING CHANGE: with a space
|
||||||
|
or two newlines. The rest of the commit message is then used for this.
|
||||||
|
|
||||||
Tags
|
Tags
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -83,4 +121,125 @@ Closes: https://github.com/balena-io/etcher/issues/XXX
|
|||||||
Fixes: https://github.com/balena-io/etcher/issues/XXX
|
Fixes: https://github.com/balena-io/etcher/issues/XXX
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `Change-Type: <type>`
|
||||||
|
|
||||||
|
This tag is used to determine the change type that a commit introduces. The
|
||||||
|
following types are supported:
|
||||||
|
|
||||||
|
- `major`
|
||||||
|
- `minor`
|
||||||
|
- `patch`
|
||||||
|
|
||||||
|
This tag can be omitted for commits that don't change the application from the
|
||||||
|
user's point of view, such as for refactoring commits.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```
|
||||||
|
Change-Type: major
|
||||||
|
Change-Type: minor
|
||||||
|
Change-Type: patch
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [Semantic Versioning][semver] specification for a more detailed
|
||||||
|
explanation of the meaning of these types.
|
||||||
|
|
||||||
|
### `Changelog-Entry: <message>`
|
||||||
|
|
||||||
|
This tag is used to describe the changes introduced by the commit in a more
|
||||||
|
human style that would fit the `CHANGELOG.md` better.
|
||||||
|
|
||||||
|
If the commit type is either `fix` or `feat`, the commit will take part in the
|
||||||
|
CHANGELOG. If this tag is not defined, then the commit subject will be used
|
||||||
|
instead.
|
||||||
|
|
||||||
|
You explicitly can use this tag to make a commit whose type is not `fix` nor
|
||||||
|
`feat` appear in the `CHANGELOG.md`.
|
||||||
|
|
||||||
|
Since whatever your write here will be shown *as it is* in the `CHANGELOG.md`,
|
||||||
|
take some time to write a decent entry. Consider the following guidelines:
|
||||||
|
|
||||||
|
- Use the imperative, present tense.
|
||||||
|
- Capitalize the first letter.
|
||||||
|
|
||||||
|
There is no fixed length limit for the contents of this tag, but always strive
|
||||||
|
to make as short as possible without compromising its quality.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```
|
||||||
|
Changelog-Entry: Fix EPERM errors when flashing to a GPT drive.
|
||||||
|
```
|
||||||
|
|
||||||
|
Complete examples
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
```
|
||||||
|
fix(GUI): ignore extensions before the first non-compressed extension
|
||||||
|
|
||||||
|
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 valid , 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 at all.
|
||||||
|
|
||||||
|
As a way to allow these corner cases but still make use of our enforced check
|
||||||
|
controls, the validation routine now only consider extensions starting from the
|
||||||
|
first non compressed extension.
|
||||||
|
|
||||||
|
Change-Type: patch
|
||||||
|
Changelog-Entry: Don't interpret image file name information between dots as image extensions.
|
||||||
|
Fixes: https://github.com/balena-io/etcher/issues/492
|
||||||
|
```
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
```
|
||||||
|
upgrade: etcher-image-write to v5.0.2
|
||||||
|
|
||||||
|
This version contains a fix to an `EPERM` issue happening to some Windows user,
|
||||||
|
triggered by the `write` system call during the first ~5% of a flash given that
|
||||||
|
the operating system still thinks the drive has a file system.
|
||||||
|
|
||||||
|
Change-Type: patch
|
||||||
|
Changelog-Entry: Upgrade `etcher-image-write` to v5.0.2.
|
||||||
|
Link: https://github.com/balena-io-modules/etcher-image-write/blob/master/CHANGELOG.md#502---2016-06-27
|
||||||
|
Fixes: https://github.com/balena-io/etcher/issues/531
|
||||||
|
```
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(GUI): implement update notifier functionality
|
||||||
|
|
||||||
|
Auto-update functionality is not ready for usage. As a workaround to
|
||||||
|
prevent users staying with older versions, we now check for updates at
|
||||||
|
startup, and if the user is not running the latest version, we present a
|
||||||
|
modal informing the user of the availiblity of a new version, and
|
||||||
|
provide a call to action to open the Etcher website in his web browser.
|
||||||
|
|
||||||
|
Extra features:
|
||||||
|
|
||||||
|
- The user can skip the update, and tell the program to delay the
|
||||||
|
notification for 7 days.
|
||||||
|
|
||||||
|
Misc changes:
|
||||||
|
|
||||||
|
- Center modal with flexbox, to allow more flexibility on the modal height.
|
||||||
|
interacting with the S3 server.
|
||||||
|
- Implement `ManifestBindService`, which now serves as a backend for the
|
||||||
|
`manifest-bind` directive to allow the directive's functionality to be
|
||||||
|
re-used by other services.
|
||||||
|
- Namespace checkbox styles that are specific to the settings page.
|
||||||
|
|
||||||
|
Change-Type: minor
|
||||||
|
Changelog-Entry: Check for updates and show a modal prompting the user to download the latest version.
|
||||||
|
Closes: https://github.com/balena-io/etcher/issues/396
|
||||||
|
```
|
||||||
|
|
||||||
|
[angular-commit-guidelines]: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit
|
||||||
[semver]: http://semver.org
|
[semver]: http://semver.org
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ Developing
|
|||||||
|
|
||||||
#### Common
|
#### Common
|
||||||
|
|
||||||
- [NodeJS](https://nodejs.org) (at least v16.11)
|
- [NodeJS](https://nodejs.org) (at least v6.11)
|
||||||
- [Python 3](https://www.python.org)
|
- [Python 2.7](https://www.python.org)
|
||||||
- [jq](https://stedolan.github.io/jq/)
|
- [jq](https://stedolan.github.io/jq/)
|
||||||
- [curl](https://curl.haxx.se/)
|
- [curl](https://curl.haxx.se/)
|
||||||
- [npm](https://www.npmjs.com/)
|
- [npm](https://www.npmjs.com/) (version 6.7)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
@@ -33,16 +33,16 @@ You might need to run this with `sudo` or administrator permissions.
|
|||||||
|
|
||||||
- [NSIS v2.51](http://nsis.sourceforge.net/Main_Page) (v3.x won't work)
|
- [NSIS v2.51](http://nsis.sourceforge.net/Main_Page) (v3.x won't work)
|
||||||
- Either one of the following:
|
- Either one of the following:
|
||||||
- [Visual C++ 2019 Build Tools](https://visualstudio.microsoft.com/vs/features/cplusplus/) containing standalone compilers, libraries and scripts
|
- [Visual C++ 2015 Build Tools](http://landinghub.visualstudio.com/visual-cpp-build-tools) containing standalone compilers, libraries and scripts
|
||||||
- The [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools#windows-build-tools) should be installed along with NodeJS
|
- Install the [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools) via npm with `npm install --global windows-build-tools`
|
||||||
- [Visual Studio Community 2019](https://visualstudio.microsoft.com/vs/) (free) (other editions, like Professional and Enterprise, should work too)
|
- [Visual Studio Community 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48146) (free) (other editions, like Professional and Enterprise, should work too)
|
||||||
**NOTE:** Visual Studio doesn't install C++ by default. You have to rerun the
|
**NOTE:** Visual Studio 2015 doesn't install C++ by default. You have to rerun the
|
||||||
setup, select "Modify" and then check `Visual C++ -> Common Tools for Visual
|
setup, select "Modify" and then check `Visual C++ -> Common Tools for Visual
|
||||||
C++` (see http://stackoverflow.com/a/31955339)
|
C++ 2015` (see http://stackoverflow.com/a/31955339)
|
||||||
- [MinGW](http://www.mingw.org)
|
- [MinGW](http://www.mingw.org)
|
||||||
|
|
||||||
You might need to `npm config set msvs_version 2019` for node-gyp to correctly detect
|
You might need to `npm config set msvs_version 2015` for node-gyp to correctly detect
|
||||||
the version of Visual Studio you're using (in this example VS2019).
|
the version of Visual Studio you're using (in this example VS2015).
|
||||||
|
|
||||||
The following MinGW packages are required:
|
The following MinGW packages are required:
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ as well.
|
|||||||
|
|
||||||
#### Linux
|
#### Linux
|
||||||
|
|
||||||
- `libudev-dev` for libusb (for example install with `sudo apt install libudev-dev`, or on fedora `systemd-devel` contains the required package)
|
- `libudev-dev` for libusb (install with `sudo apt install libudev-dev` for example)
|
||||||
|
|
||||||
### Cloning the project
|
### Cloning the project
|
||||||
|
|
||||||
@@ -70,13 +70,28 @@ git clone --recursive https://github.com/balena-io/etcher
|
|||||||
cd etcher
|
cd etcher
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Installing npm dependencies
|
||||||
|
|
||||||
|
**NOTE:** Please make use of the following command to install npm dependencies rather
|
||||||
|
than simply running `npm install` given that we need to do extra configuration
|
||||||
|
to make sure native dependencies are correctly compiled for Electron, otherwise
|
||||||
|
the application might not run successfully.
|
||||||
|
|
||||||
|
If you're on Windows, **run the command from the _Developer Command Prompt for
|
||||||
|
VS2015_**, to ensure all Visual Studio command utilities are available in the
|
||||||
|
`%PATH%`.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make electron-develop
|
||||||
|
```
|
||||||
|
|
||||||
### Running the application
|
### Running the application
|
||||||
|
|
||||||
#### GUI
|
#### GUI
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Build the GUI
|
# Build the GUI
|
||||||
npm run webpack #or npm run build
|
npm run webpack
|
||||||
# Start Electron
|
# Start Electron
|
||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
@@ -104,6 +119,10 @@ systems as they can before sending a pull request.
|
|||||||
*The test suite is run automatically by CI servers when you send a pull
|
*The test suite is run automatically by CI servers when you send a pull
|
||||||
request.*
|
request.*
|
||||||
|
|
||||||
|
We also rely on various `make` targets to perform some common tasks:
|
||||||
|
|
||||||
|
- `make lint`: Run the linter.
|
||||||
|
- `make sass`: Compile SCSS files.
|
||||||
|
|
||||||
We make use of [EditorConfig] to communicate indentation, line endings and
|
We make use of [EditorConfig] to communicate indentation, line endings and
|
||||||
other text editing default. We encourage you to install the relevant plugin in
|
other text editing default. We encourage you to install the relevant plugin in
|
||||||
@@ -113,7 +132,20 @@ process.
|
|||||||
Updating a dependency
|
Updating a dependency
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
- Commit *both* `package.json` and `package-lock.json`.
|
Given we use [npm shrinkwrap][shrinkwrap], we have to take extra steps to make
|
||||||
|
sure the `npm-shrinkwrap.json` file gets updated correctly when we update a
|
||||||
|
dependency.
|
||||||
|
|
||||||
|
Use the following steps to ensure everything goes flawlessly:
|
||||||
|
|
||||||
|
- Run `make electron-develop` to ensure you don't have extraneous dependencies
|
||||||
|
you might have brought during development, or you are running older
|
||||||
|
dependencies because you come from another branch or reference.
|
||||||
|
|
||||||
|
- Install the new version of the dependency. For example: `npm install --save
|
||||||
|
<package>@<version>`. This will update the `npm-shrinkwrap.json` file.
|
||||||
|
|
||||||
|
- Commit *both* `package.json` and `npm-shrinkwrap.json`.
|
||||||
|
|
||||||
Diffing Binaries
|
Diffing Binaries
|
||||||
----------------
|
----------------
|
||||||
|
|||||||
@@ -8,14 +8,10 @@ Releasing
|
|||||||
|
|
||||||
### Release Types
|
### Release Types
|
||||||
|
|
||||||
- **draft**: A continues snapshot of current master, made by the CI services
|
- **snapshot** (default): A continues snapshot of current master, made by the CI services
|
||||||
- **pre-release** (default): A continues snapshot of current master, made by the CI services
|
- **production**: Full releases
|
||||||
- **release**: Full releases
|
|
||||||
|
|
||||||
Draft release is created from each PR, tagged with the branch name.
|
|
||||||
All merged PR will generate a new tag/version as a *pre-release*.
|
|
||||||
Mark the pre-release as final when it is necessary, then distribute the packages in alternative channels as necessary.
|
|
||||||
|
|
||||||
|
### Flight Plan
|
||||||
|
|
||||||
#### Preparation
|
#### Preparation
|
||||||
|
|
||||||
@@ -35,10 +31,11 @@ Mark the pre-release as final when it is necessary, then distribute the packages
|
|||||||
- [Post release note to forums](https://forums.balena.io/c/etcher)
|
- [Post release note to forums](https://forums.balena.io/c/etcher)
|
||||||
- [Submit Windows binaries to Symantec for whitelisting](#submitting-binaries-to-symantec)
|
- [Submit Windows binaries to Symantec for whitelisting](#submitting-binaries-to-symantec)
|
||||||
- [Update the website](https://github.com/balena-io/etcher-homepage)
|
- [Update the website](https://github.com/balena-io/etcher-homepage)
|
||||||
- Wait 2-3 hours for analytics (Sentry, Amplitude) to trickle in and check for elevated error rates, or regressions
|
- Wait 2-3 hours for analytics (Sentry, Mixpanel) to trickle in and check for elevated error rates, or regressions
|
||||||
- If regressions arise; pull the release, and release a patched version, else:
|
- If regressions arise; pull the release, and release a patched version, else:
|
||||||
- [Upload deb & rpm packages to Cloudfront](#uploading-packages-to-cloudfront)
|
- [Upload deb & rpm packages to Bintray](#uploading-packages-to-bintray)
|
||||||
- Post changelog with `#release-notes` tag on internal chat
|
- [Upload build artifacts to Amazon S3](#uploading-binaries-to-amazon-s3)
|
||||||
|
- Post changelog with `#release-notes` tag on Flowdock
|
||||||
- If this release packs noteworthy major changes:
|
- If this release packs noteworthy major changes:
|
||||||
- Write a blog post about it, and / or
|
- Write a blog post about it, and / or
|
||||||
- Write about it to the Etcher mailing list
|
- Write about it to the Etcher mailing list
|
||||||
@@ -51,7 +48,7 @@ Make sure to set the analytics tokens when generating production release binarie
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
export ANALYTICS_SENTRY_TOKEN="xxxxxx"
|
export ANALYTICS_SENTRY_TOKEN="xxxxxx"
|
||||||
export ANALYTICS_AMPLITUDE_TOKEN="xxxxxx"
|
export ANALYTICS_MIXPANEL_TOKEN="xxxxxx"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Linux
|
#### Linux
|
||||||
@@ -60,16 +57,46 @@ export ANALYTICS_AMPLITUDE_TOKEN="xxxxxx"
|
|||||||
|
|
||||||
**NOTE:** Make sure to adjust the path as necessary (here the Etcher repository has been cloned to `/home/$USER/code/etcher`)
|
**NOTE:** Make sure to adjust the path as necessary (here the Etcher repository has been cloned to `/home/$USER/code/etcher`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/build/docker/run-command.sh -r x64 -s . -c "make distclean"
|
||||||
|
```
|
||||||
|
|
||||||
##### Generating artifacts
|
##### Generating artifacts
|
||||||
|
|
||||||
The artifacts are generated by the CI and published as draft-release or pre-release.
|
```bash
|
||||||
`electron-builder` is used to create the packaged application.
|
# x64
|
||||||
|
|
||||||
|
# Build Debian packages
|
||||||
|
./scripts/build/docker/run-command.sh -r x64 -s . -c "make electron-develop && make RELEASE_TYPE=production electron-installer-debian"
|
||||||
|
# Build RPM packages
|
||||||
|
./scripts/build/docker/run-command.sh -r x64 -s . -c "make electron-develop && make RELEASE_TYPE=production electron-installer-redhat"
|
||||||
|
# Build AppImages
|
||||||
|
./scripts/build/docker/run-command.sh -r x64 -s . -c "make electron-develop && make RELEASE_TYPE=production electron-installer-appimage"
|
||||||
|
|
||||||
|
# x86
|
||||||
|
|
||||||
|
# Build Debian packages
|
||||||
|
./scripts/build/docker/run-command.sh -r x86 -s . -c "make electron-develop && make RELEASE_TYPE=production electron-installer-debian"
|
||||||
|
# Build RPM packages
|
||||||
|
./scripts/build/docker/run-command.sh -r x86 -s . -c "make electron-develop && make RELEASE_TYPE=production electron-installer-redhat"
|
||||||
|
# Build AppImages
|
||||||
|
./scripts/build/docker/run-command.sh -r x86 -s . -c "make electron-develop && make RELEASE_TYPE=production electron-installer-appimage"
|
||||||
|
```
|
||||||
|
|
||||||
#### Mac OS
|
#### Mac OS
|
||||||
|
|
||||||
**ATTENTION:** For production releases you'll need the code-signing key,
|
**ATTENTION:** For production releases you'll need the code-signing key,
|
||||||
and set `CSC_NAME` to generate signed binaries on Mac OS.
|
and set `CSC_NAME` to generate signed binaries on Mac OS.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make electron-develop
|
||||||
|
|
||||||
|
# Build the zip
|
||||||
|
make RELEASE_TYPE=production electron-installer-app-zip
|
||||||
|
# Build the dmg
|
||||||
|
make RELEASE_TYPE=production electron-installer-dmg
|
||||||
|
```
|
||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
**ATTENTION:** For production releases you'll need the code-signing key,
|
**ATTENTION:** For production releases you'll need the code-signing key,
|
||||||
@@ -78,10 +105,38 @@ and set `CSC_LINK`, and `CSC_KEY_PASSWORD` to generate signed binaries on Window
|
|||||||
**NOTE:**
|
**NOTE:**
|
||||||
- Keep in mind to also generate artifacts for x86, with `TARGET_ARCH=x86`.
|
- Keep in mind to also generate artifacts for x86, with `TARGET_ARCH=x86`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make electron-develop
|
||||||
|
|
||||||
### Uploading packages to Cloudfront
|
# Build the Portable version
|
||||||
|
make RELEASE_TYPE=production electron-installer-portable
|
||||||
|
# Build the Installer
|
||||||
|
make RELEASE_TYPE=production electron-installer-nsis
|
||||||
|
```
|
||||||
|
|
||||||
Log in to cloudfront and upload the `rpm` and `deb` files.
|
### Uploading packages to Bintray
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export BINTRAY_USER="username@account"
|
||||||
|
export BINTRAY_API_KEY="youruserapikey"
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/publish/bintray.sh -c "etcher" -t "production" -v "1.2.1" -o "etcher" -p "debian" -y "debian" -r "x64" -f "dist/etcher-electron_1.2.1_amd64.deb"
|
||||||
|
./scripts/publish/bintray.sh -c "etcher" -t "production" -v "1.2.1" -o "etcher" -p "debian" -y "debian" -r "x86" -f "dist/etcher-electron_1.2.1_i386.deb"
|
||||||
|
./scripts/publish/bintray.sh -c "etcher" -t "production" -v "1.2.1" -o "etcher" -p "redhat" -y "redhat" -r "x64" -f "dist/etcher-electron-1.2.1.x86_64.rpm"
|
||||||
|
./scripts/publish/bintray.sh -c "etcher" -t "production" -v "1.2.1" -o "etcher" -p "redhat" -y "redhat" -r "x86" -f "dist/etcher-electron-1.2.1.i686.rpm"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Uploading binaries to Amazon S3
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export S3_KEY="..."
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/publish/aws-s3.sh -b "balena-production-downloads" -v "1.2.1" -p "etcher" -f "dist/<filename>"
|
||||||
|
```
|
||||||
|
|
||||||
### Dealing with a Problematic Release
|
### Dealing with a Problematic Release
|
||||||
|
|
||||||
|
|||||||
@@ -112,4 +112,4 @@ Analytics
|
|||||||
- [ ] Disable analytics, open DevTools Network pane or a packet sniffer, and
|
- [ ] Disable analytics, open DevTools Network pane or a packet sniffer, and
|
||||||
check that no request is sent
|
check that no request is sent
|
||||||
- [ ] **Disable analytics, refresh application from DevTools (using Cmd-R or
|
- [ ] **Disable analytics, refresh application from DevTools (using Cmd-R or
|
||||||
F5), and check that initial events are not sent to Amplitude**
|
F5), and check that initial events are not sent to Mixpanel**
|
||||||
|
|||||||
@@ -7,9 +7,44 @@ systems.
|
|||||||
Release Types
|
Release Types
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Etcher supports **pre-release** and **final** release types as does Github. Each is
|
Etcher supports **production** and **snapshot** release types. Each is
|
||||||
published to Github releases.
|
published to a different S3 bucket, and production release types are code
|
||||||
The release version is generated automatically from the commit messasges.
|
signed, while snapshot release types aren't and include a short git commit-hash
|
||||||
|
as a build number. For example, `1.0.0-beta.19` is a production release type,
|
||||||
|
while `1.0.0-beta.19+531ab82` is a snapshot release type.
|
||||||
|
|
||||||
|
In terms of comparison: `1.0.0-beta.19` (production) < `1.0.0-beta.19+531ab82`
|
||||||
|
(snapshot) < `1.0.0-rc.1` (production) < `1.0.0-rc.1+7fde24a` (snapshot) <
|
||||||
|
`1.0.0` (production) < `1.0.0+2201e5f` (snapshot). Keep in mind that if you're
|
||||||
|
running a production release type, you'll only be prompted to update to
|
||||||
|
production release types, and if you're running a snapshot release type, you'll
|
||||||
|
only be prompted to update to other snapshot release types.
|
||||||
|
|
||||||
|
The build system creates (and publishes) snapshot release types by default, but
|
||||||
|
you can build a specific release type by setting the `RELEASE_TYPE` make
|
||||||
|
variable. For example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make <target> RELEASE_TYPE=snapshot
|
||||||
|
make <target> RELEASE_TYPE=production
|
||||||
|
```
|
||||||
|
|
||||||
|
We can control the version range a specific Etcher version will consider when
|
||||||
|
showing the update notification dialog by tweaking the `updates.semverRange`
|
||||||
|
property of `package.json`.
|
||||||
|
|
||||||
|
Update Channels
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Etcher has a setting to include the unstable update channel. If this option is
|
||||||
|
set, Etcher will consider both stable and unstable versions when showing the
|
||||||
|
update notifier dialog. Unstable versions are the ones that contain a `beta`
|
||||||
|
pre-release tag. For example:
|
||||||
|
|
||||||
|
- Production unstable version: `1.4.0-beta.1`
|
||||||
|
- Snapshot unstable version: `1.4.0-beta.1+7fde24a`
|
||||||
|
- Production stable version: `1.4.0`
|
||||||
|
- Snapshot stable version: `1.4.0+7fde24a`
|
||||||
|
|
||||||
Signing
|
Signing
|
||||||
-------
|
-------
|
||||||
@@ -38,19 +73,63 @@ Packaging
|
|||||||
|
|
||||||
The resulting installers will be saved to `dist/out`.
|
The resulting installers will be saved to `dist/out`.
|
||||||
|
|
||||||
Run the following commands on all platforms with the right arguments:
|
Run the following commands:
|
||||||
|
|
||||||
|
### OS X
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./node_modules/electron-builder build <...>
|
make electron-installer-dmg
|
||||||
|
make electron-installer-app-zip
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### GNU/Linux
|
||||||
|
|
||||||
Publishing to Cloudfront
|
```sh
|
||||||
|
make electron-installer-appimage
|
||||||
|
make electron-installer-debian
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make electron-installer-zip
|
||||||
|
make electron-installer-nsis
|
||||||
|
```
|
||||||
|
|
||||||
|
Publishing to Bintray
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
We publish GNU/Linux Debian packages to [Cloudfront][cloudfront].
|
We publish GNU/Linux Debian packages to [Bintray][bintray].
|
||||||
|
|
||||||
Log in to cloudfront and upload the `rpm` and `deb` files.
|
Make sure you set the following environment variables:
|
||||||
|
|
||||||
|
- `BINTRAY_USER`
|
||||||
|
- `BINTRAY_API_KEY`
|
||||||
|
|
||||||
|
Run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make publish-bintray-debian
|
||||||
|
```
|
||||||
|
|
||||||
|
Publishing to S3
|
||||||
|
----------------
|
||||||
|
|
||||||
|
- [AWS CLI][aws-cli]
|
||||||
|
|
||||||
|
Make sure you have the [AWS CLI tool][aws-cli] installed and configured to
|
||||||
|
access balena.io's production or snapshot S3 bucket.
|
||||||
|
|
||||||
|
Run the following command to publish all files for the current combination of
|
||||||
|
_platform_ and _arch_ (building them if necessary):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make publish-aws-s3
|
||||||
|
```
|
||||||
|
|
||||||
|
Also add links to each AWS S3 file in [GitHub Releases][github-releases]. See
|
||||||
|
[`v1.0.0-beta.17`](https://github.com/balena-io/etcher/releases/tag/v1.0.0-beta.17)
|
||||||
|
as an example.
|
||||||
|
|
||||||
Publishing to Homebrew Cask
|
Publishing to Homebrew Cask
|
||||||
---------------------------
|
---------------------------
|
||||||
@@ -68,12 +147,8 @@ Post messages to the [Etcher forum][balena-forum-etcher] announcing the new vers
|
|||||||
of Etcher, and including the relevant section of the Changelog.
|
of Etcher, and including the relevant section of the Changelog.
|
||||||
|
|
||||||
[aws-cli]: https://aws.amazon.com/cli
|
[aws-cli]: https://aws.amazon.com/cli
|
||||||
[cloudfront]: https://cloudfront.com
|
[bintray]: https://bintray.com
|
||||||
[etcher-cask-file]: https://github.com/caskroom/homebrew-cask/blob/master/Casks/balenaetcher.rb
|
[etcher-cask-file]: https://github.com/caskroom/homebrew-cask/blob/master/Casks/balenaetcher.rb
|
||||||
[homebrew-cask]: https://github.com/caskroom/homebrew-cask
|
[homebrew-cask]: https://github.com/caskroom/homebrew-cask
|
||||||
[balena-forum-etcher]: https://forums.balena.io/c/etcher
|
[balena-forum-etcher]: https://forums.balena.io/c/etcher
|
||||||
[github-releases]: https://github.com/balena-io/etcher/releases
|
[github-releases]: https://github.com/balena-io/etcher/releases
|
||||||
|
|
||||||
Updating EFP / Success-Banner
|
|
||||||
-----------------------------
|
|
||||||
Etcher Featured Project is automatically run based on an algorithm which promoted projects from the balena marketplace which have been contributed by the community, the algorithm prioritises projects which give uses the best experience. Editing both EFP and the Etcher Success-Banner can only be done by someone from balena, instruction are on the [Etcher-EFP repo (private)](https://github.com/balena-io/etcher-efp)
|
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ Etcher User Documentation
|
|||||||
|
|
||||||
This document contains how-tos and FAQs oriented to Etcher users.
|
This document contains how-tos and FAQs oriented to Etcher users.
|
||||||
|
|
||||||
Config
|
|
||||||
------
|
|
||||||
Etcher's configuration is saved to the `config.json` file in the apps folder.
|
|
||||||
Not all the options are surfaced to the UI. You may edit this file to tweak settings even before launching the app.
|
|
||||||
|
|
||||||
Why is my drive not bootable?
|
Why is my drive not bootable?
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
@@ -223,5 +218,3 @@ macOS 10.10 (Yosemite) and newer versions][electron-supported-platforms].
|
|||||||
[unetbootin]: https://unetbootin.github.io
|
[unetbootin]: https://unetbootin.github.io
|
||||||
[windows-iot-dashboard]: https://developer.microsoft.com/en-us/windows/iot/downloads
|
[windows-iot-dashboard]: https://developer.microsoft.com/en-us/windows/iot/downloads
|
||||||
[woeusb]: https://github.com/slacka/WoeUSB
|
[woeusb]: https://github.com/slacka/WoeUSB
|
||||||
|
|
||||||
See [PUBLISHING](/docs/PUBLISHING.md) for more details about release types.
|
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as electron from 'electron';
|
import * as electron from 'electron';
|
||||||
import * as remote from '@electron/remote';
|
|
||||||
import * as sdk from 'etcher-sdk';
|
import * as sdk from 'etcher-sdk';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import outdent from 'outdent';
|
import outdent from 'outdent';
|
||||||
@@ -297,8 +296,6 @@ driveScanner.start();
|
|||||||
|
|
||||||
let popupExists = false;
|
let popupExists = false;
|
||||||
|
|
||||||
analytics.initAnalytics();
|
|
||||||
|
|
||||||
window.addEventListener('beforeunload', async (event) => {
|
window.addEventListener('beforeunload', async (event) => {
|
||||||
if (!flashState.isFlashing() || popupExists) {
|
if (!flashState.isFlashing() || popupExists) {
|
||||||
analytics.logEvent('Close application', {
|
analytics.logEvent('Close application', {
|
||||||
@@ -328,8 +325,8 @@ window.addEventListener('beforeunload', async (event) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// This circumvents the 'beforeunload' event unlike
|
// This circumvents the 'beforeunload' event unlike
|
||||||
// remote.app.quit() which does not.
|
// electron.remote.app.quit() which does not.
|
||||||
remote.process.exit(EXIT_CODES.SUCCESS);
|
electron.remote.process.exit(EXIT_CODES.SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
analytics.logEvent('Close rejected while flashing', {
|
analytics.logEvent('Close rejected while flashing', {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ function restart(goToMain: () => void) {
|
|||||||
async function getSuccessBannerURL() {
|
async function getSuccessBannerURL() {
|
||||||
return (
|
return (
|
||||||
(await settings.get('successBannerURL')) ??
|
(await settings.get('successBannerURL')) ??
|
||||||
'https://efp.balena.io/success-banner?borderTop=false&darkBackground=true'
|
'https://www.balena.io/etcher/success-banner?borderTop=false&darkBackground=true'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as electron from 'electron';
|
import * as electron from 'electron';
|
||||||
import * as remote from '@electron/remote';
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
@@ -98,7 +97,7 @@ export class SafeWebview extends React.PureComponent<
|
|||||||
this.didFailLoad = _.bind(this.didFailLoad, this);
|
this.didFailLoad = _.bind(this.didFailLoad, this);
|
||||||
this.didGetResponseDetails = _.bind(this.didGetResponseDetails, this);
|
this.didGetResponseDetails = _.bind(this.didGetResponseDetails, this);
|
||||||
// Make a persistent electron session for the webview
|
// Make a persistent electron session for the webview
|
||||||
this.session = remote.session.fromPartition(ELECTRON_SESSION, {
|
this.session = electron.remote.session.fromPartition(ELECTRON_SESSION, {
|
||||||
// Disable the cache for the session such that new content shows up when refreshing
|
// Disable the cache for the session such that new content shows up when refreshing
|
||||||
cache: false,
|
cache: false,
|
||||||
});
|
});
|
||||||
@@ -184,10 +183,7 @@ export class SafeWebview extends React.PureComponent<
|
|||||||
// only care about this event if it's a request for the main frame
|
// only care about this event if it's a request for the main frame
|
||||||
if (event.resourceType === 'mainFrame') {
|
if (event.resourceType === 'mainFrame') {
|
||||||
const HTTP_OK = 200;
|
const HTTP_OK = 200;
|
||||||
const { webContents, ...webviewEvent } = event;
|
analytics.logEvent('SafeWebview loaded', { event });
|
||||||
analytics.logEvent('SafeWebview loaded', {
|
|
||||||
...webviewEvent,
|
|
||||||
});
|
|
||||||
this.setState({
|
this.setState({
|
||||||
shouldShow: event.statusCode === HTTP_OK,
|
shouldShow: event.statusCode === HTTP_OK,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,6 +39,4 @@ i18next.use(initReactI18next).init({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const supportedLocales = ['en', 'zh'];
|
|
||||||
|
|
||||||
export default i18next;
|
export default i18next;
|
||||||
|
|||||||
@@ -138,8 +138,7 @@ const translation = {
|
|||||||
autoUpdate: 'Auto-updates enabled',
|
autoUpdate: 'Auto-updates enabled',
|
||||||
settings: 'Settings',
|
settings: 'Settings',
|
||||||
systemInformation: 'System Information',
|
systemInformation: 'System Information',
|
||||||
trimExtPartitions:
|
trimExtPartitions: 'Trim unallocated space on raw images (in ext-type partitions)',
|
||||||
'Trim unallocated space on raw images (in ext-type partitions)',
|
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
edit: 'Edit',
|
edit: 'Edit',
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
const translation = {
|
const translation = {
|
||||||
translation: {
|
translation: {
|
||||||
continue: '繼續',
|
|
||||||
ok: '好',
|
ok: '好',
|
||||||
cancel: '取消',
|
cancel: '取消',
|
||||||
|
continue: '繼續',
|
||||||
skip: '跳過',
|
skip: '跳過',
|
||||||
sure: '我確定',
|
sure: '我確定',
|
||||||
warning: '請注意!',
|
warning: '請注意!',
|
||||||
attention: '請注意',
|
attention: '請注意',
|
||||||
failed: '失敗',
|
failed: '失敗',
|
||||||
completed: '完成',
|
completed: '完畢',
|
||||||
|
yesExit: '是的,可以退出',
|
||||||
|
reallyExit: '真的要現在退出 Etcher 嗎?',
|
||||||
yesContinue: '是的,繼續',
|
yesContinue: '是的,繼續',
|
||||||
reallyExit: '真的要現在結束 Etcher 嗎?',
|
|
||||||
yesExit: '是的,可以結束',
|
|
||||||
progress: {
|
progress: {
|
||||||
starting: '正在啟動……',
|
starting: '正在啓動……',
|
||||||
decompressing: '正在解壓縮……',
|
decompressing: '正在解壓……',
|
||||||
flashing: '正在燒錄……',
|
flashing: '正在燒錄……',
|
||||||
finishing: '正在結束……',
|
finishing: '正在結束……',
|
||||||
verifying: '正在驗證……',
|
verifying: '正在驗證……',
|
||||||
failing: '失敗……',
|
failing: '失敗……',
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
sizeNotRecommended: '大小不建議',
|
sizeNotRecommended: '大小不推薦',
|
||||||
tooSmall: '空間太小',
|
tooSmall: '空間太小',
|
||||||
locked: '被鎖定',
|
locked: '被鎖定',
|
||||||
system: '系統',
|
system: '系統盤',
|
||||||
containsImage: '存放來源映像檔',
|
containsImage: '存放源鏡像',
|
||||||
largeDrive: '很大的磁碟',
|
largeDrive: '很大的磁盤',
|
||||||
sourceLarger: '所選的映像檔比目標磁碟大了 {{byte}} 位元組。',
|
sourceLarger: '所選的鏡像比目標盤大了 {{byte}} 比特。',
|
||||||
flashSucceed_one: '燒錄成功',
|
flashSucceed_one: '燒錄成功',
|
||||||
flashSucceed_other: '燒錄成功',
|
flashSucceed_other: '燒錄成功',
|
||||||
flashFail_one: '燒錄失敗',
|
flashFail_one: '燒錄失敗',
|
||||||
@@ -39,72 +39,87 @@ const translation = {
|
|||||||
andFailTarget_other: '並燒錄失敗了 {{num}} 個目標',
|
andFailTarget_other: '並燒錄失敗了 {{num}} 個目標',
|
||||||
succeedTo: '{{name}} 被成功燒錄 {{target}}',
|
succeedTo: '{{name}} 被成功燒錄 {{target}}',
|
||||||
exitWhileFlashing:
|
exitWhileFlashing:
|
||||||
'您目前正在刷寫。關閉 Etcher 可能會導致您的磁碟無法使用。',
|
'您當前正在刷機。 關閉 Etcher 可能會導致您的磁盤無法使用。',
|
||||||
looksLikeWindowsImage:
|
looksLikeWindowsImage:
|
||||||
'看起來您正在嘗試燒錄 Windows 映像檔。\n\n與其他映像檔不同,Windows 映像檔需要特殊處理才能使其可啟動。我們建議您使用專門為此目的設計的工具,例如 <a href="https://rufus.akeo.ie">Rufus</a> (Windows)、<a href="https://github. com/slacka/WoeUSB">WoeUSB</a> (Linux) 或 Boot Camp 助理 (macOS)。',
|
'看起來您正在嘗試刻錄 Windows 鏡像。\n\n與其他鏡像不同,Windows 鏡像需要特殊處理才能使其可啓動。 我們建議您使用專門爲此目的設計的工具,例如 <a href="https://rufus.akeo.ie">Rufus</a> (Windows)、<a href="https://github. com/slacka/WoeUSB">WoeUSB</a> (Linux) 或 Boot Camp 助理 (macOS)。',
|
||||||
image: '映像檔',
|
image: '鏡像',
|
||||||
drive: '磁碟',
|
drive: '磁盤',
|
||||||
missingPartitionTable:
|
missingPartitionTable:
|
||||||
'看起來這不是一個可啟動的{{type}}。\n\n這個{{type}}似乎不包含分割表,因此您的設備可能無法識別或無法正確啟動。',
|
'看起來這不是一個可啓動的{{type}}。\n\n這個{{type}}似乎不包含分區表,因此您的設備可能無法識別或無法正確啓動。',
|
||||||
largeDriveSize: '這是個很大容量的磁碟!請檢查並確認它不包含對您來說存放很重要的資料',
|
largeDriveSize: '這是個很大的磁盤!請檢查並確認它不包含對您很重要的信息',
|
||||||
systemDrive: '選擇系統分割區很危險,因為這將會刪除你的系統',
|
systemDrive: '選擇系統盤很危險,因爲這將會刪除你的系統',
|
||||||
sourceDrive: '來源映像檔位於這個分割區中',
|
sourceDrive: '源鏡像位於這個分區中',
|
||||||
noSpace: '磁碟空間不足。請插入另一個較大的磁碟並重試。',
|
noSpace: '磁盤空間不足。 請插入另一個較大的磁盤並重試。',
|
||||||
genericFlashError:
|
genericFlashError:
|
||||||
'出了點問題。如果來源映像檔曾被壓縮過,請檢查它是否已損壞。\n{{error}}',
|
'出了點問題。如果源鏡像曾被壓縮過,請檢查它是否已損壞。\n{{error}}',
|
||||||
validation:
|
validation:
|
||||||
'寫入已成功完成,但 Etcher 在從磁碟讀取映像檔時檢測到潛在的損壞問題。\n\n請考慮將映像檔寫入其他磁碟。',
|
'寫入已成功完成,但 Etcher 在從磁盤讀取鏡像時檢測到潛在的損壞問題。 \n\n請考慮將鏡像寫入其他磁盤。',
|
||||||
openError: '打開 {{source}} 時發生錯誤。\n\n錯誤訊息: {{error}}',
|
openError: '打開 {{source}} 時出錯。\n\n錯誤信息: {{error}}',
|
||||||
flashError: '燒錄 {{image}} {{targets}} 失敗。',
|
flashError: '燒錄 {{image}} {{targets}} 失敗。',
|
||||||
unplug:
|
unplug:
|
||||||
'看起來 Etcher 失去了對磁碟的連接。是不是被意外拔掉了?\n\n有時這個錯誤是因為讀卡器出了故障。',
|
'看起來 Etcher 失去了對磁盤的連接。 它是不是被意外拔掉了?\n\n有時這個錯誤是因爲讀卡器出了故障。',
|
||||||
cannotWrite:
|
cannotWrite:
|
||||||
'看起來 Etcher 無法寫入磁碟的這個位置。此錯誤通常是由故障的磁碟、讀取器或連接埠引起的。\n\n請使用其他磁碟、讀卡器或連接埠重試。',
|
'看起來 Etcher 無法寫入磁盤的這個位置。 此錯誤通常是由故障的磁盤、讀取器或端口引起的。 \n\n請使用其他磁盤、讀卡器或端口重試。',
|
||||||
childWriterDied:
|
childWriterDied:
|
||||||
'寫入處理程序意外崩潰。請再試一次,如果問題仍然存在,請聯絡 Etcher 團隊。',
|
'寫入進程意外崩潰。請再試一次,如果問題仍然存在,請聯繫 Etcher 團隊。',
|
||||||
badProtocol: '僅支援 http:// 和 https:// 開頭的網址。',
|
badProtocol: '僅支持 http:// 和 https:// 開頭的網址。',
|
||||||
},
|
},
|
||||||
target: {
|
target: {
|
||||||
selectTarget: '選擇目標磁碟',
|
selectTarget: '選擇目標磁盤',
|
||||||
plugTarget: '請插入目標磁碟',
|
plugTarget: '請插入目標磁盤',
|
||||||
targets: '個目標',
|
targets: '個目標',
|
||||||
change: '更改',
|
change: '更改',
|
||||||
},
|
},
|
||||||
|
menu: {
|
||||||
|
edit: '編輯',
|
||||||
|
view: '視圖',
|
||||||
|
devTool: '打開開發者工具',
|
||||||
|
window: '窗口',
|
||||||
|
help: '幫助',
|
||||||
|
pro: 'Etcher 專業版',
|
||||||
|
website: 'Etcher 的官網',
|
||||||
|
issue: '提交一個 issue',
|
||||||
|
about: '關於 Etcher',
|
||||||
|
hide: '隱藏 Etcher',
|
||||||
|
hideOthers: '隱藏其它窗口',
|
||||||
|
unhide: '取消隱藏',
|
||||||
|
quit: '退出 Etcher',
|
||||||
|
},
|
||||||
source: {
|
source: {
|
||||||
useSourceURL: '使用映像檔網址',
|
useSourceURL: '使用鏡像網絡地址',
|
||||||
auth: '驗證',
|
auth: '驗證',
|
||||||
username: '輸入使用者名稱',
|
username: '輸入用戶名',
|
||||||
password: '輸入密碼',
|
password: '輸入密碼',
|
||||||
unsupportedProtocol: '不支持的通訊協定',
|
unsupportedProtocol: '不支持的協議',
|
||||||
windowsImage: '這可能是 Windows 系統映像檔',
|
windowsImage: '這可能是 Windows 系統鏡像',
|
||||||
partitionTable: '找不到分割表',
|
partitionTable: '找不到分區表',
|
||||||
errorOpen: '打開來源映像檔時出錯',
|
errorOpen: '打開源鏡像時出錯',
|
||||||
fromFile: '從檔案燒錄',
|
fromFile: '從文件燒錄',
|
||||||
fromURL: '從網址燒錄',
|
fromURL: '從在線地址燒錄',
|
||||||
clone: '再製磁碟',
|
clone: '克隆磁盤',
|
||||||
image: '映像檔訊息',
|
image: '鏡像信息',
|
||||||
name: '名稱:',
|
name: '名稱:',
|
||||||
path: '路徑:',
|
path: '路徑:',
|
||||||
selectSource: '選擇來源',
|
selectSource: '選擇源',
|
||||||
plugSource: '請插入來源磁碟',
|
plugSource: '請插入源磁盤',
|
||||||
osImages: '系統映像檔格式',
|
osImages: '系統鏡像格式',
|
||||||
allFiles: '任何檔案格式',
|
allFiles: '任何文件格式',
|
||||||
enterValidURL: '請輸入正確的網址',
|
enterValidURL: '請輸入一個正確的地址',
|
||||||
},
|
},
|
||||||
drives: {
|
drives: {
|
||||||
name: '名稱',
|
name: '名稱',
|
||||||
size: '大小',
|
size: '大小',
|
||||||
location: '位置',
|
location: '位置',
|
||||||
find: '找到 {{length}} 個',
|
find: '找到 {{length}} 個',
|
||||||
select: '選取 {{select}}',
|
select: '選定 {{select}}',
|
||||||
showHidden: '顯示 {{num}} 個隱藏的磁碟',
|
showHidden: '顯示 {{num}} 個隱藏的磁盤',
|
||||||
systemDriveDanger: '選擇系統分割區很危險,因為這將會刪除你的系統!',
|
systemDriveDanger: '選擇系統盤很危險,因爲這將會刪除你的系統!',
|
||||||
openInBrowser: 'Etcher 會在瀏覽器中打開 {{link}}',
|
openInBrowser: 'Etcher 會在瀏覽器中打開 {{link}}',
|
||||||
changeTarget: '更改目標',
|
changeTarget: '改變目標',
|
||||||
largeDriveWarning: '您即將格式化一個非常大的磁碟',
|
largeDriveWarning: '您即將擦除一個非常大的磁盤',
|
||||||
largeDriveWarningMsg: '您確定所選磁碟不是儲存資料的磁碟嗎?',
|
largeDriveWarningMsg: '您確定所選磁盤不是存儲磁盤嗎?',
|
||||||
systemDriveWarning: '您將要格式化系統分割區',
|
systemDriveWarning: '您將要擦除系統盤',
|
||||||
systemDriveWarningMsg: '您確定要燒錄到系統分割區嗎?',
|
systemDriveWarningMsg: '您確定要燒錄到系統盤嗎?',
|
||||||
},
|
},
|
||||||
flash: {
|
flash: {
|
||||||
another: '燒錄另一目標',
|
another: '燒錄另一目標',
|
||||||
@@ -114,39 +129,22 @@ const translation = {
|
|||||||
flash: '燒錄',
|
flash: '燒錄',
|
||||||
flashNow: '現在燒錄!',
|
flashNow: '現在燒錄!',
|
||||||
skip: '跳過了驗證',
|
skip: '跳過了驗證',
|
||||||
moreInfo: '更多資訊',
|
moreInfo: '更多信息',
|
||||||
speedTip:
|
speedTip:
|
||||||
'透過將映像檔大小除以燒錄時間來計算速度。\n由於我們能夠跳過未使用的部分,因此具有 ext 分割區的磁碟映像檔燒錄速度更快。',
|
'通過將鏡像大小除以燒錄時間來計算速度。\n由於我們能夠跳過未使用的部分,因此具有EXT分區的磁盤鏡像燒錄速度更快。',
|
||||||
speed: '速度:{{speed}} MB/秒',
|
speed: '速度:{{speed}} MB/秒',
|
||||||
speedShort: '{{speed}} MB/秒',
|
speedShort: '{{speed}} MB/秒',
|
||||||
eta: '預計還需要:{{eta}}',
|
eta: '預計還需要:{{eta}}',
|
||||||
failedTarget: '目標燒錄失敗',
|
failedTarget: '失敗的燒錄目標',
|
||||||
failedRetry: '重試燒錄失敗的目標',
|
failedRetry: '重試燒錄失敗目標',
|
||||||
flashFailed: '燒錄失敗。',
|
flashFailed: '燒錄失敗。',
|
||||||
flashCompleted: '燒錄成功!',
|
flashCompleted: '燒錄成功!',
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
errorReporting: '匿名向 balena.io 回報程式錯誤和使用統計資料',
|
errorReporting: '匿名地向 balena.io 報告運行錯誤和使用統計',
|
||||||
autoUpdate: '自動更新',
|
autoUpdate: '自動更新',
|
||||||
settings: '軟體設定',
|
settings: '軟件設置',
|
||||||
systemInformation: '系統資訊',
|
systemInformation: '系統信息',
|
||||||
trimExtPartitions:
|
|
||||||
'修改原始映像檔上未分配的空間(在 ext 類型分割區中)',
|
|
||||||
},
|
|
||||||
menu: {
|
|
||||||
edit: '編輯',
|
|
||||||
view: '預覽',
|
|
||||||
devTool: '打開開發者工具',
|
|
||||||
window: '視窗',
|
|
||||||
help: '協助',
|
|
||||||
pro: 'Etcher 專業版',
|
|
||||||
website: 'Etcher 的官網',
|
|
||||||
issue: '提交 issue',
|
|
||||||
about: '關於 Etcher',
|
|
||||||
hide: '隱藏 Etcher',
|
|
||||||
hideOthers: '隱藏其它視窗',
|
|
||||||
unhide: '取消隱藏',
|
|
||||||
quit: '結束 Etcher',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,13 +47,7 @@ export function isFlashing(): boolean {
|
|||||||
*/
|
*/
|
||||||
export function setFlashingFlag() {
|
export function setFlashingFlag() {
|
||||||
// see https://github.com/balenablocks/balena-electron-env/blob/4fce9c461f294d4a768db8f247eea6f75d7b08b0/README.md#remote-methods
|
// see https://github.com/balenablocks/balena-electron-env/blob/4fce9c461f294d4a768db8f247eea6f75d7b08b0/README.md#remote-methods
|
||||||
try {
|
electron.ipcRenderer.invoke('disable-screensaver');
|
||||||
electron.ipcRenderer.invoke('disable-screensaver');
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
"Can't disable-screensaver, we're probably not running on a balena-electron env",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
type: Actions.SET_FLASHING_FLAG,
|
type: Actions.SET_FLASHING_FLAG,
|
||||||
data: {},
|
data: {},
|
||||||
|
|||||||
@@ -41,10 +41,11 @@ export const DEFAULT_HEIGHT = 480;
|
|||||||
* NOTE: We use the remote property when this module
|
* NOTE: We use the remote property when this module
|
||||||
* is loaded in the Electron's renderer process
|
* is loaded in the Electron's renderer process
|
||||||
*/
|
*/
|
||||||
function getConfigPath() {
|
const app = electron.app || electron.remote.app;
|
||||||
const app = electron.app || require('@electron/remote').app;
|
|
||||||
return join(app.getPath('userData'), 'config.json');
|
const USER_DATA_DIR = app.getPath('userData');
|
||||||
}
|
|
||||||
|
const CONFIG_PATH = join(USER_DATA_DIR, 'config.json');
|
||||||
|
|
||||||
async function readConfigFile(filename: string): Promise<_.Dictionary<any>> {
|
async function readConfigFile(filename: string): Promise<_.Dictionary<any>> {
|
||||||
let contents = '{}';
|
let contents = '{}';
|
||||||
@@ -63,7 +64,7 @@ async function readConfigFile(filename: string): Promise<_.Dictionary<any>> {
|
|||||||
|
|
||||||
// exported for tests
|
// exported for tests
|
||||||
export async function readAll() {
|
export async function readAll() {
|
||||||
return await readConfigFile(getConfigPath());
|
return await readConfigFile(CONFIG_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// exported for tests
|
// exported for tests
|
||||||
@@ -102,7 +103,7 @@ export async function set(
|
|||||||
const previousValue = settings[key];
|
const previousValue = settings[key];
|
||||||
settings[key] = value;
|
settings[key] = value;
|
||||||
try {
|
try {
|
||||||
await writeConfigFileFn(getConfigPath(), settings);
|
await writeConfigFileFn(CONFIG_PATH, settings);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
// Revert to previous value if persisting settings failed
|
// Revert to previous value if persisting settings failed
|
||||||
settings[key] = previousValue;
|
settings[key] = previousValue;
|
||||||
|
|||||||
@@ -15,188 +15,84 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { Client, createClient, createNoopClient } from 'analytics-client';
|
import * as resinCorvus from 'resin-corvus/browser';
|
||||||
import * as SentryRenderer from '@sentry/electron/renderer';
|
|
||||||
|
import * as packageJSON from '../../../../package.json';
|
||||||
|
import { getConfig } from '../../../shared/utils';
|
||||||
import * as settings from '../models/settings';
|
import * as settings from '../models/settings';
|
||||||
import { store } from '../models/store';
|
import { store } from '../models/store';
|
||||||
import * as packageJSON from '../../../../package.json';
|
|
||||||
|
|
||||||
type AnalyticsPayload = _.Dictionary<any>;
|
const DEFAULT_PROBABILITY = 0.1;
|
||||||
|
|
||||||
const clearUserPath = (filename: string): string => {
|
async function installCorvus(): Promise<void> {
|
||||||
const generatedFile = filename.split('generated').reverse()[0];
|
const sentryToken =
|
||||||
return generatedFile !== filename ? `generated${generatedFile}` : filename;
|
(await settings.get('analyticsSentryToken')) ||
|
||||||
};
|
_.get(packageJSON, ['analytics', 'sentry', 'token']);
|
||||||
|
const mixpanelToken =
|
||||||
export const anonymizeSentryData = (
|
(await settings.get('analyticsMixpanelToken')) ||
|
||||||
event: SentryRenderer.Event,
|
_.get(packageJSON, ['analytics', 'mixpanel', 'token']);
|
||||||
): SentryRenderer.Event => {
|
resinCorvus.install({
|
||||||
event.exception?.values?.forEach((exception) => {
|
services: {
|
||||||
exception.stacktrace?.frames?.forEach((frame) => {
|
sentry: sentryToken,
|
||||||
if (frame.filename) {
|
mixpanel: mixpanelToken,
|
||||||
frame.filename = clearUserPath(frame.filename);
|
},
|
||||||
}
|
options: {
|
||||||
});
|
release: packageJSON.version,
|
||||||
|
shouldReport: () => {
|
||||||
|
return settings.getSync('errorReporting');
|
||||||
|
},
|
||||||
|
mixpanelDeferred: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
event.breadcrumbs?.forEach((breadcrumb) => {
|
let mixpanelSample = DEFAULT_PROBABILITY;
|
||||||
if (breadcrumb.data?.url) {
|
|
||||||
breadcrumb.data.url = clearUserPath(breadcrumb.data.url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (event.request?.url) {
|
|
||||||
event.request.url = clearUserPath(event.request.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
return event;
|
|
||||||
};
|
|
||||||
|
|
||||||
const extractPathRegex = /(.*)(^|\s)(file\:\/\/)?(\w\:)?([\\\/].+)/;
|
|
||||||
const etcherSegmentMarkers = ['app.asar', 'Resources'];
|
|
||||||
|
|
||||||
export const anonymizePath = (input: string) => {
|
|
||||||
// First, extract a part of the value that matches a path pattern.
|
|
||||||
const match = extractPathRegex.exec(input);
|
|
||||||
if (match === null) {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
const mainPart = match[5];
|
|
||||||
const space = match[2];
|
|
||||||
const beginning = match[1];
|
|
||||||
const uriPrefix = match[3] || '';
|
|
||||||
|
|
||||||
// We have to deal with both Windows and POSIX here.
|
|
||||||
// The path starts with its separator (we work with absolute paths).
|
|
||||||
const sep = mainPart[0];
|
|
||||||
const segments = mainPart.split(sep);
|
|
||||||
|
|
||||||
// Moving from the end, find the first marker and cut the path from there.
|
|
||||||
const startCutIndex = _.findLastIndex(segments, (segment) =>
|
|
||||||
etcherSegmentMarkers.includes(segment),
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
beginning +
|
|
||||||
space +
|
|
||||||
uriPrefix +
|
|
||||||
'[PERSONAL PATH]' +
|
|
||||||
sep +
|
|
||||||
segments.splice(startCutIndex).join(sep)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const safeAnonymizePath = (input: string) => {
|
|
||||||
try {
|
|
||||||
return anonymizePath(input);
|
|
||||||
} catch (e) {
|
|
||||||
return '[ANONYMIZE PATH FAILED]';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const sensitiveEtcherProperties = [
|
|
||||||
'error.description',
|
|
||||||
'error.message',
|
|
||||||
'error.stack',
|
|
||||||
'image',
|
|
||||||
'image.path',
|
|
||||||
'path',
|
|
||||||
];
|
|
||||||
|
|
||||||
export const anonymizeAnalyticsPayload = (
|
|
||||||
data: AnalyticsPayload,
|
|
||||||
): AnalyticsPayload => {
|
|
||||||
for (const prop of sensitiveEtcherProperties) {
|
|
||||||
const value = data[prop];
|
|
||||||
if (value != null) {
|
|
||||||
data[prop] = safeAnonymizePath(value.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
let analyticsClient: Client;
|
|
||||||
/**
|
/**
|
||||||
* @summary Init analytics configurations
|
* @summary Init analytics configurations
|
||||||
*/
|
*/
|
||||||
export const initAnalytics = _.once(() => {
|
async function initConfig() {
|
||||||
const dsn =
|
await installCorvus();
|
||||||
settings.getSync('analyticsSentryToken') ||
|
let validatedConfig = null;
|
||||||
_.get(packageJSON, ['analytics', 'sentry', 'token']);
|
try {
|
||||||
SentryRenderer.init({ dsn, beforeSend: anonymizeSentryData });
|
const configUrl = await settings.get('configUrl');
|
||||||
|
const config = await getConfig(configUrl);
|
||||||
const projectName =
|
const mixpanel = _.get(config, ['analytics', 'mixpanel'], {});
|
||||||
settings.getSync('analyticsAmplitudeToken') ||
|
mixpanelSample = mixpanel.probability || DEFAULT_PROBABILITY;
|
||||||
_.get(packageJSON, ['analytics', 'amplitude', 'token']);
|
if (isClientEligible(mixpanelSample)) {
|
||||||
|
validatedConfig = validateMixpanelConfig(mixpanel);
|
||||||
const clientConfig = {
|
|
||||||
projectName,
|
|
||||||
endpoint: 'data.balena-cloud.com',
|
|
||||||
componentName: 'etcher',
|
|
||||||
componentVersion: packageJSON.version,
|
|
||||||
};
|
|
||||||
analyticsClient = projectName
|
|
||||||
? createClient(clientConfig)
|
|
||||||
: createNoopClient();
|
|
||||||
});
|
|
||||||
|
|
||||||
const getCircularReplacer = () => {
|
|
||||||
const seen = new WeakSet();
|
|
||||||
return (key: any, value: any) => {
|
|
||||||
if (typeof value === 'object' && value !== null) {
|
|
||||||
if (seen.has(value)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seen.add(value);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function flattenObject(obj: any) {
|
|
||||||
const toReturn: AnalyticsPayload = {};
|
|
||||||
|
|
||||||
for (const i in obj) {
|
|
||||||
if (!obj.hasOwnProperty(i)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(obj[i])) {
|
|
||||||
toReturn[i] = obj[i];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof obj[i] === 'object' && obj[i] !== null) {
|
|
||||||
const flatObject = flattenObject(obj[i]);
|
|
||||||
for (const x in flatObject) {
|
|
||||||
if (!flatObject.hasOwnProperty(x)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
toReturn[i.toLowerCase() + '.' + x.toLowerCase()] = flatObject[x];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
toReturn[i] = obj[i];
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
resinCorvus.logException(err);
|
||||||
}
|
}
|
||||||
return toReturn;
|
resinCorvus.setConfigs({
|
||||||
}
|
mixpanel: validatedConfig,
|
||||||
|
|
||||||
function formatEvent(data: any): AnalyticsPayload {
|
|
||||||
const event = JSON.parse(JSON.stringify(data, getCircularReplacer()));
|
|
||||||
return anonymizeAnalyticsPayload(flattenObject(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
function reportAnalytics(message: string, data: AnalyticsPayload = {}) {
|
|
||||||
const { applicationSessionUuid, flashingWorkflowUuid } = store
|
|
||||||
.getState()
|
|
||||||
.toJS();
|
|
||||||
|
|
||||||
const event = formatEvent({
|
|
||||||
...data,
|
|
||||||
applicationSessionUuid,
|
|
||||||
flashingWorkflowUuid,
|
|
||||||
});
|
});
|
||||||
analyticsClient.track(message, event);
|
}
|
||||||
|
|
||||||
|
initConfig();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Check that the client is eligible for analytics
|
||||||
|
*/
|
||||||
|
function isClientEligible(probability: number) {
|
||||||
|
return Math.random() < probability;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Check that config has at least HTTP_PROTOCOL and api_host
|
||||||
|
*/
|
||||||
|
function validateMixpanelConfig(config: {
|
||||||
|
api_host?: string;
|
||||||
|
HTTP_PROTOCOL?: string;
|
||||||
|
}) {
|
||||||
|
const mixpanelConfig = {
|
||||||
|
api_host: 'https://api.mixpanel.com',
|
||||||
|
};
|
||||||
|
if (config.HTTP_PROTOCOL !== undefined && config.api_host !== undefined) {
|
||||||
|
mixpanelConfig.api_host = `${config.HTTP_PROTOCOL}://${config.api_host}`;
|
||||||
|
}
|
||||||
|
return mixpanelConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,12 +101,16 @@ function reportAnalytics(message: string, data: AnalyticsPayload = {}) {
|
|||||||
* @description
|
* @description
|
||||||
* This function sends the debug message to product analytics services.
|
* This function sends the debug message to product analytics services.
|
||||||
*/
|
*/
|
||||||
export async function logEvent(message: string, data: AnalyticsPayload = {}) {
|
export function logEvent(message: string, data: _.Dictionary<any> = {}) {
|
||||||
const shouldReportAnalytics = await settings.get('errorReporting');
|
const { applicationSessionUuid, flashingWorkflowUuid } = store
|
||||||
if (shouldReportAnalytics) {
|
.getState()
|
||||||
initAnalytics();
|
.toJS();
|
||||||
reportAnalytics(message, data);
|
resinCorvus.logEvent(message, {
|
||||||
}
|
...data,
|
||||||
|
sample: mixpanelSample,
|
||||||
|
applicationSessionUuid,
|
||||||
|
flashingWorkflowUuid,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -219,11 +119,4 @@ export async function logEvent(message: string, data: AnalyticsPayload = {}) {
|
|||||||
* @description
|
* @description
|
||||||
* This function logs an exception to error reporting services.
|
* This function logs an exception to error reporting services.
|
||||||
*/
|
*/
|
||||||
export function logException(error: any) {
|
export const logException = resinCorvus.logException;
|
||||||
const shouldReportErrors = settings.getSync('errorReporting');
|
|
||||||
console.error(error);
|
|
||||||
if (shouldReportErrors) {
|
|
||||||
initAnalytics();
|
|
||||||
SentryRenderer.captureException(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as electron from 'electron';
|
import * as electron from 'electron';
|
||||||
import * as remote from '@electron/remote';
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import * as errors from '../../../shared/errors';
|
import * as errors from '../../../shared/errors';
|
||||||
@@ -64,9 +63,10 @@ export async function selectImage(): Promise<string | undefined> {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const currentWindow = remote.getCurrentWindow();
|
const currentWindow = electron.remote.getCurrentWindow();
|
||||||
const [file] = (await remote.dialog.showOpenDialog(currentWindow, options))
|
const [file] = (
|
||||||
.filePaths;
|
await electron.remote.dialog.showOpenDialog(currentWindow, options)
|
||||||
|
).filePaths;
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,8 +92,8 @@ export async function showWarning(options: {
|
|||||||
);
|
);
|
||||||
const BUTTON_REJECTION_INDEX = _.indexOf(BUTTONS, options.rejectionLabel);
|
const BUTTON_REJECTION_INDEX = _.indexOf(BUTTONS, options.rejectionLabel);
|
||||||
|
|
||||||
const { response } = await remote.dialog.showMessageBox(
|
const { response } = await electron.remote.dialog.showMessageBox(
|
||||||
remote.getCurrentWindow(),
|
electron.remote.getCurrentWindow(),
|
||||||
{
|
{
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
buttons: BUTTONS,
|
buttons: BUTTONS,
|
||||||
@@ -113,5 +113,5 @@ export async function showWarning(options: {
|
|||||||
export function showError(error: Error) {
|
export function showError(error: Error) {
|
||||||
const title = errors.getTitle(error);
|
const title = errors.getTitle(error);
|
||||||
const message = errors.getDescription(error);
|
const message = errors.getDescription(error);
|
||||||
remote.dialog.showErrorBox(title, message);
|
electron.remote.dialog.showErrorBox(title, message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as remote from '@electron/remote';
|
import * as electron from 'electron';
|
||||||
|
|
||||||
import * as settings from '../models/settings';
|
import * as settings from '../models/settings';
|
||||||
|
|
||||||
@@ -28,8 +28,8 @@ export async function send(title: string, body: string, icon: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// `app.dock` is only defined in OS X
|
// `app.dock` is only defined in OS X
|
||||||
if (remote.app.dock) {
|
if (electron.remote.app.dock) {
|
||||||
remote.app.dock.bounce();
|
electron.remote.app.dock.bounce();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new window.Notification(title, { body, icon });
|
return new window.Notification(title, { body, icon });
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as remote from '@electron/remote';
|
import * as electron from 'electron';
|
||||||
|
|
||||||
import { percentageToFloat } from '../../../shared/utils';
|
import { percentageToFloat } from '../../../shared/utils';
|
||||||
import { FlashState, titleFromFlashState } from '../modules/progress-status';
|
import { FlashState, titleFromFlashState } from '../modules/progress-status';
|
||||||
@@ -40,7 +40,7 @@ function getWindowTitle(state?: FlashState) {
|
|||||||
* @description
|
* @description
|
||||||
* We expose this property to `this` for testability purposes.
|
* We expose this property to `this` for testability purposes.
|
||||||
*/
|
*/
|
||||||
export const currentWindow = remote.getCurrentWindow();
|
export const currentWindow = electron.remote.getCurrentWindow();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Set operating system window progress
|
* @summary Set operating system window progress
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ export class MainPage extends React.Component<
|
|||||||
private async getFeaturedProjectURL() {
|
private async getFeaturedProjectURL() {
|
||||||
const url = new URL(
|
const url = new URL(
|
||||||
(await settings.get('featuredProjectEndpoint')) ||
|
(await settings.get('featuredProjectEndpoint')) ||
|
||||||
'https://efp.balena.io/index.html',
|
'https://assets.balena.io/etcher-featured/index.html',
|
||||||
);
|
);
|
||||||
url.searchParams.append('borderRight', 'false');
|
url.searchParams.append('borderRight', 'false');
|
||||||
url.searchParams.append('darkBackground', 'true');
|
url.searchParams.append('darkBackground', 'true');
|
||||||
|
|||||||
@@ -17,10 +17,10 @@
|
|||||||
import { Dictionary } from 'lodash';
|
import { Dictionary } from 'lodash';
|
||||||
|
|
||||||
type BalenaTag = {
|
type BalenaTag = {
|
||||||
id: number;
|
id: number,
|
||||||
name: string;
|
name: string,
|
||||||
value: string;
|
value: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export class EtcherPro {
|
export class EtcherPro {
|
||||||
private supervisorAddr: string;
|
private supervisorAddr: string;
|
||||||
|
|||||||
@@ -15,24 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as electron from 'electron';
|
import * as electron from 'electron';
|
||||||
import * as remoteMain from '@electron/remote/main';
|
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import { platform } from 'os';
|
import { platform } from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
import * as _ from 'lodash';
|
|
||||||
|
|
||||||
import './app/i18n';
|
import './app/i18n';
|
||||||
|
|
||||||
import { packageType, version } from '../../package.json';
|
import { packageType, version } from '../../package.json';
|
||||||
import * as EXIT_CODES from '../shared/exit-codes';
|
import * as EXIT_CODES from '../shared/exit-codes';
|
||||||
|
import { delay, getConfig } from '../shared/utils';
|
||||||
import * as settings from './app/models/settings';
|
import * as settings from './app/models/settings';
|
||||||
|
import { logException } from './app/modules/analytics';
|
||||||
import { buildWindowMenu } from './menu';
|
import { buildWindowMenu } from './menu';
|
||||||
import * as i18n from 'i18next';
|
import * as i18n from 'i18next';
|
||||||
import * as SentryMain from '@sentry/electron/main';
|
|
||||||
import * as packageJSON from '../../package.json';
|
|
||||||
import { anonymizeSentryData } from './app/modules/analytics';
|
|
||||||
|
|
||||||
const customProtocol = 'etcher';
|
const customProtocol = 'etcher';
|
||||||
const scheme = `${customProtocol}://`;
|
const scheme = `${customProtocol}://`;
|
||||||
@@ -41,8 +38,6 @@ const packageUpdatable = updatablePackageTypes.includes(packageType);
|
|||||||
let packageUpdated = false;
|
let packageUpdated = false;
|
||||||
let mainWindow: any = null;
|
let mainWindow: any = null;
|
||||||
|
|
||||||
remoteMain.initialize();
|
|
||||||
|
|
||||||
async function checkForUpdates(interval: number) {
|
async function checkForUpdates(interval: number) {
|
||||||
// We use a while loop instead of a setInterval to preserve
|
// We use a while loop instead of a setInterval to preserve
|
||||||
// async execution time between each function call
|
// async execution time between each function call
|
||||||
@@ -51,28 +46,20 @@ async function checkForUpdates(interval: number) {
|
|||||||
try {
|
try {
|
||||||
const release = await autoUpdater.checkForUpdates();
|
const release = await autoUpdater.checkForUpdates();
|
||||||
const isOutdated =
|
const isOutdated =
|
||||||
semver.compare(release!.updateInfo.version, version) > 0;
|
semver.compare(release.updateInfo.version, version) > 0;
|
||||||
const shouldUpdate = release!.updateInfo.stagingPercentage !== 0; // undefinded (default) means 100%
|
const shouldUpdate = release.updateInfo.stagingPercentage !== 0; // undefinded (default) means 100%
|
||||||
if (shouldUpdate && isOutdated) {
|
if (shouldUpdate && isOutdated) {
|
||||||
await autoUpdater.downloadUpdate();
|
await autoUpdater.downloadUpdate();
|
||||||
packageUpdated = true;
|
packageUpdated = true;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logMainProcessException(err);
|
logException(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await delay(interval);
|
await delay(interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function logMainProcessException(error: any) {
|
|
||||||
const shouldReportErrors = settings.getSync('errorReporting');
|
|
||||||
console.error(error);
|
|
||||||
if (shouldReportErrors) {
|
|
||||||
SentryMain.captureException(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function isFile(filePath: string): Promise<boolean> {
|
async function isFile(filePath: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const stat = await fs.stat(filePath);
|
const stat = await fs.stat(filePath);
|
||||||
@@ -107,14 +94,6 @@ async function getCommandLineURL(argv: string[]): Promise<string | undefined> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const initSentryMain = _.once(() => {
|
|
||||||
const dsn =
|
|
||||||
settings.getSync('analyticsSentryToken') ||
|
|
||||||
_.get(packageJSON, ['analytics', 'sentry', 'token']);
|
|
||||||
|
|
||||||
SentryMain.init({ dsn, beforeSend: anonymizeSentryData });
|
|
||||||
});
|
|
||||||
|
|
||||||
const sourceSelectorReady = new Promise((resolve) => {
|
const sourceSelectorReady = new Promise((resolve) => {
|
||||||
electron.ipcMain.on('source-selector-ready', resolve);
|
electron.ipcMain.on('source-selector-ready', resolve);
|
||||||
});
|
});
|
||||||
@@ -176,6 +155,7 @@ async function createMainWindow() {
|
|||||||
contextIsolation: false,
|
contextIsolation: false,
|
||||||
webviewTag: true,
|
webviewTag: true,
|
||||||
zoomFactor: width / defaultWidth,
|
zoomFactor: width / defaultWidth,
|
||||||
|
enableRemoteModule: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -208,26 +188,34 @@ async function createMainWindow() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const page = mainWindow.webContents;
|
const page = mainWindow.webContents;
|
||||||
remoteMain.enable(page);
|
|
||||||
|
|
||||||
page.once('did-frame-finish-load', async () => {
|
page.once('did-frame-finish-load', async () => {
|
||||||
console.log('packageUpdatable', packageUpdatable);
|
|
||||||
autoUpdater.on('error', (err) => {
|
autoUpdater.on('error', (err) => {
|
||||||
logMainProcessException(err);
|
logException(err);
|
||||||
});
|
});
|
||||||
if (packageUpdatable) {
|
if (packageUpdatable) {
|
||||||
try {
|
try {
|
||||||
const checkForUpdatesTimer = 300000;
|
const configUrl = await settings.get('configUrl');
|
||||||
|
const onlineConfig = await getConfig(configUrl);
|
||||||
|
const autoUpdaterConfig: AutoUpdaterConfig = onlineConfig?.autoUpdates
|
||||||
|
?.autoUpdaterConfig ?? {
|
||||||
|
autoDownload: false,
|
||||||
|
};
|
||||||
|
for (const [key, value] of Object.entries(autoUpdaterConfig)) {
|
||||||
|
autoUpdater[key as keyof AutoUpdaterConfig] = value;
|
||||||
|
}
|
||||||
|
const checkForUpdatesTimer =
|
||||||
|
onlineConfig?.autoUpdates?.checkForUpdatesTimer ?? 300000;
|
||||||
checkForUpdates(checkForUpdatesTimer);
|
checkForUpdates(checkForUpdatesTimer);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logMainProcessException(err);
|
logException(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return mainWindow;
|
return mainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
electron.app.allowRendererProcessReuse = false;
|
||||||
electron.app.on('window-all-closed', electron.app.quit);
|
electron.app.on('window-all-closed', electron.app.quit);
|
||||||
|
|
||||||
// Sending a `SIGINT` (e.g: Ctrl-C) to an Electron app that registers
|
// Sending a `SIGINT` (e.g: Ctrl-C) to an Electron app that registers
|
||||||
@@ -245,7 +233,6 @@ async function main(): Promise<void> {
|
|||||||
if (!electron.app.requestSingleInstanceLock()) {
|
if (!electron.app.requestSingleInstanceLock()) {
|
||||||
electron.app.quit();
|
electron.app.quit();
|
||||||
} else {
|
} else {
|
||||||
initSentryMain();
|
|
||||||
await electron.app.whenReady();
|
await electron.app.whenReady();
|
||||||
const window = await createMainWindow();
|
const window = await createMainWindow();
|
||||||
electron.app.on('second-instance', async (_event, argv) => {
|
electron.app.on('second-instance', async (_event, argv) => {
|
||||||
@@ -269,6 +256,7 @@ async function main(): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|
||||||
console.time('ready-to-show');
|
console.time('ready-to-show');
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import { env } from 'process';
|
|||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
|
|
||||||
import { getAppPath } from '../utils';
|
import { getAppPath } from '../utils';
|
||||||
import { supportedLocales } from '../../gui/app/i18n';
|
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
const execFileAsync = promisify(execFile);
|
||||||
|
|
||||||
@@ -33,12 +32,6 @@ export async function sudo(
|
|||||||
try {
|
try {
|
||||||
let lang = Intl.DateTimeFormat().resolvedOptions().locale;
|
let lang = Intl.DateTimeFormat().resolvedOptions().locale;
|
||||||
lang = lang.substr(0, 2);
|
lang = lang.substr(0, 2);
|
||||||
if (supportedLocales.indexOf(lang) > -1) {
|
|
||||||
// language should be present
|
|
||||||
} else {
|
|
||||||
// fallback to eng
|
|
||||||
lang = 'en';
|
|
||||||
}
|
|
||||||
|
|
||||||
const { stdout, stderr } = await execFileAsync(
|
const { stdout, stderr } = await execFileAsync(
|
||||||
'sudo',
|
'sudo',
|
||||||
@@ -50,7 +43,7 @@ export async function sudo(
|
|||||||
SUDO_ASKPASS: join(
|
SUDO_ASKPASS: join(
|
||||||
getAppPath(),
|
getAppPath(),
|
||||||
__dirname,
|
__dirname,
|
||||||
`sudo-askpass.osascript-${lang}.js`,
|
'sudo-askpass.osascript-' + lang + '.js',
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { app, remote } from 'electron';
|
||||||
import { Dictionary } from 'lodash';
|
import { Dictionary } from 'lodash';
|
||||||
|
|
||||||
import * as errors from './errors';
|
import * as errors from './errors';
|
||||||
@@ -32,6 +33,16 @@ export function percentageToFloat(percentage: any) {
|
|||||||
return percentage / 100;
|
return percentage / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get etcher configs stored online
|
||||||
|
* @param {String} - url where config.json is stored
|
||||||
|
*/
|
||||||
|
export async function getConfig(configUrl?: string): Promise<Dictionary<any>> {
|
||||||
|
configUrl = configUrl ?? 'https://balena.io/etcher/static/config.json';
|
||||||
|
const response = await axios.get(configUrl, { responseType: 'json' });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
export async function delay(duration: number): Promise<void> {
|
export async function delay(duration: number): Promise<void> {
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
setTimeout(resolve, duration);
|
setTimeout(resolve, duration);
|
||||||
@@ -40,7 +51,7 @@ export async function delay(duration: number): Promise<void> {
|
|||||||
|
|
||||||
export function getAppPath(): string {
|
export function getAppPath(): string {
|
||||||
return (
|
return (
|
||||||
(require('electron').app || require('@electron/remote').app)
|
(app || remote.app)
|
||||||
.getAppPath()
|
.getAppPath()
|
||||||
// With macOS universal builds, getAppPath() returns the path to an app.asar file containing an index.js file which will
|
// 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.
|
// include the app-x64 or app-arm64 folder depending on the arch.
|
||||||
|
|||||||
24743
package-lock.json
generated
24743
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
46
package.json
46
package.json
@@ -2,7 +2,7 @@
|
|||||||
"name": "balena-etcher",
|
"name": "balena-etcher",
|
||||||
"private": true,
|
"private": true,
|
||||||
"displayName": "balenaEtcher",
|
"displayName": "balenaEtcher",
|
||||||
"version": "1.18.6",
|
"version": "1.13.4",
|
||||||
"packageType": "local",
|
"packageType": "local",
|
||||||
"main": "generated/etcher.js",
|
"main": "generated/etcher.js",
|
||||||
"description": "Flash OS images to SD cards and USB drives, safely and easily.",
|
"description": "Flash OS images to SD cards and USB drives, safely and easily.",
|
||||||
@@ -14,9 +14,9 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run webpack",
|
"build": "npm run webpack",
|
||||||
"flowzone-preinstall-linux": "sudo apt-get update && sudo apt-get install -y xvfb libudev-dev && cat < electron-builder.yml | yq e .deb.depends[] - | xargs -L1 echo | sed 's/|//g' | xargs -L1 sudo apt-get --ignore-missing install || true",
|
"flowzone-preinstall-linux": "sudo apt-get install -y xvfb libudev-dev && cat < electron-builder.yml | yq e .deb.depends[] - | xargs -L1 echo | sed 's/|//g' | xargs -L1 sudo apt-get --ignore-missing install || true",
|
||||||
"flowzone-preinstall-macos": "true",
|
"flowzone-preinstall-macos": "true",
|
||||||
"flowzone-preinstall-windows": "npx node-gyp install",
|
"flowzone-preinstall-windows": "true",
|
||||||
"flowzone-preinstall": "npm run flowzone-preinstall-linux",
|
"flowzone-preinstall": "npm run flowzone-preinstall-linux",
|
||||||
"lint-css": "prettier --write lib/**/*.css",
|
"lint-css": "prettier --write lib/**/*.css",
|
||||||
"lint-ts": "balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts",
|
"lint-ts": "balena-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts",
|
||||||
@@ -24,12 +24,14 @@
|
|||||||
"postinstall": "electron-rebuild -t prod,dev,optional",
|
"postinstall": "electron-rebuild -t prod,dev,optional",
|
||||||
"sanity-checks": "bash scripts/ci/ensure-all-file-extensions-in-gitattributes.sh",
|
"sanity-checks": "bash scripts/ci/ensure-all-file-extensions-in-gitattributes.sh",
|
||||||
"start": "./node_modules/.bin/electron .",
|
"start": "./node_modules/.bin/electron .",
|
||||||
"test-gui": "electron-mocha --recursive --reporter spec --window-config tests/gui/window-config.json --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox --renderer tests/gui/**/*.ts",
|
"test-macos": "npm run lint && npm run test-gui && npm run test-shared && npm run test-spectron && npm run sanity-checks",
|
||||||
|
"test-gui": "electron-mocha --recursive --reporter spec --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox --renderer tests/gui/**/*.ts",
|
||||||
|
"test-linux": "npm run lint && xvfb-run --auto-servernum npm run test-gui && xvfb-run --auto-servernum npm run test-shared && xvfb-run --auto-servernum npm run test-spectron && npm run sanity-checks",
|
||||||
"test-shared": "electron-mocha --recursive --reporter spec --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox tests/shared/**/*.ts",
|
"test-shared": "electron-mocha --recursive --reporter spec --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox tests/shared/**/*.ts",
|
||||||
"test-macos": "npm run lint && npm run test-gui && npm run test-shared && npm run sanity-checks",
|
"test-spectron": "mocha --recursive --reporter spec --require ts-node/register/transpile-only --require-main tests/gui/allow-renderer-process-reuse.ts tests/spectron/runner.spec.ts",
|
||||||
"test-linux": "npm run lint && xvfb-run --auto-servernum npm run test-gui && xvfb-run --auto-servernum npm run test-shared && npm run sanity-checks",
|
"test-windows": "npm run lint && npm run test-gui && npm run test-shared && npm run test-spectron && npm run sanity-checks",
|
||||||
"test-windows": "npm run lint && npm run test-gui && npm run test-shared && npm run sanity-checks",
|
|
||||||
"test": "echo npm run test-{linux,windows,macos}",
|
"test": "echo npm run test-{linux,windows,macos}",
|
||||||
|
"uploadSourcemap": "sentry-cli releases files $npm_config_SENTRY_VERSION upload-sourcemaps ./generated/*.js.map --org $npm_config_SENTRY_ORG --project $npm_config_SENTRY_PROJECT",
|
||||||
"watch": "webpack serve --no-optimization-minimize --config ./webpack.dev.config.ts",
|
"watch": "webpack serve --no-optimization-minimize --config ./webpack.dev.config.ts",
|
||||||
"webpack": "webpack"
|
"webpack": "webpack"
|
||||||
},
|
},
|
||||||
@@ -46,21 +48,20 @@
|
|||||||
"npm run lint-css"
|
"npm run lint-css"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"author": "Balena Ltd. <hello@balena.io>",
|
"author": "Balena Inc. <hello@etcher.io>",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@balena/lint": "5.4.2",
|
"@balena/lint": "5.4.2",
|
||||||
"@balena/sudo-prompt": "9.2.1-workaround-windows-amperstand-in-username-0849e215b947987a643fe5763902aea201255534",
|
"@balena/sudo-prompt": "9.2.1-workaround-windows-amperstand-in-username-0849e215b947987a643fe5763902aea201255534",
|
||||||
"@electron/remote": "^2.0.9",
|
|
||||||
"@fortawesome/fontawesome-free": "5.15.4",
|
"@fortawesome/fontawesome-free": "5.15.4",
|
||||||
"@sentry/electron": "^4.1.2",
|
"@sentry/cli": "^2.11.0",
|
||||||
"@svgr/webpack": "5.5.0",
|
"@svgr/webpack": "5.5.0",
|
||||||
"@types/chai": "4.3.4",
|
"@types/chai": "4.3.4",
|
||||||
"@types/copy-webpack-plugin": "6.4.3",
|
"@types/copy-webpack-plugin": "6.4.3",
|
||||||
"@types/mime-types": "2.1.1",
|
"@types/mime-types": "2.1.1",
|
||||||
"@types/mini-css-extract-plugin": "1.4.3",
|
"@types/mini-css-extract-plugin": "1.4.3",
|
||||||
"@types/mocha": "^9.1.1",
|
"@types/mocha": "8.2.3",
|
||||||
"@types/node": "^16.18.12",
|
"@types/node": "14.18.34",
|
||||||
"@types/node-ipc": "9.2.0",
|
"@types/node-ipc": "9.2.0",
|
||||||
"@types/react": "16.14.34",
|
"@types/react": "16.14.34",
|
||||||
"@types/react-dom": "16.9.17",
|
"@types/react-dom": "16.9.17",
|
||||||
@@ -69,21 +70,20 @@
|
|||||||
"@types/terser-webpack-plugin": "5.0.4",
|
"@types/terser-webpack-plugin": "5.0.4",
|
||||||
"@types/tmp": "0.2.3",
|
"@types/tmp": "0.2.3",
|
||||||
"@types/webpack-node-externals": "2.5.3",
|
"@types/webpack-node-externals": "2.5.3",
|
||||||
"analytics-client": "^2.0.1",
|
"aws4-axios": "2.4.9",
|
||||||
"axios": "^0.27.2",
|
|
||||||
"chai": "4.3.7",
|
"chai": "4.3.7",
|
||||||
"copy-webpack-plugin": "7.0.0",
|
"copy-webpack-plugin": "7.0.0",
|
||||||
"css-loader": "5.2.7",
|
"css-loader": "5.2.7",
|
||||||
"d3": "4.13.0",
|
"d3": "4.13.0",
|
||||||
"debug": "4.3.4",
|
"debug": "4.3.4",
|
||||||
"electron": "^19.1.9",
|
"electron": "^13.5.0",
|
||||||
"electron-builder": "^23.6.0",
|
"electron-builder": "^23.0.9",
|
||||||
"electron-mocha": "^11.0.2",
|
"electron-mocha": "9.3.3",
|
||||||
"electron-notarize": "1.2.2",
|
"electron-notarize": "1.2.2",
|
||||||
"electron-rebuild": "^3.2.9",
|
"electron-rebuild": "3.2.9",
|
||||||
"electron-updater": "5.3.0",
|
"electron-updater": "5.3.0",
|
||||||
"esbuild-loader": "2.20.0",
|
"esbuild-loader": "2.20.0",
|
||||||
"etcher-sdk": "8.3.1",
|
"etcher-sdk": "^7.4.7",
|
||||||
"file-loader": "6.2.0",
|
"file-loader": "6.2.0",
|
||||||
"husky": "4.3.8",
|
"husky": "4.3.8",
|
||||||
"i18next": "21.10.0",
|
"i18next": "21.10.0",
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
"lint-staged": "10.5.4",
|
"lint-staged": "10.5.4",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"mini-css-extract-plugin": "1.6.2",
|
"mini-css-extract-plugin": "1.6.2",
|
||||||
"mocha": "^9.1.1",
|
"mocha": "8.4.0",
|
||||||
"native-addon-loader": "2.0.1",
|
"native-addon-loader": "2.0.1",
|
||||||
"node-ipc": "9.2.1",
|
"node-ipc": "9.2.1",
|
||||||
"omit-deep-lodash": "1.1.7",
|
"omit-deep-lodash": "1.1.7",
|
||||||
@@ -104,9 +104,11 @@
|
|||||||
"react-i18next": "11.18.6",
|
"react-i18next": "11.18.6",
|
||||||
"redux": "4.2.0",
|
"redux": "4.2.0",
|
||||||
"rendition": "19.3.2",
|
"rendition": "19.3.2",
|
||||||
|
"resin-corvus": "2.0.5",
|
||||||
"semver": "7.3.8",
|
"semver": "7.3.8",
|
||||||
"simple-progress-webpack-plugin": "1.1.2",
|
"simple-progress-webpack-plugin": "1.1.2",
|
||||||
"sinon": "9.2.4",
|
"sinon": "9.2.4",
|
||||||
|
"spectron": "15.0.0",
|
||||||
"string-replace-loader": "3.1.0",
|
"string-replace-loader": "3.1.0",
|
||||||
"style-loader": "2.0.0",
|
"style-loader": "2.0.0",
|
||||||
"styled-components": "5.3.6",
|
"styled-components": "5.3.6",
|
||||||
@@ -123,9 +125,9 @@
|
|||||||
"webpack-dev-server": "4.11.1"
|
"webpack-dev-server": "4.11.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=14 < 16"
|
||||||
},
|
},
|
||||||
"versionist": {
|
"versionist": {
|
||||||
"publishedAt": "2023-03-21T13:24:18.905Z"
|
"publishedAt": "2023-01-12T15:10:50.986Z"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
// tslint:disable-next-line:no-var-requires
|
// tslint:disable-next-line:no-var-requires
|
||||||
const { app } = require('electron');
|
const { app } = require('electron');
|
||||||
|
|
||||||
if (app !== undefined) {
|
if (app !== undefined) {
|
||||||
// tslint:disable-next-line:no-var-requires
|
app.allowRendererProcessReuse = false;
|
||||||
const remoteMain = require('@electron/remote/main');
|
|
||||||
|
|
||||||
remoteMain.initialize();
|
|
||||||
|
|
||||||
app.on('browser-window-created', (_event, window) =>
|
|
||||||
remoteMain.enable(window.webContents),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"webPreferences": {
|
|
||||||
"enableRemoteModule": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
66
tests/spectron/runner.spec.ts
Normal file
66
tests/spectron/runner.spec.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 balena.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { platform } from 'os';
|
||||||
|
import { Application } from 'spectron';
|
||||||
|
import * as electronPath from 'electron';
|
||||||
|
|
||||||
|
// 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()) ||
|
||||||
|
(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('balenaEtcher');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as CopyPlugin from 'copy-webpack-plugin';
|
import * as CopyPlugin from 'copy-webpack-plugin';
|
||||||
import { readdirSync } from 'fs';
|
import { readdirSync, existsSync } from 'fs';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import outdent from 'outdent';
|
import outdent from 'outdent';
|
||||||
@@ -23,17 +23,13 @@ import * as path from 'path';
|
|||||||
import { env } from 'process';
|
import { env } from 'process';
|
||||||
import * as SimpleProgressWebpackPlugin from 'simple-progress-webpack-plugin';
|
import * as SimpleProgressWebpackPlugin from 'simple-progress-webpack-plugin';
|
||||||
import * as TerserPlugin from 'terser-webpack-plugin';
|
import * as TerserPlugin from 'terser-webpack-plugin';
|
||||||
import {
|
import { BannerPlugin, NormalModuleReplacementPlugin } from 'webpack';
|
||||||
BannerPlugin,
|
|
||||||
IgnorePlugin,
|
|
||||||
NormalModuleReplacementPlugin,
|
|
||||||
} from 'webpack';
|
|
||||||
import * as PnpWebpackPlugin from 'pnp-webpack-plugin';
|
import * as PnpWebpackPlugin from 'pnp-webpack-plugin';
|
||||||
|
|
||||||
import * as tsconfigRaw from './tsconfig.webpack.json';
|
import * as tsconfigRaw from './tsconfig.webpack.json';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Don't webpack package.json as sentry tokens
|
* Don't webpack package.json as mixpanel & sentry tokens
|
||||||
* will be inserted in it after webpacking
|
* will be inserted in it after webpacking
|
||||||
*/
|
*/
|
||||||
function externalPackageJson(packageJsonPath: string) {
|
function externalPackageJson(packageJsonPath: string) {
|
||||||
@@ -81,6 +77,26 @@ function renameNodeModules(resourcePath: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findExt2fsFolder(): string {
|
||||||
|
const ext2fs = 'node_modules/ext2fs';
|
||||||
|
const biFsExt2fs = 'node_modules/balena-image-fs/node_modules/ext2fs';
|
||||||
|
|
||||||
|
if (existsSync(ext2fs)) {
|
||||||
|
return ext2fs;
|
||||||
|
} else if (existsSync(biFsExt2fs)) {
|
||||||
|
return biFsExt2fs;
|
||||||
|
} else {
|
||||||
|
throw Error('ext2fs not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeExt2FsRegex(): RegExp {
|
||||||
|
const folder = findExt2fsFolder();
|
||||||
|
const libpath = '/lib/libext2fs\\.js$';
|
||||||
|
|
||||||
|
return new RegExp(folder.concat(libpath));
|
||||||
|
}
|
||||||
|
|
||||||
function findUsbPrebuild(): string[] {
|
function findUsbPrebuild(): string[] {
|
||||||
const usbPrebuildsFolder = path.join('node_modules', 'usb', 'prebuilds');
|
const usbPrebuildsFolder = path.join('node_modules', 'usb', 'prebuilds');
|
||||||
const prebuildFolders = readdirSync(usbPrebuildsFolder);
|
const prebuildFolders = readdirSync(usbPrebuildsFolder);
|
||||||
@@ -164,6 +180,31 @@ function replace(test: RegExp, ...replacements: ReplacementRule[]) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fetchWasm(...where: string[]) {
|
||||||
|
const whereStr = where.map((x) => `'${x}'`).join(', ');
|
||||||
|
return outdent`
|
||||||
|
const Path = require('path');
|
||||||
|
let electron;
|
||||||
|
try {
|
||||||
|
// This doesn't exist in the child-writer
|
||||||
|
electron = require('electron');
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
function appPath() {
|
||||||
|
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}, '/');
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
const commonConfig = {
|
const commonConfig = {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
optimization: {
|
optimization: {
|
||||||
@@ -276,17 +317,19 @@ const commonConfig = {
|
|||||||
`,
|
`,
|
||||||
replace: "require('./build/Release/Generator.node')",
|
replace: "require('./build/Release/Generator.node')",
|
||||||
}),
|
}),
|
||||||
|
// Use the copy of blobs in the generated folder and rename node_modules -> modules
|
||||||
|
// See the renameNodeModules function above
|
||||||
replace(/node_modules\/node-raspberrypi-usbboot\/build\/index\.js$/, {
|
replace(/node_modules\/node-raspberrypi-usbboot\/build\/index\.js$/, {
|
||||||
search:
|
search:
|
||||||
"return await readFile(Path.join(__dirname, '..', 'blobs', filename));",
|
"return await readFile(Path.join(__dirname, '..', 'blobs', filename));",
|
||||||
replace: outdent`
|
replace: outdent`
|
||||||
const remote = require('@electron/remote');
|
const { app, remote } = require('electron');
|
||||||
return await readFile(
|
return await readFile(
|
||||||
Path.join(
|
Path.join(
|
||||||
// With macOS universal builds, getAppPath() returns the path to an app.asar file containing an index.js file which will
|
// 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.
|
// 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.
|
// We don't care about the app.asar file, we want the actual folder.
|
||||||
remote.app.getAppPath().replace(/\\.asar$/, () => process.platform === 'darwin' ? '-' + process.arch : ''),
|
(app || remote.app).getAppPath().replace(/\\.asar$/, () => process.platform === 'darwin' ? '-' + process.arch : ''),
|
||||||
'generated',
|
'generated',
|
||||||
__dirname.replace('node_modules', 'modules'),
|
__dirname.replace('node_modules', 'modules'),
|
||||||
'..',
|
'..',
|
||||||
@@ -296,6 +339,18 @@ const commonConfig = {
|
|||||||
);
|
);
|
||||||
`,
|
`,
|
||||||
}),
|
}),
|
||||||
|
// Use the libext2fs.wasm file in the generated folder
|
||||||
|
// The way to find the app directory depends on whether we run in the renderer or in the child-writer
|
||||||
|
// We use __dirname in the child-writer and electron.remote.app.getAppPath() in the renderer
|
||||||
|
replace(makeExt2FsRegex(), {
|
||||||
|
search: 'scriptDirectory = __dirname + "/";',
|
||||||
|
replace: fetchWasm('ext2fs', 'lib'),
|
||||||
|
}),
|
||||||
|
// Same for node-crc-utils
|
||||||
|
replace(/node_modules\/@balena\/node-crc-utils\/crc32\.js$/, {
|
||||||
|
search: 'scriptDirectory=__dirname+"/"',
|
||||||
|
replace: fetchWasm('@balena', 'node-crc-utils'),
|
||||||
|
}),
|
||||||
// Copy native modules to generated folder
|
// Copy native modules to generated folder
|
||||||
{
|
{
|
||||||
test: /\.node$/,
|
test: /\.node$/,
|
||||||
@@ -322,14 +377,6 @@ const commonConfig = {
|
|||||||
slashOrAntislash(/node_modules\/axios\/lib\/adapters\/xhr\.js/),
|
slashOrAntislash(/node_modules\/axios\/lib\/adapters\/xhr\.js/),
|
||||||
'./http.js',
|
'./http.js',
|
||||||
),
|
),
|
||||||
// Ignore `aws-crt` which is a dependency of (ultimately) `aws4-axios` which is used
|
|
||||||
// by etcher-sdk and does a runtime check to its availability. We’re not currently
|
|
||||||
// using the “assume role” functionality (AFAIU) of aws4-axios and we don’t care that
|
|
||||||
// it’s not found, so force webpack to ignore the import.
|
|
||||||
// See https://github.com/aws/aws-sdk-js-v3/issues/3025
|
|
||||||
new IgnorePlugin({
|
|
||||||
resourceRegExp: /^aws-crt$/,
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
resolveLoader: {
|
resolveLoader: {
|
||||||
plugins: [PnpWebpackPlugin.moduleLoader(module)],
|
plugins: [PnpWebpackPlugin.moduleLoader(module)],
|
||||||
@@ -357,6 +404,14 @@ const guiConfigCopyPatterns = [
|
|||||||
from: 'node_modules/node-raspberrypi-usbboot/blobs',
|
from: 'node_modules/node-raspberrypi-usbboot/blobs',
|
||||||
to: 'modules/node-raspberrypi-usbboot/blobs',
|
to: 'modules/node-raspberrypi-usbboot/blobs',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
from: `${findExt2fsFolder()}/lib/libext2fs.wasm`,
|
||||||
|
to: 'modules/ext2fs/lib/libext2fs.wasm',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'node_modules/@balena/node-crc-utils/crc32.wasm',
|
||||||
|
to: 'modules/@balena/node-crc-utils/crc32.wasm',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (os.platform() === 'win32') {
|
if (os.platform() === 'win32') {
|
||||||
@@ -400,6 +455,7 @@ const guiConfig = {
|
|||||||
const mainConfig = {
|
const mainConfig = {
|
||||||
...commonConfig,
|
...commonConfig,
|
||||||
target: 'electron-main',
|
target: 'electron-main',
|
||||||
|
devtool: 'source-map',
|
||||||
node: {
|
node: {
|
||||||
__dirname: false,
|
__dirname: false,
|
||||||
__filename: true,
|
__filename: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user