From f2ea54433677184c59edb836babad30ed0101b8d Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Thu, 4 Jul 2024 23:49:45 +0100 Subject: [PATCH 01/18] refactor: Remove unused log file paths in electron/install.js --- electron/install.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/electron/install.js b/electron/install.js index 306b88bb9..b9c6486e3 100644 --- a/electron/install.js +++ b/electron/install.js @@ -25,8 +25,6 @@ const paths = { VenvDir: path.join(OperateDirectory, '.operate', 'venv'), TempDir: path.join(OperateDirectory, '.operate', 'temp'), VersionFile: path.join(OperateDirectory, '.operate', 'version.txt'), - LogFile: path.join(OperateDirectory, '.operate', 'logs.txt'), - OperateInstallationLog: path.join(os.homedir(), 'operate.log'), }; const Env = { From 90144f4bcc813e7d5d1bede6225d5ab97af613e4 Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Thu, 4 Jul 2024 23:50:10 +0100 Subject: [PATCH 02/18] Create winston logger module for better logging --- electron/logger.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 electron/logger.js diff --git a/electron/logger.js b/electron/logger.js new file mode 100644 index 000000000..b008524f4 --- /dev/null +++ b/electron/logger.js @@ -0,0 +1,68 @@ +const winston = require('winston'); +const { format } = require('logform'); + +const { combine, timestamp, printf } = format; +const logFormat = printf(({ level, message, timestamp }) => { + return `${timestamp} ${level}: ${message}`; +}); + +const customLevels = { + levels: { + error: 0, + warn: 1, + info: 2, + next: 3, + cli: 4, + electron: 5, + }, + colors: { + error: 'red', + warn: 'yellow', + info: 'blue', + cli: 'green bold underline', + electron: 'magenta bold underline', + next: 'cyan bold underline', + }, +}; + +// Custom filter for specific levels, otherwise higher levels will include lower levels +const levelFilter = (level) => + format((info, _opts) => { + return info.level === level ? info : false; + })(); + +const logger = winston.createLogger({ + levels: customLevels.levels, + transports: [ + new winston.transports.Console({ + level: 'electron', + format: combine(winston.format.colorize(), timestamp(), logFormat), + }), + new winston.transports.File({ + filename: 'cli.log', + level: 'cli', + format: combine(levelFilter('cli'), timestamp(), logFormat), + maxFiles: 1, + maxsize: 1024 * 1024 * 10, + }), + new winston.transports.File({ + filename: 'electron.log', + level: 'electron', + format: combine(levelFilter('electron'), timestamp(), logFormat), + maxFiles: 1, + maxsize: 1024 * 1024 * 10, + }), + new winston.transports.File({ + filename: 'next.log', + level: 'next', + format: combine(levelFilter('next'), timestamp(), logFormat), + maxFiles: 1, + maxsize: 1024 * 1024 * 10, + }), + ], + format: combine(timestamp(), logFormat), +}); + +winston.addColors(customLevels.colors); + +module.exports = { logger }; From f64b1ddd19bcce7fce967ecb08a21f903dd820f4 Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Thu, 4 Jul 2024 23:50:32 +0100 Subject: [PATCH 03/18] chore: Refactor logging in electron/main.js and add winston logger module --- electron/main.js | 73 ++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/electron/main.js b/electron/main.js index 7e4a582fa..e4b875b70 100644 --- a/electron/main.js +++ b/electron/main.js @@ -1,8 +1,5 @@ const dotenv = require('dotenv'); -const console = require('electron-log/main'); // Supports log levels and file logging -console.initialize(); - const { app, BrowserWindow, @@ -29,6 +26,7 @@ const { isPortAvailable, findAvailablePort } = require('./ports'); const { PORT_RANGE, isWindows, isMac } = require('./constants'); const { macUpdater } = require('./update'); const { setupStoreIpc } = require('./store'); +const { logger } = require('./logger'); // Configure environment variables dotenv.config(); @@ -77,7 +75,7 @@ async function beforeQuit() { try { await killProcesses(operateDaemonPid); } catch (e) { - console.error(e); + logger.electron(e); } } @@ -85,7 +83,7 @@ async function beforeQuit() { try { await killProcesses(nextAppProcessPid); } catch (e) { - console.error(e); + logger.electron(e); } } @@ -274,21 +272,10 @@ const createMainWindow = () => { }; async function launchDaemon() { - function appendLog(data) { - fs.appendFileSync( - `${paths.OperateDirectory}/logs.txt`, - data.trim() + '\n', - { - encoding: 'utf-8', - }, - ); - return data; - } - // Free up backend port if already occupied try { await fetch(`http://localhost:${appConfig.ports.prod.operate}/api`); - console.log('Killing backend server!'); + logger.electron('Killing backend server!'); let endpoint = fs .readFileSync(`${paths.OperateDirectory}/operate.kill`) .toString() @@ -296,7 +283,7 @@ async function launchDaemon() { await fetch(`http://localhost:${appConfig.ports.prod.operate}/${endpoint}`); } catch (err) { - console.log('Backend not running!'); + logger.electron('Backend not running!'); } const check = new Promise(function (resolve, _reject) { @@ -330,10 +317,10 @@ async function launchDaemon() { ) { resolve({ running: false, error: 'Port already in use' }); } - console.log(appendLog(data.toString().trim())); + logger.cli(data.toString().trim()); }); operateDaemon.stdout.on('data', (data) => { - console.log(appendLog(data.toString().trim())); + logger.cli(data.toString().trim()); }); }); @@ -359,10 +346,10 @@ async function launchDaemonDev() { ) { resolve({ running: false, error: 'Port already in use' }); } - console.log(data.toString().trim()); + logger.cli(data.toString().trim()); }); operateDaemon.stdout.on('data', (data) => { - console.log(data.toString().trim()); + logger.cli(data.toString().trim()); }); }); return await check; @@ -392,7 +379,7 @@ async function launchNextApp() { }); server.listen(appConfig.ports.prod.next, (err) => { if (err) throw err; - console.log( + logger.next( `> Next server running on http://localhost:${appConfig.ports.prod.next}`, ); }); @@ -413,7 +400,7 @@ async function launchNextAppDev() { ); nextAppProcessPid = nextAppProcess.pid; nextAppProcess.stdout.on('data', (data) => { - console.log(data.toString().trim()); + logger.next(data.toString().trim()); resolve(); }); }); @@ -438,7 +425,7 @@ ipcMain.on('check', async function (event, _argument) { // }); // }); } catch (e) { - console.error(e); + logger.electron(e); } // Setup @@ -508,7 +495,7 @@ ipcMain.on('check', async function (event, _argument) { createTray(); splashWindow.destroy(); } catch (e) { - console.log(e); + logger.electron(e); new Notification({ title: 'Error', body: e, @@ -543,7 +530,7 @@ macUpdater.on('update-downloaded', () => { // PROCESS SPECIFIC EVENTS (HANDLES NON-GRACEFUL TERMINATION) process.on('uncaughtException', (error) => { - console.error('Uncaught Exception:', error); + logger.electron('Uncaught Exception:', error); // Clean up your child processes here beforeQuit().then(() => { process.exit(1); // Exit with a failure code @@ -552,7 +539,7 @@ process.on('uncaughtException', (error) => { ['SIGINT', 'SIGTERM'].forEach((signal) => { process.on(signal, () => { - console.log(`Received ${signal}. Cleaning up...`); + logger.electron(`Received ${signal}. Cleaning up...`); beforeQuit().then(() => { process.exit(0); }); @@ -589,10 +576,24 @@ ipcMain.handle('save-logs', async (_, data) => { filePath: paths.LogFile, }); - // operate.log - const installationLog = getSanitizedLogs({ - name: 'installation_log.txt', - filePath: paths.OperateInstallationLog, + // // operate.log + // const installationLog = getSanitizedLogs({ + // name: 'installation_log.txt', + // filePath: paths.OperateInstallationLog, + // }); + + // winston logs + const cliLogFile = getSanitizedLogs({ + name: 'cli.log', + filePath: 'cli.log', + }); + const nextLogFile = getSanitizedLogs({ + name: 'next.log', + filePath: 'next.log', + }); + const electronLogFile = getSanitizedLogs({ + name: 'electron.log', + filePath: 'electron.log', }); const tempDir = os.tmpdir(); @@ -629,7 +630,9 @@ ipcMain.handle('save-logs', async (_, data) => { const zip = new AdmZip(); fs.existsSync(versionFile) && zip.addLocalFile(versionFile); fs.existsSync(logFile) && zip.addLocalFile(logFile); - fs.existsSync(installationLog) && zip.addLocalFile(installationLog); + fs.existsSync(cliLogFile) && zip.addLocalFile(cliLogFile); + fs.existsSync(electronLogFile) && zip.addLocalFile(electronLogFile); + fs.existsSync(nextLogFile) && zip.addLocalFile(nextLogFile); fs.existsSync(osInfoFilePath) && zip.addLocalFile(osInfoFilePath); fs.existsSync(storeFilePath) && zip.addLocalFile(storeFilePath); fs.existsSync(debugDataFilePath) && zip.addLocalFile(debugDataFilePath); @@ -653,7 +656,9 @@ ipcMain.handle('save-logs', async (_, data) => { // Remove temporary files fs.existsSync(logFile) && fs.unlinkSync(logFile); - fs.existsSync(installationLog) && fs.unlinkSync(installationLog); + fs.existsSync(cliLogFile) && fs.unlinkSync(cliLogFile); + fs.existsSync(electronLogFile) && fs.unlinkSync(electronLogFile); + fs.existsSync(nextLogFile) && fs.unlinkSync(nextLogFile); fs.existsSync(osInfo) && fs.unlinkSync(osInfoFilePath); fs.existsSync(storeFilePath) && fs.unlinkSync(storeFilePath); fs.existsSync(debugDataFilePath) && fs.unlinkSync(debugDataFilePath); From 4a6c5dd812e872a24143e7f32a54cf1541d724f0 Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Thu, 4 Jul 2024 23:50:44 +0100 Subject: [PATCH 04/18] Remove unused brew script --- electron/scripts.js | 1098 ------------------------------------------- 1 file changed, 1098 deletions(-) delete mode 100644 electron/scripts.js diff --git a/electron/scripts.js b/electron/scripts.js deleted file mode 100644 index d3f388aa7..000000000 --- a/electron/scripts.js +++ /dev/null @@ -1,1098 +0,0 @@ -const BrewScript = "# We don't need return codes for \"$(command)\", only stdout is needed.\n" + -"# Allow `[[ -n \"$(command)\" ]]`, `func \"$(command)\"`, pipes, etc.\n" + -"# shellcheck disable=SC2312\n" + -"\n" + -"set -u\n" + -"\n" + -"abort() {\n" + -" printf \"%s\\n\" \"$@\" >&2\n" + -" exit 1\n" + -"}\n" + -"\n" + -"# Fail fast with a concise message when not using bash\n" + -"# Single brackets are needed here for POSIX compatibility\n" + -"# shellcheck disable=SC2292\n" + -"if [ -z \"${BASH_VERSION:-}\" ]\n" + -"then\n" + -" abort \"Bash is required to interpret this script.\"\n" + -"fi\n" + -"\n" + -"# Check if script is run with force-interactive mode in CI\n" + -"if [[ -n \"${CI-}\" && -n \"${INTERACTIVE-}\" ]]\n" + -"then\n" + -" abort \"Cannot run force-interactive mode in CI.\"\n" + -"fi\n" + -"\n" + -"# Check if both `INTERACTIVE` and `NONINTERACTIVE` are set\n" + -"# Always use single-quoted strings with `exp` expressions\n" + -"# shellcheck disable=SC2016\n" + -"if [[ -n \"${INTERACTIVE-}\" && -n \"${NONINTERACTIVE-}\" ]]\n" + -"then\n" + -" abort 'Both `$INTERACTIVE` and `$NONINTERACTIVE` are set. Please unset at least one variable and try again.'\n" + -"fi\n" + -"\n" + -"# Check if script is run in POSIX mode\n" + -"if [[ -n \"${POSIXLY_CORRECT+1}\" ]]\n" + -"then\n" + -" abort 'Bash must not run in POSIX mode. Please unset POSIXLY_CORRECT and try again.'\n" + -"fi\n" + -"\n" + -"usage() {\n" + -" cat <${tty_bold} %s${tty_reset}\\n\" \"$(shell_join \"$@\")\"\n" + -"}\n" + -"\n" + -"warn() {\n" + -" printf \"${tty_red}Warning${tty_reset}: %s\\n\" \"$(chomp \"$1\")\" >&2\n" + -"}\n" + -"\n" + -"# Check if script is run non-interactively (e.g. CI)\n" + -"# If it is run non-interactively we should not prompt for passwords.\n" + -"# Always use single-quoted strings with `exp` expressions\n" + -"# shellcheck disable=SC2016\n" + -"if [[ -z \"${NONINTERACTIVE-}\" ]]\n" + -"then\n" + -" if [[ -n \"${CI-}\" ]]\n" + -" then\n" + -" warn 'Running in non-interactive mode because `$CI` is set.'\n" + -" NONINTERACTIVE=1\n" + -" elif [[ ! -t 0 ]]\n" + -" then\n" + -" if [[ -z \"${INTERACTIVE-}\" ]]\n" + -" then\n" + -" warn 'Running in non-interactive mode because `stdin` is not a TTY.'\n" + -" NONINTERACTIVE=1\n" + -" else\n" + -" warn 'Running in interactive mode despite `stdin` not being a TTY because `$INTERACTIVE` is set.'\n" + -" fi\n" + -" fi\n" + -"else\n" + -" ohai 'Running in non-interactive mode because `$NONINTERACTIVE` is set.'\n" + -"fi\n" + -"\n" + -"# USER isn't always set so provide a fall back for the installer and subprocesses.\n" + -"if [[ -z \"${USER-}\" ]]\n" + -"then\n" + -" USER=\"$(chomp \"$(id -un)\")\"\n" + -" export USER\n" + -"fi\n" + -"\n" + -"# First check OS.\n" + -"OS=\"$(uname)\"\n" + -"if [[ \"${OS}\" == \"Linux\" ]]\n" + -"then\n" + -" HOMEBREW_ON_LINUX=1\n" + -"elif [[ \"${OS}\" == \"Darwin\" ]]\n" + -"then\n" + -" HOMEBREW_ON_MACOS=1\n" + -"else\n" + -" abort \"Homebrew is only supported on macOS and Linux.\"\n" + -"fi\n" + -"\n" + -"# Required installation paths. To install elsewhere (which is unsupported)\n" + -"# you can untar https://github.com/Homebrew/brew/tarball/master\n" + -"# anywhere you like.\n" + -"if [[ -n \"${HOMEBREW_ON_MACOS-}\" ]]\n" + -"then\n" + -" UNAME_MACHINE=\"$(/usr/bin/uname -m)\"\n" + -"\n" + -" if [[ \"${UNAME_MACHINE}\" == \"arm64\" ]]\n" + -" then\n" + -" # On ARM macOS, this script installs to /opt/homebrew only\n" + -" HOMEBREW_PREFIX=\"/opt/homebrew\"\n" + -" HOMEBREW_REPOSITORY=\"${HOMEBREW_PREFIX}\"\n" + -" else\n" + -" # On Intel macOS, this script installs to /usr/local only\n" + -" HOMEBREW_PREFIX=\"/usr/local\"\n" + -" HOMEBREW_REPOSITORY=\"${HOMEBREW_PREFIX}/Homebrew\"\n" + -" fi\n" + -" HOMEBREW_CACHE=\"${HOME}/Library/Caches/Homebrew\"\n" + -"\n" + -" STAT_PRINTF=(\"/usr/bin/stat\" \"-f\")\n" + -" PERMISSION_FORMAT=\"%A\"\n" + -" CHOWN=(\"/usr/sbin/chown\")\n" + -" CHGRP=(\"/usr/bin/chgrp\")\n" + -" GROUP=\"admin\"\n" + -" TOUCH=(\"/usr/bin/touch\")\n" + -" INSTALL=(\"/usr/bin/install\" -d -o \"root\" -g \"wheel\" -m \"0755\")\n" + -"else\n" + -" UNAME_MACHINE=\"$(uname -m)\"\n" + -"\n" + -" # On Linux, this script installs to /home/linuxbrew/.linuxbrew only\n" + -" HOMEBREW_PREFIX=\"/home/linuxbrew/.linuxbrew\"\n" + -" HOMEBREW_REPOSITORY=\"${HOMEBREW_PREFIX}/Homebrew\"\n" + -" HOMEBREW_CACHE=\"${HOME}/.cache/Homebrew\"\n" + -"\n" + -" STAT_PRINTF=(\"/usr/bin/stat\" \"--printf\")\n" + -" PERMISSION_FORMAT=\"%a\"\n" + -" CHOWN=(\"/bin/chown\")\n" + -" CHGRP=(\"/bin/chgrp\")\n" + -" GROUP=\"$(id -gn)\"\n" + -" TOUCH=(\"/bin/touch\")\n" + -" INSTALL=(\"/usr/bin/install\" -d -o \"${USER}\" -g \"${GROUP}\" -m \"0755\")\n" + -"fi\n" + -"CHMOD=(\"/bin/chmod\")\n" + -"MKDIR=(\"/bin/mkdir\" \"-p\")\n" + -"HOMEBREW_BREW_DEFAULT_GIT_REMOTE=\"https://github.com/Homebrew/brew\"\n" + -"HOMEBREW_CORE_DEFAULT_GIT_REMOTE=\"https://github.com/Homebrew/homebrew-core\"\n" + -"\n" + -"# Use remote URLs of Homebrew repositories from environment if set.\n" + -"HOMEBREW_BREW_GIT_REMOTE=\"${HOMEBREW_BREW_GIT_REMOTE:-\"${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}\"}\"\n" + -"HOMEBREW_CORE_GIT_REMOTE=\"${HOMEBREW_CORE_GIT_REMOTE:-\"${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}\"}\"\n" + -"# The URLs with and without the '.git' suffix are the same Git remote. Do not prompt.\n" + -"if [[ \"${HOMEBREW_BREW_GIT_REMOTE}\" == \"${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}.git\" ]]\n" + -"then\n" + -" HOMEBREW_BREW_GIT_REMOTE=\"${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}\"\n" + -"fi\n" + -"if [[ \"${HOMEBREW_CORE_GIT_REMOTE}\" == \"${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}.git\" ]]\n" + -"then\n" + -" HOMEBREW_CORE_GIT_REMOTE=\"${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}\"\n" + -"fi\n" + -"export HOMEBREW_{BREW,CORE}_GIT_REMOTE\n" + -"\n" + -"# TODO: bump version when new macOS is released or announced\n" + -"MACOS_NEWEST_UNSUPPORTED=\"15.0\"\n" + -"# TODO: bump version when new macOS is released\n" + -"MACOS_OLDEST_SUPPORTED=\"12.0\"\n" + -"\n" + -"# For Homebrew on Linux\n" + -"REQUIRED_RUBY_VERSION=2.6 # https://github.com/Homebrew/brew/pull/6556\n" + -"REQUIRED_GLIBC_VERSION=2.13 # https://docs.brew.sh/Homebrew-on-Linux#requirements\n" + -"REQUIRED_CURL_VERSION=7.41.0 # HOMEBREW_MINIMUM_CURL_VERSION in brew.sh in Homebrew/brew\n" + -"REQUIRED_GIT_VERSION=2.7.0 # HOMEBREW_MINIMUM_GIT_VERSION in brew.sh in Homebrew/brew\n" + -"\n" + -"# no analytics during installation\n" + -"export HOMEBREW_NO_ANALYTICS_THIS_RUN=1\n" + -"export HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT=1\n" + -"\n" + -"unset HAVE_SUDO_ACCESS # unset this from the environment\n" + -"\n" + -"have_sudo_access() {\n" + -" if [[ ! -x \"/usr/bin/sudo\" ]]\n" + -" then\n" + -" return 1\n" + -" fi\n" + -"\n" + -" local -a SUDO=(\"/usr/bin/sudo\")\n" + -" if [[ -n \"${SUDO_ASKPASS-}\" ]]\n" + -" then\n" + -" SUDO+=(\"-A\")\n" + -" elif [[ -n \"${NONINTERACTIVE-}\" ]]\n" + -" then\n" + -" SUDO+=(\"-n\")\n" + -" fi\n" + -"\n" + -" if [[ -z \"${HAVE_SUDO_ACCESS-}\" ]]\n" + -" then\n" + -" if [[ -n \"${NONINTERACTIVE-}\" ]]\n" + -" then\n" + -" \"${SUDO[@]}\" -l mkdir &>/dev/null\n" + -" else\n" + -" \"${SUDO[@]}\" -v && \"${SUDO[@]}\" -l mkdir &>/dev/null\n" + -" fi\n" + -" HAVE_SUDO_ACCESS=\"$?\"\n" + -" fi\n" + -"\n" + -" if [[ -n \"${HOMEBREW_ON_MACOS-}\" ]] && [[ \"${HAVE_SUDO_ACCESS}\" -ne 0 ]]\n" + -" then\n" + -" abort \"Need sudo access on macOS (e.g. the user ${USER} needs to be an Administrator)!\"\n" + -" fi\n" + -"\n" + -" return \"${HAVE_SUDO_ACCESS}\"\n" + -"}\n" + -"\n" + -"execute() {\n" + -" if ! \"$@\"\n" + -" then\n" + -" abort \"$(printf \"Failed during: %s\" \"$(shell_join \"$@\")\")\"\n" + -" fi\n" + -"}\n" + -"\n" + -"execute_sudo() {\n" + -" local -a args=(\"$@\")\n" + -" if [[ \"${EUID:-${UID}}\" != \"0\" ]] && have_sudo_access\n" + -" then\n" + -" if [[ -n \"${SUDO_ASKPASS-}\" ]]\n" + -" then\n" + -" args=(\"-A\" \"${args[@]}\")\n" + -" fi\n" + -" ohai \"/usr/bin/sudo\" \"${args[@]}\"\n" + -" execute \"/usr/bin/sudo\" \"${args[@]}\"\n" + -" else\n" + -" ohai \"${args[@]}\"\n" + -" execute \"${args[@]}\"\n" + -" fi\n" + -"}\n" + -"\n" + -"getc() {\n" + -" local save_state\n" + -" save_state=\"$(/bin/stty -g)\"\n" + -" /bin/stty raw -echo\n" + -" IFS='' read -r -n 1 -d '' \"$@\"\n" + -" /bin/stty \"${save_state}\"\n" + -"}\n" + -"\n" + -"ring_bell() {\n" + -" # Use the shell's audible bell.\n" + -" if [[ -t 1 ]]\n" + -" then\n" + -" printf \"\\a\"\n" + -" fi\n" + -"}\n" + -"\n" + -"wait_for_user() {\n" + -" local c\n" + -" echo\n" + -" echo \"Press ${tty_bold}RETURN${tty_reset}/${tty_bold}ENTER${tty_reset} to continue or any other key to abort:\"\n" + -" getc c\n" + -" if ! [[ \"${c}\" == $'\\r' || \"${c}\" == $'\\n' ]]\n" + -" then\n" + -" exit 1\n" + -" fi\n" + -"}\n" + -"\n" + -"major_minor() {\n" + -" echo \"${1%%.*}.$(\n" + -" x=\"${1#*.}\"\n" + -" echo \"${x%%.*}\"\n" + -" )\"\n" + -"}\n" + -"\n" + -"version_gt() {\n" + -" [[ \"${1%.*}\" -gt \"${2%.*}\" ]] || [[ \"${1%.*}\" -eq \"${2%.*}\" && \"${1#*.}\" -gt \"${2#*.}\" ]]\n" + -"}\n" + -"version_ge() {\n" + -" [[ \"${1%.*}\" -gt \"${2%.*}\" ]] || [[ \"${1%.*}\" -eq \"${2%.*}\" && \"${1#*.}\" -ge \"${2#*.}\" ]]\n" + -"}\n" + -"version_lt() {\n" + -" [[ \"${1%.*}\" -lt \"${2%.*}\" ]] || [[ \"${1%.*}\" -eq \"${2%.*}\" && \"${1#*.}\" -lt \"${2#*.}\" ]]\n" + -"}\n" + -"\n" + -"check_run_command_as_root() {\n" + -" [[ \"${EUID:-${UID}}\" == \"0\" ]] || return\n" + -"\n" + -" # Allow Azure Pipelines/GitHub Actions/Docker/Concourse/Kubernetes to do everything as root (as it's normal there)\n" + -" [[ -f /.dockerenv ]] && return\n" + -" [[ -f /run/.containerenv ]] && return\n" + -" [[ -f /proc/1/cgroup ]] && grep -E \"azpl_job|actions_job|docker|garden|kubepods\" -q /proc/1/cgroup && return\n" + -"\n" + -" abort \"Don't run this as root!\"\n" + -"}\n" + -"\n" + -"should_install_command_line_tools() {\n" + -" if [[ -n \"${HOMEBREW_ON_LINUX-}\" ]]\n" + -" then\n" + -" return 1\n" + -" fi\n" + -"\n" + -" if version_gt \"${macos_version}\" \"10.13\"\n" + -" then\n" + -" ! [[ -e \"/Library/Developer/CommandLineTools/usr/bin/git\" ]]\n" + -" else\n" + -" ! [[ -e \"/Library/Developer/CommandLineTools/usr/bin/git\" ]] ||\n" + -" ! [[ -e \"/usr/include/iconv.h\" ]]\n" + -" fi\n" + -"}\n" + -"\n" + -"get_permission() {\n" + -" \"${STAT_PRINTF[@]}\" \"${PERMISSION_FORMAT}\" \"$1\"\n" + -"}\n" + -"\n" + -"user_only_chmod() {\n" + -" [[ -d \"$1\" ]] && [[ \"$(get_permission \"$1\")\" != 75[0145] ]]\n" + -"}\n" + -"\n" + -"exists_but_not_writable() {\n" + -" [[ -e \"$1\" ]] && ! [[ -r \"$1\" && -w \"$1\" && -x \"$1\" ]]\n" + -"}\n" + -"\n" + -"get_owner() {\n" + -" \"${STAT_PRINTF[@]}\" \"%u\" \"$1\"\n" + -"}\n" + -"\n" + -"file_not_owned() {\n" + -" [[ \"$(get_owner \"$1\")\" != \"$(id -u)\" ]]\n" + -"}\n" + -"\n" + -"get_group() {\n" + -" \"${STAT_PRINTF[@]}\" \"%g\" \"$1\"\n" + -"}\n" + -"\n" + -"file_not_grpowned() {\n" + -" [[ \" $(id -G \"${USER}\") \" != *\" $(get_group \"$1\") \"* ]]\n" + -"}\n" + -"\n" + -"# Please sync with 'test_ruby()' in 'Library/Homebrew/utils/ruby.sh' from the Homebrew/brew repository.\n" + -"test_ruby() {\n" + -" if [[ ! -x \"$1\" ]]\n" + -" then\n" + -" return 1\n" + -" fi\n" + -"\n" + -" \"$1\" --enable-frozen-string-literal --disable=gems,did_you_mean,rubyopt -rrubygems -e \\\n" + -" \"abort if Gem::Version.new(RUBY_VERSION.to_s.dup).to_s.split('.').first(2) != \\\n" + -" Gem::Version.new('${REQUIRED_RUBY_VERSION}').to_s.split('.').first(2)\" 2>/dev/null\n" + -"}\n" + -"\n" + -"test_curl() {\n" + -" if [[ ! -x \"$1\" ]]\n" + -" then\n" + -" return 1\n" + -" fi\n" + -"\n" + -" local curl_version_output curl_name_and_version\n" + -" curl_version_output=\"$(\"$1\" --version 2>/dev/null)\"\n" + -" curl_name_and_version=\"${curl_version_output%% (*}\"\n" + -" version_ge \"$(major_minor \"${curl_name_and_version##* }\")\" \"$(major_minor \"${REQUIRED_CURL_VERSION}\")\"\n" + -"}\n" + -"\n" + -"test_git() {\n" + -" if [[ ! -x \"$1\" ]]\n" + -" then\n" + -" return 1\n" + -" fi\n" + -"\n" + -" local git_version_output\n" + -" git_version_output=\"$(\"$1\" --version 2>/dev/null)\"\n" + -" if [[ \"${git_version_output}\" =~ \"git version \"([^ ]*).* ]]\n" + -" then\n" + -" version_ge \"$(major_minor \"${BASH_REMATCH[1]}\")\" \"$(major_minor \"${REQUIRED_GIT_VERSION}\")\"\n" + -" else\n" + -" abort \"Unexpected Git version: '${git_version_output}'!\"\n" + -" fi\n" + -"}\n" + -"\n" + -"# Search for the given executable in PATH (avoids a dependency on the `which` command)\n" + -"which() {\n" + -" # Alias to Bash built-in command `type -P`\n" + -" type -P \"$@\"\n" + -"}\n" + -"\n" + -"# Search PATH for the specified program that satisfies Homebrew requirements\n" + -"# function which is set above\n" + -"# shellcheck disable=SC2230\n" + -"find_tool() {\n" + -" if [[ $# -ne 1 ]]\n" + -" then\n" + -" return 1\n" + -" fi\n" + -"\n" + -" local executable\n" + -" while read -r executable\n" + -" do\n" + -" if [[ \"${executable}\" != /* ]]\n" + -" then\n" + -" warn \"Ignoring ${executable} (relative paths don't work)\"\n" + -" elif \"test_$1\" \"${executable}\"\n" + -" then\n" + -" echo \"${executable}\"\n" + -" break\n" + -" fi\n" + -" done < <(which -a \"$1\")\n" + -"}\n" + -"\n" + -"no_usable_ruby() {\n" + -" [[ -z \"$(find_tool ruby)\" ]]\n" + -"}\n" + -"\n" + -"outdated_glibc() {\n" + -" local glibc_version\n" + -" glibc_version=\"$(ldd --version | head -n1 | grep -o '[0-9.]*$' | grep -o '^[0-9]\\\+\\\.[0-9]\\\+')\"\n" + -" version_lt \"${glibc_version}\" \"${REQUIRED_GLIBC_VERSION}\"\n" + -"}\n" + -"\n" + -"if [[ -n \"${HOMEBREW_ON_LINUX-}\" ]] && no_usable_ruby && outdated_glibc\n" + -"then\n" + -" abort \"$(\n" + -" cat </dev/null\n" + -"then\n" + -" trap '/usr/bin/sudo -k' EXIT\n" + -"fi\n" + -"\n" + -"# Things can fail later if `pwd` doesn't exist.\n" + -"# Also sudo prints a warning message for no good reason\n" + -"cd \"/usr\" || exit 1\n" + -"\n" + -"####################################################################### script\n" + -"\n" + -"# shellcheck disable=SC2016\n" + -"ohai 'Checking for `sudo` access (which may request your password)...'\n" + -"\n" + -"if [[ -n \"${HOMEBREW_ON_MACOS-}\" ]]\n" + -"then\n" + -" [[ \"${EUID:-${UID}}\" == \"0\" ]] || have_sudo_access\n" + -"elif ! [[ -w \"${HOMEBREW_PREFIX}\" ]] &&\n" + -" ! [[ -w \"/home/linuxbrew\" ]] &&\n" + -" ! [[ -w \"/home\" ]] &&\n" + -" ! have_sudo_access\n" + -"then\n" + -" abort \"$(\n" + -" cat <&1)\" && [[ \"${output}\" == *\"license\"* ]]\n" + -"then\n" + -" abort \"$(\n" + -" cat </dev/null\n" + -"then\n" + -" abort \"$(\n" + -" cat </dev/null || return\n" + -"\n" + -" # we do it in four steps to avoid merge errors when reinstalling\n" + -" execute \"${USABLE_GIT}\" \"-c\" \"init.defaultBranch=master\" \"init\" \"--quiet\"\n" + -"\n" + -" # \"git remote add\" will fail if the remote is defined in the global config\n" + -" execute \"${USABLE_GIT}\" \"config\" \"remote.origin.url\" \"${HOMEBREW_BREW_GIT_REMOTE}\"\n" + -" execute \"${USABLE_GIT}\" \"config\" \"remote.origin.fetch\" \"+refs/heads/*:refs/remotes/origin/*\"\n" + -"\n" + -" # ensure we don't munge line endings on checkout\n" + -" execute \"${USABLE_GIT}\" \"config\" \"--bool\" \"core.autocrlf\" \"false\"\n" + -"\n" + -" # make sure symlinks are saved as-is\n" + -" execute \"${USABLE_GIT}\" \"config\" \"--bool\" \"core.symlinks\" \"true\"\n" + -"\n" + -" execute \"${USABLE_GIT}\" \"fetch\" \"--force\" \"origin\"\n" + -" execute \"${USABLE_GIT}\" \"fetch\" \"--force\" \"--tags\" \"origin\"\n" + -" execute \"${USABLE_GIT}\" \"remote\" \"set-head\" \"origin\" \"--auto\" >/dev/null\n" + -"\n" + -" LATEST_GIT_TAG=\"$(\"${USABLE_GIT}\" tag --list --sort=\"-version:refname\" | head -n1)\"\n" + -" if [[ -z \"${LATEST_GIT_TAG}\" ]]\n" + -" then\n" + -" abort \"Failed to query latest Homebrew/brew Git tag.\"\n" + -" fi\n" + -" execute \"${USABLE_GIT}\" \"checkout\" \"--force\" \"-B\" \"stable\" \"${LATEST_GIT_TAG}\"\n" + -"\n" + -" if [[ \"${HOMEBREW_REPOSITORY}\" != \"${HOMEBREW_PREFIX}\" ]]\n" + -" then\n" + -" if [[ \"${HOMEBREW_REPOSITORY}\" == \"${HOMEBREW_PREFIX}/Homebrew\" ]]\n" + -" then\n" + -" execute \"ln\" \"-sf\" \"../Homebrew/bin/brew\" \"${HOMEBREW_PREFIX}/bin/brew\"\n" + -" else\n" + -" abort \"The Homebrew/brew repository should be placed in the Homebrew prefix directory.\"\n" + -" fi\n" + -" fi\n" + -"\n" + -" if [[ -n \"${HOMEBREW_NO_INSTALL_FROM_API-}\" && ! -d \"${HOMEBREW_CORE}\" ]]\n" + -" then\n" + -" # Always use single-quoted strings with `exp` expressions\n" + -" # shellcheck disable=SC2016\n" + -" ohai 'Tapping homebrew/core because `$HOMEBREW_NO_INSTALL_FROM_API` is set.'\n" + -" (\n" + -" execute \"${MKDIR[@]}\" \"${HOMEBREW_CORE}\"\n" + -" cd \"${HOMEBREW_CORE}\" >/dev/null || return\n" + -"\n" + -" execute \"${USABLE_GIT}\" \"-c\" \"init.defaultBranch=master\" \"init\" \"--quiet\"\n" + -" execute \"${USABLE_GIT}\" \"config\" \"remote.origin.url\" \"${HOMEBREW_CORE_GIT_REMOTE}\"\n" + -" execute \"${USABLE_GIT}\" \"config\" \"remote.origin.fetch\" \"+refs/heads/*:refs/remotes/origin/*\"\n" + -" execute \"${USABLE_GIT}\" \"config\" \"--bool\" \"core.autocrlf\" \"false\"\n" + -" execute \"${USABLE_GIT}\" \"config\" \"--bool\" \"core.symlinks\" \"true\"\n" + -" execute \"${USABLE_GIT}\" \"fetch\" \"--force\" \"origin\" \"refs/heads/master:refs/remotes/origin/master\"\n" + -" execute \"${USABLE_GIT}\" \"remote\" \"set-head\" \"origin\" \"--auto\" >/dev/null\n" + -" execute \"${USABLE_GIT}\" \"reset\" \"--hard\" \"origin/master\"\n" + -"\n" + -" cd \"${HOMEBREW_REPOSITORY}\" >/dev/null || return\n" + -" ) || exit 1\n" + -" fi\n" + -"\n" + -" execute \"${HOMEBREW_PREFIX}/bin/brew\" \"update\" \"--force\" \"--quiet\"\n" + -") || exit 1\n" + -"\n" + -"if [[ \":${PATH}:\" != *\":${HOMEBREW_PREFIX}/bin:\"* ]]\n" + -"then\n" + -" warn \"${HOMEBREW_PREFIX}/bin is not in your PATH.\n" + -" Instructions on how to configure your shell for Homebrew\n" + -" can be found in the 'Next steps' section below.\"\n" + -"fi\n" + -"\n" + -"ohai \"Installation successful!\"\n" + -"echo\n" + -"\n" + -"ring_bell\n" + -"\n" + -"# Use an extra newline and bold to avoid this being missed.\n" + -"ohai \"Homebrew has enabled anonymous aggregate formulae and cask analytics.\"\n" + -"echo \"$(\n" + -" cat </dev/null || return\n" + -" execute \"${USABLE_GIT}\" \"config\" \"--replace-all\" \"homebrew.analyticsmessage\" \"true\"\n" + -" execute \"${USABLE_GIT}\" \"config\" \"--replace-all\" \"homebrew.caskanalyticsmessage\" \"true\"\n" + -") || exit 1\n" + -"\n" + -"ohai \"Next steps:\"\n" + -"case \"${SHELL}\" in\n" + -" */bash*)\n" + -" if [[ -n \"${HOMEBREW_ON_LINUX-}\" ]]\n" + -" then\n" + -" shell_rcfile=\"${HOME}/.bashrc\"\n" + -" else\n" + -" shell_rcfile=\"${HOME}/.bash_profile\"\n" + -" fi\n" + -" ;;\n" + -" */zsh*)\n" + -" if [[ -n \"${HOMEBREW_ON_LINUX-}\" ]]\n" + -" then\n" + -" shell_rcfile=\"${ZDOTDIR:-\"${HOME}\"}/.zshrc\"\n" + -" else\n" + -" shell_rcfile=\"${ZDOTDIR:-\"${HOME}\"}/.zprofile\"\n" + -" fi\n" + -" ;;\n" + -" */fish*)\n" + -" shell_rcfile=\"${HOME}/.config/fish/config.fish\"\n" + -" ;;\n" + -" *)\n" + -" shell_rcfile=\"${ENV:-\"${HOME}/.profile\"}\"\n" + -" ;;\n" + -"esac\n" + -"\n" + -"if grep -qs \"eval \\\"\\$(${HOMEBREW_PREFIX}/bin/brew shellenv)\\\"\" \"${shell_rcfile}\"\n" + -"then\n" + -" if ! [[ -x \"$(command -v brew)\" ]]\n" + -" then\n" + -" cat <> ${shell_rcfile}\n" + -" eval \"\\$(${HOMEBREW_PREFIX}/bin/brew shellenv)\"\n" + -"EOS\n" + -"fi\n" + -"\n" + -"if [[ -n \"${non_default_repos}\" ]]\n" + -"then\n" + -" plural=\"\"\n" + -" if [[ \"${#additional_shellenv_commands[@]}\" -gt 1 ]]\n" + -" then\n" + -" plural=\"s\"\n" + -" fi\n" + -" printf -- \"- Run these commands in your terminal to add the non-default Git remote%s for %s:\\n\" \"${plural}\" \"${non_default_repos}\"\n" + -" printf \" echo '# Set PATH, MANPATH, etc., for Homebrew.' >> %s\\n\" \"${shell_rcfile}\"\n" + -" printf \" echo '%s' >> ${shell_rcfile}\\n\" \"${additional_shellenv_commands[@]}\"\n" + -" printf \" %s\\n\" \"${additional_shellenv_commands[@]}\"\n" + -"fi\n" + -"\n" + -"if [[ -n \"${HOMEBREW_ON_LINUX-}\" ]]\n" + -"then\n" + -" echo \"- Install Homebrew's dependencies if you have sudo access:\"\n" + -"\n" + -" if [[ -x \"$(command -v apt-get)\" ]]\n" + -" then\n" + -" echo \" sudo apt-get install build-essential\"\n" + -" elif [[ -x \"$(command -v yum)\" ]]\n" + -" then\n" + -" echo \" sudo yum groupinstall 'Development Tools'\"\n" + -" elif [[ -x \"$(command -v pacman)\" ]]\n" + -" then\n" + -" echo \" sudo pacman -S base-devel\"\n" + -" elif [[ -x \"$(command -v apk)\" ]]\n" + -" then\n" + -" echo \" sudo apk add build-base\"\n" + -" fi\n" + -"\n" + -" cat < Date: Thu, 4 Jul 2024 23:51:02 +0100 Subject: [PATCH 05/18] Attach winston logger to macUpdater --- .gitignore | 3 + electron/update.js | 6 +- package.json | 3 +- yarn.lock | 153 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 156 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 1a841eec3..48f19fa83 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,6 @@ leak_report *.dist *.build /electron/bins/ + +# logs +*.log \ No newline at end of file diff --git a/electron/update.js b/electron/update.js index b975e5ee6..cd9affa5f 100644 --- a/electron/update.js +++ b/electron/update.js @@ -1,18 +1,16 @@ const { publishOptions } = require('./constants/publishOptions'); const electronUpdater = require('electron-updater'); -const electronLogger = require('electron-log'); +const logger = require('./logger'); const macUpdater = new electronUpdater.MacUpdater({ ...publishOptions, channels: ['latest', 'beta', 'alpha'], // automatically update to all channels }); -macUpdater.logger = electronLogger; - macUpdater.setFeedURL({ ...publishOptions }); macUpdater.autoDownload = true; macUpdater.autoInstallOnAppQuit = true; -macUpdater.logger = electronLogger; +macUpdater.logger = logger; module.exports = { macUpdater }; diff --git a/package.json b/package.json index 7b593fe07..6589155ad 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "sass": "^1.72.0", "styled-components": "^6.1.8", "sudo-prompt": "9.2.1", - "usehooks-ts": "^2.14.0" + "usehooks-ts": "^2.14.0", + "winston": "^3.13.0" }, "devDependencies": { "@electron/notarize": "^2.3.0", diff --git a/yarn.lock b/yarn.lock index 66f0d7b22..96dc2f329 100644 --- a/yarn.lock +++ b/yarn.lock @@ -97,11 +97,25 @@ "@chainsafe/persistent-merkle-tree" "^0.4.2" case "^1.6.3" +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + "@ctrl/tinycolor@^3.6.1": version "3.6.1" resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31" integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA== +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@develar/schema-utils@~2.6.5": version "2.6.5" resolved "https://registry.yarnpkg.com/@develar/schema-utils/-/schema-utils-2.6.5.tgz#3ece22c5838402419a6e0425f85742b961d9b6c6" @@ -1240,6 +1254,11 @@ resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.2.5.tgz#1daa6456f40959d06157698a653a9ab0a70281df" integrity sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw== +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + "@types/verror@^1.10.3": version "1.10.10" resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.10.tgz#d5a4b56abac169bfbc8b23d291363a682e6fa087" @@ -1957,7 +1976,7 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -1976,11 +1995,35 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -2420,6 +2463,11 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -2759,6 +2807,11 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -2814,6 +2867,11 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + follow-redirects@^1.12.1, follow-redirects@^1.15.6: version "1.15.6" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" @@ -3312,6 +3370,11 @@ io-ts@1.10.4: dependencies: fp-ts "^1.0.0" +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -3368,6 +3431,11 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" @@ -3517,6 +3585,11 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + lazy-val@^1.0.4, lazy-val@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.5.tgz#6cf3b9f5bc31cee7ee3e369c0832b7583dcd923d" @@ -3600,6 +3673,18 @@ log-symbols@4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +logform@^2.3.2, logform@^2.4.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.0.tgz#8c82a983f05d6eaeb2d75e3decae7a768b2bf9b5" + integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + loose-envify@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -3824,7 +3909,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3914,6 +3999,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -4551,7 +4643,7 @@ read-config-file@6.3.2: json5 "^2.2.0" lazy-val "^1.0.4" -readable-stream@^3.6.0: +readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -4698,6 +4790,11 @@ safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-stable-stringify@^2.3.1: + version "2.4.3" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -4831,6 +4928,13 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + simple-update-notifier@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb" @@ -4902,6 +5006,11 @@ sprintf-js@^1.1.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + stacktrace-parser@^0.1.10: version "0.1.10" resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" @@ -5080,6 +5189,11 @@ temp-file@^3.4.0: async-exit-hook "^2.0.1" fs-extra "^10.0.0" +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -5141,6 +5255,11 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + truncate-utf8-bytes@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" @@ -5297,6 +5416,32 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +winston-transport@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.0.tgz#e302e6889e6ccb7f383b926df6936a5b781bd1f0" + integrity sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg== + dependencies: + logform "^2.3.2" + readable-stream "^3.6.0" + triple-beam "^1.3.0" + +winston@^3.13.0: + version "3.13.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.13.0.tgz#e76c0d722f78e04838158c61adc1287201de7ce3" + integrity sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.4.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.7.0" + word-wrap@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" From 7ce448d4095f662e578f04020b34274ef41b4308 Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 00:20:23 +0100 Subject: [PATCH 06/18] refactor: Remove unused log file paths in electron/main.js --- electron/main.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/electron/main.js b/electron/main.js index e4b875b70..0b08b106a 100644 --- a/electron/main.js +++ b/electron/main.js @@ -570,17 +570,6 @@ function getSanitizedLogs({ name, filePath, data }) { ipcMain.handle('save-logs', async (_, data) => { // version.txt const versionFile = paths.VersionFile; - // logs.txt - const logFile = getSanitizedLogs({ - name: 'log.txt', - filePath: paths.LogFile, - }); - - // // operate.log - // const installationLog = getSanitizedLogs({ - // name: 'installation_log.txt', - // filePath: paths.OperateInstallationLog, - // }); // winston logs const cliLogFile = getSanitizedLogs({ @@ -629,7 +618,6 @@ ipcMain.handle('save-logs', async (_, data) => { // Create a zip archive const zip = new AdmZip(); fs.existsSync(versionFile) && zip.addLocalFile(versionFile); - fs.existsSync(logFile) && zip.addLocalFile(logFile); fs.existsSync(cliLogFile) && zip.addLocalFile(cliLogFile); fs.existsSync(electronLogFile) && zip.addLocalFile(electronLogFile); fs.existsSync(nextLogFile) && zip.addLocalFile(nextLogFile); @@ -655,7 +643,6 @@ ipcMain.handle('save-logs', async (_, data) => { } // Remove temporary files - fs.existsSync(logFile) && fs.unlinkSync(logFile); fs.existsSync(cliLogFile) && fs.unlinkSync(cliLogFile); fs.existsSync(electronLogFile) && fs.unlinkSync(electronLogFile); fs.existsSync(nextLogFile) && fs.unlinkSync(nextLogFile); From 06a95136b3b8cf6b41be3ddc61118cfec7aff0a0 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 5 Jul 2024 10:25:35 +0100 Subject: [PATCH 07/18] refactor: Update file paths for log files in electron/main.js and electron/install.js --- electron/install.js | 6 +++++- electron/logger.js | 5 +++++ electron/main.js | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/electron/install.js b/electron/install.js index b9c6486e3..01fa6291f 100644 --- a/electron/install.js +++ b/electron/install.js @@ -1,3 +1,5 @@ +const { isDev } = require('./constants'); + // Installation helpers. const fs = require('fs'); const os = require('os'); @@ -13,7 +15,9 @@ const { spawnSync } = require('child_process'); * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ const OlasMiddlewareVersion = '0.1.0rc60'; -const OperateDirectory = path.join(os.homedir(), '.operate'); +const OperateDirectory = isDev + ? '.operate' + : path.join(os.homedir(), '.operate'); // Create operate directory if it doesn't exist if (!fs.existsSync(OperateDirectory)) { diff --git a/electron/logger.js b/electron/logger.js index b008524f4..ef36a873f 100644 --- a/electron/logger.js +++ b/electron/logger.js @@ -1,6 +1,8 @@ const winston = require('winston'); const { format } = require('logform'); +const { OperateDirectory } = require('./constants/paths'); + const { combine, timestamp, printf } = format; const logFormat = printf(({ level, message, timestamp }) => { return `${timestamp} ${level}: ${message}`; @@ -40,6 +42,7 @@ const logger = winston.createLogger({ }), new winston.transports.File({ filename: 'cli.log', + dirname: OperateDirectory, level: 'cli', format: combine(levelFilter('cli'), timestamp(), logFormat), maxFiles: 1, @@ -47,6 +50,7 @@ const logger = winston.createLogger({ }), new winston.transports.File({ filename: 'electron.log', + dirname: OperateDirectory, level: 'electron', format: combine(levelFilter('electron'), timestamp(), logFormat), maxFiles: 1, @@ -54,6 +58,7 @@ const logger = winston.createLogger({ }), new winston.transports.File({ filename: 'next.log', + dirname: OperateDirectory, level: 'next', format: combine(levelFilter('next'), timestamp(), logFormat), maxFiles: 1, diff --git a/electron/main.js b/electron/main.js index 0b08b106a..c9b730452 100644 --- a/electron/main.js +++ b/electron/main.js @@ -574,15 +574,15 @@ ipcMain.handle('save-logs', async (_, data) => { // winston logs const cliLogFile = getSanitizedLogs({ name: 'cli.log', - filePath: 'cli.log', + filePath: path.join(paths.OperateDirectory, 'cli.log'), }); const nextLogFile = getSanitizedLogs({ name: 'next.log', - filePath: 'next.log', + filePath: path.join(paths.OperateDirectory, 'next.log'), }); const electronLogFile = getSanitizedLogs({ name: 'electron.log', - filePath: 'electron.log', + filePath: path.join(paths.OperateDirectory, 'electron.log'), }); const tempDir = os.tmpdir(); From bc9bf56c3e8350ec27ca8d475bf8a94c42742f74 Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 10:44:45 +0100 Subject: [PATCH 08/18] assign logs to .operate folder --- electron/install.js | 9 ++++----- electron/logger.js | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/electron/install.js b/electron/install.js index 01fa6291f..57afe207f 100644 --- a/electron/install.js +++ b/electron/install.js @@ -1,5 +1,3 @@ -const { isDev } = require('./constants'); - // Installation helpers. const fs = require('fs'); const os = require('os'); @@ -15,9 +13,10 @@ const { spawnSync } = require('child_process'); * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ const OlasMiddlewareVersion = '0.1.0rc60'; -const OperateDirectory = isDev - ? '.operate' - : path.join(os.homedir(), '.operate'); +const OperateDirectory = + process.env.NODE_ENV === 'production' + ? path.join(os.homedir(), '.operate') + : '.operate'; // Create operate directory if it doesn't exist if (!fs.existsSync(OperateDirectory)) { diff --git a/electron/logger.js b/electron/logger.js index ef36a873f..6e6e5301d 100644 --- a/electron/logger.js +++ b/electron/logger.js @@ -1,7 +1,6 @@ const winston = require('winston'); const { format } = require('logform'); - -const { OperateDirectory } = require('./constants/paths'); +const { paths } = require('./install'); const { combine, timestamp, printf } = format; const logFormat = printf(({ level, message, timestamp }) => { @@ -42,7 +41,7 @@ const logger = winston.createLogger({ }), new winston.transports.File({ filename: 'cli.log', - dirname: OperateDirectory, + dirname: paths.OperateDirectory, level: 'cli', format: combine(levelFilter('cli'), timestamp(), logFormat), maxFiles: 1, @@ -50,7 +49,7 @@ const logger = winston.createLogger({ }), new winston.transports.File({ filename: 'electron.log', - dirname: OperateDirectory, + dirname: paths.OperateDirectory, level: 'electron', format: combine(levelFilter('electron'), timestamp(), logFormat), maxFiles: 1, @@ -58,7 +57,7 @@ const logger = winston.createLogger({ }), new winston.transports.File({ filename: 'next.log', - dirname: OperateDirectory, + dirname: paths.OperateDirectory, level: 'next', format: combine(levelFilter('next'), timestamp(), logFormat), maxFiles: 1, From 34cd493c90c36ce133d5a4be29bd62562a983755 Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 10:47:01 +0100 Subject: [PATCH 09/18] fix venv, temp and version paths --- electron/install.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/electron/install.js b/electron/install.js index 57afe207f..08bfd321b 100644 --- a/electron/install.js +++ b/electron/install.js @@ -25,9 +25,9 @@ if (!fs.existsSync(OperateDirectory)) { const paths = { OperateDirectory, - VenvDir: path.join(OperateDirectory, '.operate', 'venv'), - TempDir: path.join(OperateDirectory, '.operate', 'temp'), - VersionFile: path.join(OperateDirectory, '.operate', 'version.txt'), + VenvDir: path.join(OperateDirectory, 'venv'), + TempDir: path.join(OperateDirectory, 'temp'), + VersionFile: path.join(OperateDirectory, 'version.txt'), }; const Env = { From 833c5d6e5bca7078b36d30f82a7a7c4602fa7966 Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:05:51 +0100 Subject: [PATCH 10/18] cleanup paths object --- electron/constants/paths.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 electron/constants/paths.js diff --git a/electron/constants/paths.js b/electron/constants/paths.js new file mode 100644 index 000000000..32c7325cc --- /dev/null +++ b/electron/constants/paths.js @@ -0,0 +1,27 @@ +const os = require('os'); +const path = require('path'); +const fs = require('fs'); + +const dotOperateDirectory = + process.env.NODE_ENV === 'production' + ? path.join(os.homedir(), '.operate') + : '.operate'; + +// Create operate directory if it doesn't exist +if (!fs.existsSync(dotOperateDirectory)) { + fs.mkdirSync(dotOperateDirectory); +} + +const paths = { + dotOperateDirectory, + servicesDir: path.join(dotOperateDirectory, 'services'), + venvDir: path.join(dotOperateDirectory, 'venv'), + tempDir: path.join(dotOperateDirectory, 'temp'), + versionFile: path.join(dotOperateDirectory, 'version.txt'), + cliLogFile: path.join(dotOperateDirectory, 'cli.log'), + electronLogFile: path.join(dotOperateDirectory, 'electron.log'), + nextLogFile: path.join(dotOperateDirectory, 'next.log'), + osPearlTempDir: path.join(os.tmpdir(), 'pearl'), +}; + +module.exports = { paths }; From db787907a73f460dd919d660e7197ee11040167e Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:06:10 +0100 Subject: [PATCH 11/18] move paths to an appropriate constants file --- electron/install.js | 56 ++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/electron/install.js b/electron/install.js index 08bfd321b..6ad242ac2 100644 --- a/electron/install.js +++ b/electron/install.js @@ -1,34 +1,19 @@ // Installation helpers. const fs = require('fs'); const os = require('os'); -const path = require('path'); const sudo = require('sudo-prompt'); const process = require('process'); const axios = require('axios'); const { spawnSync } = require('child_process'); +const { paths } = require('./constants/paths'); + /** * current version of the pearl release * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ const OlasMiddlewareVersion = '0.1.0rc60'; -const OperateDirectory = - process.env.NODE_ENV === 'production' - ? path.join(os.homedir(), '.operate') - : '.operate'; - -// Create operate directory if it doesn't exist -if (!fs.existsSync(OperateDirectory)) { - fs.mkdirSync(OperateDirectory); -} - -const paths = { - OperateDirectory, - VenvDir: path.join(OperateDirectory, 'venv'), - TempDir: path.join(OperateDirectory, 'temp'), - VersionFile: path.join(OperateDirectory, 'version.txt'), -}; const Env = { ...process.env, @@ -153,7 +138,7 @@ async function downloadFile(url, dest) { async function installTendermintUnix() { const cwd = process.cwd(); - process.chdir(paths.TempDir); + process.chdir(paths.tempDir); console.log( appendInstallationLog( @@ -165,7 +150,7 @@ async function installTendermintUnix() { console.log( appendInstallationLog(`Downloading ${url}, might take a while...`), ); - await downloadFile(url, `${paths.TempDir}/tendermint.tar.gz`); + await downloadFile(url, `${paths.tempDir}/tendermint.tar.gz`); console.log(appendInstallationLog(`Installing tendermint binary`)); runCmdUnix('tar', ['-xvf', 'tendermint.tar.gz']); @@ -227,7 +212,7 @@ function installOperateCli(path) { } return new Promise((resolve, _reject) => { fs.copyFile( - `${OperateDirectory}/venv/bin/operate`, + `${paths.dotOperateDirectory}/venv/bin/operate`, installPath, function (error, _stdout, _stderr) { resolve(!error); @@ -248,15 +233,15 @@ function createDirectory(path) { } function writeVersion() { - fs.writeFileSync(paths.VersionFile, OlasMiddlewareVersion); + fs.writeFileSync(paths.versionFile, OlasMiddlewareVersion); } function versionBumpRequired() { - if (!fs.existsSync(paths.VersionFile)) { + if (!fs.existsSync(paths.versionFile)) { return true; } const olasMiddlewareVersionInFile = fs - .readFileSync(paths.VersionFile) + .readFileSync(paths.versionFile) .toString(); return olasMiddlewareVersionInFile != OlasMiddlewareVersion; } @@ -280,8 +265,8 @@ function removeInstallationLogFile() { async function setupDarwin(ipcChannel) { removeInstallationLogFile(); console.log(appendInstallationLog('Creating required directories')); - await createDirectory(`${OperateDirectory}`); - await createDirectory(`${OperateDirectory}/temp`); + await createDirectory(`${paths.dotOperateDirectory}`); + await createDirectory(`${paths.dotOperateDirectory}/temp`); console.log(appendInstallationLog('Checking tendermint installation')); if (!isTendermintInstalledUnix()) { @@ -311,19 +296,19 @@ async function setupUbuntu(ipcChannel) { if (!isPythonInstalledUbuntu()) { ipcChannel.send('response', 'Installing Pearl Daemon'); console.log(appendInstallationLog('Installing Python')); - await installPythonUbuntu(OperateDirectory); + await installPythonUbuntu(paths.dotOperateDirectory); } console.log(appendInstallationLog('Checking git installation')); if (!isGitInstalledUbuntu()) { ipcChannel.send('response', 'Installing Pearl Daemon'); console.log(appendInstallationLog('Installing git')); - await installGitUbuntu(OperateDirectory); + await installGitUbuntu(paths.dotOperateDirectory); } console.log(appendInstallationLog('Creating required directories')); - await createDirectory(`${OperateDirectory}`); - await createDirectory(`${OperateDirectory}/temp`); + await createDirectory(`${paths.dotOperateDirectory}`); + await createDirectory(`${paths.dotOperateDirectory}/temp`); console.log(appendInstallationLog('Checking tendermint installation')); if (!isTendermintInstalledUnix()) { @@ -332,13 +317,13 @@ async function setupUbuntu(ipcChannel) { await installTendermintUnix(); } - if (!fs.existsSync(paths.VenvDir)) { + if (!fs.existsSync(paths.venvDir)) { ipcChannel.send('response', 'Installing Pearl Daemon'); console.log(appendInstallationLog('Creating virtual environment')); - createVirtualEnvUnix(paths.VenvDir); + createVirtualEnvUnix(paths.venvDir); console.log(appendInstallationLog('Installing pearl backend')); - installOperatePackageUnix(OperateDirectory); + installOperatePackageUnix(paths.dotOperateDirectory); } console.log(appendInstallationLog('Checking if upgrade is required')); @@ -348,13 +333,13 @@ async function setupUbuntu(ipcChannel) { `Upgrading pearl daemon to ${OlasMiddlewareVersion}`, ), ); - reInstallOperatePackageUnix(OperateDirectory); + reInstallOperatePackageUnix(paths.dotOperateDirectory); writeVersion(); removeLogFile(); } - if (!fs.existsSync(`${OperateDirectory}/venv/bin/operate`)) { - reInstallOperatePackageUnix(OperateDirectory); + if (!fs.existsSync(`${paths.dotOperateDirectory}/venv/bin/operate`)) { + reInstallOperatePackageUnix(paths.dotOperateDirectory); } console.log(appendInstallationLog('Installing pearl CLI')); @@ -365,5 +350,4 @@ module.exports = { setupDarwin, setupUbuntu, Env, - paths, }; From 2d90e8151687dcac7016809a39ade2552257f56f Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:06:31 +0100 Subject: [PATCH 12/18] update paths for log writes --- electron/logger.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/electron/logger.js b/electron/logger.js index 6e6e5301d..7c1a318c2 100644 --- a/electron/logger.js +++ b/electron/logger.js @@ -1,8 +1,9 @@ const winston = require('winston'); const { format } = require('logform'); -const { paths } = require('./install'); +const { paths } = require('./constants/paths'); const { combine, timestamp, printf } = format; + const logFormat = printf(({ level, message, timestamp }) => { return `${timestamp} ${level}: ${message}`; }); @@ -41,7 +42,7 @@ const logger = winston.createLogger({ }), new winston.transports.File({ filename: 'cli.log', - dirname: paths.OperateDirectory, + dirname: paths.dotOperateDirectory, level: 'cli', format: combine(levelFilter('cli'), timestamp(), logFormat), maxFiles: 1, @@ -49,7 +50,7 @@ const logger = winston.createLogger({ }), new winston.transports.File({ filename: 'electron.log', - dirname: paths.OperateDirectory, + dirname: paths.dotOperateDirectory, level: 'electron', format: combine(levelFilter('electron'), timestamp(), logFormat), maxFiles: 1, @@ -57,7 +58,7 @@ const logger = winston.createLogger({ }), new winston.transports.File({ filename: 'next.log', - dirname: paths.OperateDirectory, + dirname: paths.dotOperateDirectory, level: 'next', format: combine(levelFilter('next'), timestamp(), logFormat), maxFiles: 1, From 727b50a990e40373bcbdaa4f57f8e15460026bfa Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:07:08 +0100 Subject: [PATCH 13/18] better log exports --- electron/main.js | 107 +++++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/electron/main.js b/electron/main.js index c9b730452..f9526e877 100644 --- a/electron/main.js +++ b/electron/main.js @@ -19,8 +19,9 @@ const http = require('http'); const AdmZip = require('adm-zip'); const { TRAY_ICONS, TRAY_ICONS_PATHS } = require('./icons'); -const { paths, Env } = require('./install'); +const { Env } = require('./install'); +const { paths } = require('./constants/paths'); const { killProcesses } = require('./processes'); const { isPortAvailable, findAvailablePort } = require('./ports'); const { PORT_RANGE, isWindows, isMac } = require('./constants'); @@ -277,7 +278,7 @@ async function launchDaemon() { await fetch(`http://localhost:${appConfig.ports.prod.operate}/api`); logger.electron('Killing backend server!'); let endpoint = fs - .readFileSync(`${paths.OperateDirectory}/operate.kill`) + .readFileSync(`${paths.dotOperateDirectory}/operate.kill`) .toString() .trim(); @@ -295,7 +296,7 @@ async function launchDaemon() { [ 'daemon', `--port=${appConfig.ports.prod.operate}`, - `--home=${paths.OperateDirectory}`, + `--home=${paths.dotOperateDirectory}`, ], { env: Env }, ); @@ -551,16 +552,30 @@ ipcMain.on('open-path', (_, filePath) => { shell.openPath(filePath); }); -function getSanitizedLogs({ name, filePath, data }) { +/** + * Sanitizes logs by replacing usernames in the log data with asterisks. + * If a file path is provided, it reads the log data from the file and sanitizes it. + * If the file path does not exist, it returns null. + * If no file path is provided, it sanitizes the provided data directly. + * The sanitized log data is then written to a file in the temporary directory. + * @param {Object} options - The options for sanitizing logs. + * @param {string} options.name - The name of the log file. + * @param {string} [options.filePath] - The file path to read the log data from. + * @param {string} [options.data] - The log data to sanitize if no file path is provided. + * @returns {string|null} - The file path of the sanitized log data, or null if the file path does not exist. + */ +function sanitizeLogs({ name, filePath, data }) { if (filePath && !fs.existsSync(filePath)) return null; const logs = filePath ? fs.readFileSync(filePath, 'utf-8') : data; - const tempDir = os.tmpdir(); const usernameRegex = /\/Users\/([^/]+)/g; const sanitizedData = logs.replace(usernameRegex, '/Users/*****'); - const sanitizedLogsFilePath = path.join(tempDir, name); + const sanitizedLogsFilePath = path.join(paths.osPearlTempDir, name); + + if (!fs.existsSync(paths.osPearlTempDir)) fs.mkdirSync(paths.osPearlTempDir); + fs.writeFileSync(sanitizedLogsFilePath, sanitizedData); return sanitizedLogsFilePath; @@ -568,25 +583,21 @@ function getSanitizedLogs({ name, filePath, data }) { // EXPORT LOGS ipcMain.handle('save-logs', async (_, data) => { - // version.txt - const versionFile = paths.VersionFile; - - // winston logs - const cliLogFile = getSanitizedLogs({ + sanitizeLogs({ name: 'cli.log', - filePath: path.join(paths.OperateDirectory, 'cli.log'), + filePath: paths.cliLogFile, }); - const nextLogFile = getSanitizedLogs({ + + sanitizeLogs({ name: 'next.log', - filePath: path.join(paths.OperateDirectory, 'next.log'), + filePath: paths.nextLogFile, }); - const electronLogFile = getSanitizedLogs({ + + sanitizeLogs({ name: 'electron.log', - filePath: path.join(paths.OperateDirectory, 'electron.log'), + filePath: paths.electronLogFile, }); - const tempDir = os.tmpdir(); - // OS info const osInfo = ` OS Type: ${os.type()} @@ -596,34 +607,57 @@ ipcMain.handle('save-logs', async (_, data) => { Total Memory: ${os.totalmem()} Free Memory: ${os.freemem()} `; - const osInfoFilePath = path.join(tempDir, 'os_info.txt'); + const osInfoFilePath = path.join(paths.osPearlTempDir, 'os_info.txt'); fs.writeFileSync(osInfoFilePath, osInfo); // Persistent store - let storeFilePath; + let storeFile; if (data.store) { - storeFilePath = path.join(tempDir, 'store.txt'); - fs.writeFileSync(storeFilePath, JSON.stringify(data.store, null, 2)); + storeFile = path.join(paths.osPearlTempDir, 'store.txt'); + fs.writeFileSync(storeFile, JSON.stringify(data.store, null, 2)); } // Other debug data: balances, addresses, etc. - let debugDataFilePath; if (data.debugData) { - debugDataFilePath = getSanitizedLogs({ + sanitizeLogs({ name: 'debug_data.txt', data: JSON.stringify(data.debugData, null, 2), }); } + // Agent logs + try { + fs.readdirSync(paths.servicesDir).map((serviceDirName) => { + const servicePath = path.join(paths.servicesDir, serviceDirName); + if (!fs.existsSync(servicePath)) return; + if (!fs.statSync(servicePath).isDirectory()) return; + + const agentLogFilePath = path.join( + servicePath, + 'deployment', + 'agent', + 'log.txt', + ); + if (!fs.existsSync(agentLogFilePath)) return; + + return sanitizeLogs({ + name: `${serviceDirName}_agent.log`, + filePath: agentLogFilePath, + }); + }); + } catch (e) { + logger.electron(e); + } + // Create a zip archive const zip = new AdmZip(); - fs.existsSync(versionFile) && zip.addLocalFile(versionFile); - fs.existsSync(cliLogFile) && zip.addLocalFile(cliLogFile); - fs.existsSync(electronLogFile) && zip.addLocalFile(electronLogFile); - fs.existsSync(nextLogFile) && zip.addLocalFile(nextLogFile); - fs.existsSync(osInfoFilePath) && zip.addLocalFile(osInfoFilePath); - fs.existsSync(storeFilePath) && zip.addLocalFile(storeFilePath); - fs.existsSync(debugDataFilePath) && zip.addLocalFile(debugDataFilePath); + fs.readdirSync(paths.osPearlTempDir).forEach((file) => { + const filePath = path.join(paths.osPearlTempDir, file); + if (!fs.existsSync(filePath)) return; + if (fs.statSync(filePath).isDirectory()) return; + + zip.addLocalFile(filePath); + }); // Show save dialog const { filePath } = await dialog.showSaveDialog({ @@ -643,12 +677,11 @@ ipcMain.handle('save-logs', async (_, data) => { } // Remove temporary files - fs.existsSync(cliLogFile) && fs.unlinkSync(cliLogFile); - fs.existsSync(electronLogFile) && fs.unlinkSync(electronLogFile); - fs.existsSync(nextLogFile) && fs.unlinkSync(nextLogFile); - fs.existsSync(osInfo) && fs.unlinkSync(osInfoFilePath); - fs.existsSync(storeFilePath) && fs.unlinkSync(storeFilePath); - fs.existsSync(debugDataFilePath) && fs.unlinkSync(debugDataFilePath); + fs.existsSync(paths.osPearlTempDir) && + fs.rmSync(paths.osPearlTempDir, { + recursive: true, + force: true, + }); return result; }); From f7eaa6c95d7ccc1e95a69ab7b552fd0b71b84bf5 Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:17:12 +0100 Subject: [PATCH 14/18] Update electron/logger.js --- electron/logger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electron/logger.js b/electron/logger.js index 7c1a318c2..444d0f926 100644 --- a/electron/logger.js +++ b/electron/logger.js @@ -37,7 +37,7 @@ const logger = winston.createLogger({ levels: customLevels.levels, transports: [ new winston.transports.Console({ - level: 'electron', + level: 'electron', // Set to the highest level so it captures everything. format: combine(winston.format.colorize(), timestamp(), logFormat), }), new winston.transports.File({ From 140fee5f81305472bd9a3ff268fc327f793e96b8 Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:23:57 +0100 Subject: [PATCH 15/18] refactor: Update file paths for log files in electron/main.js and electron/install.js --- electron/main.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/electron/main.js b/electron/main.js index f9526e877..77f7fd987 100644 --- a/electron/main.js +++ b/electron/main.js @@ -611,19 +611,18 @@ ipcMain.handle('save-logs', async (_, data) => { fs.writeFileSync(osInfoFilePath, osInfo); // Persistent store - let storeFile; - if (data.store) { - storeFile = path.join(paths.osPearlTempDir, 'store.txt'); - fs.writeFileSync(storeFile, JSON.stringify(data.store, null, 2)); - } + if (data.store) + sanitizeLogs({ + name: 'store.txt', + data: JSON.stringify(data.store, null, 2), + }); // Other debug data: balances, addresses, etc. - if (data.debugData) { + if (data.debugData) sanitizeLogs({ name: 'debug_data.txt', data: JSON.stringify(data.debugData, null, 2), }); - } // Agent logs try { @@ -667,7 +666,6 @@ ipcMain.handle('save-logs', async (_, data) => { }); let result; - if (filePath) { // Write the zip file to the selected path zip.writeZip(filePath); From b96e9317492db0d477f27f5cd0320c3452aeb84d Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:34:02 +0100 Subject: [PATCH 16/18] refactor: Update log file paths and add destination path for sanitization --- electron/main.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/electron/main.js b/electron/main.js index 77f7fd987..815f6aaa0 100644 --- a/electron/main.js +++ b/electron/main.js @@ -560,21 +560,26 @@ ipcMain.on('open-path', (_, filePath) => { * The sanitized log data is then written to a file in the temporary directory. * @param {Object} options - The options for sanitizing logs. * @param {string} options.name - The name of the log file. - * @param {string} [options.filePath] - The file path to read the log data from. - * @param {string} [options.data] - The log data to sanitize if no file path is provided. + * @param {string} options.filePath - The file path to read the log data from. + * @param {string} options.data - The log data to sanitize if no file path is provided. + * @param {string} options.destPath - The destination path where the logs should be stored after sanitization. * @returns {string|null} - The file path of the sanitized log data, or null if the file path does not exist. */ -function sanitizeLogs({ name, filePath, data }) { +function sanitizeLogs({ + name, + filePath, + data, + destPath = paths.osPearlTempDir, +}) { if (filePath && !fs.existsSync(filePath)) return null; const logs = filePath ? fs.readFileSync(filePath, 'utf-8') : data; const usernameRegex = /\/Users\/([^/]+)/g; const sanitizedData = logs.replace(usernameRegex, '/Users/*****'); + const sanitizedLogsFilePath = path.join(destPath, name); - const sanitizedLogsFilePath = path.join(paths.osPearlTempDir, name); - - if (!fs.existsSync(paths.osPearlTempDir)) fs.mkdirSync(paths.osPearlTempDir); + if (!fs.existsSync(destPath)) fs.mkdirSync(destPath); fs.writeFileSync(sanitizedLogsFilePath, sanitizedData); From d6b2d401d2873a6724ba2132045bd8f8b901694c Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:34:56 +0100 Subject: [PATCH 17/18] refactor: Update log file paths and add destination path for sanitization --- electron/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electron/main.js b/electron/main.js index 815f6aaa0..090dff450 100644 --- a/electron/main.js +++ b/electron/main.js @@ -557,7 +557,7 @@ ipcMain.on('open-path', (_, filePath) => { * If a file path is provided, it reads the log data from the file and sanitizes it. * If the file path does not exist, it returns null. * If no file path is provided, it sanitizes the provided data directly. - * The sanitized log data is then written to a file in the temporary directory. + * The sanitized log data is then written to the destination path. * @param {Object} options - The options for sanitizing logs. * @param {string} options.name - The name of the log file. * @param {string} options.filePath - The file path to read the log data from. From a31a368e67925eebb00425c152c6d48b346e7aab Mon Sep 17 00:00:00 2001 From: truemiller <31908788+truemiller@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:13:53 +0100 Subject: [PATCH 18/18] Extend santization regex to support Linux and Mac. Add version and date ISO string to export zip. --- electron/main.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/electron/main.js b/electron/main.js index 090dff450..c7edf4263 100644 --- a/electron/main.js +++ b/electron/main.js @@ -575,8 +575,8 @@ function sanitizeLogs({ const logs = filePath ? fs.readFileSync(filePath, 'utf-8') : data; - const usernameRegex = /\/Users\/([^/]+)/g; - const sanitizedData = logs.replace(usernameRegex, '/Users/*****'); + const usernameRegex = /\/(Users|home)\/([^/]+)/g; + const sanitizedData = logs.replace(usernameRegex, '/$1/*****'); const sanitizedLogsFilePath = path.join(destPath, name); if (!fs.existsSync(destPath)) fs.mkdirSync(destPath); @@ -666,7 +666,10 @@ ipcMain.handle('save-logs', async (_, data) => { // Show save dialog const { filePath } = await dialog.showSaveDialog({ title: 'Save Logs', - defaultPath: path.join(os.homedir(), 'pearl_logs.zip'), + defaultPath: path.join( + os.homedir(), + `pearl_logs_${new Date(Date.now()).toISOString()}-${app.getVersion()}.zip`, + ), filters: [{ name: 'Zip Files', extensions: ['zip'] }], });