mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-19 12:57:16 +00:00
Merge pull request #4132 from balena-io/switch-to-electron-forge
Modernize build pipeline
This commit is contained in:
commit
6e4db830e9
186
.github/actions/publish/action.yml
vendored
186
.github/actions/publish/action.yml
vendored
@ -10,12 +10,12 @@ inputs:
|
||||
required: true
|
||||
|
||||
# --- custom environment
|
||||
XCODE_APP_LOADER_EMAIL:
|
||||
type: string
|
||||
default: "accounts+apple@balena.io"
|
||||
NODE_VERSION:
|
||||
type: string
|
||||
default: "18.x"
|
||||
# Beware that native modules will be built for this version,
|
||||
# which might not be compatible with the one used by pkg (see forge.sidecar.ts)
|
||||
# https://github.com/vercel/pkg-fetch/releases
|
||||
default: "18.18"
|
||||
VERBOSE:
|
||||
type: string
|
||||
default: "true"
|
||||
@ -27,12 +27,12 @@ runs:
|
||||
- name: Download custom source artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}
|
||||
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}-${{ runner.arch }}
|
||||
path: ${{ runner.temp }}
|
||||
|
||||
- name: Extract custom source artifact
|
||||
if: runner.os != 'Windows'
|
||||
shell: pwsh
|
||||
shell: bash
|
||||
working-directory: .
|
||||
run: tar -xf ${{ runner.temp }}/custom.tgz
|
||||
|
||||
@ -48,22 +48,54 @@ runs:
|
||||
node-version: ${{ inputs.NODE_VERSION }}
|
||||
cache: npm
|
||||
|
||||
- name: Install yq
|
||||
shell: bash --noprofile --norc -eo pipefail -x {0}
|
||||
run: choco install yq
|
||||
if: runner.os == 'Windows'
|
||||
- name: Install host dependencies
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
run: sudo apt-get install -y --no-install-recommends fakeroot dpkg rpm
|
||||
|
||||
- name: Install host dependencies
|
||||
if: runner.os == 'macOS'
|
||||
# FIXME: Python 3.12 dropped distutils that node-gyp depends upon.
|
||||
# This is a temporary workaround to make the job use Python 3.11 until
|
||||
# we update to npm 10+.
|
||||
uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
# https://www.electron.build/code-signing.html
|
||||
# https://github.com/Apple-Actions/import-codesign-certs
|
||||
# https://dev.to/rwwagner90/signing-electron-apps-with-github-actions-4cof
|
||||
- name: Import Apple code signing certificate
|
||||
if: runner.os == 'macOS'
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
with:
|
||||
p12-file-base64: ${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
|
||||
p12-password: ${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}
|
||||
shell: bash
|
||||
run: |
|
||||
KEY_CHAIN=build.keychain
|
||||
CERTIFICATE_P12=certificate.p12
|
||||
|
||||
# Recreate the certificate from the secure environment variable
|
||||
echo $CERTIFICATE_P12_B64 | base64 --decode > $CERTIFICATE_P12
|
||||
|
||||
# Create a keychain
|
||||
security create-keychain -p actions $KEY_CHAIN
|
||||
|
||||
# Make the keychain the default so identities are found
|
||||
security default-keychain -s $KEY_CHAIN
|
||||
|
||||
# Unlock the keychain
|
||||
security unlock-keychain -p actions $KEY_CHAIN
|
||||
|
||||
security import $CERTIFICATE_P12 -k $KEY_CHAIN -P $CERTIFICATE_PASSWORD -T /usr/bin/codesign
|
||||
|
||||
security set-key-partition-list -S apple-tool:,apple: -s -k actions $KEY_CHAIN
|
||||
|
||||
# remove certs
|
||||
rm -fr *.p12
|
||||
env:
|
||||
CERTIFICATE_P12_B64: ${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
|
||||
CERTIFICATE_PASSWORD: ${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}
|
||||
|
||||
- name: Import Windows code signing certificate
|
||||
if: runner.os == 'Windows'
|
||||
id: import_win_signing_cert
|
||||
shell: powershell
|
||||
run: |
|
||||
Set-Content -Path ${{ runner.temp }}/certificate.base64 -Value $env:WINDOWS_CERTIFICATE
|
||||
@ -75,95 +107,79 @@ runs:
|
||||
-CertStoreLocation Cert:\CurrentUser\My `
|
||||
-Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||
|
||||
Remove-Item -path ${{ runner.temp }} -include certificate.pfx
|
||||
echo "certFilePath=${{ runner.temp }}/certificate.pfx" >> $GITHUB_OUTPUT
|
||||
|
||||
env:
|
||||
WINDOWS_CERTIFICATE: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }}
|
||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
|
||||
|
||||
# ... or refactor (e.g.) https://github.com/samuelmeuli/action-electron-builder
|
||||
# https://github.com/product-os/scripts/tree/master/electron
|
||||
# https://github.com/product-os/scripts/tree/master/shared
|
||||
# https://github.com/product-os/balena-concourse/blob/master/pipelines/github-events/template.yml
|
||||
- name: Package release
|
||||
id: package_release
|
||||
shell: bash --noprofile --norc -eo pipefail -x {0}
|
||||
shell: bash
|
||||
# IMPORTANT: before making changes to this step please consult @engineering in balena's chat.
|
||||
run: |
|
||||
set -ea
|
||||
|
||||
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
|
||||
|
||||
runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')"
|
||||
runner_arch="$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
ELECTRON_BUILDER_ARCHITECTURE="${runner_arch}"
|
||||
APPLICATION_VERSION="$(jq -r '.version' package.json)"
|
||||
ARCHITECTURE_FLAGS="--${ELECTRON_BUILDER_ARCHITECTURE}"
|
||||
|
||||
if [[ $runner_os =~ linux ]]; then
|
||||
ELECTRON_BUILDER_OS='--linux'
|
||||
TARGETS="$(yq e .linux.target[] electron-builder.yml)"
|
||||
|
||||
elif [[ $runner_os =~ darwin|macos|osx ]]; then
|
||||
CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}
|
||||
CSC_KEYCHAIN=signing_temp
|
||||
CSC_LINK=${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
|
||||
ELECTRON_BUILDER_OS='--mac'
|
||||
TARGETS="$(yq e .mac.target[] electron-builder.yml)"
|
||||
|
||||
elif [[ $runner_os =~ windows|win ]]; then
|
||||
ARCHITECTURE_FLAGS="--ia32 ${ARCHITECTURE_FLAGS}"
|
||||
CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
|
||||
CSC_LINK=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }}
|
||||
ELECTRON_BUILDER_OS='--win'
|
||||
TARGETS="$(yq e .win.target[] electron-builder.yml)"
|
||||
|
||||
else
|
||||
exit 1
|
||||
if [[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]]; then
|
||||
export DEBUG='electron-forge:*,sidecar'
|
||||
fi
|
||||
|
||||
npm link electron-builder
|
||||
APPLICATION_VERSION="$(jq -r '.version' package.json)"
|
||||
HOST_ARCH="$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
for target in ${TARGETS}; do
|
||||
electron-builder ${ELECTRON_BUILDER_OS} ${target} ${ARCHITECTURE_FLAGS} \
|
||||
--c.extraMetadata.analytics.sentry.token='https://739bbcfc0ba4481481138d3fc831136d@o95242.ingest.sentry.io/4504451487301632' \
|
||||
--c.extraMetadata.analytics.amplitude.token='balena-etcher' \
|
||||
--c.extraMetadata.packageType="${target}"
|
||||
if [[ "${RUNNER_OS}" == Linux ]]; then
|
||||
PLATFORM=Linux
|
||||
SHA256SUM_BIN=sha256sum
|
||||
|
||||
find dist -type f -maxdepth 1
|
||||
done
|
||||
elif [[ "${RUNNER_OS}" == macOS ]]; then
|
||||
PLATFORM=Darwin
|
||||
SHA256SUM_BIN='shasum -a 256'
|
||||
|
||||
elif [[ "${RUNNER_OS}" == Windows ]]; then
|
||||
PLATFORM=Windows
|
||||
SHA256SUM_BIN=sha256sum
|
||||
|
||||
else
|
||||
echo "ERROR: unexpected runner OS: ${RUNNER_OS}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Currently, we can only build for the host architecture.
|
||||
npx electron-forge make
|
||||
|
||||
echo "version=${APPLICATION_VERSION}" >> $GITHUB_OUTPUT
|
||||
|
||||
# collect all artifacts from subdirectories under a common top-level directory
|
||||
mkdir -p dist
|
||||
find ./out/make -type f \( \
|
||||
-iname "*.zip" -o \
|
||||
-iname "*.dmg" -o \
|
||||
-iname "*.rpm" -o \
|
||||
-iname "*.deb" -o \
|
||||
-iname "*.AppImage" -o \
|
||||
-iname "*Setup.exe" \
|
||||
\) -ls -exec cp '{}' dist/ \;
|
||||
|
||||
if [[ -n "${SHA256SUM_BIN}" ]]; then
|
||||
# Compute and save digests.
|
||||
cd dist/
|
||||
${SHA256SUM_BIN} *.* >"SHA256SUMS.${PLATFORM}.${HOST_ARCH}.txt"
|
||||
fi
|
||||
env:
|
||||
# Apple notarization (afterSignHook.js)
|
||||
XCODE_APP_LOADER_EMAIL: ${{ inputs.XCODE_APP_LOADER_EMAIL }}
|
||||
# ensure we sign the artifacts
|
||||
NODE_ENV: production
|
||||
# analytics tokens
|
||||
SENTRY_TOKEN: https://739bbcfc0ba4481481138d3fc831136d@o95242.ingest.sentry.io/4504451487301632
|
||||
AMPLITUDE_TOKEN: 'balena-etcher'
|
||||
# Apple notarization
|
||||
XCODE_APP_LOADER_EMAIL: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_EMAIL }}
|
||||
XCODE_APP_LOADER_PASSWORD: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_PASSWORD }}
|
||||
# https://github.blog/2020-08-03-github-actions-improvements-for-fork-and-pull-request-workflows/#improvements-for-public-repository-forks
|
||||
# https://docs.github.com/en/actions/managing-workflow-runs/approving-workflow-runs-from-public-forks#about-workflow-runs-from-public-forks
|
||||
CSC_FOR_PULL_REQUEST: true
|
||||
|
||||
# https://www.electron.build/auto-update.html#staged-rollouts
|
||||
- name: Configure staged rollout(s)
|
||||
shell: bash --noprofile --norc -eo pipefail -x {0}
|
||||
run: |
|
||||
set -ea
|
||||
|
||||
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
|
||||
|
||||
percentage="$(cat < repo.yml | yq e .triggerNotification.stagingPercentage)"
|
||||
|
||||
find dist -type f -maxdepth 1 \
|
||||
-name "latest*.yml" \
|
||||
-exec yq -i e .version=\"${{ steps.package_release.outputs.version }}\" {} \;
|
||||
|
||||
find dist -type f -maxdepth 1 \
|
||||
-name "latest*.yml" \
|
||||
-exec yq -i e .stagingPercentage=\"$percentage\" {} \;
|
||||
XCODE_APP_LOADER_TEAM_ID: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_TEAM_ID }}
|
||||
# Windows signing
|
||||
WINDOWS_SIGNING_CERT_PATH: ${{ steps.import_win_signing_cert.outputs.certFilePath }}
|
||||
WINDOWS_SIGNING_PASSWORD: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: gh-release-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}
|
||||
name: gh-release-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}-${{ runner.arch }}
|
||||
path: dist
|
||||
retention-days: 1
|
||||
if-no-files-found: error
|
||||
|
38
.github/actions/test/action.yml
vendored
38
.github/actions/test/action.yml
vendored
@ -12,7 +12,7 @@ inputs:
|
||||
# --- custom environment
|
||||
NODE_VERSION:
|
||||
type: string
|
||||
default: "16.x"
|
||||
default: "18.18"
|
||||
VERBOSE:
|
||||
type: string
|
||||
default: "true"
|
||||
@ -28,27 +28,45 @@ runs:
|
||||
node-version: ${{ inputs.NODE_VERSION }}
|
||||
cache: npm
|
||||
|
||||
- name: Test release
|
||||
shell: bash --noprofile --norc -eo pipefail -x {0}
|
||||
- name: Install host dependencies
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
run: |
|
||||
set -ea
|
||||
sudo apt-get install -y --no-install-recommends xvfb libudev-dev
|
||||
cat < package.json | jq -r '.hostDependencies[][]' - | \
|
||||
xargs -L1 echo | sed 's/|//g' | xargs -L1 \
|
||||
sudo apt-get --ignore-missing install || true
|
||||
|
||||
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
|
||||
- name: Install host dependencies
|
||||
if: runner.os == 'macOS'
|
||||
# FIXME: Python 3.12 dropped distutils that node-gyp depends upon.
|
||||
# This is a temporary workaround to make the job use Python 3.11 until
|
||||
# we update to npm 10+.
|
||||
uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Test release
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]]; then
|
||||
export DEBUG='electron-forge:*,sidecar'
|
||||
fi
|
||||
|
||||
runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
npm run flowzone-preinstall-${runner_os}
|
||||
npm ci
|
||||
npm run build
|
||||
npm run lint
|
||||
npm run package
|
||||
npm run test-${runner_os}
|
||||
|
||||
env:
|
||||
# https://www.electronjs.org/docs/latest/api/environment-variables
|
||||
ELECTRON_NO_ATTACH_CONSOLE: true
|
||||
ELECTRON_NO_ATTACH_CONSOLE: 'true'
|
||||
|
||||
- name: Compress custom source
|
||||
if: runner.os != 'Windows'
|
||||
shell: pwsh
|
||||
shell: bash
|
||||
run: tar -acf ${{ runner.temp }}/custom.tgz .
|
||||
|
||||
- name: Compress custom source
|
||||
@ -59,6 +77,6 @@ runs:
|
||||
- name: Upload custom artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}
|
||||
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}-${{ runner.arch }}
|
||||
path: ${{ runner.temp }}/custom.tgz
|
||||
retention-days: 1
|
||||
|
2
.github/workflows/flowzone.yml
vendored
2
.github/workflows/flowzone.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
(github.event.pull_request.head.repo.full_name != github.repository && github.event_name == 'pull_request_target')
|
||||
secrets: inherit
|
||||
with:
|
||||
tests_run_on: '["ubuntu-20.04","macos-latest","windows-2019"]'
|
||||
tests_run_on: '["ubuntu-20.04","windows-2019","macos-12","macos-latest-xlarge"]'
|
||||
restrict_custom_actions: false
|
||||
github_prerelease: true
|
||||
cloudflare_website: "etcher"
|
||||
|
3
.github/workflows/winget.yml
vendored
3
.github/workflows/winget.yml
vendored
@ -9,5 +9,6 @@ jobs:
|
||||
- uses: vedantmgoyal2009/winget-releaser@v1
|
||||
with:
|
||||
identifier: Balena.Etcher
|
||||
installers-regex: 'balenaEtcher-Setup.*.exe$'
|
||||
# matches something like "balenaEtcher-1.19.0.Setup.exe"
|
||||
installers-regex: 'balenaEtcher-[\d.-]+\.Setup.exe$'
|
||||
token: ${{ secrets.WINGET_PAT }}
|
||||
|
113
.gitignore
vendored
113
.gitignore
vendored
@ -1,41 +1,103 @@
|
||||
|
||||
# -- ADD NEW ENTRIES AT THE END OF THE FILE ---
|
||||
|
||||
# Logs
|
||||
/logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
.DS_Store
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
/lib-cov
|
||||
|
||||
# Image stream output directory
|
||||
/tests/image-stream/output
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
/coverage
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
/build
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Generated files
|
||||
/generated
|
||||
/binaries
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Dependency directory
|
||||
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
|
||||
node_modules
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Compiled Etcher releases
|
||||
/dist
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# Webpack
|
||||
.webpack/
|
||||
|
||||
# Vite
|
||||
.vite/
|
||||
|
||||
# Electron-Forge
|
||||
out/
|
||||
|
||||
# ---- Do not modify entries above this line ----
|
||||
|
||||
# Build artifacts
|
||||
dist/
|
||||
|
||||
# Certificates
|
||||
*.spc
|
||||
@ -45,16 +107,17 @@ node_modules
|
||||
*.crt
|
||||
*.pem
|
||||
|
||||
# OSX files
|
||||
|
||||
.DS_Store
|
||||
|
||||
# VSCode files
|
||||
|
||||
.vscode
|
||||
# Secrets
|
||||
.gitsecret/keys/random_seed
|
||||
!*.secret
|
||||
secrets/APPLE_SIGNING_PASSWORD.txt
|
||||
secrets/WINDOWS_SIGNING_PASSWORD.txt
|
||||
secrets/XCODE_APP_LOADER_PASSWORD.txt
|
||||
secrets/WINDOWS_SIGNING.pfx
|
||||
|
||||
# Image stream output directory
|
||||
/tests/image-stream/output
|
||||
|
||||
#local development
|
||||
.yalc
|
||||
yalc.lock
|
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -1,4 +0,0 @@
|
||||
[submodule "scripts/resin"]
|
||||
path = scripts/resin
|
||||
url = https://github.com/balena-io/scripts.git
|
||||
branch = master
|
152
Makefile
152
Makefile
@ -1,152 +0,0 @@
|
||||
# ---------------------------------------------------------------------
|
||||
# Build configuration
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
RESIN_SCRIPTS ?= ./scripts/resin
|
||||
export NPM_VERSION ?= 6.14.8
|
||||
S3_BUCKET = artifacts.ci.balena-cloud.com
|
||||
|
||||
# This directory will be completely deleted by the `clean` rule
|
||||
BUILD_DIRECTORY ?= dist
|
||||
|
||||
BUILD_TEMPORARY_DIRECTORY = $(BUILD_DIRECTORY)/.tmp
|
||||
|
||||
$(BUILD_DIRECTORY):
|
||||
mkdir $@
|
||||
|
||||
$(BUILD_TEMPORARY_DIRECTORY): | $(BUILD_DIRECTORY)
|
||||
mkdir $@
|
||||
|
||||
SHELL := /bin/bash
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Operating system and architecture detection
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
# http://stackoverflow.com/a/12099167
|
||||
ifeq ($(OS),Windows_NT)
|
||||
PLATFORM = win32
|
||||
|
||||
ifeq ($(PROCESSOR_ARCHITEW6432),AMD64)
|
||||
HOST_ARCH = x64
|
||||
else
|
||||
ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
|
||||
HOST_ARCH = x64
|
||||
endif
|
||||
ifeq ($(PROCESSOR_ARCHITECTURE),x86)
|
||||
HOST_ARCH = x86
|
||||
endif
|
||||
endif
|
||||
else
|
||||
ifeq ($(shell uname -s),Linux)
|
||||
PLATFORM = linux
|
||||
|
||||
ifeq ($(shell uname -m),x86_64)
|
||||
HOST_ARCH = x64
|
||||
endif
|
||||
ifneq ($(filter %86,$(shell uname -m)),)
|
||||
HOST_ARCH = x86
|
||||
endif
|
||||
ifeq ($(shell uname -m),armv7l)
|
||||
HOST_ARCH = armv7hf
|
||||
endif
|
||||
ifeq ($(shell uname -m),aarch64)
|
||||
HOST_ARCH = aarch64
|
||||
endif
|
||||
ifeq ($(shell uname -m),armv8)
|
||||
HOST_ARCH = aarch64
|
||||
endif
|
||||
ifeq ($(shell uname -m),arm64)
|
||||
HOST_ARCH = aarch64
|
||||
endif
|
||||
endif
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
PLATFORM = darwin
|
||||
|
||||
ifeq ($(shell uname -m),x86_64)
|
||||
HOST_ARCH = x64
|
||||
endif
|
||||
ifeq ($(shell uname -m),arm64)
|
||||
HOST_ARCH = aarch64
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef PLATFORM
|
||||
$(error We could not detect your host platform)
|
||||
endif
|
||||
ifndef HOST_ARCH
|
||||
$(error We could not detect your host architecture)
|
||||
endif
|
||||
|
||||
# Default to host architecture. You can override by doing:
|
||||
#
|
||||
# make <target> TARGET_ARCH=<arch>
|
||||
#
|
||||
TARGET_ARCH ?= $(HOST_ARCH)
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Electron
|
||||
# ---------------------------------------------------------------------
|
||||
electron-develop:
|
||||
git submodule update --init && \
|
||||
npm ci && \
|
||||
npm run webpack
|
||||
|
||||
electron-test:
|
||||
$(RESIN_SCRIPTS)/electron/test.sh \
|
||||
-b $(shell pwd) \
|
||||
-s $(PLATFORM)
|
||||
|
||||
assets/dmg/background.tiff: assets/dmg/background.png assets/dmg/background@2x.png
|
||||
tiffutil -cathidpicheck $^ -out $@
|
||||
|
||||
electron-build: assets/dmg/background.tiff | $(BUILD_TEMPORARY_DIRECTORY)
|
||||
$(RESIN_SCRIPTS)/electron/build.sh \
|
||||
-b $(shell pwd) \
|
||||
-r $(TARGET_ARCH) \
|
||||
-s $(PLATFORM) \
|
||||
-v production \
|
||||
-n $(BUILD_TEMPORARY_DIRECTORY)/npm
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Phony targets
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
TARGETS = \
|
||||
help \
|
||||
info \
|
||||
lint \
|
||||
test \
|
||||
clean \
|
||||
distclean \
|
||||
electron-develop \
|
||||
electron-test \
|
||||
electron-build
|
||||
|
||||
.PHONY: $(TARGETS)
|
||||
|
||||
lint:
|
||||
npm run lint
|
||||
|
||||
test:
|
||||
npm run test
|
||||
|
||||
help:
|
||||
@echo "Available targets: $(TARGETS)"
|
||||
|
||||
info:
|
||||
@echo "Platform : $(PLATFORM)"
|
||||
@echo "Host arch : $(HOST_ARCH)"
|
||||
@echo "Target arch : $(TARGET_ARCH)"
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIRECTORY)
|
||||
|
||||
distclean: clean
|
||||
rm -rf node_modules
|
||||
rm -rf dist
|
||||
rm -rf generated
|
||||
rm -rf $(BUILD_TEMPORARY_DIRECTORY)
|
||||
|
||||
.DEFAULT_GOAL = help
|
10
README.md
10
README.md
@ -17,13 +17,9 @@ was written correctly, and much more. It can also directly flash Raspberry Pi de
|
||||
|
||||
## Supported Operating Systems
|
||||
|
||||
- Linux (most distros)
|
||||
- macOS 10.10 (Yosemite) and later
|
||||
- Microsoft Windows 7 and later
|
||||
|
||||
**Note**: Etcher will run on any platform officially supported by
|
||||
[Electron][electron]. Read more in their
|
||||
[documentation][electron-supported-platforms].
|
||||
- Linux; most distros; Intel 64-bit.
|
||||
- Windows 10 and later; Intel 64-bit.
|
||||
- macOS 10.13 (High Sierra) and later; both Intel and Apple Silicon.
|
||||
|
||||
## Installers
|
||||
|
||||
|
31
afterPack.js
31
afterPack.js
@ -1,31 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const cp = require('child_process')
|
||||
const fs = require('fs')
|
||||
const outdent = require('outdent')
|
||||
const path = require('path')
|
||||
|
||||
exports.default = function(context) {
|
||||
if (context.packager.platform.name !== 'linux') {
|
||||
return
|
||||
}
|
||||
const scriptPath = path.join(context.appOutDir, context.packager.executableName)
|
||||
const binPath = scriptPath + '.bin'
|
||||
cp.execFileSync('mv', [scriptPath, binPath])
|
||||
fs.writeFileSync(
|
||||
scriptPath,
|
||||
outdent({trimTrailingNewline: false})`
|
||||
#!/bin/bash
|
||||
|
||||
# Resolve symlinks. Warning, readlink -f doesn't work on MacOS/BSD
|
||||
script_dir="$(dirname "$(readlink -f "\${BASH_SOURCE[0]}")")"
|
||||
|
||||
if [[ $EUID -ne 0 ]] || [[ $ELECTRON_RUN_AS_NODE ]]; then
|
||||
"\${script_dir}"/${context.packager.executableName}.bin "$@"
|
||||
else
|
||||
"\${script_dir}"/${context.packager.executableName}.bin "$@" --no-sandbox
|
||||
fi
|
||||
`
|
||||
)
|
||||
cp.execFileSync('chmod', ['+x', scriptPath])
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const { notarize } = require('electron-notarize')
|
||||
const { ELECTRON_SKIP_NOTARIZATION } = process.env
|
||||
|
||||
async function main(context) {
|
||||
const { electronPlatformName, appOutDir } = context
|
||||
if (electronPlatformName !== 'darwin' || ELECTRON_SKIP_NOTARIZATION === 'true') {
|
||||
return
|
||||
}
|
||||
|
||||
const appName = context.packager.appInfo.productFilename
|
||||
const appleId = process.env.XCODE_APP_LOADER_EMAIL || 'accounts+apple@balena.io'
|
||||
const appleIdPassword = process.env.XCODE_APP_LOADER_PASSWORD
|
||||
|
||||
// https://github.com/electron/notarize/blob/main/README.md
|
||||
await notarize({
|
||||
appBundleId: 'io.balena.etcher',
|
||||
appPath: `${appOutDir}/${appName}.app`,
|
||||
appleId,
|
||||
appleIdPassword
|
||||
})
|
||||
}
|
||||
|
||||
exports.default = main
|
@ -1,4 +0,0 @@
|
||||
owner: balena-io
|
||||
repo: etcher
|
||||
provider: github
|
||||
updaterCacheDirName: balena-etcher-updater
|
@ -1,9 +0,0 @@
|
||||
boolen->boolean
|
||||
aknowledge->acknowledge
|
||||
seleted->selected
|
||||
reming->remind
|
||||
locl->local
|
||||
subsribe->subscribe
|
||||
unsubsribe->unsubscribe
|
||||
calcluate->calculate
|
||||
dictionaty->dictionary
|
@ -75,9 +75,7 @@ cd etcher
|
||||
#### GUI
|
||||
|
||||
```sh
|
||||
# Build the GUI
|
||||
npm run webpack #or npm run build
|
||||
# Start Electron
|
||||
# Build and start application
|
||||
npm start
|
||||
```
|
||||
|
||||
@ -104,7 +102,6 @@ systems as they can before sending a pull request.
|
||||
*The test suite is run automatically by CI servers when you send a pull
|
||||
request.*
|
||||
|
||||
|
||||
We make use of [EditorConfig] to communicate indentation, line endings and
|
||||
other text editing default. We encourage you to install the relevant plugin in
|
||||
your text editor of choice to avoid having to fix any issues during the review
|
||||
@ -113,7 +110,8 @@ process.
|
||||
Updating a dependency
|
||||
---------------------
|
||||
|
||||
- Commit *both* `package.json` and `package-lock.json`.
|
||||
- Install new version of dependency using npm
|
||||
- Commit *both* `package.json` and `npm-shrinkwrap.json`.
|
||||
|
||||
Diffing Binaries
|
||||
----------------
|
||||
|
@ -58,30 +58,23 @@ export ANALYTICS_AMPLITUDE_TOKEN="xxxxxx"
|
||||
|
||||
##### Clean dist folder
|
||||
|
||||
**NOTE:** Make sure to adjust the path as necessary (here the Etcher repository has been cloned to `/home/$USER/code/etcher`)
|
||||
Delete `.webpack` and `out/`.
|
||||
|
||||
##### Generating artifacts
|
||||
|
||||
The artifacts are generated by the CI and published as draft-release or pre-release.
|
||||
`electron-builder` is used to create the packaged application.
|
||||
Etcher is built with electron-forge. Run:
|
||||
|
||||
#### Mac OS
|
||||
```
|
||||
npm run make
|
||||
```
|
||||
|
||||
**ATTENTION:** For production releases you'll need the code-signing key,
|
||||
and set `CSC_NAME` to generate signed binaries on Mac OS.
|
||||
|
||||
#### Windows
|
||||
|
||||
**ATTENTION:** For production releases you'll need the code-signing key,
|
||||
and set `CSC_LINK`, and `CSC_KEY_PASSWORD` to generate signed binaries on Windows.
|
||||
|
||||
**NOTE:**
|
||||
- Keep in mind to also generate artifacts for x86, with `TARGET_ARCH=x86`.
|
||||
Our CI will appropriately sign artifacts for macOS and some Windows targets.
|
||||
|
||||
|
||||
### Uploading packages to Cloudfront
|
||||
|
||||
Log in to cloudfront and upload the `rpm` and `deb` files.
|
||||
Log in to cloudfront and upload the `rpm` and `deb` files.
|
||||
|
||||
### Dealing with a Problematic Release
|
||||
|
||||
|
@ -36,14 +36,17 @@ employee by asking for it from the relevant people.
|
||||
Packaging
|
||||
---------
|
||||
|
||||
The resulting installers will be saved to `dist/out`.
|
||||
|
||||
Run the following commands on all platforms with the right arguments:
|
||||
Run the following command on each platform:
|
||||
|
||||
```sh
|
||||
./node_modules/electron-builder build <...>
|
||||
npm run make
|
||||
```
|
||||
|
||||
This will produce all targets (eg. zip, dmg) specified in forge.config.ts for the
|
||||
host platform and architecture.
|
||||
|
||||
The resulting artifacts can be found in `out/make`.
|
||||
|
||||
|
||||
Publishing to Cloudfront
|
||||
---------------------
|
||||
|
@ -1,110 +0,0 @@
|
||||
# https://www.electron.build/configuration/configuration
|
||||
appId: io.balena.etcher
|
||||
copyright: Copyright 2016-2023 Balena Ltd
|
||||
productName: balenaEtcher
|
||||
afterPack: ./afterPack.js
|
||||
afterSign: ./afterSignHook.js
|
||||
asar: false
|
||||
files:
|
||||
- generated
|
||||
- lib/shared/catalina-sudo/sudo-askpass.osascript-zh.js
|
||||
- lib/shared/catalina-sudo/sudo-askpass.osascript-en.js
|
||||
mac:
|
||||
icon: assets/icon.icns
|
||||
category: public.app-category.developer-tools
|
||||
hardenedRuntime: true
|
||||
entitlements: "entitlements.mac.plist"
|
||||
entitlementsInherit: "entitlements.mac.plist"
|
||||
artifactName: "${productName}-${version}.${ext}"
|
||||
target:
|
||||
- dmg
|
||||
dmg:
|
||||
background: assets/dmg/background.tiff
|
||||
icon: assets/icon.icns
|
||||
iconSize: 110
|
||||
contents:
|
||||
- x: 140
|
||||
y: 225
|
||||
- x: 415
|
||||
y: 225
|
||||
type: link
|
||||
path: /Applications
|
||||
window:
|
||||
width: 540
|
||||
height: 405
|
||||
win:
|
||||
icon: assets/icon.ico
|
||||
target:
|
||||
- zip
|
||||
- nsis
|
||||
- portable
|
||||
nsis:
|
||||
oneClick: true
|
||||
runAfterFinish: true
|
||||
installerIcon: assets/icon.ico
|
||||
uninstallerIcon: assets/icon.ico
|
||||
deleteAppDataOnUninstall: true
|
||||
license: LICENSE
|
||||
artifactName: "${productName}-Setup-${version}.${ext}"
|
||||
portable:
|
||||
artifactName: "${productName}-Portable-${version}.${ext}"
|
||||
requestExecutionLevel: user
|
||||
linux:
|
||||
icon: assets/iconset
|
||||
target:
|
||||
- AppImage
|
||||
- rpm
|
||||
- deb
|
||||
category: Utility
|
||||
packageCategory: utils
|
||||
executableName: balena-etcher
|
||||
synopsis: balenaEtcher is a powerful OS image flasher built with web technologies to ensure flashing an SDCard or USB drive is a pleasant and safe experience. It protects you from accidentally writing to your hard-drives, ensures every byte of data was written correctly and much more.
|
||||
appImage:
|
||||
artifactName: ${productName}-${version}-${env.ELECTRON_BUILDER_ARCHITECTURE}.${ext}
|
||||
deb:
|
||||
priority: optional
|
||||
compression: bzip2
|
||||
depends:
|
||||
- gconf-service
|
||||
- gconf2
|
||||
- libasound2
|
||||
- libatk1.0-0
|
||||
- libc6
|
||||
- libcairo2
|
||||
- libcups2
|
||||
- libdbus-1-3
|
||||
- libexpat1
|
||||
- libfontconfig1
|
||||
- libfreetype6
|
||||
- libgbm1
|
||||
- libgcc1
|
||||
- libgconf-2-4
|
||||
- libgdk-pixbuf2.0-0
|
||||
- libglib2.0-0
|
||||
- libgtk-3-0
|
||||
- liblzma5
|
||||
- libnotify4
|
||||
- libnspr4
|
||||
- libnss3
|
||||
- libpango1.0-0 | libpango-1.0-0
|
||||
- libstdc++6
|
||||
- libx11-6
|
||||
- libxcomposite1
|
||||
- libxcursor1
|
||||
- libxdamage1
|
||||
- libxext6
|
||||
- libxfixes3
|
||||
- libxi6
|
||||
- libxrandr2
|
||||
- libxrender1
|
||||
- libxss1
|
||||
- libxtst6
|
||||
- polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1
|
||||
afterInstall: "./after-install.tpl"
|
||||
rpm:
|
||||
depends:
|
||||
- util-linux
|
||||
protocols:
|
||||
name: etcher
|
||||
schemes:
|
||||
- etcher
|
158
forge.config.ts
Normal file
158
forge.config.ts
Normal file
@ -0,0 +1,158 @@
|
||||
import type { ForgeConfig } from '@electron-forge/shared-types';
|
||||
import { MakerSquirrel } from '@electron-forge/maker-squirrel';
|
||||
import { MakerZIP } from '@electron-forge/maker-zip';
|
||||
import { MakerDeb } from '@electron-forge/maker-deb';
|
||||
import { MakerRpm } from '@electron-forge/maker-rpm';
|
||||
import { MakerDMG } from '@electron-forge/maker-dmg';
|
||||
import { MakerAppImage } from '@reforged/maker-appimage';
|
||||
import { AutoUnpackNativesPlugin } from '@electron-forge/plugin-auto-unpack-natives';
|
||||
import { WebpackPlugin } from '@electron-forge/plugin-webpack';
|
||||
|
||||
import { mainConfig, rendererConfig } from './webpack.config';
|
||||
import * as sidecar from './forge.sidecar';
|
||||
|
||||
import { hostDependencies, productDescription } from './package.json';
|
||||
|
||||
const osxSigningConfig: any = {};
|
||||
let winSigningConfig: any = {};
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
osxSigningConfig.osxNotarize = {
|
||||
tool: 'notarytool',
|
||||
appleId: process.env.XCODE_APP_LOADER_EMAIL,
|
||||
appleIdPassword: process.env.XCODE_APP_LOADER_PASSWORD,
|
||||
teamId: process.env.XCODE_APP_LOADER_TEAM_ID,
|
||||
};
|
||||
|
||||
winSigningConfig = {
|
||||
certificateFile: process.env.WINDOWS_SIGNING_CERT_PATH,
|
||||
certificatePassword: process.env.WINDOWS_SIGNING_PASSWORD,
|
||||
};
|
||||
}
|
||||
|
||||
const config: ForgeConfig = {
|
||||
packagerConfig: {
|
||||
asar: true,
|
||||
icon: './assets/icon',
|
||||
executableName:
|
||||
process.platform === 'linux' ? 'balena-etcher' : 'balenaEtcher',
|
||||
appBundleId: 'io.balena.etcher',
|
||||
appCategoryType: 'public.app-category.developer-tools',
|
||||
appCopyright: 'Copyright 2016-2023 Balena Ltd',
|
||||
darwinDarkModeSupport: true,
|
||||
protocols: [{ name: 'etcher', schemes: ['etcher'] }],
|
||||
extraResource: [
|
||||
'lib/shared/catalina-sudo/sudo-askpass.osascript-zh.js',
|
||||
'lib/shared/catalina-sudo/sudo-askpass.osascript-en.js',
|
||||
],
|
||||
osxSign: {
|
||||
optionsForFile: () => ({
|
||||
entitlements: './entitlements.mac.plist',
|
||||
hardenedRuntime: true,
|
||||
}),
|
||||
},
|
||||
...osxSigningConfig,
|
||||
},
|
||||
rebuildConfig: {},
|
||||
makers: [
|
||||
new MakerZIP(),
|
||||
new MakerSquirrel({
|
||||
setupIcon: 'assets/icon.ico',
|
||||
...winSigningConfig,
|
||||
}),
|
||||
new MakerDMG({
|
||||
background: './assets/dmg/background.tiff',
|
||||
icon: './assets/icon.icns',
|
||||
iconSize: 110,
|
||||
contents: ((opts: { appPath: string }) => {
|
||||
return [
|
||||
{ x: 140, y: 250, type: 'file', path: opts.appPath },
|
||||
{ x: 415, y: 250, type: 'link', path: '/Applications' },
|
||||
];
|
||||
}) as any, // type of MakerDMGConfig omits `appPath`
|
||||
additionalDMGOptions: {
|
||||
window: {
|
||||
size: {
|
||||
width: 540,
|
||||
height: 425,
|
||||
},
|
||||
position: {
|
||||
x: 400,
|
||||
y: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
new MakerAppImage({
|
||||
options: {
|
||||
icon: './assets/icon.png',
|
||||
categories: ['Utility'],
|
||||
},
|
||||
}),
|
||||
new MakerRpm({
|
||||
options: {
|
||||
icon: './assets/icon.png',
|
||||
categories: ['Utility'],
|
||||
productDescription,
|
||||
requires: ['util-linux'],
|
||||
},
|
||||
}),
|
||||
new MakerDeb({
|
||||
options: {
|
||||
icon: './assets/icon.png',
|
||||
categories: ['Utility'],
|
||||
section: 'utils',
|
||||
priority: 'optional',
|
||||
productDescription,
|
||||
scripts: {
|
||||
postinst: './after-install.tpl',
|
||||
},
|
||||
depends: hostDependencies['debian'],
|
||||
},
|
||||
}),
|
||||
],
|
||||
plugins: [
|
||||
new AutoUnpackNativesPlugin({}),
|
||||
new WebpackPlugin({
|
||||
mainConfig,
|
||||
renderer: {
|
||||
config: rendererConfig,
|
||||
nodeIntegration: true,
|
||||
entryPoints: [
|
||||
{
|
||||
html: './lib/gui/app/index.html',
|
||||
js: './lib/gui/app/renderer.ts',
|
||||
name: 'main_window',
|
||||
preload: {
|
||||
js: './lib/gui/app/preload.ts',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
new sidecar.SidecarPlugin(),
|
||||
],
|
||||
hooks: {
|
||||
readPackageJson: async (_config, packageJson) => {
|
||||
packageJson.analytics = {};
|
||||
|
||||
if (process.env.SENTRY_TOKEN) {
|
||||
packageJson.analytics.sentry = {
|
||||
token: process.env.SENTRY_TOKEN,
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.AMPLITUDE_TOKEN) {
|
||||
packageJson.analytics.amplitude = {
|
||||
token: 'balena-etcher',
|
||||
};
|
||||
}
|
||||
|
||||
// packageJson.packageType = 'dmg' | 'AppImage' | 'rpm' | 'deb' | 'zip' | 'nsis' | 'portable'
|
||||
|
||||
return packageJson;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
168
forge.sidecar.ts
Normal file
168
forge.sidecar.ts
Normal file
@ -0,0 +1,168 @@
|
||||
import { PluginBase } from '@electron-forge/plugin-base';
|
||||
import {
|
||||
ForgeHookMap,
|
||||
ResolvedForgeConfig,
|
||||
} from '@electron-forge/shared-types';
|
||||
import { WebpackPlugin } from '@electron-forge/plugin-webpack';
|
||||
import { DefinePlugin } from 'webpack';
|
||||
|
||||
import { execFileSync } from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import * as d from 'debug';
|
||||
|
||||
const debug = d('sidecar');
|
||||
|
||||
function isStartScrpt(): boolean {
|
||||
return process.env.npm_lifecycle_event === 'start';
|
||||
}
|
||||
|
||||
function addWebpackDefine(
|
||||
config: ResolvedForgeConfig,
|
||||
defineName: string,
|
||||
binDir: string,
|
||||
binName: string,
|
||||
): ResolvedForgeConfig {
|
||||
config.plugins.forEach((plugin) => {
|
||||
if (plugin.name !== 'webpack' || !(plugin instanceof WebpackPlugin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { mainConfig } = plugin.config as any;
|
||||
if (mainConfig.plugins == null) {
|
||||
mainConfig.plugins = [];
|
||||
}
|
||||
|
||||
const value = isStartScrpt()
|
||||
? // on `npm start`, point directly to the binary
|
||||
path.resolve(binDir, binName)
|
||||
: // otherwise point relative to the resources folder of the bundled app
|
||||
binName;
|
||||
|
||||
debug(`define '${defineName}'='${value}'`);
|
||||
|
||||
mainConfig.plugins.push(
|
||||
new DefinePlugin({
|
||||
// expose path to helper via this webpack define
|
||||
[defineName]: JSON.stringify(value),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
function build(
|
||||
sourcesDir: string,
|
||||
buildForArchs: string,
|
||||
binDir: string,
|
||||
binName: string,
|
||||
) {
|
||||
const commands: Array<[string, string[], object?]> = [
|
||||
['tsc', ['--project', 'tsconfig.sidecar.json', '--outDir', sourcesDir]],
|
||||
];
|
||||
|
||||
buildForArchs.split(',').forEach((arch) => {
|
||||
const binPath = isStartScrpt()
|
||||
? // on `npm start`, we don't know the arch we're building for at the time we're
|
||||
// adding the webpack define, so we just build under binDir
|
||||
path.resolve(binDir, binName)
|
||||
: // otherwise build in arch-specific directory within binDir
|
||||
path.resolve(binDir, arch, binName);
|
||||
|
||||
// FIXME: rebuilding mountutils shouldn't be necessary, but it is.
|
||||
// It's coming from etcher-sdk, a fix has been upstreamed but to use
|
||||
// the latest etcher-sdk we need to upgrade axios at the same time.
|
||||
commands.push(['npm', ['rebuild', 'mountutils', `--arch=${arch}`]]);
|
||||
|
||||
commands.push([
|
||||
'pkg',
|
||||
[
|
||||
path.join(sourcesDir, 'util', 'api.js'),
|
||||
'-c',
|
||||
'pkg-sidecar.json',
|
||||
// `--no-bytecode` so that we can cross-compile for arm64 on x64
|
||||
'--no-bytecode',
|
||||
'--public',
|
||||
'--public-packages',
|
||||
'"*"',
|
||||
// always build for host platform and node version
|
||||
// https://github.com/vercel/pkg-fetch/releases
|
||||
'--target',
|
||||
`node18-${arch}`,
|
||||
'--output',
|
||||
binPath,
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
commands.forEach(([cmd, args, opt]) => {
|
||||
debug('running command:', cmd, args.join(' '));
|
||||
execFileSync(cmd, args, { shell: true, stdio: 'inherit', ...opt });
|
||||
});
|
||||
}
|
||||
|
||||
function copyArtifact(
|
||||
buildPath: string,
|
||||
arch: string,
|
||||
binDir: string,
|
||||
binName: string,
|
||||
) {
|
||||
const binPath = isStartScrpt()
|
||||
? // on `npm start`, we don't know the arch we're building for at the time we're
|
||||
// adding the webpack define, so look for the binary directly under binDir
|
||||
path.resolve(binDir, binName)
|
||||
: // otherwise look into arch-specific directory within binDir
|
||||
path.resolve(binDir, arch, binName);
|
||||
|
||||
// buildPath points to appPath, which is inside resources dir which is the one we actually want
|
||||
const resourcesPath = path.dirname(buildPath);
|
||||
const dest = path.resolve(resourcesPath, path.basename(binPath));
|
||||
debug(`copying '${binPath}' to '${dest}'`);
|
||||
fs.copyFileSync(binPath, dest);
|
||||
}
|
||||
|
||||
export class SidecarPlugin extends PluginBase<void> {
|
||||
name = 'sidecar';
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.getHooks = this.getHooks.bind(this);
|
||||
debug('isStartScript:', isStartScrpt());
|
||||
}
|
||||
|
||||
getHooks(): ForgeHookMap {
|
||||
const DEFINE_NAME = 'ETCHER_UTIL_BIN_PATH';
|
||||
const BASE_DIR = path.join('out', 'sidecar');
|
||||
const SRC_DIR = path.join(BASE_DIR, 'src');
|
||||
const BIN_DIR = path.join(BASE_DIR, 'bin');
|
||||
const BIN_NAME = `etcher-util${process.platform === 'win32' ? '.exe' : ''}`;
|
||||
|
||||
return {
|
||||
resolveForgeConfig: async (currentConfig) => {
|
||||
debug('resolveForgeConfig');
|
||||
return addWebpackDefine(currentConfig, DEFINE_NAME, BIN_DIR, BIN_NAME);
|
||||
},
|
||||
generateAssets: async (_config, platform, arch) => {
|
||||
debug('generateAssets', { platform, arch });
|
||||
build(SRC_DIR, arch, BIN_DIR, BIN_NAME);
|
||||
},
|
||||
packageAfterCopy: async (
|
||||
_config,
|
||||
buildPath,
|
||||
electronVersion,
|
||||
platform,
|
||||
arch,
|
||||
) => {
|
||||
debug('packageAfterCopy', {
|
||||
buildPath,
|
||||
electronVersion,
|
||||
platform,
|
||||
arch,
|
||||
});
|
||||
copyArtifact(buildPath, arch, BIN_DIR, BIN_NAME);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>balenaEtcher</title>
|
||||
<link rel="stylesheet" type="text/css" href="index.css">
|
||||
</head>
|
||||
<body>
|
||||
<main id="main"></main>
|
||||
<script src="http://localhost:3030/gui.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -3,10 +3,8 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>balenaEtcher</title>
|
||||
<link rel="stylesheet" type="text/css" href="index.css">
|
||||
</head>
|
||||
<body>
|
||||
<main id="main"></main>
|
||||
<script src="gui.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -18,7 +18,6 @@ import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as packageJSON from '../../../../package.json';
|
||||
import * as permissions from '../../../shared/permissions';
|
||||
import { getAppPath } from '../../../shared/get-app-path';
|
||||
import * as errors from '../../../shared/errors';
|
||||
|
||||
const THREADS_PER_CPU = 16;
|
||||
@ -27,8 +26,8 @@ const THREADS_PER_CPU = 16;
|
||||
// the stdout maxBuffer size to be exceeded when flashing
|
||||
ipc.config.silent = true;
|
||||
|
||||
function writerArgv(): string[] {
|
||||
let entryPoint = path.join(getAppPath(), 'generated', 'etcher-util');
|
||||
async function writerArgv(): Promise<string[]> {
|
||||
let entryPoint = await window.etcher.getEtcherUtilPath();
|
||||
// AppImages run over FUSE, so the files inside the mount point
|
||||
// can only be accessed by the user that mounted the AppImage.
|
||||
// This means we can't re-spawn Etcher as root from the same
|
||||
@ -75,7 +74,7 @@ async function spawnChild({
|
||||
IPC_SERVER_ID: string;
|
||||
IPC_SOCKET_ROOT: string;
|
||||
}) {
|
||||
const argv = writerArgv();
|
||||
const argv = await writerArgv();
|
||||
const env = writerEnv(IPC_CLIENT_ID, IPC_SERVER_ID, IPC_SOCKET_ROOT);
|
||||
if (withPrivileges) {
|
||||
return await permissions.elevateCommand(argv, {
|
||||
|
12
lib/gui/app/preload.ts
Normal file
12
lib/gui/app/preload.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// See the Electron documentation for details on how to use preload scripts:
|
||||
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
|
||||
|
||||
import * as webapi from '../webapi';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
etcher: typeof webapi;
|
||||
}
|
||||
}
|
||||
|
||||
window['etcher'] = webapi;
|
@ -6,10 +6,4 @@ import { ipcRenderer } from 'electron';
|
||||
|
||||
ipcRenderer.send('change-lng', langParser());
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.accept('./app', () => {
|
||||
main();
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
|
@ -14,6 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack
|
||||
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
|
||||
// whether you're running in development or production).
|
||||
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
|
||||
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
|
||||
|
||||
import * as electron from 'electron';
|
||||
import * as remoteMain from '@electron/remote/main';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
@ -176,6 +182,7 @@ async function createMainWindow() {
|
||||
contextIsolation: false,
|
||||
webviewTag: true,
|
||||
zoomFactor: width / defaultWidth,
|
||||
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
|
||||
},
|
||||
});
|
||||
|
||||
@ -199,13 +206,7 @@ async function createMainWindow() {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
mainWindow.loadURL(
|
||||
`file://${path.join(
|
||||
'/',
|
||||
...__dirname.split(path.sep).map(encodeURIComponent),
|
||||
'index.html',
|
||||
)}`,
|
||||
);
|
||||
mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
|
||||
|
||||
const page = mainWindow.webContents;
|
||||
remoteMain.enable(page);
|
||||
@ -241,6 +242,20 @@ electron.app.on('before-quit', () => {
|
||||
process.exit(EXIT_CODES.SUCCESS);
|
||||
});
|
||||
|
||||
// this is replaced at build-time with the path to helper binary,
|
||||
// relative to the app resources directory.
|
||||
declare const ETCHER_UTIL_BIN_PATH: string;
|
||||
|
||||
electron.ipcMain.handle('get-util-path', () => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// In development there is no "app bundle" and we're working directly with
|
||||
// artifacts from the "out" directory, where this value point to.
|
||||
return ETCHER_UTIL_BIN_PATH;
|
||||
}
|
||||
// In any other case, resolve the helper relative to resources path.
|
||||
return path.resolve(process.resourcesPath, ETCHER_UTIL_BIN_PATH);
|
||||
});
|
||||
|
||||
async function main(): Promise<void> {
|
||||
if (!electron.app.requestSingleInstanceLock()) {
|
||||
electron.app.quit();
|
||||
@ -287,6 +302,13 @@ async function main(): Promise<void> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||
// tslint:disable-next-line:no-var-requires
|
||||
if (require('electron-squirrel-startup')) {
|
||||
app.quit();
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
console.time('ready-to-show');
|
||||
|
15
lib/gui/webapi.ts
Normal file
15
lib/gui/webapi.ts
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// Anything exported from this module will become available to the
|
||||
// renderer process via preload. They're accessible as `window.etcher.foo()`.
|
||||
//
|
||||
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
// FIXME: this is a workaround for the renderer to be able to find the etcher-util
|
||||
// binary. We should instead export a function that asks the main process to launch
|
||||
// the binary itself.
|
||||
export async function getEtcherUtilPath(): Promise<string> {
|
||||
const utilPath = await ipcRenderer.invoke('get-util-path');
|
||||
console.log(utilPath);
|
||||
return utilPath;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"bin": "build/util/child-writer.js",
|
||||
"pkg": {
|
||||
"assets": [
|
||||
"node_modules/usb/prebuilds/darwin-x64+arm64/node.napi.node",
|
||||
"node_modules/lzma-native/prebuilds/darwin-arm64/node.napi.node",
|
||||
"node_modules/drivelist/build/Release/drivelist.node"
|
||||
]
|
||||
}
|
||||
}
|
@ -19,7 +19,6 @@ import { join } from 'path';
|
||||
import { env } from 'process';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import { getAppPath } from '../get-app-path';
|
||||
import { supportedLocales } from '../../gui/app/i18n';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
@ -27,6 +26,15 @@ const execFileAsync = promisify(execFile);
|
||||
const SUCCESSFUL_AUTH_MARKER = 'AUTHENTICATION SUCCEEDED';
|
||||
const EXPECTED_SUCCESSFUL_AUTH_MARKER = `${SUCCESSFUL_AUTH_MARKER}\n`;
|
||||
|
||||
function getAskPassScriptPath(lang: string): string {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// Force webpack's hand to bundle the script.
|
||||
return require.resolve(`./sudo-askpass.osascript-${lang}.js`);
|
||||
}
|
||||
// Otherwise resolve the script relative to resources path.
|
||||
return join(process.resourcesPath, `sudo-askpass.osascript-${lang}.js`);
|
||||
}
|
||||
|
||||
export async function sudo(
|
||||
command: string,
|
||||
): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> {
|
||||
@ -47,11 +55,7 @@ export async function sudo(
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
PATH: env.PATH,
|
||||
SUDO_ASKPASS: join(
|
||||
getAppPath(),
|
||||
__dirname,
|
||||
`sudo-askpass.osascript-${lang}.js`,
|
||||
),
|
||||
SUDO_ASKPASS: getAskPassScriptPath(lang),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
@ -1,12 +0,0 @@
|
||||
export function getAppPath(): string {
|
||||
return (
|
||||
(require('electron').app || require('@electron/remote').app)
|
||||
.getAppPath()
|
||||
// With macOS universal builds, getAppPath() returns the path to an app.asar file containing an index.js file which will
|
||||
// include the app-x64 or app-arm64 folder depending on the arch.
|
||||
// We don't care about the app.asar file, we want the actual folder.
|
||||
.replace(/\.asar$/, () =>
|
||||
process.platform === 'darwin' ? '-' + process.arch : '',
|
||||
)
|
||||
);
|
||||
}
|
12624
npm-shrinkwrap.json
generated
12624
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
150
package.json
150
package.json
@ -2,9 +2,10 @@
|
||||
"name": "balena-etcher",
|
||||
"private": true,
|
||||
"displayName": "balenaEtcher",
|
||||
"productName": "balenaEtcher",
|
||||
"version": "1.18.14",
|
||||
"packageType": "local",
|
||||
"main": "generated/etcher.js",
|
||||
"main": ".webpack/main",
|
||||
"description": "Flash OS images to SD cards and USB drives, safely and easily.",
|
||||
"productDescription": "Etcher is a powerful OS image flasher built with web technologies to ensure flashing an SDCard or USB drive is a pleasant and safe experience. It protects you from accidentally writing to your hard-drives, ensures every byte of data was written correctly and much more.",
|
||||
"homepage": "https://github.com/balena-io/etcher",
|
||||
@ -13,27 +14,18 @@
|
||||
"url": "git@github.com:balena-io/etcher.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run webpack && npm run build:sidecar",
|
||||
"build:rebuild-mountutils": "cd node_modules/mountutils && npm rebuild",
|
||||
"build:sidecar": "npm run build:rebuild-mountutils && tsc --project tsconfig.sidecar.json && pkg build/util/api.js -c pkg-sidecar.json --target node18 --output generated/etcher-util",
|
||||
"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-macos": "true",
|
||||
"flowzone-preinstall-windows": "npx node-gyp install",
|
||||
"flowzone-preinstall": "npm run flowzone-preinstall-linux",
|
||||
"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 forge.config.ts forge.sidecar.ts webpack.config.ts",
|
||||
"lint": "npm run lint-ts && npm run lint-css",
|
||||
"postinstall": "electron-rebuild -t prod,dev,optional",
|
||||
"sanity-checks": "bash scripts/ci/ensure-all-file-extensions-in-gitattributes.sh",
|
||||
"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-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-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 sanity-checks",
|
||||
"test-windows": "npm run lint && npm run test-gui && npm run test-shared",
|
||||
"test-macos": "npm run lint && npm run test-gui && npm run test-shared",
|
||||
"test-linux": "npm run lint && xvfb-run --auto-servernum npm run test-gui && xvfb-run --auto-servernum npm run test-shared",
|
||||
"test": "echo npm run test-{linux,windows,macos}",
|
||||
"watch": "webpack serve --no-optimization-minimize --config ./webpack.dev.config.ts",
|
||||
"webpack": "webpack"
|
||||
"package": "electron-forge package",
|
||||
"start": "electron-forge start",
|
||||
"make": "electron-forge make"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
@ -50,16 +42,50 @@
|
||||
},
|
||||
"author": "Balena Ltd. <hello@balena.io>",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@babel/register": "^7.22.15",
|
||||
"@balena/lint": "5.4.2",
|
||||
"dependencies": {
|
||||
"@balena/sudo-prompt": "9.2.1-workaround-windows-amperstand-in-username-0849e215b947987a643fe5763902aea201255534",
|
||||
"@electron/remote": "^2.0.9",
|
||||
"@fortawesome/fontawesome-free": "5.15.4",
|
||||
"@sentry/electron": "^4.1.2",
|
||||
"analytics-client": "^2.0.1",
|
||||
"axios": "^0.27.2",
|
||||
"d3": "4.13.0",
|
||||
"debug": "4.3.4",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"electron-updater": "5.3.0",
|
||||
"etcher-sdk": "8.3.1",
|
||||
"i18next": "21.10.0",
|
||||
"immutable": "3.8.2",
|
||||
"lodash": "4.17.21",
|
||||
"node-ipc": "9.2.1",
|
||||
"outdent": "0.8.0",
|
||||
"path-is-inside": "1.0.2",
|
||||
"pretty-bytes": "5.6.0",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5",
|
||||
"react-i18next": "11.18.6",
|
||||
"redux": "4.2.0",
|
||||
"rendition": "19.3.2",
|
||||
"semver": "7.3.8",
|
||||
"styled-components": "5.3.6",
|
||||
"sys-class-rgb-led": "3.0.1",
|
||||
"uuid": "8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@balena/lint": "5.4.2",
|
||||
"@electron-forge/cli": "6.4.2",
|
||||
"@electron-forge/maker-deb": "6.4.2",
|
||||
"@electron-forge/maker-dmg": "6.4.2",
|
||||
"@electron-forge/maker-rpm": "6.4.2",
|
||||
"@electron-forge/maker-squirrel": "6.4.2",
|
||||
"@electron-forge/maker-zip": "6.4.2",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "6.4.2",
|
||||
"@electron-forge/plugin-webpack": "6.4.2",
|
||||
"@reforged/maker-appimage": "3.3.1",
|
||||
"@svgr/webpack": "5.5.0",
|
||||
"@types/chai": "4.3.4",
|
||||
"@types/copy-webpack-plugin": "6.4.3",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/mime-types": "2.1.1",
|
||||
"@types/mini-css-extract-plugin": "1.4.3",
|
||||
"@types/mocha": "^9.1.1",
|
||||
@ -69,62 +95,68 @@
|
||||
"@types/react-dom": "16.9.17",
|
||||
"@types/semver": "7.3.13",
|
||||
"@types/sinon": "9.0.11",
|
||||
"@types/terser-webpack-plugin": "5.0.4",
|
||||
"@types/tmp": "0.2.3",
|
||||
"@types/webpack-node-externals": "2.5.3",
|
||||
"analytics-client": "^2.0.1",
|
||||
"axios": "^0.27.2",
|
||||
"@vercel/webpack-asset-relocator-loader": "1.7.3",
|
||||
"chai": "4.3.7",
|
||||
"copy-webpack-plugin": "7.0.0",
|
||||
"css-loader": "5.2.7",
|
||||
"d3": "4.13.0",
|
||||
"debug": "4.3.4",
|
||||
"electron": "^25.8.2",
|
||||
"electron-builder": "^23.6.0",
|
||||
"electron": "25.8.2",
|
||||
"electron-mocha": "^11.0.2",
|
||||
"electron-notarize": "1.2.2",
|
||||
"electron-rebuild": "^3.2.9",
|
||||
"electron-updater": "5.3.0",
|
||||
"esbuild-loader": "2.20.0",
|
||||
"etcher-sdk": "8.3.1",
|
||||
"file-loader": "6.2.0",
|
||||
"husky": "4.3.8",
|
||||
"i18next": "21.10.0",
|
||||
"immutable": "3.8.2",
|
||||
"lint-staged": "10.5.4",
|
||||
"lodash": "4.17.21",
|
||||
"mini-css-extract-plugin": "1.6.2",
|
||||
"mocha": "^9.1.1",
|
||||
"native-addon-loader": "2.0.1",
|
||||
"node-ipc": "9.2.1",
|
||||
"node-loader": "^2.0.0",
|
||||
"omit-deep-lodash": "1.1.7",
|
||||
"outdent": "0.8.0",
|
||||
"path-is-inside": "1.0.2",
|
||||
"pkg": "^5.8.1",
|
||||
"pnp-webpack-plugin": "1.7.0",
|
||||
"pretty-bytes": "5.6.0",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5",
|
||||
"react-i18next": "11.18.6",
|
||||
"redux": "4.2.0",
|
||||
"rendition": "19.3.2",
|
||||
"semver": "7.3.8",
|
||||
"simple-progress-webpack-plugin": "1.1.2",
|
||||
"sinon": "9.2.4",
|
||||
"string-replace-loader": "3.1.0",
|
||||
"style-loader": "2.0.0",
|
||||
"styled-components": "5.3.6",
|
||||
"sys-class-rgb-led": "3.0.1",
|
||||
"terser-webpack-plugin": "5.3.6",
|
||||
"ts-loader": "8.4.0",
|
||||
"ts-node": "9.1.1",
|
||||
"ts-loader": "^9.5.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"tslib": "2.4.1",
|
||||
"typescript": "4.4.4",
|
||||
"url-loader": "4.1.1",
|
||||
"uuid": "8.3.2",
|
||||
"webpack": "5.75.0",
|
||||
"webpack-cli": "4.10.0",
|
||||
"webpack-dev-server": "4.11.1"
|
||||
"url-loader": "4.1.1"
|
||||
},
|
||||
"hostDependencies": {
|
||||
"debian": [
|
||||
"gconf-service",
|
||||
"gconf2",
|
||||
"libasound2",
|
||||
"libatk1.0-0",
|
||||
"libc6",
|
||||
"libcairo2",
|
||||
"libcups2",
|
||||
"libdbus-1-3",
|
||||
"libexpat1",
|
||||
"libfontconfig1",
|
||||
"libfreetype6",
|
||||
"libgbm1",
|
||||
"libgcc1",
|
||||
"libgconf-2-4",
|
||||
"libgdk-pixbuf2.0-0",
|
||||
"libglib2.0-0",
|
||||
"libgtk-3-0",
|
||||
"liblzma5",
|
||||
"libnotify4",
|
||||
"libnspr4",
|
||||
"libnss3",
|
||||
"libpango1.0-0 | libpango-1.0-0",
|
||||
"libstdc++6",
|
||||
"libx11-6",
|
||||
"libxcomposite1",
|
||||
"libxcursor1",
|
||||
"libxdamage1",
|
||||
"libxext6",
|
||||
"libxfixes3",
|
||||
"libxi6",
|
||||
"libxrandr2",
|
||||
"libxrender1",
|
||||
"libxss1",
|
||||
"libxtst6",
|
||||
"polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18 <20"
|
||||
|
@ -1,2 +0,0 @@
|
||||
awscli==1.27.28
|
||||
shyaml==0.6.2
|
@ -1,52 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
###
|
||||
# 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.
|
||||
###
|
||||
|
||||
set -u
|
||||
set -e
|
||||
|
||||
# Read list of wildcards from .gitattributes
|
||||
wildcards=()
|
||||
while IFS='' read -r line || [[ -n "$line" ]]; do
|
||||
if [[ -n "$line" ]]; then
|
||||
if [[ ! "$line" =~ "^#" ]]; then
|
||||
filetype=$(echo "$line" | cut -d ' ' -f 2)
|
||||
if [[ "$filetype" == "text" ]] || [[ "$filetype" == "binary" ]]; then
|
||||
wildcards+=("$(echo "$line" | cut -d ' ' -f 1)")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done < .gitattributes
|
||||
|
||||
# Verify those wildcards against all files stored in the repo
|
||||
git ls-tree -r HEAD | while IFS='' read line; do
|
||||
if [[ "$(echo $line | cut -d ' ' -f 2)" == "blob" ]]; then
|
||||
# the cut delimiter in the line below is actually a tab character, not a space
|
||||
filename=$(basename $(echo "$line" | cut -d ' ' -f 2))
|
||||
found_match=0
|
||||
for wildcard in "${wildcards[@]}"; do
|
||||
if [[ "$filename" = $wildcard ]]; then
|
||||
found_match=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ $found_match -eq 0 ]]; then
|
||||
echo "No wildcards match $filename"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
@ -1,52 +0,0 @@
|
||||
/**
|
||||
* This script is in charge of cleaning the `shrinkwrap` file.
|
||||
*
|
||||
* `npm shrinkwrap` has a bug where it will add optional dependencies
|
||||
* to `npm-shrinkwrap.json`, therefore causing errors if these optional
|
||||
* dependendencies are platform dependent and you then try to build
|
||||
* the project in another platform.
|
||||
*
|
||||
* As a workaround, we keep a list of platform dependent dependencies in
|
||||
* the `platformSpecificDependencies` property of `package.json`,
|
||||
* and manually remove them from `npm-shrinkwrap.json` if they exist.
|
||||
*
|
||||
* See: https://github.com/npm/npm/issues/2679
|
||||
*/
|
||||
|
||||
import { writeFile } from 'fs';
|
||||
import * as omit from 'omit-deep-lodash';
|
||||
import * as path from 'path';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import * as shrinkwrap from '../npm-shrinkwrap.json';
|
||||
import * as packageInfo from '../package.json';
|
||||
|
||||
const writeFileAsync = promisify(writeFile);
|
||||
|
||||
const JSON_INDENT = 2;
|
||||
const SHRINKWRAP_FILENAME = path.join(__dirname, '..', 'npm-shrinkwrap.json');
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const cleaned = omit(shrinkwrap, packageInfo.platformSpecificDependencies);
|
||||
for (const item of Object.values(cleaned.dependencies)) {
|
||||
// @ts-ignore
|
||||
item.dev = true;
|
||||
}
|
||||
await writeFileAsync(
|
||||
SHRINKWRAP_FILENAME,
|
||||
JSON.stringify(cleaned, null, JSON_INDENT),
|
||||
);
|
||||
} catch (error: any) {
|
||||
console.log(`[ERROR] Couldn't write shrinkwrap file: ${error.stack}`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
console.log(
|
||||
`[OK] Wrote shrinkwrap file to ${path.relative(
|
||||
__dirname,
|
||||
SHRINKWRAP_FILENAME,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
@ -1 +0,0 @@
|
||||
Subproject commit 8dfa21cfc23b1dbc0eaa22b5dbdf1f5c796b0c2c
|
@ -11,8 +11,7 @@
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"outDir": "build"
|
||||
"isolatedModules": true
|
||||
},
|
||||
"include": ["lib/util"]
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"module": "es2015",
|
||||
"target": "es2019",
|
||||
"jsx": "react",
|
||||
"typeRoots": ["./node_modules/@types", "./typings"],
|
||||
"importHelpers": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"lib": ["dom", "esnext"],
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"pretty": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": "./src",
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"allowJs": true
|
||||
},
|
||||
"include": [
|
||||
"lib/**/*.ts",
|
||||
"node_modules/electron/**/*.d.ts"
|
||||
]
|
||||
}
|
1
typings/pnp-webpack-plugin/index.d.ts
vendored
1
typings/pnp-webpack-plugin/index.d.ts
vendored
@ -1 +0,0 @@
|
||||
declare module 'pnp-webpack-plugin';
|
1
typings/resin-corvus/index.d.ts
vendored
1
typings/resin-corvus/index.d.ts
vendored
@ -1 +0,0 @@
|
||||
declare module 'resin-corvus/browser';
|
@ -1 +0,0 @@
|
||||
declare module 'simple-progress-webpack-plugin';
|
@ -14,48 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as CopyPlugin from 'copy-webpack-plugin';
|
||||
import type { Configuration, ModuleOptions } from 'webpack';
|
||||
|
||||
import * as _ from 'lodash';
|
||||
import * as path from 'path';
|
||||
import * as SimpleProgressWebpackPlugin from 'simple-progress-webpack-plugin';
|
||||
import * as TerserPlugin from 'terser-webpack-plugin';
|
||||
import {
|
||||
BannerPlugin,
|
||||
IgnorePlugin,
|
||||
NormalModuleReplacementPlugin,
|
||||
} from 'webpack';
|
||||
import * as PnpWebpackPlugin from 'pnp-webpack-plugin';
|
||||
|
||||
import * as tsconfigRaw from './tsconfig.webpack.json';
|
||||
|
||||
/**
|
||||
* Don't webpack package.json as sentry tokens
|
||||
* will be inserted in it after webpacking
|
||||
*/
|
||||
function externalPackageJson(packageJsonPath: string) {
|
||||
return (
|
||||
{ request }: { context: string; request: string },
|
||||
callback: (error?: Error | null, result?: string) => void,
|
||||
) => {
|
||||
if (_.endsWith(request, 'package.json')) {
|
||||
return callback(null, `commonjs ${packageJsonPath}`);
|
||||
}
|
||||
return callback();
|
||||
};
|
||||
}
|
||||
|
||||
function renameNodeModules(resourcePath: string) {
|
||||
// electron-builder excludes the node_modules folder even if you specifically include it
|
||||
// Work around by renaming it to "modules"
|
||||
// See https://github.com/electron-userland/electron-builder/issues/4545
|
||||
return (
|
||||
path
|
||||
.relative(__dirname, resourcePath)
|
||||
.replace('node_modules', 'modules')
|
||||
// file-loader expects posix paths, even on Windows
|
||||
.replace(/\\/g, '/')
|
||||
);
|
||||
}
|
||||
|
||||
interface ReplacementRule {
|
||||
search: string;
|
||||
@ -75,74 +41,58 @@ function replace(test: RegExp, ...replacements: ReplacementRule[]) {
|
||||
};
|
||||
}
|
||||
|
||||
const commonConfig = {
|
||||
mode: 'production',
|
||||
optimization: {
|
||||
moduleIds: 'natural',
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
parallel: true,
|
||||
terserOptions: {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
format: {
|
||||
comments: false,
|
||||
ecma: 2020,
|
||||
},
|
||||
},
|
||||
extractComments: false,
|
||||
}),
|
||||
],
|
||||
const rules: Required<ModuleOptions>['rules'] = [
|
||||
// Add support for native node modules
|
||||
{
|
||||
// We're specifying native_modules in the test because the asset relocator loader generates a
|
||||
// "fake" .node file which is really a cjs file.
|
||||
test: /native_modules[/\\].+\.node$/,
|
||||
use: 'node-loader',
|
||||
},
|
||||
{
|
||||
test: /[/\\]node_modules[/\\].+\.(m?js|node)$/,
|
||||
parser: { amd: false },
|
||||
use: {
|
||||
loader: '@vercel/webpack-asset-relocator-loader',
|
||||
options: {
|
||||
outputAssetBase: 'native_modules',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
exclude: /(node_modules|\.webpack)/,
|
||||
use: {
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||
loader: 'file-loader',
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: '@svgr/webpack',
|
||||
},
|
||||
// force axios to use http backend (not xhr) to support streams
|
||||
replace(/node_modules\/axios\/lib\/defaults\.js$/, {
|
||||
search: './adapters/xhr',
|
||||
replace: './adapters/http',
|
||||
}),
|
||||
];
|
||||
|
||||
export const rendererConfig: Configuration = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||
loader: 'file-loader',
|
||||
options: { name: renameNodeModules },
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: '@svgr/webpack',
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'esbuild-loader',
|
||||
options: {
|
||||
loader: 'tsx',
|
||||
target: 'es2021',
|
||||
tsconfigRaw,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// don't import WeakMap polyfill in deep-map-keys (required in corvus)
|
||||
replace(/node_modules\/deep-map-keys\/lib\/deep-map-keys\.js$/, {
|
||||
search: "var WeakMap = require('es6-weak-map');",
|
||||
replace: '',
|
||||
}),
|
||||
// force axios to use http backend (not xhr) to support streams
|
||||
replace(/node_modules\/axios\/lib\/defaults\.js$/, {
|
||||
search: './adapters/xhr',
|
||||
replace: './adapters/http',
|
||||
}),
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.json', '.ts', '.tsx'],
|
||||
rules,
|
||||
},
|
||||
plugins: [
|
||||
PnpWebpackPlugin,
|
||||
new SimpleProgressWebpackPlugin({
|
||||
format: process.env.WEBPACK_PROGRESS || 'verbose',
|
||||
}),
|
||||
// Force axios to use http.js, not xhr.js as we need stream support
|
||||
// (its package.json file replaces http with xhr for browser targets).
|
||||
new NormalModuleReplacementPlugin(
|
||||
@ -157,62 +107,25 @@ const commonConfig = {
|
||||
new IgnorePlugin({
|
||||
resourceRegExp: /^aws-crt$/,
|
||||
}),
|
||||
],
|
||||
resolveLoader: {
|
||||
plugins: [PnpWebpackPlugin.moduleLoader(module)],
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, 'generated'),
|
||||
filename: '[name].js',
|
||||
},
|
||||
externals: [
|
||||
// '../package.json' because we are in 'generated'
|
||||
externalPackageJson('../package.json'),
|
||||
],
|
||||
};
|
||||
|
||||
const guiConfig = {
|
||||
...commonConfig,
|
||||
target: 'electron-renderer',
|
||||
node: {
|
||||
__dirname: true,
|
||||
__filename: true,
|
||||
},
|
||||
entry: {
|
||||
gui: path.join(__dirname, 'lib', 'gui', 'app', 'renderer.ts'),
|
||||
},
|
||||
plugins: [
|
||||
...commonConfig.plugins,
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: 'lib/gui/app/index.html', to: 'index.html' },
|
||||
// electron-builder doesn't bundle folders named "assets"
|
||||
// See https://github.com/electron-userland/electron-builder/issues/4545
|
||||
{ from: 'assets/icon.png', to: 'media/icon.png' },
|
||||
],
|
||||
}),
|
||||
// Remove "Download the React DevTools for a better development experience" message
|
||||
new BannerPlugin({
|
||||
banner: '__REACT_DEVTOOLS_GLOBAL_HOOK__ = { isDisabled: true };',
|
||||
raw: true,
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
const mainConfig = {
|
||||
...commonConfig,
|
||||
target: 'electron-main',
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: true,
|
||||
resolve: {
|
||||
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css'],
|
||||
},
|
||||
};
|
||||
|
||||
const etcherConfig = {
|
||||
...mainConfig,
|
||||
export const mainConfig: Configuration = {
|
||||
entry: {
|
||||
etcher: path.join(__dirname, 'lib', 'gui', 'etcher.ts'),
|
||||
etcher: './lib/gui/etcher.ts',
|
||||
},
|
||||
module: {
|
||||
rules,
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css', '.json'],
|
||||
},
|
||||
};
|
||||
|
||||
export default [guiConfig, etcherConfig];
|
||||
|
@ -1,24 +0,0 @@
|
||||
import configs from './webpack.config';
|
||||
import { WebpackOptionsNormalized } from 'webpack';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const [
|
||||
guiConfig,
|
||||
etcherConfig,
|
||||
childWriterConfig,
|
||||
] = (configs as unknown) as WebpackOptionsNormalized[];
|
||||
|
||||
configs.forEach((config) => {
|
||||
config.mode = 'development';
|
||||
// @ts-ignore
|
||||
config.devtool = 'source-map';
|
||||
});
|
||||
|
||||
guiConfig.devServer = {
|
||||
hot: true,
|
||||
port: 3030,
|
||||
};
|
||||
|
||||
fs.copyFileSync('./lib/gui/app/index.dev.html', './generated/index.html');
|
||||
|
||||
export default [guiConfig, etcherConfig, childWriterConfig];
|
Loading…
x
Reference in New Issue
Block a user