Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial win support #260

Merged
merged 18 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .github/workflows/release_win.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Release for Windows

on:
push:
tags:
- 'v*.*.*'

jobs:
build-windows:
runs-on: windows-latest
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v3

- uses: actions/setup-python@v4
with:
python-version: '3.10'

- uses: actions/setup-node@v4
with:
node-version: lts/*

- name: Install and configure Poetry
uses: snok/install-poetry@v1
with:
version: '1.4.0'
virtualenvs-create: true
virtualenvs-in-project: false
virtualenvs-path: ~/my-custom-path
installer-parallel: true
- name: Install dependencies
run: poetry install

- name: install node deps
run: yarn install-deps

- name: set env vars to prod.env
env:
NODE_ENV: production
DEV_RPC: https://rpc-gate.autonolas.tech/gnosis-rpc/
IS_STAGING: ${{ github.ref != 'refs/heads/main' && 'true' || 'false' }}
FORK_URL: https://rpc-gate.autonolas.tech/gnosis-rpc/
GH_TOKEN: ${{ secrets.github_token}}
run: |
echo NODE_ENV=$NODE_ENV >> prod.env
echo DEV_RPC=$DEV_RPC >> prod.env
echo IS_STAGING=$IS_STAGING >> prod.env
echo FORK_URL=$FORK_URL >> prod.env
cat prod.env
echo GH_TOKEN=$GH_TOKEN >> prod.env
- run: rm -rf /dist
- name: "Build, notarize, publish"
run: make build
49 changes: 49 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

define setup_env
$(eval ENV_FILE := $(1).env)
@echo " - setup env $(ENV_FILE)"
$(eval include $(1).env)
$(eval export)
endef


./trader/:
pwd
git clone https://github.com/valory-xyz/trader.git

./dist/aea_win.exe: ./trader/
mkdir -p dist
cd trader && poetry install && poetry run pyinstaller --collect-data eth_account --collect-all aea --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots --hidden-import grpc --hidden-import openapi_core --collect-all google.protobuf --collect-all openapi_core --collect-all openapi_spec_validator --collect-all asn1crypto --hidden-import py_ecc --hidden-import pytz --onefile pyinstaller/trader_bin.py --name trader_win
cp -f trader/dist/trader_win.exe ./dist/aea_win.exe
pwd


./dist/tendermint_win.exe: ./operate/
pwd
poetry install && poetry run pyinstaller operate/services/utils/tendermint.py --onefile --name tendermint_win


./dist/pearl_win.exe: ./operate/ ./dist/aea_win.exe ./dist/tendermint_win.exe
pwd
poetry install && poetry run pyinstaller --collect-data eth_account --collect-all aea --collect-all coincurve --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots operate/pearl.py --add-binary dist/aea_win.exe:. --add-binary dist/tendermint_win.exe:. --onefile --name pearl_win


.PHONY: build
build: ./dist/pearl_win.exe
$(call setup_env, prod)
echo ${DEV_RPC}
mkdir -p ./electron/bins
cp -f dist/pearl_win.exe ./electron/bins/pearl_win.exe
echo ${NODE_ENV}
NODE_ENV=${NODE_ENV} DEV_RPC=${DEV_RPC} FORK_URL=${FORK_URL} yarn build:frontend
NODE_ENV=${NODE_ENV} DEV_RPC=${DEV_RPC} FORK_URL=${FORK_URL} GH_TOKEN=${GH_TOKEN} node build-win.js


.PHONY: build-tenderly
build-tenderly: ./dist/pearl_win.exe
$(call setup_env, dev-tenderly)
echo ${DEV_RPC}
cp -f dist/pearl_win.exe ./electron/bins/pearl_win.exe
echo ${NODE_ENV}
NODE_ENV=${NODE_ENV} DEV_RPC=${DEV_RPC} FORK_URL=${FORK_URL} yarn build:frontend
GH_TOKEN=${GH_TOKEN} node build-win-tenderly.js
38 changes: 38 additions & 0 deletions build-win-tenderly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* This script is used to build the electron app **with notarization**. It is used for the final build and release process.
*/
require('dotenv').config();
const build = require('electron-builder').build;

const { publishOptions } = require('./electron/constants');

const main = async () => {
console.log('Building...');

/** @type import {CliOptions} from "electron-builder" */
await build({
publish: 'onTag',
config: {
appId: 'xyz.valory.olas-operate-app',
artifactName: '${productName}-${version}-${platform}-${arch}-tenderly.${ext}',
productName: 'Pearl',
files: ['electron/**/*', 'package.json'],
directories: {
output: 'dist',
},
nsis: {
oneClick: false,
},
extraResources: [
{
from: 'electron/bins',
to: 'bins',
filter: ['**/*'],
},
],

},
});
};

main().then((response) => { console.log('Build & Notarize complete'); }).catch((e) => console.error(e));
49 changes: 49 additions & 0 deletions build-win.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* This script is used to build the electron app **with notarization**. It is used for the final build and release process.
*/
require('dotenv').config();
const build = require('electron-builder').build;

const { publishOptions } = require('./electron/constants');


function artifactName() {
const env = process.env.NODE_ENV;
const prefix = env === 'production' ? '' : 'dev-';
return prefix + '${productName}-${version}-${platform}-${arch}.${ext}';
}

const main = async () => {
console.log('Building...');

/** @type import {CliOptions} from "electron-builder" */
await build({
publish: 'onTag',
config: {
appId: 'xyz.valory.olas-operate-app',
artifactName: artifactName(),
productName: 'Pearl',
files: ['electron/**/*', 'package.json'],
directories: {
output: 'dist',
},
nsis: {
oneClick: false,
},
win: {
publish: publishOptions,
icon: 'electron/assets/icons/splash-robot-head-dock.png',
},
extraResources: [
{
from: 'electron/bins',
to: 'bins',
filter: ['**/*'],
},
],

},
});
};

main().then((response) => { console.log('Build & Notarize complete'); }).catch((e) => console.error(e));
77 changes: 75 additions & 2 deletions electron/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ const process = require('process');
const axios = require('axios');
const { spawnSync } = require('child_process');
const { logger } = require('./logger');

const { execSync} = require('child_process');
const { paths } = require('./constants');

const homedir = os.homedir();
/**
* current version of the pearl release
* - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26"
Expand Down Expand Up @@ -55,6 +55,21 @@ const TendermintUrls = {
},
};


function execSyncExitCode(cmd) {
try {
execSync(cmd);
return 0;
}
catch (error) {
logger.electron(error.status); // Might be 127 in your example.
logger.electron(error.message); // Holds the message you typically want.
logger.electron(error.stderr.toString()); // Holds the stderr output. Use `.toString()`.
logger.electron(error.stdout.toString()); // Holds the stdout output. Use `.toString()`.
return error.status;
}
}

function getBinPath(command) {
return spawnSync('/usr/bin/which', [command], { env: Env })
.stdout?.toString()
Expand All @@ -79,6 +94,7 @@ function runCmdUnix(command, options) {
logger.electron(`===== stderr ===== \n${output.stderr}`);
}


function runSudoUnix(command, options) {
let bin = getBinPath(command);
if (!bin) {
Expand Down Expand Up @@ -113,6 +129,12 @@ function isTendermintInstalledUnix() {
return Boolean(getBinPath('tendermint'));
}

function isTendermintInstalledWindows() {
return true;
//always installed cause bundled in
return execSyncExitCode('tendermint --help') === 0;
}

async function downloadFile(url, dest) {
const writer = fs.createWriteStream(dest);
try {
Expand All @@ -132,6 +154,41 @@ async function downloadFile(url, dest) {
}
}

async function installTendermintWindows() {
return;
// bundled in
logger.electron(`Installing tendermint for ${os.platform()}-${process.arch}`);
const cwd = process.cwd();
process.chdir(paths.tempDir);

const url = TendermintUrls[os.platform()][process.arch];

logger.electron(
`Downloading ${url} to ${paths.tempDir}. This might take a while...`,
);
await downloadFile(url, `${paths.tempDir}/tendermint.tar.gz`);

logger.electron(`Installing tendermint binary`);
try {
execSync('tar -xvf tendermint.tar.gz');
} catch (error){
logger.electron(error.status); // Might be 127 in your example.
logger.electron(error.message); // Holds the message you typically want.
logger.electron(error.stderr.toString()); // Holds the stderr output. Use `.toString()`.
logger.electron(error.stdout.toString()); // Holds the stdout output. Use `.toString()`.
}

const bin_dir = homedir + "//AppData//Local//Microsoft//WindowsApps//"
if (!Env.CI) {
if (!fs.existsSync(bin_dir)) {
fs.mkdirSync(bin_dir, {recursive: true});
}
fs.copyFileSync("tendermint.exe", bin_dir + "tendermint.exe");
}
process.chdir(cwd);
}


async function installTendermintUnix() {
logger.electron(`Installing tendermint for ${os.platform()}-${process.arch}`);
const cwd = process.cwd();
Expand Down Expand Up @@ -202,8 +259,24 @@ async function setupUbuntu(ipcChannel) {
}
}



async function setupWindows(ipcChannel) {
logger.electron('Creating required directories');
await createDirectory(`${paths.dotOperateDirectory}`);
await createDirectory(`${paths.tempDir}`);

logger.electron('Checking tendermint installation: ' + isTendermintInstalledWindows());
if (!isTendermintInstalledWindows()) {
ipcChannel.send('response', 'Installing tendermint');
logger.electron('Installing tendermint');
await installTendermintWindows();
}
}

module.exports = {
setupDarwin,
setupUbuntu,
setupWindows,
Env,
};
9 changes: 7 additions & 2 deletions electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const http = require('http');
const AdmZip = require('adm-zip');
const { TRAY_ICONS, TRAY_ICONS_PATHS } = require('./icons');

const { setupDarwin, setupUbuntu, Env } = require('./install');
const { setupDarwin, setupUbuntu, setupWindows, Env } = require('./install');

const { paths } = require('./constants');
const { killProcesses } = require('./processes');
Expand All @@ -39,6 +39,9 @@ const binaryPaths = {
arm64: 'bins/pearl_arm64',
x64: 'bins/pearl_x64',
},
win32: {
x64: 'bins/pearl_win.exe',
},
};

let appConfig = {
Expand Down Expand Up @@ -334,6 +337,7 @@ async function launchDaemon() {
}

async function launchDaemonDev() {

const check = new Promise(function (resolve, _reject) {
operateDaemon = spawn('poetry', [
'run',
Expand Down Expand Up @@ -398,6 +402,7 @@ async function launchNextAppDev() {
'yarn',
['dev:frontend', '--port', appConfig.ports.dev.next],
{
shell: true,
env: {
...process.env,
NEXT_PUBLIC_BACKEND_PORT: appConfig.ports.dev.operate,
Expand Down Expand Up @@ -441,7 +446,7 @@ ipcMain.on('check', async function (event, _argument) {
if (platform === 'darwin') {
await setupDarwin(event.sender);
} else if (platform === 'win32') {
// TODO
await setupWindows(event.sender);
} else {
await setupUbuntu(event.sender);
}
Expand Down
Loading
Loading