mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-26 04:36:35 +00:00
Merge pull request #4132 from balena-io/switch-to-electron-forge
Modernize build pipeline
This commit is contained in:
commit
6e4db830e9
174
.github/actions/publish/action.yml
vendored
174
.github/actions/publish/action.yml
vendored
@ -10,12 +10,12 @@ inputs:
|
|||||||
required: true
|
required: true
|
||||||
|
|
||||||
# --- custom environment
|
# --- custom environment
|
||||||
XCODE_APP_LOADER_EMAIL:
|
|
||||||
type: string
|
|
||||||
default: "accounts+apple@balena.io"
|
|
||||||
NODE_VERSION:
|
NODE_VERSION:
|
||||||
type: string
|
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:
|
VERBOSE:
|
||||||
type: string
|
type: string
|
||||||
default: "true"
|
default: "true"
|
||||||
@ -27,12 +27,12 @@ runs:
|
|||||||
- name: Download custom source artifact
|
- name: Download custom source artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
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 }}
|
path: ${{ runner.temp }}
|
||||||
|
|
||||||
- name: Extract custom source artifact
|
- name: Extract custom source artifact
|
||||||
if: runner.os != 'Windows'
|
if: runner.os != 'Windows'
|
||||||
shell: pwsh
|
shell: bash
|
||||||
working-directory: .
|
working-directory: .
|
||||||
run: tar -xf ${{ runner.temp }}/custom.tgz
|
run: tar -xf ${{ runner.temp }}/custom.tgz
|
||||||
|
|
||||||
@ -48,22 +48,54 @@ runs:
|
|||||||
node-version: ${{ inputs.NODE_VERSION }}
|
node-version: ${{ inputs.NODE_VERSION }}
|
||||||
cache: npm
|
cache: npm
|
||||||
|
|
||||||
- name: Install yq
|
- name: Install host dependencies
|
||||||
shell: bash --noprofile --norc -eo pipefail -x {0}
|
if: runner.os == 'Linux'
|
||||||
run: choco install yq
|
shell: bash
|
||||||
if: runner.os == 'Windows'
|
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://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
|
- name: Import Apple code signing certificate
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
uses: apple-actions/import-codesign-certs@v1
|
shell: bash
|
||||||
with:
|
run: |
|
||||||
p12-file-base64: ${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
|
KEY_CHAIN=build.keychain
|
||||||
p12-password: ${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}
|
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
|
- name: Import Windows code signing certificate
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
|
id: import_win_signing_cert
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
Set-Content -Path ${{ runner.temp }}/certificate.base64 -Value $env:WINDOWS_CERTIFICATE
|
Set-Content -Path ${{ runner.temp }}/certificate.base64 -Value $env:WINDOWS_CERTIFICATE
|
||||||
@ -75,95 +107,79 @@ runs:
|
|||||||
-CertStoreLocation Cert:\CurrentUser\My `
|
-CertStoreLocation Cert:\CurrentUser\My `
|
||||||
-Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
-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:
|
env:
|
||||||
WINDOWS_CERTIFICATE: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }}
|
WINDOWS_CERTIFICATE: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }}
|
||||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
|
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
|
- name: Package release
|
||||||
id: package_release
|
shell: bash
|
||||||
shell: bash --noprofile --norc -eo pipefail -x {0}
|
# IMPORTANT: before making changes to this step please consult @engineering in balena's chat.
|
||||||
run: |
|
run: |
|
||||||
set -ea
|
if [[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]]; then
|
||||||
|
export DEBUG='electron-forge:*,sidecar'
|
||||||
|
fi
|
||||||
|
|
||||||
[[ '${{ 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)"
|
APPLICATION_VERSION="$(jq -r '.version' package.json)"
|
||||||
ARCHITECTURE_FLAGS="--${ELECTRON_BUILDER_ARCHITECTURE}"
|
HOST_ARCH="$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
|
||||||
if [[ $runner_os =~ linux ]]; then
|
if [[ "${RUNNER_OS}" == Linux ]]; then
|
||||||
ELECTRON_BUILDER_OS='--linux'
|
PLATFORM=Linux
|
||||||
TARGETS="$(yq e .linux.target[] electron-builder.yml)"
|
SHA256SUM_BIN=sha256sum
|
||||||
|
|
||||||
elif [[ $runner_os =~ darwin|macos|osx ]]; then
|
elif [[ "${RUNNER_OS}" == macOS ]]; then
|
||||||
CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}
|
PLATFORM=Darwin
|
||||||
CSC_KEYCHAIN=signing_temp
|
SHA256SUM_BIN='shasum -a 256'
|
||||||
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
|
elif [[ "${RUNNER_OS}" == Windows ]]; then
|
||||||
ARCHITECTURE_FLAGS="--ia32 ${ARCHITECTURE_FLAGS}"
|
PLATFORM=Windows
|
||||||
CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
|
SHA256SUM_BIN=sha256sum
|
||||||
CSC_LINK=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }}
|
|
||||||
ELECTRON_BUILDER_OS='--win'
|
|
||||||
TARGETS="$(yq e .win.target[] electron-builder.yml)"
|
|
||||||
|
|
||||||
else
|
else
|
||||||
|
echo "ERROR: unexpected runner OS: ${RUNNER_OS}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
npm link electron-builder
|
# Currently, we can only build for the host architecture.
|
||||||
|
npx electron-forge make
|
||||||
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}"
|
|
||||||
|
|
||||||
find dist -type f -maxdepth 1
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "version=${APPLICATION_VERSION}" >> $GITHUB_OUTPUT
|
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:
|
env:
|
||||||
# Apple notarization (afterSignHook.js)
|
# ensure we sign the artifacts
|
||||||
XCODE_APP_LOADER_EMAIL: ${{ inputs.XCODE_APP_LOADER_EMAIL }}
|
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 }}
|
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
|
XCODE_APP_LOADER_TEAM_ID: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_TEAM_ID }}
|
||||||
# https://docs.github.com/en/actions/managing-workflow-runs/approving-workflow-runs-from-public-forks#about-workflow-runs-from-public-forks
|
# Windows signing
|
||||||
CSC_FOR_PULL_REQUEST: true
|
WINDOWS_SIGNING_CERT_PATH: ${{ steps.import_win_signing_cert.outputs.certFilePath }}
|
||||||
|
WINDOWS_SIGNING_PASSWORD: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
|
||||||
# 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\" {} \;
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
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
|
path: dist
|
||||||
retention-days: 1
|
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
|
# --- custom environment
|
||||||
NODE_VERSION:
|
NODE_VERSION:
|
||||||
type: string
|
type: string
|
||||||
default: "16.x"
|
default: "18.18"
|
||||||
VERBOSE:
|
VERBOSE:
|
||||||
type: string
|
type: string
|
||||||
default: "true"
|
default: "true"
|
||||||
@ -28,27 +28,45 @@ runs:
|
|||||||
node-version: ${{ inputs.NODE_VERSION }}
|
node-version: ${{ inputs.NODE_VERSION }}
|
||||||
cache: npm
|
cache: npm
|
||||||
|
|
||||||
- name: Test release
|
- name: Install host dependencies
|
||||||
shell: bash --noprofile --norc -eo pipefail -x {0}
|
if: runner.os == 'Linux'
|
||||||
|
shell: bash
|
||||||
run: |
|
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:]')"
|
runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
|
||||||
npm run flowzone-preinstall-${runner_os}
|
|
||||||
npm ci
|
npm ci
|
||||||
npm run build
|
npm run lint
|
||||||
|
npm run package
|
||||||
npm run test-${runner_os}
|
npm run test-${runner_os}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# https://www.electronjs.org/docs/latest/api/environment-variables
|
# https://www.electronjs.org/docs/latest/api/environment-variables
|
||||||
ELECTRON_NO_ATTACH_CONSOLE: true
|
ELECTRON_NO_ATTACH_CONSOLE: 'true'
|
||||||
|
|
||||||
- name: Compress custom source
|
- name: Compress custom source
|
||||||
if: runner.os != 'Windows'
|
if: runner.os != 'Windows'
|
||||||
shell: pwsh
|
shell: bash
|
||||||
run: tar -acf ${{ runner.temp }}/custom.tgz .
|
run: tar -acf ${{ runner.temp }}/custom.tgz .
|
||||||
|
|
||||||
- name: Compress custom source
|
- name: Compress custom source
|
||||||
@ -59,6 +77,6 @@ runs:
|
|||||||
- name: Upload custom artifact
|
- name: Upload custom artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
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
|
path: ${{ runner.temp }}/custom.tgz
|
||||||
retention-days: 1
|
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')
|
(github.event.pull_request.head.repo.full_name != github.repository && github.event_name == 'pull_request_target')
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
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
|
restrict_custom_actions: false
|
||||||
github_prerelease: true
|
github_prerelease: true
|
||||||
cloudflare_website: "etcher"
|
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
|
- uses: vedantmgoyal2009/winget-releaser@v1
|
||||||
with:
|
with:
|
||||||
identifier: Balena.Etcher
|
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 }}
|
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
|
logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.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
|
# Runtime data
|
||||||
pids
|
pids
|
||||||
*.pid
|
*.pid
|
||||||
*.seed
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
/lib-cov
|
lib-cov
|
||||||
|
|
||||||
# Image stream output directory
|
|
||||||
/tests/image-stream/output
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
# Coverage directory used by tools like istanbul
|
||||||
/coverage
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
# nyc test coverage
|
||||||
.grunt
|
.nyc_output
|
||||||
|
|
||||||
# node-waf configuration
|
# node-waf configuration
|
||||||
.lock-wscript
|
.lock-wscript
|
||||||
|
|
||||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
/build
|
build/Release
|
||||||
|
|
||||||
# Generated files
|
# Dependency directories
|
||||||
/generated
|
node_modules/
|
||||||
/binaries
|
jspm_packages/
|
||||||
|
|
||||||
# Dependency directory
|
# TypeScript v1 declaration files
|
||||||
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
|
typings/
|
||||||
node_modules
|
|
||||||
|
|
||||||
# Compiled Etcher releases
|
# TypeScript cache
|
||||||
/dist
|
*.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
|
# Certificates
|
||||||
*.spc
|
*.spc
|
||||||
@ -45,16 +107,17 @@ node_modules
|
|||||||
*.crt
|
*.crt
|
||||||
*.pem
|
*.pem
|
||||||
|
|
||||||
# OSX files
|
# Secrets
|
||||||
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# VSCode files
|
|
||||||
|
|
||||||
.vscode
|
|
||||||
.gitsecret/keys/random_seed
|
.gitsecret/keys/random_seed
|
||||||
!*.secret
|
!*.secret
|
||||||
secrets/APPLE_SIGNING_PASSWORD.txt
|
secrets/APPLE_SIGNING_PASSWORD.txt
|
||||||
secrets/WINDOWS_SIGNING_PASSWORD.txt
|
secrets/WINDOWS_SIGNING_PASSWORD.txt
|
||||||
secrets/XCODE_APP_LOADER_PASSWORD.txt
|
secrets/XCODE_APP_LOADER_PASSWORD.txt
|
||||||
secrets/WINDOWS_SIGNING.pfx
|
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
|
## Supported Operating Systems
|
||||||
|
|
||||||
- Linux (most distros)
|
- Linux; most distros; Intel 64-bit.
|
||||||
- macOS 10.10 (Yosemite) and later
|
- Windows 10 and later; Intel 64-bit.
|
||||||
- Microsoft Windows 7 and later
|
- macOS 10.13 (High Sierra) and later; both Intel and Apple Silicon.
|
||||||
|
|
||||||
**Note**: Etcher will run on any platform officially supported by
|
|
||||||
[Electron][electron]. Read more in their
|
|
||||||
[documentation][electron-supported-platforms].
|
|
||||||
|
|
||||||
## Installers
|
## 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
|
#### GUI
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Build the GUI
|
# Build and start application
|
||||||
npm run webpack #or npm run build
|
|
||||||
# Start Electron
|
|
||||||
npm start
|
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
|
*The test suite is run automatically by CI servers when you send a pull
|
||||||
request.*
|
request.*
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
your text editor of choice to avoid having to fix any issues during the review
|
your text editor of choice to avoid having to fix any issues during the review
|
||||||
@ -113,7 +110,8 @@ process.
|
|||||||
Updating a dependency
|
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
|
Diffing Binaries
|
||||||
----------------
|
----------------
|
||||||
|
@ -58,25 +58,18 @@ export ANALYTICS_AMPLITUDE_TOKEN="xxxxxx"
|
|||||||
|
|
||||||
##### Clean dist folder
|
##### 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
|
##### Generating artifacts
|
||||||
|
|
||||||
The artifacts are generated by the CI and published as draft-release or pre-release.
|
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,
|
Our CI will appropriately sign artifacts for macOS and some Windows targets.
|
||||||
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`.
|
|
||||||
|
|
||||||
|
|
||||||
### Uploading packages to Cloudfront
|
### Uploading packages to Cloudfront
|
||||||
|
@ -36,14 +36,17 @@ employee by asking for it from the relevant people.
|
|||||||
Packaging
|
Packaging
|
||||||
---------
|
---------
|
||||||
|
|
||||||
The resulting installers will be saved to `dist/out`.
|
Run the following command on each platform:
|
||||||
|
|
||||||
Run the following commands on all platforms with the right arguments:
|
|
||||||
|
|
||||||
```sh
|
```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
|
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>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>balenaEtcher</title>
|
<title>balenaEtcher</title>
|
||||||
<link rel="stylesheet" type="text/css" href="index.css">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main id="main"></main>
|
<main id="main"></main>
|
||||||
<script src="gui.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -18,7 +18,6 @@ import * as os from 'os';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as packageJSON from '../../../../package.json';
|
import * as packageJSON from '../../../../package.json';
|
||||||
import * as permissions from '../../../shared/permissions';
|
import * as permissions from '../../../shared/permissions';
|
||||||
import { getAppPath } from '../../../shared/get-app-path';
|
|
||||||
import * as errors from '../../../shared/errors';
|
import * as errors from '../../../shared/errors';
|
||||||
|
|
||||||
const THREADS_PER_CPU = 16;
|
const THREADS_PER_CPU = 16;
|
||||||
@ -27,8 +26,8 @@ const THREADS_PER_CPU = 16;
|
|||||||
// the stdout maxBuffer size to be exceeded when flashing
|
// the stdout maxBuffer size to be exceeded when flashing
|
||||||
ipc.config.silent = true;
|
ipc.config.silent = true;
|
||||||
|
|
||||||
function writerArgv(): string[] {
|
async function writerArgv(): Promise<string[]> {
|
||||||
let entryPoint = path.join(getAppPath(), 'generated', 'etcher-util');
|
let entryPoint = await window.etcher.getEtcherUtilPath();
|
||||||
// AppImages run over FUSE, so the files inside the mount point
|
// AppImages run over FUSE, so the files inside the mount point
|
||||||
// can only be accessed by the user that mounted the AppImage.
|
// can only be accessed by the user that mounted the AppImage.
|
||||||
// This means we can't re-spawn Etcher as root from the same
|
// 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_SERVER_ID: string;
|
||||||
IPC_SOCKET_ROOT: string;
|
IPC_SOCKET_ROOT: string;
|
||||||
}) {
|
}) {
|
||||||
const argv = writerArgv();
|
const argv = await writerArgv();
|
||||||
const env = writerEnv(IPC_CLIENT_ID, IPC_SERVER_ID, IPC_SOCKET_ROOT);
|
const env = writerEnv(IPC_CLIENT_ID, IPC_SERVER_ID, IPC_SOCKET_ROOT);
|
||||||
if (withPrivileges) {
|
if (withPrivileges) {
|
||||||
return await permissions.elevateCommand(argv, {
|
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());
|
ipcRenderer.send('change-lng', langParser());
|
||||||
|
|
||||||
if (module.hot) {
|
|
||||||
module.hot.accept('./app', () => {
|
|
||||||
main();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
@ -14,6 +14,12 @@
|
|||||||
* limitations under the License.
|
* 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 electron from 'electron';
|
||||||
import * as remoteMain from '@electron/remote/main';
|
import * as remoteMain from '@electron/remote/main';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
@ -176,6 +182,7 @@ async function createMainWindow() {
|
|||||||
contextIsolation: false,
|
contextIsolation: false,
|
||||||
webviewTag: true,
|
webviewTag: true,
|
||||||
zoomFactor: width / defaultWidth,
|
zoomFactor: width / defaultWidth,
|
||||||
|
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -199,13 +206,7 @@ async function createMainWindow() {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.loadURL(
|
mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
|
||||||
`file://${path.join(
|
|
||||||
'/',
|
|
||||||
...__dirname.split(path.sep).map(encodeURIComponent),
|
|
||||||
'index.html',
|
|
||||||
)}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const page = mainWindow.webContents;
|
const page = mainWindow.webContents;
|
||||||
remoteMain.enable(page);
|
remoteMain.enable(page);
|
||||||
@ -241,6 +242,20 @@ electron.app.on('before-quit', () => {
|
|||||||
process.exit(EXIT_CODES.SUCCESS);
|
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> {
|
async function main(): Promise<void> {
|
||||||
if (!electron.app.requestSingleInstanceLock()) {
|
if (!electron.app.requestSingleInstanceLock()) {
|
||||||
electron.app.quit();
|
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();
|
main();
|
||||||
|
|
||||||
console.time('ready-to-show');
|
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 { env } from 'process';
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
|
|
||||||
import { getAppPath } from '../get-app-path';
|
|
||||||
import { supportedLocales } from '../../gui/app/i18n';
|
import { supportedLocales } from '../../gui/app/i18n';
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
const execFileAsync = promisify(execFile);
|
||||||
@ -27,6 +26,15 @@ const execFileAsync = promisify(execFile);
|
|||||||
const SUCCESSFUL_AUTH_MARKER = 'AUTHENTICATION SUCCEEDED';
|
const SUCCESSFUL_AUTH_MARKER = 'AUTHENTICATION SUCCEEDED';
|
||||||
const EXPECTED_SUCCESSFUL_AUTH_MARKER = `${SUCCESSFUL_AUTH_MARKER}\n`;
|
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(
|
export async function sudo(
|
||||||
command: string,
|
command: string,
|
||||||
): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> {
|
): Promise<{ cancelled: boolean; stdout?: string; stderr?: string }> {
|
||||||
@ -47,11 +55,7 @@ export async function sudo(
|
|||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
env: {
|
env: {
|
||||||
PATH: env.PATH,
|
PATH: env.PATH,
|
||||||
SUDO_ASKPASS: join(
|
SUDO_ASKPASS: getAskPassScriptPath(lang),
|
||||||
getAppPath(),
|
|
||||||
__dirname,
|
|
||||||
`sudo-askpass.osascript-${lang}.js`,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -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 : '',
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
12620
npm-shrinkwrap.json
generated
12620
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",
|
"name": "balena-etcher",
|
||||||
"private": true,
|
"private": true,
|
||||||
"displayName": "balenaEtcher",
|
"displayName": "balenaEtcher",
|
||||||
|
"productName": "balenaEtcher",
|
||||||
"version": "1.18.14",
|
"version": "1.18.14",
|
||||||
"packageType": "local",
|
"packageType": "local",
|
||||||
"main": "generated/etcher.js",
|
"main": ".webpack/main",
|
||||||
"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.",
|
||||||
"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.",
|
"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",
|
"homepage": "https://github.com/balena-io/etcher",
|
||||||
@ -13,27 +14,18 @@
|
|||||||
"url": "git@github.com:balena-io/etcher.git"
|
"url": "git@github.com:balena-io/etcher.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"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-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",
|
"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-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-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-windows": "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 && npm run sanity-checks",
|
"test-macos": "npm run lint && npm run test-gui && npm run test-shared",
|
||||||
"test-windows": "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",
|
||||||
"test": "echo npm run test-{linux,windows,macos}",
|
"test": "echo npm run test-{linux,windows,macos}",
|
||||||
"watch": "webpack serve --no-optimization-minimize --config ./webpack.dev.config.ts",
|
"package": "electron-forge package",
|
||||||
"webpack": "webpack"
|
"start": "electron-forge start",
|
||||||
|
"make": "electron-forge make"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
@ -50,16 +42,50 @@
|
|||||||
},
|
},
|
||||||
"author": "Balena Ltd. <hello@balena.io>",
|
"author": "Balena Ltd. <hello@balena.io>",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"dependencies": {
|
||||||
"@babel/register": "^7.22.15",
|
|
||||||
"@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",
|
"@electron/remote": "^2.0.9",
|
||||||
"@fortawesome/fontawesome-free": "5.15.4",
|
"@fortawesome/fontawesome-free": "5.15.4",
|
||||||
"@sentry/electron": "^4.1.2",
|
"@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",
|
"@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/debug": "^4.1.12",
|
||||||
"@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": "^9.1.1",
|
||||||
@ -69,62 +95,68 @@
|
|||||||
"@types/react-dom": "16.9.17",
|
"@types/react-dom": "16.9.17",
|
||||||
"@types/semver": "7.3.13",
|
"@types/semver": "7.3.13",
|
||||||
"@types/sinon": "9.0.11",
|
"@types/sinon": "9.0.11",
|
||||||
"@types/terser-webpack-plugin": "5.0.4",
|
|
||||||
"@types/tmp": "0.2.3",
|
"@types/tmp": "0.2.3",
|
||||||
"@types/webpack-node-externals": "2.5.3",
|
"@vercel/webpack-asset-relocator-loader": "1.7.3",
|
||||||
"analytics-client": "^2.0.1",
|
|
||||||
"axios": "^0.27.2",
|
|
||||||
"chai": "4.3.7",
|
"chai": "4.3.7",
|
||||||
"copy-webpack-plugin": "7.0.0",
|
|
||||||
"css-loader": "5.2.7",
|
"css-loader": "5.2.7",
|
||||||
"d3": "4.13.0",
|
"electron": "25.8.2",
|
||||||
"debug": "4.3.4",
|
|
||||||
"electron": "^25.8.2",
|
|
||||||
"electron-builder": "^23.6.0",
|
|
||||||
"electron-mocha": "^11.0.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",
|
"file-loader": "6.2.0",
|
||||||
"husky": "4.3.8",
|
"husky": "4.3.8",
|
||||||
"i18next": "21.10.0",
|
|
||||||
"immutable": "3.8.2",
|
|
||||||
"lint-staged": "10.5.4",
|
"lint-staged": "10.5.4",
|
||||||
"lodash": "4.17.21",
|
|
||||||
"mini-css-extract-plugin": "1.6.2",
|
"mini-css-extract-plugin": "1.6.2",
|
||||||
"mocha": "^9.1.1",
|
"mocha": "^9.1.1",
|
||||||
"native-addon-loader": "2.0.1",
|
"native-addon-loader": "2.0.1",
|
||||||
"node-ipc": "9.2.1",
|
"node-loader": "^2.0.0",
|
||||||
"omit-deep-lodash": "1.1.7",
|
"omit-deep-lodash": "1.1.7",
|
||||||
"outdent": "0.8.0",
|
|
||||||
"path-is-inside": "1.0.2",
|
|
||||||
"pkg": "^5.8.1",
|
"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",
|
"sinon": "9.2.4",
|
||||||
"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",
|
"ts-loader": "^9.5.0",
|
||||||
"sys-class-rgb-led": "3.0.1",
|
"ts-node": "^10.9.1",
|
||||||
"terser-webpack-plugin": "5.3.6",
|
|
||||||
"ts-loader": "8.4.0",
|
|
||||||
"ts-node": "9.1.1",
|
|
||||||
"tslib": "2.4.1",
|
"tslib": "2.4.1",
|
||||||
"typescript": "4.4.4",
|
"typescript": "4.4.4",
|
||||||
"url-loader": "4.1.1",
|
"url-loader": "4.1.1"
|
||||||
"uuid": "8.3.2",
|
},
|
||||||
"webpack": "5.75.0",
|
"hostDependencies": {
|
||||||
"webpack-cli": "4.10.0",
|
"debian": [
|
||||||
"webpack-dev-server": "4.11.1"
|
"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": {
|
"engines": {
|
||||||
"node": ">=18 <20"
|
"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",
|
"module": "CommonJS",
|
||||||
"moduleResolution": "Node",
|
"moduleResolution": "Node",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true
|
||||||
"outDir": "build"
|
|
||||||
},
|
},
|
||||||
"include": ["lib/util"]
|
"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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as CopyPlugin from 'copy-webpack-plugin';
|
import type { Configuration, ModuleOptions } from 'webpack';
|
||||||
|
|
||||||
import * as _ from 'lodash';
|
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 {
|
import {
|
||||||
BannerPlugin,
|
BannerPlugin,
|
||||||
IgnorePlugin,
|
IgnorePlugin,
|
||||||
NormalModuleReplacementPlugin,
|
NormalModuleReplacementPlugin,
|
||||||
} from 'webpack';
|
} 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 {
|
interface ReplacementRule {
|
||||||
search: string;
|
search: string;
|
||||||
@ -75,28 +41,34 @@ function replace(test: RegExp, ...replacements: ReplacementRule[]) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const commonConfig = {
|
const rules: Required<ModuleOptions>['rules'] = [
|
||||||
mode: 'production',
|
// Add support for native node modules
|
||||||
optimization: {
|
{
|
||||||
moduleIds: 'natural',
|
// We're specifying native_modules in the test because the asset relocator loader generates a
|
||||||
minimize: true,
|
// "fake" .node file which is really a cjs file.
|
||||||
minimizer: [
|
test: /native_modules[/\\].+\.node$/,
|
||||||
new TerserPlugin({
|
use: 'node-loader',
|
||||||
parallel: true,
|
},
|
||||||
terserOptions: {
|
{
|
||||||
compress: false,
|
test: /[/\\]node_modules[/\\].+\.(m?js|node)$/,
|
||||||
mangle: false,
|
parser: { amd: false },
|
||||||
format: {
|
use: {
|
||||||
comments: false,
|
loader: '@vercel/webpack-asset-relocator-loader',
|
||||||
ecma: 2020,
|
options: {
|
||||||
|
outputAssetBase: 'native_modules',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
exclude: /(node_modules|\.webpack)/,
|
||||||
|
use: {
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
transpileOnly: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
extractComments: false,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: ['style-loader', 'css-loader'],
|
use: ['style-loader', 'css-loader'],
|
||||||
@ -104,45 +76,23 @@ const commonConfig = {
|
|||||||
{
|
{
|
||||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||||
loader: 'file-loader',
|
loader: 'file-loader',
|
||||||
options: { name: renameNodeModules },
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.svg$/,
|
test: /\.svg$/,
|
||||||
use: '@svgr/webpack',
|
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
|
// force axios to use http backend (not xhr) to support streams
|
||||||
replace(/node_modules\/axios\/lib\/defaults\.js$/, {
|
replace(/node_modules\/axios\/lib\/defaults\.js$/, {
|
||||||
search: './adapters/xhr',
|
search: './adapters/xhr',
|
||||||
replace: './adapters/http',
|
replace: './adapters/http',
|
||||||
}),
|
}),
|
||||||
],
|
];
|
||||||
},
|
|
||||||
resolve: {
|
export const rendererConfig: Configuration = {
|
||||||
extensions: ['.js', '.json', '.ts', '.tsx'],
|
module: {
|
||||||
|
rules,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
PnpWebpackPlugin,
|
|
||||||
new SimpleProgressWebpackPlugin({
|
|
||||||
format: process.env.WEBPACK_PROGRESS || 'verbose',
|
|
||||||
}),
|
|
||||||
// Force axios to use http.js, not xhr.js as we need stream support
|
// 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).
|
// (its package.json file replaces http with xhr for browser targets).
|
||||||
new NormalModuleReplacementPlugin(
|
new NormalModuleReplacementPlugin(
|
||||||
@ -157,62 +107,25 @@ const commonConfig = {
|
|||||||
new IgnorePlugin({
|
new IgnorePlugin({
|
||||||
resourceRegExp: /^aws-crt$/,
|
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
|
// Remove "Download the React DevTools for a better development experience" message
|
||||||
new BannerPlugin({
|
new BannerPlugin({
|
||||||
banner: '__REACT_DEVTOOLS_GLOBAL_HOOK__ = { isDisabled: true };',
|
banner: '__REACT_DEVTOOLS_GLOBAL_HOOK__ = { isDisabled: true };',
|
||||||
raw: true,
|
raw: true,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
};
|
resolve: {
|
||||||
|
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css'],
|
||||||
const mainConfig = {
|
|
||||||
...commonConfig,
|
|
||||||
target: 'electron-main',
|
|
||||||
node: {
|
|
||||||
__dirname: false,
|
|
||||||
__filename: true,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const etcherConfig = {
|
export const mainConfig: Configuration = {
|
||||||
...mainConfig,
|
|
||||||
entry: {
|
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