mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fdaebdaf7 | |||
| 6db6ac3ee4 | |||
| 4ef921bdd1 | |||
| 1979e401d4 | |||
| baf00ac514 | |||
| b5022c555a | |||
| ab21591314 | |||
| 1f9d9b160a | |||
| 50953839b1 | |||
| 438d17b933 | |||
| 31b9c3d3a5 | |||
| adf83c73b1 | |||
| 089862d990 | |||
| b5d481734f | |||
| 402c8c2485 | |||
| 41f91b6a8a | |||
| 5af7d21e4b | |||
| 6c115716b0 | |||
| 75be66bada | |||
| 189e632ff7 | |||
| bbf471566f | |||
| 0464cccf0a | |||
| 17990afd5d | |||
| 9e806d0621 | |||
| 3fa6494493 | |||
| 98385b1e0d | |||
| bdfb80e62f | |||
| b8b4dc20f5 | |||
| 314932d402 | |||
| 3f83441868 |
@@ -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 }}"
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
name: TestDriver.ai Regression Testing
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
schedule:
|
||||
- cron: "0 21 * * *" # every day at 9pm
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: "TestDriver"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dashcamio/testdriver@main
|
||||
id: testdriver
|
||||
# note that .testdriver/prerun.sh runs before this, so the app has launched already
|
||||
with:
|
||||
prompt: |
|
||||
2. click "Continue"
|
||||
2. focus the Wave input with the keyboard shorcut Command + I
|
||||
3. type 'ls' into the input
|
||||
4. press return
|
||||
5. validate Wave shows the result of 'ls'
|
||||
@@ -20,3 +20,5 @@ temp.sql
|
||||
.idea/
|
||||
test/
|
||||
.vscode/
|
||||
make/
|
||||
waveterm-builds.zip
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
rm ~/Desktop/WITH-LOVE-FROM-AMERICA.txt
|
||||
cd ~/actions-runner/_work/testdriver/testdriver/
|
||||
brew install go
|
||||
brew tap scripthaus-dev/scripthaus
|
||||
brew install scripthaus
|
||||
npm install -g yarn
|
||||
scripthaus run build-backend
|
||||
echo "Yarn"
|
||||
yarn
|
||||
echo "Rebuild"
|
||||
scripthaus run electron-rebuild
|
||||
echo "Webpack"
|
||||
scripthaus run webpack-build
|
||||
echo "Starting Electron"
|
||||
scripthaus run electron 1>/dev/null 2>&1 &
|
||||
echo "Electron Done"
|
||||
exit
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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");
|
||||
})();
|
||||
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
+33
-14
@@ -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,
|
||||
};
|
||||
|
||||
+41
-18
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/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
|
||||
|
||||
AUTOUPDATE_RELEASE_PATH="dl.waveterm.dev/releases"
|
||||
|
||||
# Copy the builds to the temp2 directory
|
||||
echo "Copying builds to temp2"
|
||||
rm -rf $TEMP2_DIR
|
||||
mkdir -p $TEMP2_DIR
|
||||
cp -r $BUILDS_DIR/* $TEMP2_DIR
|
||||
|
||||
UVERSION=$(cat $TEMP2_DIR/version.txt)
|
||||
|
||||
if [ -z "$UVERSION" ]; then
|
||||
echo "version.txt is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove files we don't want to upload
|
||||
rm $TEMP2_DIR/version.txt
|
||||
rm $TEMP2_DIR/builder-*.yml
|
||||
|
||||
# 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"
|
||||
rm -rf $TEMP2_DIR
|
||||
@@ -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;
|
||||
@@ -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"],
|
||||
},
|
||||
],
|
||||
};
|
||||
+1
-3
@@ -1,9 +1,7 @@
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVBDxyg/GY/QdcIEZw=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-github/v57 v57.0.0 h1:L+Y3UPTY8ALM8x+TV0lg+IEBI+upibemtBD8Q9u7zHs=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/wavetermdev/ssh_config v0.0.0-20240109090616-36c8da3d7376 h1:tFhJgTu7lgd+hldLfPSzDCoWUpXI8wHKR3rxq5jTLkQ=
|
||||
github.com/wavetermdev/ssh_config v0.0.0-20240109090616-36c8da3d7376/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
||||
+22
-13
@@ -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",
|
||||
@@ -71,8 +77,8 @@
|
||||
"babel-plugin-jsx-control-statements": "^4.1.2",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^6.7.1",
|
||||
"electron": "28.1.3",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron": "29.0.1",
|
||||
"electron-builder": "^24.12.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"http-server": "^14.1.1",
|
||||
"less": "^4.1.2",
|
||||
@@ -88,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"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user