diff --git a/desktop/src/main.ts b/desktop/src/main.ts index e8c290af9..eafcc009a 100644 --- a/desktop/src/main.ts +++ b/desktop/src/main.ts @@ -8,7 +8,6 @@ * * https://www.electronjs.org/docs/latest/tutorial/process-model#the-main-process */ -import log from "electron-log"; import { app, BrowserWindow } from "electron/main"; import serveNextAt from "next-electron-server"; import { existsSync } from "node:fs"; @@ -27,7 +26,7 @@ import { setupTrayItem, } from "./main/init"; import { attachFSWatchIPCHandlers, attachIPCHandlers } from "./main/ipc"; -import { initLogging, logErrorSentry } from "./main/log"; +import log, { initLogging } from "./main/log"; import { initWatcher } from "./services/chokidar"; let appIsQuitting = false; @@ -182,7 +181,7 @@ const main = () => { } catch (e) { // Log but otherwise ignore errors during non-critical startup // actions - logErrorSentry(e, "Ignoring startup error"); + log.error("Ignoring startup error", e); } }); diff --git a/desktop/src/main/init.ts b/desktop/src/main/init.ts index 0a12da353..af79f39ad 100644 --- a/desktop/src/main/init.ts +++ b/desktop/src/main/init.ts @@ -1,18 +1,15 @@ import { app, BrowserWindow, Menu, nativeImage, Tray } from "electron"; -import ElectronLog from "electron-log"; import { existsSync } from "node:fs"; -import os from "os"; -import path from "path"; -import util from "util"; +import os from "node:os"; +import path from "node:path"; import { isAppQuitting, rendererURL } from "../main"; import { setupAutoUpdater } from "../services/appUpdater"; import autoLauncher from "../services/autoLauncher"; import { getHideDockIconPreference } from "../services/userPreference"; import { isPlatform } from "../utils/common/platform"; import { buildContextMenu, buildMenuBar } from "../utils/menu"; -import { isDev } from "./general"; -import { logErrorSentry } from "./log"; -const execAsync = util.promisify(require("child_process").exec); +import log from "./log"; +import { isDev } from "./util"; /** * Create an return the {@link BrowserWindow} that will form our app's UI. @@ -167,25 +164,22 @@ export async function handleDockIconHideOnAutoLaunch() { } } -export function logSystemInfo() { +export function logStartupBanner() { + const version = isDev ? "dev" : app.getVersion(); + log.info(`hello from ente-photos-desktop ${version}`); + const systemVersion = process.getSystemVersion(); const osName = process.platform; const osRelease = os.release(); - ElectronLog.info({ osName, osRelease, systemVersion }); - const appVersion = app.getVersion(); - ElectronLog.info({ appVersion }); + log.info(`system info ${{ osName, osRelease, systemVersion }}`); } -export async function checkIfInstalledViaBrew() { - if (!isPlatform("mac")) { - return false; - } +async function checkIfInstalledViaBrew() { + if (process.platform != "darwin") return false; try { await execAsync("brew list --cask ente"); - ElectronLog.info("ente installed via brew"); return true; } catch (e) { - ElectronLog.info("ente not installed via brew"); return false; } } diff --git a/desktop/src/main/ipc.ts b/desktop/src/main/ipc.ts index beac3b721..be9798186 100644 --- a/desktop/src/main/ipc.ts +++ b/desktop/src/main/ipc.ts @@ -65,8 +65,8 @@ import { saveFileToDisk, saveStreamToDisk, } from "./fs"; -import { openDirectory, openLogDirectory } from "./general"; import { logToDisk } from "./log"; +import { openDirectory, openLogDirectory } from "./util"; /** * Listen for IPC events sent/invoked by the renderer process, and route them to diff --git a/desktop/src/main/log.ts b/desktop/src/main/log.ts index 323c71e97..25e025d82 100644 --- a/desktop/src/main/log.ts +++ b/desktop/src/main/log.ts @@ -1,5 +1,5 @@ import log from "electron-log"; -import { isDev } from "./general"; +import { isDev } from "./util"; /** * Initialize logging in the main process. diff --git a/desktop/src/main/general.ts b/desktop/src/main/util.ts similarity index 64% rename from desktop/src/main/general.ts rename to desktop/src/main/util.ts index e0b7654fe..4933e5ff4 100644 --- a/desktop/src/main/general.ts +++ b/desktop/src/main/util.ts @@ -1,10 +1,31 @@ +import shellescape from "any-shell-escape"; import { shell } from "electron"; /* TODO(MR): Why is this not in /main? */ import { app } from "electron/main"; +import { exec } from "node:child_process"; import path from "node:path"; +import { promisify } from "node:util"; /** `true` if the app is running in development mode. */ export const isDev = !app.isPackaged; +/** + * Run a shell command asynchronously. + * + * This is a convenience promisified version of child_process.exec. It runs the + * command asynchronously and returns its stdout and stderr if there were no + * errors. + * + * It also shellescapes the command before running it. + * + * Note: This is not a 1-1 replacement of child_process.exec - if you're trying + * to run a trivial shell command, say something that produces a lot of output, + * this might not be the best option and it might be better to use the + * underlying functions. + */ +export const execAsync = (command: string) => execAsync_(shellescape(command)); + +const execAsync_ = promisify(exec); + /** * Open the given {@link dirPath} in the system's folder viewer. * diff --git a/desktop/src/services/clipService.ts b/desktop/src/services/clipService.ts index 049b706b6..697905450 100644 --- a/desktop/src/services/clipService.ts +++ b/desktop/src/services/clipService.ts @@ -6,8 +6,8 @@ import path from "node:path"; import util from "util"; import { CustomErrors } from "../constants/errors"; import { writeStream } from "../main/fs"; -import { isDev } from "../main/general"; import { logErrorSentry } from "../main/log"; +import { isDev } from "../main/util"; import { Model } from "../types/ipc"; import Tokenizer from "../utils/clip-bpe-ts/mod"; import { getPlatform } from "../utils/common/platform"; diff --git a/desktop/src/services/imageProcessor.ts b/desktop/src/services/imageProcessor.ts index ffb86edea..374afe9ad 100644 --- a/desktop/src/services/imageProcessor.ts +++ b/desktop/src/services/imageProcessor.ts @@ -5,8 +5,8 @@ import fs from "node:fs/promises"; import path from "path"; import util from "util"; import { CustomErrors } from "../constants/errors"; +import { isDev } from "../main"; import { writeStream } from "../main/fs"; -import { isDev } from "../main/general"; import { logError, logErrorSentry } from "../main/log"; import { ElectronFile } from "../types/ipc"; import { isPlatform } from "../utils/common/platform"; diff --git a/desktop/src/types/any-shell-escape.d.ts b/desktop/src/types/any-shell-escape.d.ts new file mode 100644 index 000000000..4172cdb1e --- /dev/null +++ b/desktop/src/types/any-shell-escape.d.ts @@ -0,0 +1,25 @@ +/** + * Escape and stringify an array of arguments to be executed on the shell. + * + * @example + * + * const shellescape = require('any-shell-escape'); + * + * const args = ['curl', '-v', '-H', 'Location;', '-H', "User-Agent: FooBar's so-called \"Browser\"", 'http://www.daveeddy.com/?name=dave&age=24']; + * + * const escaped = shellescape(args); + * console.log(escaped); + * + * yields (on POSIX shells): + * + * curl -v -H 'Location;' -H 'User-Agent: FoorBar'"'"'s so-called "Browser"' 'http://www.daveeddy.com/?name=dave&age=24' + * + * or (on Windows): + * + * curl -v -H "Location;" -H "User-Agent: FooBar's so-called ""Browser""" "http://www.daveeddy.com/?name=dave&age=24" +Which is suitable for being executed by the shell. + */ +declare module "any-shell-escape" { + declare const shellescape: (args: readonly string | string[]) => string; + export default shellescape; +} diff --git a/desktop/src/utils/menu.ts b/desktop/src/utils/menu.ts index 941d8ae25..5604cabce 100644 --- a/desktop/src/utils/menu.ts +++ b/desktop/src/utils/menu.ts @@ -6,8 +6,7 @@ import { shell, } from "electron"; import ElectronLog from "electron-log"; -import { setIsAppQuitting } from "../main"; -import { openDirectory, openLogDirectory } from "../main/general"; +import { openDirectory, openLogDirectory, setIsAppQuitting } from "../main"; import { forceCheckForUpdateAndNotify } from "../services/appUpdater"; import autoLauncher from "../services/autoLauncher"; import { @@ -188,7 +187,8 @@ export async function buildMenuBar(mainWindow: BrowserWindow): Promise { submenu: [ { label: "Ente Help", - click: () => shell.openExternal("https://help.ente.io/photos/"), + click: () => + shell.openExternal("https://help.ente.io/photos/"), }, { type: "separator" }, {