Support Linux packaging via electron-builder (#371)

* Add linux makers

* missed some

* remove eu-strip

* blah

* add description

* remove v from version

* add exec name

* use bin

* add bin to both

* test flatpak

* test adding dev dependencies

* remove flatpak for now

* add command to flatten directory structure

* update package info

* save rpm info

* save work

* add bin to packagerConfig

* save work

* okay let's see what happens

* iterate array

* test more

* remove large

* test

* test

* remove linux arm

* test addl targets

* add quiet to zip

* revert dir flatten

* remove pacman

* add s3 bucket to electron-builder config

* make dir

* only copy artifacts

* don't merge

* zip recurse

* blah

* replace with electronupdater

* make generic

* fix

* fix stuff

* Update build-helper.yml

* test fix

* fix path

* remove tree

* messed up comment

* remove touch

* add platform name to artifact

* remove license

* remove forge

* cleanup builder config

* switch artifact name order

* Remove darwin restriction on autoupdate

* try adding back pacman

* fix license

* remove pacman again

* rewrite scripts

* add binary paths to builder

* clean up

* Update scripts

* update interval and readme

* remove flatpak and snap dependencies for now

* upload with a wildcard

* fix paths for addl binaries

* add back blockmap

* update release path

* add newline

* remove forge config

* 2 small fixes - remove double cd for waveshell building, and remove GOARCH for wavesrv binary in dev mode
This commit is contained in:
Evan Simkowitz 2024-03-04 22:03:53 -08:00 committed by GitHub
parent 1979e401d4
commit 4ef921bdd1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 1129 additions and 2056 deletions

View File

@ -11,15 +11,11 @@ jobs:
matrix:
include:
- platform: "darwin"
arch: "x64"
runner: "macos-latest"
scripthaus: "build-package"
- platform: "darwin"
arch: "arm64"
arch: "universal"
runner: "macos-latest-xlarge"
scripthaus: "build-package"
- platform: "linux"
arch: "x64"
arch: "amd64"
runner: "ubuntu-latest"
scripthaus: "build-package-linux"
runs-on: ${{ matrix.runner }}
@ -29,6 +25,11 @@ jobs:
with:
repository: scripthaus-dev/scripthaus
path: scripthaus
- name: Install Linux Build Dependencies
if: matrix.platform == 'linux'
run: |
sudo apt-get update
sudo apt-get install rpm
- uses: actions/setup-go@v5
with:
go-version: ${{env.GO_VERSION}}
@ -36,7 +37,8 @@ jobs:
wavesrv/go.sum
waveshell/go.sum
scripthaus/go.sum
- run: |
- name: Install Scripthaus
run: |
go work use ./scripthaus;
cd scripthaus;
go get ./...;
@ -45,16 +47,21 @@ jobs:
with:
node-version: ${{env.NODE_VERSION}}
cache: "yarn"
- id: set-version
- name: Set Version
id: set-version
run: |
VERSION=$(node -e 'console.log(require("./version.js"))')
echo "WAVETERM_VERSION=${VERSION}" >> "$GITHUB_OUTPUT"
- run: yarn --frozen-lockfile
- run: ./scripthaus/scripthaus run ${{ matrix.scripthaus }}
- name: Install Yarn Dependencies
run: yarn --frozen-lockfile
- name: Build ${{ matrix.platform }}/${{ matrix.arch }}
run: ./scripthaus/scripthaus run ${{ matrix.scripthaus }}
env:
GOARCH: ${{ matrix.arch }}
- uses: actions/upload-artifact@v4
with:
name: waveterm-build-${{ matrix.platform }}-${{ matrix.arch }}
path: out/make/zip/${{ matrix.platform }}/${{ matrix.arch }}/*.zip
name: waveterm-build-${{ matrix.platform }}
path: make/*.* # only upload files from the make directory, not subdirectories
retention-days: 2
upload:
name: "Upload Builds"
@ -65,10 +72,13 @@ jobs:
with:
merge-multiple: true
path: buildtemp
- run: |
echo "${{ needs.runbuild.outputs.WAVETERM_VERSION }}" > buildtemp/version.txt
- run: (cd buildtemp; zip ../waveterm-builds.zip *)
- run: aws s3 cp waveterm-builds.zip s3://waveterm-github-artifacts/
- name: Set `version.txt`
run: |
echo "${{ needs.runbuild.outputs.WAVETERM_VERSION }}" >> buildtemp/version.txt
- name: Zip Builds
run: (cd buildtemp; zip -q ../waveterm-builds.zip *)
- name: Upload to S3
run: aws s3 cp waveterm-builds.zip s3://waveterm-github-artifacts/
env:
AWS_ACCESS_KEY_ID: "${{ secrets.S3_USERID }}"
AWS_SECRET_ACCESS_KEY: "${{ secrets.S3_SECRETKEY }}"

2
.gitignore vendored
View File

@ -20,3 +20,5 @@ temp.sql
.idea/
test/
.vscode/
make/
waveterm-builds.zip

View File

@ -9,7 +9,7 @@
# Wave Terminal
A open-source, cross-platform, AI-integrated, modern terminal for seamless workflows.
An open-source, cross-platform, AI-integrated, modern terminal for seamless workflows.
Wave isn't just another terminal emulator; it's a rethink on how terminals are built. Wave combines command line with the power of the open web to help veteran CLI users and new developers alike.

67
buildres/README.md Normal file
View File

@ -0,0 +1,67 @@
# Building for release
## Build Helper workflow
Our release builds are managed by the "Build Helper" GitHub Action, which is defined
in [`build-helper.yml`](../.github/workflows/build-helper.yml).
Under the hood, this will call the `build-package` and `build-package-linux` scripts in
[`scripthaus.md`](../scripthaus.md), which will build the Electron codebase using
WebPack and then the `wavesrv` and `mshell` binaries, then it will call `electron-builder`
to generate the distributable app packages. The configuration for `electron-builder`
is [`electron-builder.config.js`](../electron-builder.config.js).
We are working to fully automate the building of release artifacts. For now,
manual steps are still required to sign and notarize the macOS artifacts. The
Linux artifacts do not require additional modification before being published.
## Local signing and notarizing for macOS
The [`prepare-macos.sh`](./prepare-macos.sh) script will download the latest build
artifacts from S3 and sign and notarize the macOS binaries within it. It will then
generate a DMG and a new ZIP archive with the new signed app.
This will call a few different JS scripts to perform more complicated operations.
[`osx-sign.js`](./osx-sign.js) and [`osx-notarize.js`](./osx-notarize.js) call
underlying Electron APIs to sign and notarize the package.
[`update-latest-mac.js`](./update-latest-mac.js) will then update the `latest-mac.yml`
file with the SHA512 checksum and file size of the new signed and notarized installer. This
is important for the `electron-updater` auto-update mechanism to then find and validate new releases.
## Uploading release artifacts for distribution
### Upload script
Once the build has been fully validated and is ready to be released, the
[`upload-release.sh`](./upload-release.sh) script is then used to grab the completed
artifacts and upload them to the `dl.waveterm.dev` S3 bucket for distribution.
### Homebrew
Homebrew currently requires a manual bump of the version, but now that we have auto-updates,
we should add our cask to the list of apps that can be automatically bumped.
### Linux
We do not currently submit the Linux packages to any of the package repositories. We
are working on addressing this in the near future.
## `electron-build` configuration
Most of our configuration is fairly standard. The main exception to this is that we exclude
our Go binaries from the ASAR archive that Electron generates. ASAR files cannot be executed
by NodeJS because they are not seen as files and therefore cannot be executed via a Shell
command. More information can be found
[here](https://www.electronjs.org/docs/latest/tutorial/asar-archives#executing-binaries-inside-asar-archive).
We also exclude most of our `node_modules` from packaging, as WebPack handles packaging
of any dependencies for us. The one exception is `monaco-editor`.
## Automatic updates
Thanks to `electron-updater`, we are able to provide automatic app updates for macOS and Linux,
as long as the app was distributed as a DMG, AppImage, RPM, or DEB file.
With each release, `latest-mac.yml` and `latest-linux.yml` files will be produced that point to the
newest release. These also include file sizes and checksums to aid in validating the packages. The app
will check these files in our S3 bucket every hour to see if a new version is available.

View File

@ -1,20 +0,0 @@
const eu = require("@electron/universal");
const path = require("path");
const x64Path = path.resolve(__dirname, "temp", "x64", "Wave.app");
const arm64Path = path.resolve(__dirname, "temp", "arm64", "Wave.app");
const outPath = path.resolve(__dirname, "temp", "Wave.app");
console.log("building universal package");
console.log("x64 path", x64Path);
console.log("arm64 path", arm64Path);
console.log("output path", outPath);
(async () => {
await eu.makeUniversalApp({
x64AppPath: x64Path,
arm64AppPath: arm64Path,
outAppPath: outPath,
});
console.log("created macos universal app");
})();

View File

@ -1,97 +0,0 @@
#!/bin/bash
# This script is used to build the universal app for macOS
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
rm -f *.zip *.dmg
ZIP_DIR=$SCRIPT_DIR/zip
rm -rf $ZIP_DIR
mkdir $ZIP_DIR
TEMP_DIR=$SCRIPT_DIR/temp
rm -rf $TEMP_DIR
mkdir $TEMP_DIR
BUILDS_DIR=$SCRIPT_DIR/builds
rm -rf $BUILDS_DIR
# Download the builds zip
aws s3 cp s3://waveterm-github-artifacts/waveterm-builds.zip .
BUILDS_ZIP=waveterm-builds.zip
if ! [ -f $BUILDS_ZIP ]; then
echo "no $BUILDS_ZIP found";
exit 1;
fi
echo "unzipping $BUILDS_ZIP"
unzip -q $BUILDS_ZIP -d $BUILDS_DIR
rm $BUILDS_ZIP
# Ensure we have exactly one of each build
find_build()
{
local BUILD_DIR=$1
local BUILD_PATTERN=$2
local BUILD_PATH=$(find $BUILD_DIR -type f -iname "$BUILD_PATTERN")
local NUM_MATCHES=$(echo $BUILD_PATH | wc -l)
if [ "0" -eq "$NUM_MATCHES" ]; then
echo "no $BUILD_NAME found in $BUILD_DIR"
exit 1
elif [ "1" -lt "$NUM_MATCHES" ]; then
echo "multiple $BUILD_NAME found in $BUILD_DIR"
exit 1
fi
echo $BUILD_PATH
}
X64_ZIP=$(find_build $BUILDS_DIR "Wave-darwin-x64-*.zip")
ARM64_ZIP=$(find_build $BUILDS_DIR "Wave-darwin-arm64-*.zip")
set -e
echo "unzipping zip files"
unzip -q $X64_ZIP -d $TEMP_DIR/x64
unzip -q $ARM64_ZIP -d $TEMP_DIR/arm64
rm $ARM64_ZIP $X64_ZIP
# Create universal app and sign and notarize it
TEMP_WAVE_DIR_ARM=$TEMP_DIR/x64/Wave.app
TEMP_WAVE_DIR_X64=$TEMP_DIR/arm64/Wave.app
TEMP_WAVE_DIR_UNIVERSAL=$TEMP_DIR/Wave.app
lipo -create -output $TEMP_DIR/wavesrv $TEMP_WAVE_DIR_X64/Contents/Resources/app/bin/wavesrv $TEMP_WAVE_DIR_ARM/Contents/Resources/app/bin/wavesrv
rm -rf $TEMP_WAVE_DIR_ARM/Contents/Resources/app
mv $TEMP_WAVE_DIR_X64/Contents/Resources/app $TEMP_DIR
cp $TEMP_DIR/wavesrv $TEMP_DIR/app/bin/wavesrv
mkdir $TEMP_WAVE_DIR_ARM/Contents/Resources/app
mkdir $TEMP_WAVE_DIR_X64/Contents/Resources/app
node $SCRIPT_DIR/build-universal.js
rm -rf $TEMP_WAVE_DIR_UNIVERSAL/Contents/Resources/app
mv $TEMP_DIR/app $TEMP_WAVE_DIR_UNIVERSAL/Contents/Resources/app
node $SCRIPT_DIR/osx-sign.js
DEBUG=electron-notarize node $SCRIPT_DIR/osx-notarize.js
echo "universal app creation success (build/sign/notarize)"
UVERSION=$(cat $BUILDS_DIR/version.txt)
DMG_NAME="waveterm-macos-universal-${UVERSION}.dmg"
ZIP_NAME="Wave-macos-universal-${UVERSION}.zip"
echo "creating universal zip"
ditto $TEMP_WAVE_DIR_UNIVERSAL $ZIP_DIR/Wave.app
cd $ZIP_DIR
zip -9yqr $ZIP_NAME Wave.app
mv $ZIP_NAME $BUILDS_DIR/
cd $SCRIPT_DIR
# Expects create-dmg repo to be cloned in the same parent directory as the waveterm repo.
echo "creating universal dmg"
$SCRIPT_DIR/../../create-dmg/create-dmg \
--volname "WaveTerm" \
--window-pos 200 120 \
--window-size 600 300 \
--icon-size 100 \
--icon "Wave.app" 200 130 \
--hide-extension "Wave.app" \
--app-drop-link 400 125 \
$DMG_NAME \
"$TEMP_WAVE_DIR_UNIVERSAL"
echo "success, created $DMG_NAME"
mv $DMG_NAME $BUILDS_DIR/
spctl -a -vvv -t install $TEMP_WAVE_DIR_UNIVERSAL/
rm -rf $TEMP_DIR $ZIP_DIR

46
buildres/generate-hash.js Normal file
View File

@ -0,0 +1,46 @@
// Usage: node generate-hash.js <path-to-installer>
// Example: node generate-hash.js ./make/Wave-0.0.1.dmg
// This script will generate a hash of the installer file, as defined by electron-builder.
// Courtesy of https://github.com/electron-userland/electron-builder/issues/3913#issuecomment-504698845
const path = require("path");
const fs = require("fs");
const crypto = require("crypto");
/**
* Generate a hash of a file, as defined by electron-builder
* @param {string} file - Path to the file
* @param {string} algorithm - Hash algorithm to use
* @param {string} encoding - Encoding to use
* @returns {Promise<string>} - The hash of the file
*/
async function hashFile(file, algorithm = "sha512", encoding = "base64") {
return new Promise((resolve, reject) => {
const hash = crypto.createHash(algorithm);
hash.on("error", reject).setEncoding(encoding);
fs.createReadStream(file, {
highWaterMark: 1024 * 1024,
/* better to use more memory but hash faster */
})
.on("error", reject)
.on("end", () => {
hash.end();
resolve(hash.read());
})
.pipe(hash, {
end: false,
});
});
}
if (require.main === module) {
const installerPath = path.resolve(process.cwd(), process.argv[2]);
(async () => {
const hash = await hashFile(installerPath);
console.log(`hash of ${installerPath}: ${hash}`);
})();
}
module.exports = {
hashFile,
};

View File

@ -1,18 +1,37 @@
// Notarize the Wave.app for macOS
const { notarize } = require("@electron/notarize");
const path = require("path");
console.log("running osx-notarize");
const waveAppPath = path.resolve(__dirname, "temp", "Wave.app");
notarize({
appPath: waveAppPath,
tool: "notarytool",
keychainProfile: "notarytool-creds",
})
.then(() => {
console.log("notarize success");
/**
* Notarize the Wave.app for macOS
* @param {string} waveAppPath - Path to the Wave.app
* @returns {Promise<void>}
*/
async function notarizeApp(waveAppPath) {
return notarize({
appPath: waveAppPath,
tool: "notarytool",
keychainProfile: "notarytool-creds",
})
.catch((e) => {
console.log("notarize error", e);
process.exit(1);
});
.then(() => {
console.log("notarize success");
})
.catch((e) => {
console.log("notarize error", e);
process.exit(1);
});
}
if (require.main === module) {
console.log("running osx-notarize");
const waveAppPath = path.resolve(__dirname, "temp", "Wave.app");
(async () => {
await notarizeApp(waveAppPath);
console.log("notarization complete");
})();
}
module.exports = {
notarizeApp,
};

View File

@ -1,22 +1,45 @@
// Sign the app and binaries for macOS
const { signAsync } = require("@electron/osx-sign");
const path = require("path");
const fs = require("fs");
console.log("running osx-sign");
const waveAppPath = path.resolve(__dirname, "temp", "Wave.app");
signAsync({
app: waveAppPath,
binaries: [
waveAppPath + "/Contents/Resources/app/bin/wavesrv",
waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.4-linux.amd64",
waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.4-linux.arm64",
waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.4-darwin.amd64",
waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.4-darwin.arm64",
],
})
.then(() => {
console.log("signing success");
/**
* Sign the app and binaries for macOS
* @param {string} waveAppPath - Path to the Wave.app
* @returns {Promise<void>}
*/
async function signApp(waveAppPath) {
const binDirPath = path.resolve(waveAppPath, "Contents", "Resources", "app.asar.unpacked", "bin");
const binFilePaths = fs
.readdirSync(binDirPath, { recursive: true, withFileTypes: true })
.filter((f) => f.isFile())
.map((f) => path.resolve(binDirPath, f.path, f.name));
console.log("waveAppPath", waveAppPath);
console.log("binDirPath", binDirPath);
console.log("binFilePaths", binFilePaths);
return signAsync({
app: waveAppPath,
binaries: binFilePaths,
})
.catch((e) => {
console.log("signing error", e);
process.exit(1);
});
.then(() => {
console.log("signing success");
})
.catch((e) => {
console.log("signing error", e);
process.exit(1);
});
}
if (require.main === module) {
console.log("running osx-sign");
const waveAppPath = path.resolve(__dirname, "temp", "Wave.app");
(async () => {
await signApp(waveAppPath);
console.log("signing complete");
})();
}
module.exports = {
signApp,
};

88
buildres/prepare-macos.sh Normal file
View File

@ -0,0 +1,88 @@
#!/bin/bash
# This script is used to sign and notarize the universal app for macOS
# Gets the directory of the script
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# Remove old files and dirs, create new ones
rm -f *.zip *.dmg
ZIP_DIR=$SCRIPT_DIR/zip
rm -rf $ZIP_DIR
mkdir $ZIP_DIR
TEMP_DIR=$SCRIPT_DIR/temp
rm -rf $TEMP_DIR
mkdir $TEMP_DIR
BUILDS_DIR=$SCRIPT_DIR/builds
rm -rf $BUILDS_DIR
# Download the builds zip
aws s3 cp s3://waveterm-github-artifacts/waveterm-builds.zip .
BUILDS_ZIP=waveterm-builds.zip
if ! [ -f $BUILDS_ZIP ]; then
echo "no $BUILDS_ZIP found";
exit 1;
fi
echo "unzipping $BUILDS_ZIP"
unzip -q $BUILDS_ZIP -d $BUILDS_DIR
rm $BUILDS_ZIP
# Finds a file in a directory matching a filename pattern. Ensures there is exactly one match.
find_file()
{
local FILE_DIR=$1
local FILE_PATTERN=$2
local FILE_PATH=$(find $FILE_DIR -type f -iname "$FILE_PATTERN")
local NUM_MATCHES=$(echo $FILE_PATH | wc -l)
if [ "0" -eq "$NUM_MATCHES" ]; then
echo "no $FILE_PATTERN found in $FILE_DIR"
exit 1
elif [ "1" -lt "$NUM_MATCHES" ]; then
echo "multiple $FILE_PATTERN found in $FILE_DIR"
exit 1
fi
echo $FILE_PATH
}
# Unzip Mac build
MAC_ZIP=$(find_file $BUILDS_DIR "Wave-darwin-universal-*.zip")
unzip -q $MAC_ZIP -d $TEMP_DIR
# Sign and notarize the app
node $SCRIPT_DIR/osx-sign.js
DEBUG=electron-notarize node $SCRIPT_DIR/osx-notarize.js
# Zip and move
echo "creating universal zip"
ZIP_NAME=$(basename $MAC_ZIP)
TEMP_WAVE_DIR_UNIVERSAL=$TEMP_DIR/Wave.app
ditto $TEMP_WAVE_DIR_UNIVERSAL $ZIP_DIR/Wave.app
cd $ZIP_DIR
zip -9yqr $ZIP_NAME Wave.app
mv $ZIP_NAME $BUILDS_DIR/
cd $SCRIPT_DIR
# Create a dmg
# Expects create-dmg repo to be cloned in the same parent directory as the waveterm repo.
echo "creating universal dmg"
DMG_NAME=$(echo $ZIP_NAME | sed 's/\.zip/\.dmg/')
$SCRIPT_DIR/../../create-dmg/create-dmg \
--volname "WaveTerm" \
--window-pos 200 120 \
--window-size 600 300 \
--icon-size 100 \
--icon "Wave.app" 200 130 \
--hide-extension "Wave.app" \
--app-drop-link 400 125 \
$DMG_NAME \
"$TEMP_WAVE_DIR_UNIVERSAL"
echo "success, created $DMG_NAME"
mv $DMG_NAME $BUILDS_DIR/
spctl -a -vvv -t install $TEMP_WAVE_DIR_UNIVERSAL/
# Update latest-mac.yml
echo "updating latest-mac.yml"
LATEST_MAC_YML=$BUILDS_DIR/latest-mac.yml
node $SCRIPT_DIR/update-latest-mac.js $MAC_ZIP $LATEST_MAC_YML
# Clean up
rm -rf $TEMP_DIR $ZIP_DIR

View File

@ -1,50 +0,0 @@
## MacOS Universal Build Notes
This doesn't work out of the box and doesn't seem to be well documented anywhere.
The basic idea is that we have to create separate x64 and a arm64 builds and
then link them together using @electron/universal. Seems easy, but in
practice it isn't.
(1) The separate x64 and arm64 builds *cannot* be signed (osx-sign). This
makes sense because once we lipo the executables together they need to be
resigned (their SHA sums will change). If you accidentally sign them
@electron/universal will also refuse to work.
(2) We already deal with architecture specific builds with Go for wavesrv and
waveshell. This upsets @electron/universal as well since these are *binaries*
and we don't want to lipo them together.
(3) Small differences in waveterm.js. The non-executable files must be
*identical*. Well, that's a problem when we inject build times into the files.
Other small differences can also happen (like different go toolchains, etc.).
(4) ASAR builds. By default if there are differences in the "app" folder
@electron/universal plays some neat tricks to separate out the x64 from the
arm64 code using a app.asar stub. That's great for standard electron builds
where the entrypoint is hardcoded to index.js. Ours isn't so this doesn't work.
(5) ASAR builds and unpacked files. I don't know all the details here, but
for Wave to work we have to have some files unpacked (not in ASAR format).
The reason is that we execute them directly (e.g. wavesrv and waveshell), they
aren't just loaded by electron.
(6) Ignoring and skipping files in @electron/universal is hard because
it just takes one minimatch pattern.
---
## Solution
1. Create unsigned builds on x64 and arm64
2. Move the builds to the core build machine and *extract* their "app" directories.
In theory because we aren't using any native node modules they function the same in
both environments.
3. Run @electron/universal on the two unsigned builds (without their app directories).
4. lipo wavesrv from x64 and arm64 manually to create a universal wavesrv binary.
5. Copy our extracted "app" directory (with the newly created universal "wavesrv")
back into the universal Wave.app created by @electron/universal.
6. Manually run osx-sign to sign the new universal build (make sure to
pass the wavesrv and waveshell programs as extra binaries).
7. Manually create the new universal dmg (using create-dmg).

View File

@ -0,0 +1,40 @@
// Updates the latest-mac.yml file with the signed and notarized version of the latest installer
// Usage: node update-latest.js <path-to-installer>
const path = require("path");
const fs = require("fs");
const { hashFile } = require("./generate-hash");
const yaml = require("yaml");
/**
* Updates the latest-mac.yml file with the signed and notarized version of the latest installer
* @param {string} installerPath - Path to the installer
* @param {string} ymlPath - Path to the latest-mac.yml file
* @returns {Promise<void>}
*/
async function updateLatestMac(installerPath, ymlPath) {
const hash = (await hashFile(installerPath)).trim();
const size = fs.statSync(installerPath).size;
const yml = yaml.parse(fs.readFileSync(ymlPath, "utf8"));
for (const file of yml.files) {
if (file.url === path.basename(installerPath)) {
file.sha512 = hash;
file.size = size;
}
}
yml.sha512 = hash;
fs.writeFileSync(ymlPath, yaml.stringify(yml));
}
if (require.main === module) {
const installerPath = path.resolve(process.cwd(), process.argv[2]);
const ymlPath = path.resolve(process.cwd(), process.argv[3]);
(async () => {
await updateLatestMac(installerPath, ymlPath);
console.log("latest-mac.yml updated");
})();
}
module.exports = {
updateLatestMac,
};

View File

@ -1,13 +1,13 @@
#!/bin/bash
# This script is used to upload signed and notarized releases to S3 and update the Electron auto-update release feeds.
# Gets the directory of the script
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
BUILDS_DIR=$SCRIPT_DIR/builds
TEMP2_DIR=$SCRIPT_DIR/temp2
MAIN_RELEASE_PATH="dl.waveterm.dev/build"
AUTOUPDATE_RELEASE_PATH="dl.waveterm.dev/autoupdate"
AUTOUPDATE_RELEASE_PATH="dl.waveterm.dev/releases"
# Copy the builds to the temp2 directory
echo "Copying builds to temp2"
@ -22,64 +22,13 @@ if [ -z "$UVERSION" ]; then
exit 1
fi
# Find the DMG file
echo "Finding DMG"
DMG=$(find $TEMP2_DIR -type f -iname "*.dmg")
# Ensure there is only one
NUM_DMGS=$(echo $DMG | wc -l)
if [ "0" -eq "$NUM_DMGS" ]; then
echo "no DMG found in $TEMP2_DIR"
exit 1
elif [ "1" -lt "$NUM_DMGS" ]; then
echo "multiple DMGs found in $TEMP2_DIR"
exit 1
fi
# Remove files we don't want to upload
rm $TEMP2_DIR/version.txt
rm $TEMP2_DIR/builder-*.yml
# Find the Mac zip
echo "Finding Mac zip"
MAC_ZIP=$(find $TEMP2_DIR -type f -iname "*mac*.zip")
# Ensure there is only one
NUM_MAC_ZIPS=$(echo $MAC_ZIP | wc -l)
if [ "0" -eq "$NUM_MAC_ZIPS" ]; then
echo "no Mac zip found in $TEMP2_DIR"
exit 1
elif [ "1" -lt "$NUM_MAC_ZIPS" ]; then
echo "multiple Mac zips found in $TEMP2_DIR"
exit 1
fi
# Find the Linux zips
echo "Finding Linux zips"
LINUX_ZIPS=$(find $TEMP2_DIR -type f -iname "*linux*.zip")
# Ensure there is at least one
NUM_LINUX_ZIPS=$(echo $LINUX_ZIPS | wc -l)
if [ "0" -eq "$NUM_LINUX_ZIPS" ]; then
echo "no Linux zips found in $TEMP2_DIR"
exit 1
fi
# Upload the DMG
echo "Uploading DMG"
DMG_NAME=$(basename $DMG)
aws s3 cp $DMG s3:/$MAIN_RELEASE_PATH/$DMG_NAME
# Upload the Linux zips
echo "Uploading Linux zips"
for LINUX_ZIP in $LINUX_ZIPS; do
LINUX_ZIP_NAME=$(basename $LINUX_ZIP)
aws s3 cp $LINUX_ZIP s3://$MAIN_RELEASE_PATH/$LINUX_ZIP_NAME
done
# Upload the autoupdate Mac zip
echo "Uploading Mac zip"
MAC_ZIP_NAME=$(basename $MAC_ZIP)
aws s3 cp $MAC_ZIP s3://$AUTOUPDATE_RELEASE_PATH/$MAC_ZIP_NAME
# Update the autoupdate feeds
echo "Updating autoupdate feeds"
RELEASES_CONTENTS="{\"name\":\"$UVERSION\",\"notes\":\"\",\"url\":\"https://$AUTOUPDATE_RELEASE_PATH/$MAC_ZIP_NAME\"}"
aws s3 cp - s3://$AUTOUPDATE_RELEASE_PATH/darwin/arm64/RELEASES.json <<< $RELEASES_CONTENTS
aws s3 cp - s3://$AUTOUPDATE_RELEASE_PATH/darwin/x64/RELEASES.json <<< $RELEASES_CONTENTS
# Upload the artifacts
echo "Uploading build artifacts to $AUTOUPDATE_RELEASE_PATH"
aws s3 cp $TEMP2_DIR/ s3://$AUTOUPDATE_RELEASE_PATH/ --recursive
# Clean up
echo "Cleaning up"

View File

@ -0,0 +1,84 @@
const pkg = require("./package.json");
const fs = require("fs");
const path = require("path");
/**
* @type {import('electron-builder').Configuration}
* @see https://www.electron.build/configuration/configuration
*/
const config = {
appId: pkg.build.appId,
productName: pkg.productName,
artifactName: "${productName}-${platform}-${arch}-${version}.${ext}",
npmRebuild: false,
nodeGypRebuild: false,
electronCompile: false,
files: [
{
from: "./dist",
to: "./dist",
filter: ["**/*"],
},
{
from: "./public",
to: "./public",
filter: ["**/*"],
},
{
from: "./bin",
to: "./bin",
filter: ["**/*"],
},
{
from: ".",
to: ".",
filter: ["package.json"],
},
"!**/node_modules/**${/*}", // Ignore node_modules by default
{
from: "./node_modules",
to: "./node_modules",
filter: ["monaco-editor/min/**/*"], // This is the only module we want to include
},
],
directories: {
output: "make",
},
asarUnpack: ["bin/**/*"],
mac: {
target: {
target: "zip",
arch: "universal",
},
icon: "public/waveterm.icns",
category: "public.app-category.developer-tools",
minimumSystemVersion: "10.15.0",
binaries: fs
.readdirSync("bin", { recursive: true, withFileTypes: true })
.filter((f) => f.isFile())
.map((f) => path.resolve(f.path, f.name)),
},
linux: {
executableName: pkg.productName,
category: "TerminalEmulator",
icon: "public/waveterm.icns",
target: ["zip", "deb", "rpm", "AppImage"],
synopsis: pkg.description,
description: null,
desktop: {
Name: pkg.productName,
Comment: pkg.description,
Keywords: "developer;terminal;emulator;",
category: "Development;Utility;",
},
},
appImage: {
license: "LICENSE",
},
publish: {
provider: "generic",
url: "https://waveterm-test-autoupdate.s3.us-west-2.amazonaws.com/autoupdate",
},
};
module.exports = config;

View File

@ -1,64 +0,0 @@
var AllowedFirstParts = {
"package.json": true,
dist: true,
public: true,
node_modules: true,
bin: true,
};
var AllowedNodeModules = {
"monaco-editor": true,
};
var modCache = {};
function ignoreFn(path) {
let parts = path.split("/");
if (parts.length <= 1) {
return false;
}
let firstPart = parts[1];
if (!AllowedFirstParts[firstPart]) {
return true;
}
if (firstPart == "node_modules") {
if (parts.length <= 2) {
return false;
}
if (parts.length > 3) {
if (parts[3] == "build") {
return true;
}
}
let nodeModule = parts[2];
if (!modCache[nodeModule]) {
modCache[nodeModule] = true;
}
if (!AllowedNodeModules[nodeModule]) {
return true;
}
if (nodeModule == "monaco-editor" && parts.length >= 4 && parts[3] != "min") {
return true;
}
}
return false;
}
module.exports = {
packagerConfig: {
ignore: ignoreFn,
files: [
"package.json",
"dist/*",
"public/*",
],
icon: "public/waveterm.icns",
},
rebuildConfig: {},
makers: [
{
name: "@electron-forge/maker-zip",
platforms: ["darwin", "linux"],
},
],
};

View File

@ -1,10 +1,22 @@
{
"name": "waveterm",
"author": "Command Line Inc",
"author": {
"name": "Command Line Inc",
"email": "info@commandline.dev"
},
"productName": "Wave",
"version": "v0.6.1",
"description": "An open-source, cross-platform, AI-integrated, modern terminal for seamless workflows.",
"version": "0.6.1",
"main": "dist/emain.js",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/wavetermdev/waveterm"
},
"homepage": "https://waveterm.dev",
"build": {
"appId": "dev.commandline.waveterm"
},
"dependencies": {
"@monaco-editor/react": "^4.5.1",
"@table-nav/core": "^0.0.7",
@ -18,6 +30,7 @@
"dayjs": "^1.11.3",
"dompurify": "^3.0.2",
"electron-squirrel-startup": "^1.0.0",
"electron-updater": "^6.1.8",
"framer-motion": "^10.16.16",
"mobx": "6.12",
"mobx-react": "^7.5.0",
@ -50,13 +63,6 @@
"@babel/preset-env": "^7.18.2",
"@babel/preset-react": "^7.23.3",
"@babel/preset-typescript": "^7.17.12",
"@electron-forge/cli": "^7.2.0",
"@electron-forge/maker-deb": "^7.2.0",
"@electron-forge/maker-rpm": "^7.2.0",
"@electron-forge/maker-snap": "^7.2.0",
"@electron-forge/maker-squirrel": "^7.2.0",
"@electron-forge/maker-zip": "^7.2.0",
"@electron/rebuild": "^3.4.0",
"@svgr/webpack": "^8.1.0",
"@types/classnames": "^2.3.1",
"@types/electron": "^1.6.10",
@ -72,6 +78,7 @@
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.1",
"electron": "29.0.1",
"electron-builder": "^24.12.0",
"file-loader": "^6.2.0",
"http-server": "^14.1.1",
"less": "^4.1.2",
@ -87,7 +94,10 @@
"webpack-bundle-analyzer": "^4.10.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.9.1",
"webpack-merge": "^5.8.0"
"webpack-merge": "^5.8.0",
"yaml": "^2.4.0"
},
"scripts": {}
"scripts": {
"postinstall": "electron-builder install-app-deps"
}
}

View File

@ -44,13 +44,21 @@ rm -rf bin/
rm -rf build/
node_modules/.bin/webpack --env prod
WAVESRV_VERSION=$(node -e 'console.log(require("./version.js"))')
WAVESHELL_VERSION=v0.4
GO_LDFLAGS="-s -w -X main.BuildTime=$(date +'%Y%m%d%H%M')"
(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.amd64 main-waveshell.go)
(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.arm64 main-waveshell.go)
(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.amd64 main-waveshell.go)
(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.arm64 main-waveshell.go)
(cd wavesrv; CGO_ENABLED=1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "-X main.BuildTime=$(date +'%Y%m%d%H%M') -X main.WaveVersion=$WAVESRV_VERSION" -o ../bin/wavesrv ./cmd)
node_modules/.bin/electron-forge make
function buildWaveShell {
(cd waveshell; CGO_ENABLED=0 GOOS=$1 GOARCH=$2 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-$WAVESHELL_VERSION-$1.$2 main-waveshell.go)
}
function buildWaveSrv {
(cd wavesrv; CGO_ENABLED=1 GOARCH=$1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "-X main.BuildTime=$(date +'%Y%m%d%H%M') -X main.WaveVersion=$WAVESRV_VERSION" -o ../bin/wavesrv.$1 ./cmd)
}
buildWaveShell darwin amd64
buildWaveShell darwin arm64
buildWaveShell linux amd64
buildWaveShell linux arm64
buildWaveSrv arm64
buildWaveSrv amd64
yarn run electron-builder -c electron-builder.config.js -m -p never
```
```bash
@ -61,20 +69,21 @@ rm -rf bin/
rm -rf build/
node_modules/.bin/webpack --env prod
WAVESRV_VERSION=$(node -e 'console.log(require("./version.js"))')
WAVESHELL_VERSION=v0.4
GO_LDFLAGS="-s -w -X main.BuildTime=$(date +'%Y%m%d%H%M')"
(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.amd64 main-waveshell.go)
(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.arm64 main-waveshell.go)
(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.amd64 main-waveshell.go)
(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.arm64 main-waveshell.go)
# adds -extldflags=-static, *only* on linux (macos does not support fully static binaries) to avoid a glibc dependency
(cd wavesrv; CGO_ENABLED=1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "-linkmode 'external' -extldflags=-static $GO_LDFLAGS -X main.WaveVersion=$WAVESRV_VERSION" -o ../bin/wavesrv ./cmd)
node_modules/.bin/electron-forge make
```
```bash
# @scripthaus command open-electron-package
# @scripthaus cd :playbook
open out/Wave-darwin-x64/Wave.app
function buildWaveShell {
(cd waveshell; CGO_ENABLED=0 GOOS=$1 GOARCH=$2 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-$WAVESHELL_VERSION-$1.$2 main-waveshell.go)
}
function buildWaveSrv {
# adds -extldflags=-static, *only* on linux (macos does not support fully static binaries) to avoid a glibc dependency
(cd wavesrv; CGO_ENABLED=1 GOARCH=$1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "-linkmode 'external' -extldflags=-static $GO_LDFLAGS -X main.WaveVersion=$WAVESRV_VERSION" -o ../bin/wavesrv.$1 ./cmd)
}
buildWaveShell darwin amd64
buildWaveShell darwin arm64
buildWaveShell linux amd64
buildWaveShell linux arm64
buildWaveSrv $GOARCH
yarn run electron-builder -c electron-builder.config.js -l -p never
```
```bash
@ -87,12 +96,15 @@ CGO_ENABLED=1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflag
```bash
# @scripthaus command fullbuild-waveshell
set -e
cd waveshell
WAVESHELL_VERSION=v0.4
GO_LDFLAGS="-s -w -X main.BuildTime=$(date +'%Y%m%d%H%M')"
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.amd64 main-waveshell.go
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.arm64 main-waveshell.go
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.amd64 main-waveshell.go
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.arm64 main-waveshell.go
function buildWaveShell {
(cd waveshell; CGO_ENABLED=0 GOOS=$1 GOARCH=$2 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-$WAVESHELL_VERSION-$1.$2 main-waveshell.go)
}
buildWaveShell darwin amd64
buildWaveShell darwin arm64
buildWaveShell linux amd64
buildWaveShell linux arm64
```
```bash

View File

@ -13,7 +13,6 @@ import { compareLoose } from "semver";
import { ReactComponent as AppsIcon } from "@/assets/icons/apps.svg";
import { ReactComponent as WorkspacesIcon } from "@/assets/icons/workspaces.svg";
import { ReactComponent as SettingsIcon } from "@/assets/icons/settings.svg";
import { ReactComponent as WaveLogoWord } from "@/assets/wave-logo_horizontal-coloronblack.svg";
import { ReactComponent as WaveLogo } from "@/assets/waveterm-logo.svg";
import localizedFormat from "dayjs/plugin/localizedFormat";
@ -176,36 +175,20 @@ class MainSideBar extends React.Component<MainSideBarProps, {}> {
*/
@boundMethod
getUpdateAppBanner(): React.ReactNode {
if (GlobalModel.platform == "darwin") {
const status = GlobalModel.appUpdateStatus.get();
if (status == "ready") {
return (
<SideBarItem
key="update-ready"
className="update-banner"
frontIcon={<i className="fa-sharp fa-regular fa-circle-up icon" />}
contents="Click to Install Update"
onClick={() => GlobalModel.installAppUpdate()}
/>
);
}
const status = GlobalModel.appUpdateStatus.get();
if (status == "ready") {
return (
<SideBarItem
key="update-ready"
className="update-banner"
frontIcon={<i className="fa-sharp fa-regular fa-circle-up icon" />}
contents="Click to Install Update"
onClick={() => GlobalModel.installAppUpdate()}
/>
);
} else {
const clientData = this.props.clientData;
if (!clientData?.clientopts.noreleasecheck && !isBlank(clientData?.releaseinfo?.latestversion)) {
if (compareLoose(appconst.VERSION, clientData.releaseinfo.latestversion) < 0) {
return (
<SideBarItem
key="update-available"
className="update-banner"
frontIcon={<i className="fa-sharp fa-regular fa-circle-up icon" />}
contents="Update Available"
onClick={() => openLink("https://www.waveterm.dev/download?ref=upgrade")}
/>
);
}
}
return null;
}
return null;
}
getSessions() {

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import * as electron from "electron";
import { autoUpdater } from "electron-updater";
import * as path from "path";
import * as fs from "fs";
import fetch from "node-fetch";
@ -69,9 +70,10 @@ function log(...msg: any[]) {
console.log = log;
console.log(
sprintf(
"waveterm-app starting, WAVETERM_HOME=%s, apppath=%s arch=%s/%s",
"waveterm-app starting, WAVETERM_HOME=%s, electronpath=%s gopath=%s arch=%s/%s",
waveHome,
getAppBasePath(),
getElectronAppBasePath(),
getGoAppBasePath(),
unamePlatform,
unameArch
)
@ -130,31 +132,49 @@ function checkPromptMigrate() {
}
}
// for dev, this is just the waveterm directory
// for prod, this is .../Wave.app/Contents/Resources/app
function getAppBasePath() {
/**
* Gets the base path to the Electron app resources. For dev, this is the root of the project. For packaged apps, this is the app.asar archive.
* @returns The base path of the Electron application
*/
function getElectronAppBasePath(): string {
return path.dirname(__dirname);
}
function getBaseHostPort() {
/**
* Gets the base path to the Go backend. If the app is packaged as an asar, the path will be in a separate unpacked directory.
* @returns The base path of the Go backend
*/
function getGoAppBasePath(): string {
const appDir = getElectronAppBasePath();
if (appDir.endsWith(".asar")) {
return `${appDir}.unpacked`;
} else {
return appDir;
}
}
function getBaseHostPort(): string {
if (isDev) {
return DevServerEndpoint;
}
return ProdServerEndpoint;
}
function getWaveSrvPath() {
return path.join(getAppBasePath(), "bin", "wavesrv");
function getWaveSrvPath(): string {
if (isDev) {
return path.join(getGoAppBasePath(), "bin", "wavesrv");
}
return path.join(getGoAppBasePath(), "bin", `wavesrv.${unameArch}`);
}
function getWaveSrvCmd() {
function getWaveSrvCmd(): string {
const waveSrvPath = getWaveSrvPath();
const waveHome = getWaveHomeDir();
const logFile = path.join(waveHome, "wavesrv.log");
return `"${waveSrvPath}" >> "${logFile}" 2>&1`;
}
function getWaveSrvCwd() {
function getWaveSrvCwd(): string {
return getWaveHomeDir();
}
@ -162,7 +182,7 @@ function ensureDir(dir: fs.PathLike) {
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
}
function readAuthKey() {
function readAuthKey(): string {
const homeDir = getWaveHomeDir();
const authKeyFileName = path.join(homeDir, AuthKeyFile);
if (!fs.existsSync(authKeyFileName)) {
@ -259,7 +279,7 @@ electron.Menu.setApplicationMenu(menu);
let MainWindow: Electron.BrowserWindow | null = null;
function getMods(input: any) {
function getMods(input: any): object {
return { meta: input.meta, shift: input.shift, ctrl: input.control, alt: input.alt };
}
@ -291,7 +311,7 @@ function shFrameNavHandler(event: Electron.Event<Electron.WebContentsWillFrameNa
console.log("frame navigation canceled");
}
function createMainWindow(clientData: ClientDataType | null) {
function createMainWindow(clientData: ClientDataType | null): Electron.BrowserWindow {
const bounds = calcBounds(clientData);
setKeyUtilPlatform(platform());
const win = new electron.BrowserWindow({
@ -305,11 +325,11 @@ function createMainWindow(clientData: ClientDataType | null) {
transparent: true,
icon: unamePlatform == "linux" ? "public/logos/wave-logo-dark.png" : undefined,
webPreferences: {
preload: path.join(getAppBasePath(), DistDir, "preload.js"),
preload: path.join(getElectronAppBasePath(), DistDir, "preload.js"),
},
});
const indexHtml = isDev ? "index-dev.html" : "index.html";
win.loadFile(path.join(getAppBasePath(), "public", indexHtml));
win.loadFile(path.join(getElectronAppBasePath(), "public", indexHtml));
win.webContents.on("before-input-event", (e, input) => {
const waveEvent = adaptFromElectronKeyEvent(input);
if (win.isFocused()) {
@ -450,7 +470,7 @@ function mainResizeHandler(_: any, win: Electron.BrowserWindow) {
});
}
function calcBounds(clientData: ClientDataType) {
function calcBounds(clientData: ClientDataType): Electron.Rectangle {
const primaryDisplay = electron.screen.getPrimaryDisplay();
const pdBounds = primaryDisplay.bounds;
const size = { x: 100, y: 100, width: pdBounds.width - 200, height: pdBounds.height - 200 };
@ -572,7 +592,7 @@ function readLastLinesOfFile(filePath: string, lineCount: number) {
});
}
function getContextMenu(): any {
function getContextMenu(): electron.Menu {
const menu = new electron.Menu();
const menuItem = new electron.MenuItem({ label: "Testing", click: () => console.log("click testing!") });
menu.append(menuItem);
@ -585,7 +605,7 @@ function getFetchHeaders() {
};
}
async function getClientDataPoll(loopNum: number) {
async function getClientDataPoll(loopNum: number): Promise<ClientDataType | null> {
const lastTime = loopNum >= 6;
const cdata = await getClientData(!lastTime, loopNum);
if (lastTime || cdata != null) {
@ -595,7 +615,7 @@ async function getClientDataPoll(loopNum: number) {
return getClientDataPoll(loopNum + 1);
}
async function getClientData(willRetry: boolean, retryNum: number) {
async function getClientData(willRetry: boolean, retryNum: number): Promise<ClientDataType | null> {
const url = new URL(getBaseHostPort() + "/api/get-client-data");
const fetchHeaders = getFetchHeaders();
return fetch(url, { headers: fetchHeaders })
@ -634,13 +654,13 @@ function runWaveSrv() {
pReject = argReject;
});
const envCopy = { ...process.env };
envCopy[WaveAppPathVarName] = getAppBasePath();
envCopy[WaveAppPathVarName] = getGoAppBasePath();
if (isDev) {
envCopy[WaveDevVarName] = "1";
}
const waveSrvCmd = getWaveSrvCmd();
console.log("trying to run local server", waveSrvCmd);
const proc = child_process.spawn("bash", ["-c", waveSrvCmd], {
const proc = child_process.execFile("bash", ["-c", waveSrvCmd], {
cwd: getWaveSrvCwd(),
env: envCopy,
});
@ -787,8 +807,6 @@ function setAppUpdateStatus(status: string) {
* @returns The interval at which the auto-updater checks for updates
*/
function initUpdater(): NodeJS.Timeout {
const { autoUpdater } = electron;
if (isDev) {
console.log("skipping auto-updater in dev mode");
return null;
@ -803,12 +821,6 @@ function initUpdater(): NodeJS.Timeout {
serverType = "json";
}
autoUpdater.setFeedURL({
url: feedURL,
headers: { "User-Agent": "Wave Auto-Update" },
serverType,
});
autoUpdater.removeAllListeners();
autoUpdater.on("error", (err) => {
@ -828,10 +840,10 @@ function initUpdater(): NodeJS.Timeout {
console.log("update-not-available");
});
autoUpdater.on("update-downloaded", (event, releaseNotes, releaseName, releaseDate, updateURL) => {
console.log("update-downloaded", [event, releaseNotes, releaseName, releaseDate, updateURL]);
availableUpdateReleaseName = releaseName;
availableUpdateReleaseNotes = releaseNotes;
autoUpdater.on("update-downloaded", (event) => {
console.log("update-downloaded", [event]);
availableUpdateReleaseName = event.releaseName;
availableUpdateReleaseNotes = event.releaseNotes as string | null;
// Display the update banner and create a system notification
setAppUpdateStatus("ready");
@ -847,7 +859,7 @@ function initUpdater(): NodeJS.Timeout {
// check for updates right away and keep checking later
autoUpdater.checkForUpdates();
return setInterval(autoUpdater.checkForUpdates, 600000); // 10 minutes in ms
return setInterval(autoUpdater.checkForUpdates, 3600000); // 1 hour in ms
}
/**
@ -863,7 +875,7 @@ async function installAppUpdate() {
};
await electron.dialog.showMessageBox(MainWindow, dialogOpts).then(({ response }) => {
if (response === 0) electron.autoUpdater.quitAndInstall();
if (response === 0) autoUpdater.quitAndInstall();
});
}
@ -896,19 +908,12 @@ function configureAutoUpdater(enabled: boolean) {
}
autoUpdateLock = true;
// only configure auto-updater on macOS
if (unamePlatform == "darwin") {
if (enabled && autoUpdateInterval == null) {
try {
console.log("configuring auto updater");
autoUpdateInterval = initUpdater();
} catch (e) {
console.log("error configuring auto updater", e.toString());
}
} else if (autoUpdateInterval != null) {
console.log("user has disabled auto-updates, stopping updater");
clearInterval(autoUpdateInterval);
autoUpdateInterval = null;
if (enabled && autoUpdateInterval == null) {
try {
console.log("configuring auto updater");
autoUpdateInterval = initUpdater();
} catch (e) {
console.log("error configuring auto updater", e.toString());
}
}
autoUpdateLock = false;

2176
yarn.lock

File diff suppressed because it is too large Load Diff