Update data and config paths to match platform defaults (#1047)

Going forward for new installations, config and data files will be
stored at the platform default paths, as defined by
[env-paths](https://www.npmjs.com/package/env-paths).

For backwards compatibility, if the `~/.waveterm` or `WAVETERM_HOME`
directory exists and contains valid data, it will be used. If this check
fails, then `WAVETERM_DATA_HOME` and `WAVETERM_CONFIG_HOME` will be
used. If these are not defined, then `XDG_DATA_HOME` and
`XDG_CONFIG_HOME` will be used. Finally, if none of these are defined,
the [env-paths](https://www.npmjs.com/package/env-paths) defaults will
be used.

As with the existing app, dev instances will write to `waveterm-dev`
directories, while all others will write to `waveterm`.
This commit is contained in:
Evan Simkowitz 2024-10-22 09:26:58 -07:00 committed by GitHub
parent 39fff9ecfd
commit 33f05c6e0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 247 additions and 111 deletions

View File

@ -184,8 +184,8 @@ tasks:
generate: generate:
desc: Generate Typescript bindings for the Go backend. desc: Generate Typescript bindings for the Go backend.
cmds: cmds:
- go run cmd/generatets/main-generatets.go - NO_PANIC=1 go run cmd/generatets/main-generatets.go
- go run cmd/generatego/main-generatego.go - NO_PANIC=1 go run cmd/generatego/main-generatego.go
sources: sources:
- "cmd/generatego/*.go" - "cmd/generatego/*.go"
- "cmd/generatets/*.go" - "cmd/generatets/*.go"

View File

@ -182,7 +182,7 @@ func main() {
log.Printf("error validating service map: %v\n", err) log.Printf("error validating service map: %v\n", err)
return return
} }
err = wavebase.EnsureWaveHomeDir() err = wavebase.EnsureWaveDataDir()
if err != nil { if err != nil {
log.Printf("error ensuring wave home dir: %v\n", err) log.Printf("error ensuring wave home dir: %v\n", err)
return return
@ -192,14 +192,14 @@ func main() {
log.Printf("error ensuring wave db dir: %v\n", err) log.Printf("error ensuring wave db dir: %v\n", err)
return return
} }
err = wconfig.EnsureWaveConfigDir() err = wavebase.EnsureWaveConfigDir()
if err != nil { if err != nil {
log.Printf("error ensuring wave config dir: %v\n", err) log.Printf("error ensuring wave config dir: %v\n", err)
return return
} }
// TODO: rather than ensure this dir exists, we should let the editor recursively create parent dirs on save // TODO: rather than ensure this dir exists, we should let the editor recursively create parent dirs on save
err = wconfig.EnsureWavePresetsDir() err = wavebase.EnsureWavePresetsDir()
if err != nil { if err != nil {
log.Printf("error ensuring wave presets dir: %v\n", err) log.Printf("error ensuring wave presets dir: %v\n", err)
return return
@ -216,7 +216,8 @@ func main() {
} }
}() }()
log.Printf("wave version: %s (%s)\n", WaveVersion, BuildTime) log.Printf("wave version: %s (%s)\n", WaveVersion, BuildTime)
log.Printf("wave home dir: %s\n", wavebase.GetWaveHomeDir()) log.Printf("wave data dir: %s\n", wavebase.GetWaveDataDir())
log.Printf("wave config dir: %s\n", wavebase.GetWaveConfigDir())
err = filestore.InitFilestore() err = filestore.InitFilestore()
if err != nil { if err != nil {
log.Printf("error initializing filestore: %v\n", err) log.Printf("error initializing filestore: %v\n", err)

View File

@ -1,6 +1,6 @@
import { getWebServerEndpoint } from "@/util/endpoints";
import { fetch } from "@/util/fetchutil";
import { ipcMain } from "electron"; import { ipcMain } from "electron";
import { getWebServerEndpoint } from "../frontend/util/endpoints";
import { fetch } from "../frontend/util/fetchutil";
const docsiteWebUrl = "https://docs.waveterm.dev/"; const docsiteWebUrl = "https://docs.waveterm.dev/";
let docsiteUrl: string; let docsiteUrl: string;

View File

@ -1,8 +1,13 @@
// Copyright 2024, Command Line Inc. // Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import { ClientService, FileService, ObjectService, WindowService } from "@/app/store/services";
import * as electron from "electron"; import * as electron from "electron";
import * as path from "path";
import { debounce } from "throttle-debounce";
import { ClientService, FileService, ObjectService, WindowService } from "../frontend/app/store/services";
import * as keyutil from "../frontend/util/keyutil";
import { configureAuthKeyRequestInjection } from "./authkey";
import { getGlobalIsQuitting, getGlobalIsStarting, setWasActive, setWasInFg } from "./emain-activity";
import { import {
delay, delay,
ensureBoundsAreVisible, ensureBoundsAreVisible,
@ -10,12 +15,7 @@ import {
handleCtrlShiftState, handleCtrlShiftState,
shFrameNavHandler, shFrameNavHandler,
shNavHandler, shNavHandler,
} from "emain/emain-util"; } from "./emain-util";
import * as keyutil from "frontend/util/keyutil";
import * as path from "path";
import { debounce } from "throttle-debounce";
import { configureAuthKeyRequestInjection } from "./authkey";
import { getGlobalIsQuitting, getGlobalIsStarting, setWasActive, setWasInFg } from "./emain-activity";
import { getElectronAppBasePath, isDevVite } from "./platform"; import { getElectronAppBasePath, isDevVite } from "./platform";
import { updater } from "./updater"; import { updater } from "./updater";

View File

@ -1,15 +1,23 @@
// Copyright 2024, Command Line Inc. // Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import { WebServerEndpointVarName, WSServerEndpointVarName } from "@/util/endpoints";
import * as electron from "electron"; import * as electron from "electron";
import { AuthKey, AuthKeyEnv } from "emain/authkey";
import { setForceQuit } from "emain/emain-activity";
import { WaveAppPathVarName } from "emain/emain-util";
import { getElectronAppUnpackedBasePath, getWaveSrvCwd, getWaveSrvPath } from "emain/platform";
import { updater } from "emain/updater";
import * as child_process from "node:child_process"; import * as child_process from "node:child_process";
import * as readline from "readline"; import * as readline from "readline";
import { WebServerEndpointVarName, WSServerEndpointVarName } from "../frontend/util/endpoints";
import { AuthKey, AuthKeyEnv } from "./authkey";
import { setForceQuit } from "./emain-activity";
import { WaveAppPathVarName } from "./emain-util";
import {
getElectronAppUnpackedBasePath,
getWaveConfigDir,
getWaveDataDir,
getWaveSrvCwd,
getWaveSrvPath,
WaveConfigHomeVarName,
WaveDataHomeVarName,
} from "./platform";
import { updater } from "./updater";
export const WaveSrvReadySignalPidVarName = "WAVETERM_READY_SIGNAL_PID"; export const WaveSrvReadySignalPidVarName = "WAVETERM_READY_SIGNAL_PID";
@ -50,6 +58,8 @@ export function runWaveSrv(handleWSEvent: (evtMsg: WSEventType) => void): Promis
envCopy[WaveAppPathVarName] = getElectronAppUnpackedBasePath(); envCopy[WaveAppPathVarName] = getElectronAppUnpackedBasePath();
envCopy[WaveSrvReadySignalPidVarName] = process.pid.toString(); envCopy[WaveSrvReadySignalPidVarName] = process.pid.toString();
envCopy[AuthKeyEnv] = AuthKey; envCopy[AuthKeyEnv] = AuthKey;
envCopy[WaveDataHomeVarName] = getWaveDataDir();
envCopy[WaveConfigHomeVarName] = getWaveConfigDir();
const waveSrvCmd = getWaveSrvPath(); const waveSrvCmd = getWaveSrvPath();
console.log("trying to run local server", waveSrvCmd); console.log("trying to run local server", waveSrvCmd);
const proc = child_process.spawn(getWaveSrvPath(), { const proc = child_process.spawn(getWaveSrvPath(), {

View File

@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import { Notification } from "electron"; import { Notification } from "electron";
import { getWaveWindowById } from "emain/emain-viewmgr";
import { RpcResponseHelper, WshClient } from "../frontend/app/store/wshclient"; import { RpcResponseHelper, WshClient } from "../frontend/app/store/wshclient";
import { getWaveWindowById } from "./emain-viewmgr";
import { getWebContentsByBlockId, webGetSelector } from "./emain-web"; import { getWebContentsByBlockId, webGetSelector } from "./emain-web";
export class ElectronWshClientType extends WshClient { export class ElectronWshClientType extends WshClient {

View File

@ -2,31 +2,6 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import * as electron from "electron"; import * as electron from "electron";
import {
getActivityState,
getForceQuit,
getGlobalIsRelaunching,
setForceQuit,
setGlobalIsQuitting,
setGlobalIsRelaunching,
setGlobalIsStarting,
setWasActive,
setWasInFg,
} from "emain/emain-activity";
import { handleCtrlShiftState } from "emain/emain-util";
import {
createBrowserWindow,
ensureHotSpareTab,
getAllWaveWindows,
getFocusedWaveWindow,
getLastFocusedWaveWindow,
getWaveTabViewByWebContentsId,
getWaveWindowById,
getWaveWindowByWebContentsId,
setActiveTab,
setMaxTabCacheSize,
} from "emain/emain-viewmgr";
import { getIsWaveSrvDead, getWaveSrvProc, getWaveSrvReady, getWaveVersion, runWaveSrv } from "emain/emain-wavesrv";
import { FastAverageColor } from "fast-average-color"; import { FastAverageColor } from "fast-average-color";
import fs from "fs"; import fs from "fs";
import * as child_process from "node:child_process"; import * as child_process from "node:child_process";
@ -44,13 +19,39 @@ import * as keyutil from "../frontend/util/keyutil";
import { fireAndForget } from "../frontend/util/util"; import { fireAndForget } from "../frontend/util/util";
import { AuthKey, configureAuthKeyRequestInjection } from "./authkey"; import { AuthKey, configureAuthKeyRequestInjection } from "./authkey";
import { initDocsite } from "./docsite"; import { initDocsite } from "./docsite";
import {
getActivityState,
getForceQuit,
getGlobalIsRelaunching,
setForceQuit,
setGlobalIsQuitting,
setGlobalIsRelaunching,
setGlobalIsStarting,
setWasActive,
setWasInFg,
} from "./emain-activity";
import { handleCtrlShiftState } from "./emain-util";
import {
createBrowserWindow,
ensureHotSpareTab,
getAllWaveWindows,
getFocusedWaveWindow,
getLastFocusedWaveWindow,
getWaveTabViewByWebContentsId,
getWaveWindowById,
getWaveWindowByWebContentsId,
setActiveTab,
setMaxTabCacheSize,
} from "./emain-viewmgr";
import { getIsWaveSrvDead, getWaveSrvProc, getWaveSrvReady, getWaveVersion, runWaveSrv } from "./emain-wavesrv";
import { ElectronWshClient, initElectronWshClient } from "./emain-wsh"; import { ElectronWshClient, initElectronWshClient } from "./emain-wsh";
import { getLaunchSettings } from "./launchsettings"; import { getLaunchSettings } from "./launchsettings";
import { getAppMenu } from "./menu"; import { getAppMenu } from "./menu";
import { import {
getElectronAppBasePath, getElectronAppBasePath,
getElectronAppUnpackedBasePath, getElectronAppUnpackedBasePath,
getWaveHomeDir, getWaveConfigDir,
getWaveDataDir,
isDev, isDev,
unameArch, unameArch,
unamePlatform, unamePlatform,
@ -59,15 +60,17 @@ import { configureAutoUpdater, updater } from "./updater";
const electronApp = electron.app; const electronApp = electron.app;
const waveDataDir = getWaveDataDir();
const waveConfigDir = getWaveConfigDir();
electron.nativeTheme.themeSource = "dark"; electron.nativeTheme.themeSource = "dark";
let webviewFocusId: number = null; // set to the getWebContentsId of the webview that has focus (null if not focused) let webviewFocusId: number = null; // set to the getWebContentsId of the webview that has focus (null if not focused)
let webviewKeys: string[] = []; // the keys to trap when webview has focus let webviewKeys: string[] = []; // the keys to trap when webview has focus
const waveHome = getWaveHomeDir();
const oldConsoleLog = console.log; const oldConsoleLog = console.log;
const loggerTransports: winston.transport[] = [ const loggerTransports: winston.transport[] = [
new winston.transports.File({ filename: path.join(getWaveHomeDir(), "waveapp.log"), level: "info" }), new winston.transports.File({ filename: path.join(waveDataDir, "waveapp.log"), level: "info" }),
]; ];
if (isDev) { if (isDev) {
loggerTransports.push(new winston.transports.Console()); loggerTransports.push(new winston.transports.Console());
@ -91,8 +94,9 @@ function log(...msg: any[]) {
console.log = log; console.log = log;
console.log( console.log(
sprintf( sprintf(
"waveterm-app starting, WAVETERM_HOME=%s, electronpath=%s gopath=%s arch=%s/%s", "waveterm-app starting, data_dir=%s, config_dir=%s electronpath=%s gopath=%s arch=%s/%s",
waveHome, waveDataDir,
waveConfigDir,
getElectronAppBasePath(), getElectronAppBasePath(),
getElectronAppUnpackedBasePath(), getElectronAppUnpackedBasePath(),
unamePlatform, unamePlatform,
@ -676,10 +680,6 @@ async function appMain() {
electronApp.quit(); electronApp.quit();
return; return;
} }
const waveHomeDir = getWaveHomeDir();
if (!fs.existsSync(waveHomeDir)) {
fs.mkdirSync(waveHomeDir);
}
makeAppMenu(); makeAppMenu();
try { try {
await runWaveSrv(handleWSEvent); await runWaveSrv(handleWSEvent);

View File

@ -1,6 +1,6 @@
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { getWaveHomeDir } from "./platform"; import { getWaveConfigDir } from "./platform";
/** /**
* Get settings directly from the Wave Home directory on launch. * Get settings directly from the Wave Home directory on launch.
@ -8,7 +8,7 @@ import { getWaveHomeDir } from "./platform";
* @returns The initial launch settings for the application. * @returns The initial launch settings for the application.
*/ */
export function getLaunchSettings(): SettingsType { export function getLaunchSettings(): SettingsType {
const settingsPath = path.join(getWaveHomeDir(), "config", "settings.json"); const settingsPath = path.join(getWaveConfigDir(), "settings.json");
try { try {
const settingsContents = fs.readFileSync(settingsPath, "utf8"); const settingsContents = fs.readFileSync(settingsPath, "utf8");
return JSON.parse(settingsContents); return JSON.parse(settingsContents);

View File

@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import * as electron from "electron"; import * as electron from "electron";
import { clearTabCache, getFocusedWaveWindow } from "emain/emain-viewmgr";
import { fireAndForget } from "../frontend/util/util"; import { fireAndForget } from "../frontend/util/util";
import { clearTabCache, getFocusedWaveWindow } from "./emain-viewmgr";
import { unamePlatform } from "./platform"; import { unamePlatform } from "./platform";
import { updater } from "./updater"; import { updater } from "./updater";

View File

@ -2,12 +2,18 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import { app, ipcMain } from "electron"; import { app, ipcMain } from "electron";
import envPaths from "env-paths";
import { existsSync, mkdirSync } from "fs";
import os from "os"; import os from "os";
import path from "path"; import path from "path";
import { WaveDevVarName, WaveDevViteVarName } from "../frontend/util/isdev"; import { WaveDevVarName, WaveDevViteVarName } from "../frontend/util/isdev";
import * as keyutil from "../frontend/util/keyutil"; import * as keyutil from "../frontend/util/keyutil";
const WaveHomeVarName = "WAVETERM_HOME"; // This is a little trick to ensure that Electron puts all its runtime data into a subdirectory to avoid conflicts with our own data.
// On macOS, it will store to ~/Library/Application \Support/waveterm/electron
// On Linux, it will store to ~/.config/waveterm/electron
// On Windows, it will store to %LOCALAPPDATA%/waveterm/electron
app.setName("waveterm/electron");
const isDev = !app.isPackaged; const isDev = !app.isPackaged;
const isDevVite = isDev && process.env.ELECTRON_RENDERER_URL; const isDevVite = isDev && process.env.ELECTRON_RENDERER_URL;
@ -18,18 +24,100 @@ if (isDevVite) {
process.env[WaveDevViteVarName] = "1"; process.env[WaveDevViteVarName] = "1";
} }
const waveDirNamePrefix = "waveterm";
const waveDirNameSuffix = isDev ? "dev" : "";
const waveDirName = `${waveDirNamePrefix}${waveDirNameSuffix ? `-${waveDirNameSuffix}` : ""}`;
const paths = envPaths("waveterm", { suffix: waveDirNameSuffix });
app.setName(isDev ? "Wave (Dev)" : "Wave"); app.setName(isDev ? "Wave (Dev)" : "Wave");
const unamePlatform = process.platform; const unamePlatform = process.platform;
const unameArch: string = process.arch; const unameArch: string = process.arch;
keyutil.setKeyUtilPlatform(unamePlatform); keyutil.setKeyUtilPlatform(unamePlatform);
// must match golang const WaveConfigHomeVarName = "WAVETERM_CONFIG_HOME";
function getWaveHomeDir() { const WaveDataHomeVarName = "WAVETERM_DATA_HOME";
const override = process.env[WaveHomeVarName]; const WaveHomeVarName = "WAVETERM_HOME";
if (override) {
return override; /**
* Gets the path to the old Wave home directory (defaults to `~/.waveterm`).
* @returns The path to the directory if it exists and contains valid data for the current app, otherwise null.
*/
function getWaveHomeDir(): string {
let home = process.env[WaveHomeVarName];
if (!home) {
const homeDir = process.env.HOME;
if (homeDir) {
home = path.join(homeDir, `.${waveDirName}`);
} }
return path.join(os.homedir(), isDev ? ".waveterm-dev" : ".waveterm"); }
// If home exists and it has `wave.lock` in it, we know it has valid data from Wave >=v0.8. Otherwise, it could be for WaveLegacy (<v0.8)
if (home && existsSync(home) && existsSync(path.join(home, "wave.lock"))) {
return home;
}
return null;
}
/**
* Ensure the given path exists, creating it recursively if it doesn't.
* @param path The path to ensure.
* @returns The same path, for chaining.
*/
function ensurePathExists(path: string): string {
if (!existsSync(path)) {
mkdirSync(path, { recursive: true });
}
return path;
}
/**
* Gets the path to the directory where Wave configurations are stored. Creates the directory if it does not exist.
* Handles backwards compatibility with the old Wave Home directory model, where configurations and data were stored together.
* @returns The path where configurations should be stored.
*/
function getWaveConfigDir(): string {
// If wave home dir exists, use it for backwards compatibility
const waveHomeDir = getWaveHomeDir();
if (waveHomeDir) {
return path.join(waveHomeDir, "config");
}
const override = process.env[WaveConfigHomeVarName];
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
let retVal: string;
if (override) {
retVal = override;
} else if (xdgConfigHome) {
retVal = path.join(xdgConfigHome, waveDirName);
} else {
retVal = path.join(app.getPath("home"), ".config", waveDirName);
}
return ensurePathExists(retVal);
}
/**
* Gets the path to the directory where Wave data is stored. Creates the directory if it does not exist.
* Handles backwards compatibility with the old Wave Home directory model, where configurations and data were stored together.
* @returns The path where data should be stored.
*/
function getWaveDataDir(): string {
// If wave home dir exists, use it for backwards compatibility
const waveHomeDir = getWaveHomeDir();
if (waveHomeDir) {
return waveHomeDir;
}
const override = process.env[WaveDataHomeVarName];
const xdgDataHome = process.env.XDG_DATA_HOME;
let retVal: string;
if (override) {
retVal = override;
} else if (xdgDataHome) {
retVal = path.join(xdgDataHome, waveDirName);
} else {
retVal = paths.data;
}
return ensurePathExists(retVal);
} }
function getElectronAppBasePath(): string { function getElectronAppBasePath(): string {
@ -52,7 +140,7 @@ function getWaveSrvPath(): string {
} }
function getWaveSrvCwd(): string { function getWaveSrvCwd(): string {
return getWaveHomeDir(); return getWaveDataDir();
} }
ipcMain.on("get-is-dev", (event) => { ipcMain.on("get-is-dev", (event) => {
@ -71,18 +159,24 @@ ipcMain.on("get-host-name", (event) => {
ipcMain.on("get-webview-preload", (event) => { ipcMain.on("get-webview-preload", (event) => {
event.returnValue = path.join(getElectronAppBasePath(), "preload", "preload-webview.cjs"); event.returnValue = path.join(getElectronAppBasePath(), "preload", "preload-webview.cjs");
}); });
ipcMain.on("get-data-dir", (event) => {
event.returnValue = getWaveDataDir();
});
ipcMain.on("get-config-dir", (event) => { ipcMain.on("get-config-dir", (event) => {
event.returnValue = path.join(getWaveHomeDir(), "config"); event.returnValue = getWaveConfigDir();
}); });
export { export {
getElectronAppBasePath, getElectronAppBasePath,
getElectronAppUnpackedBasePath, getElectronAppUnpackedBasePath,
getWaveHomeDir, getWaveConfigDir,
getWaveDataDir,
getWaveSrvCwd, getWaveSrvCwd,
getWaveSrvPath, getWaveSrvPath,
isDev, isDev,
isDevVite, isDevVite,
unameArch, unameArch,
unamePlatform, unamePlatform,
WaveConfigHomeVarName,
WaveDataHomeVarName,
}; };

View File

@ -10,6 +10,7 @@ contextBridge.exposeInMainWorld("api", {
getCursorPoint: () => ipcRenderer.sendSync("get-cursor-point"), getCursorPoint: () => ipcRenderer.sendSync("get-cursor-point"),
getUserName: () => ipcRenderer.sendSync("get-user-name"), getUserName: () => ipcRenderer.sendSync("get-user-name"),
getHostName: () => ipcRenderer.sendSync("get-host-name"), getHostName: () => ipcRenderer.sendSync("get-host-name"),
getDataDir: () => ipcRenderer.sendSync("get-data-dir"),
getConfigDir: () => ipcRenderer.sendSync("get-config-dir"), getConfigDir: () => ipcRenderer.sendSync("get-config-dir"),
getAboutModalDetails: () => ipcRenderer.sendSync("get-about-modal-details"), getAboutModalDetails: () => ipcRenderer.sendSync("get-about-modal-details"),
getDocsiteUrl: () => ipcRenderer.sendSync("get-docsite-url"), getDocsiteUrl: () => ipcRenderer.sendSync("get-docsite-url"),

View File

@ -1,16 +1,16 @@
// Copyright 2024, Command Line Inc. // Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import { RpcApi } from "@/app/store/wshclientapi";
import { dialog, ipcMain, Notification } from "electron"; import { dialog, ipcMain, Notification } from "electron";
import { autoUpdater } from "electron-updater"; import { autoUpdater } from "electron-updater";
import { getAllWaveWindows, getFocusedWaveWindow } from "emain/emain-viewmgr";
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import path from "path"; import path from "path";
import YAML from "yaml"; import YAML from "yaml";
import { FileService } from "../frontend/app/store/services"; import { FileService } from "../frontend/app/store/services";
import { RpcApi } from "../frontend/app/store/wshclientapi";
import { isDev } from "../frontend/util/isdev"; import { isDev } from "../frontend/util/isdev";
import { fireAndForget } from "../frontend/util/util"; import { fireAndForget } from "../frontend/util/util";
import { getAllWaveWindows, getFocusedWaveWindow } from "./emain-viewmgr";
import { ElectronWshClient } from "./emain-wsh"; import { ElectronWshClient } from "./emain-wsh";
export let updater: Updater; export let updater: Updater;

View File

@ -64,6 +64,7 @@ declare global {
getEnv: (varName: string) => string; getEnv: (varName: string) => string;
getUserName: () => string; getUserName: () => string;
getHostName: () => string; getHostName: () => string;
getDataDir: () => string;
getConfigDir: () => string; getConfigDir: () => string;
getWebviewPreload: () => string; getWebviewPreload: () => string;
getAboutModalDetails: () => AboutModalDetails; getAboutModalDetails: () => AboutModalDetails;

View File

@ -102,6 +102,7 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"debug": "^4.3.7", "debug": "^4.3.7",
"electron-updater": "6.3.9", "electron-updater": "6.3.9",
"env-paths": "^3.0.0",
"fast-average-color": "^9.4.0", "fast-average-color": "^9.4.0",
"htl": "^0.3.1", "htl": "^0.3.1",
"html-to-image": "^1.11.11", "html-to-image": "^1.11.11",

View File

@ -50,7 +50,7 @@ func InitFilestore() error {
} }
func GetDBName() string { func GetDBName() string {
waveHome := wavebase.GetWaveHomeDir() waveHome := wavebase.GetWaveDataDir()
return filepath.Join(waveHome, wavebase.WaveDBDir, FilestoreDBName) return filepath.Join(waveHome, wavebase.WaveDBDir, FilestoreDBName)
} }

View File

@ -289,7 +289,7 @@ func StartShellProc(termSize waveobj.TermSize, cmdStr string, cmdOpts CommandOpt
// cant set -l or -i with --rcfile // cant set -l or -i with --rcfile
shellOpts = append(shellOpts, "--rcfile", shellutil.GetBashRcFileOverride()) shellOpts = append(shellOpts, "--rcfile", shellutil.GetBashRcFileOverride())
} else if isFishShell(shellPath) { } else if isFishShell(shellPath) {
wshBinDir := filepath.Join(wavebase.GetWaveHomeDir(), shellutil.WaveHomeBinDir) wshBinDir := filepath.Join(wavebase.GetWaveDataDir(), shellutil.WaveHomeBinDir)
quotedWshBinDir := utilfn.ShellQuote(wshBinDir, false, 300) quotedWshBinDir := utilfn.ShellQuote(wshBinDir, false, 300)
shellOpts = append(shellOpts, "-C", fmt.Sprintf("set -x PATH %s $PATH", quotedWshBinDir)) shellOpts = append(shellOpts, "-C", fmt.Sprintf("set -x PATH %s $PATH", quotedWshBinDir))
} else if remote.IsPowershell(shellPath) { } else if remote.IsPowershell(shellPath) {

15
pkg/util/panic/panic.go Normal file
View File

@ -0,0 +1,15 @@
package panic
import (
"log"
"os"
)
var shouldPanic = len(os.Getenv("NO_PANIC")) == 0
// Wraps log.Panic, ignored if NO_PANIC is set
func Panic(message string) {
if shouldPanic {
log.Panic(message)
}
}

View File

@ -149,7 +149,7 @@ func WaveshellLocalEnvVars(termType string) map[string]string {
rtn["TERM_PROGRAM"] = "waveterm" rtn["TERM_PROGRAM"] = "waveterm"
rtn["WAVETERM"], _ = os.Executable() rtn["WAVETERM"], _ = os.Executable()
rtn["WAVETERM_VERSION"] = wavebase.WaveVersion rtn["WAVETERM_VERSION"] = wavebase.WaveVersion
rtn["WAVETERM_WSHBINDIR"] = filepath.Join(wavebase.GetWaveHomeDir(), WaveHomeBinDir) rtn["WAVETERM_WSHBINDIR"] = filepath.Join(wavebase.GetWaveDataDir(), WaveHomeBinDir)
return rtn return rtn
} }
@ -202,15 +202,15 @@ func InitCustomShellStartupFiles() error {
} }
func GetBashRcFileOverride() string { func GetBashRcFileOverride() string {
return filepath.Join(wavebase.GetWaveHomeDir(), BashIntegrationDir, ".bashrc") return filepath.Join(wavebase.GetWaveDataDir(), BashIntegrationDir, ".bashrc")
} }
func GetWavePowershellEnv() string { func GetWavePowershellEnv() string {
return filepath.Join(wavebase.GetWaveHomeDir(), PwshIntegrationDir, "wavepwsh.ps1") return filepath.Join(wavebase.GetWaveDataDir(), PwshIntegrationDir, "wavepwsh.ps1")
} }
func GetZshZDotDir() string { func GetZshZDotDir() string {
return filepath.Join(wavebase.GetWaveHomeDir(), ZshIntegrationDir) return filepath.Join(wavebase.GetWaveDataDir(), ZshIntegrationDir)
} }
func GetWshBaseName(version string, goos string, goarch string) string { func GetWshBaseName(version string, goos string, goarch string) string {
@ -289,9 +289,9 @@ func InitRcFiles(waveHome string, wshBinDir string) error {
func initCustomShellStartupFilesInternal() error { func initCustomShellStartupFilesInternal() error {
log.Printf("initializing wsh and shell startup files\n") log.Printf("initializing wsh and shell startup files\n")
waveHome := wavebase.GetWaveHomeDir() waveDataHome := wavebase.GetWaveDataDir()
binDir := filepath.Join(waveHome, WaveHomeBinDir) binDir := filepath.Join(waveDataHome, WaveHomeBinDir)
err := InitRcFiles(waveHome, `$WAVETERM_WSHBINDIR`) err := InitRcFiles(waveDataHome, `$WAVETERM_WSHBINDIR`)
if err != nil { if err != nil {
return err return err
} }

View File

@ -14,8 +14,8 @@ import (
) )
func AcquireWaveLock() (FDLock, error) { func AcquireWaveLock() (FDLock, error) {
homeDir := GetWaveHomeDir() dataHomeDir := GetWaveDataDir()
lockFileName := filepath.Join(homeDir, WaveLockFile) lockFileName := filepath.Join(dataHomeDir, WaveLockFile)
log.Printf("[base] acquiring lock on %s\n", lockFileName) log.Printf("[base] acquiring lock on %s\n", lockFileName)
fd, err := os.OpenFile(lockFileName, os.O_RDWR|os.O_CREATE, 0600) fd, err := os.OpenFile(lockFileName, os.O_RDWR|os.O_CREATE, 0600)
if err != nil { if err != nil {

View File

@ -14,8 +14,8 @@ import (
) )
func AcquireWaveLock() (FDLock, error) { func AcquireWaveLock() (FDLock, error) {
homeDir := GetWaveHomeDir() dataHomeDir := GetWaveDataDir()
lockFileName := filepath.Join(homeDir, WaveLockFile) lockFileName := filepath.Join(dataHomeDir, WaveLockFile)
log.Printf("[base] acquiring lock on %s\n", lockFileName) log.Printf("[base] acquiring lock on %s\n", lockFileName)
m, err := filemutex.New(lockFileName) m, err := filemutex.New(lockFileName)
if err != nil { if err != nil {

View File

@ -17,15 +17,16 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/wavetermdev/waveterm/pkg/util/panic"
) )
// set by main-server.go // set by main-server.go
var WaveVersion = "0.0.0" var WaveVersion = "0.0.0"
var BuildTime = "0" var BuildTime = "0"
const DefaultWaveHome = "~/.waveterm" const WaveConfigHomeEnvVar = "WAVETERM_CONFIG_HOME"
const DevWaveHome = "~/.waveterm-dev" const WaveDataHomeEnvVar = "WAVETERM_DATA_HOME"
const WaveHomeVarName = "WAVETERM_HOME"
const WaveDevVarName = "WAVETERM_DEV" const WaveDevVarName = "WAVETERM_DEV"
const WaveLockFile = "wave.lock" const WaveLockFile = "wave.lock"
const DomainSocketBaseName = "wave.sock" const DomainSocketBaseName = "wave.sock"
@ -97,26 +98,39 @@ func ReplaceHomeDir(pathStr string) string {
} }
func GetDomainSocketName() string { func GetDomainSocketName() string {
return filepath.Join(GetWaveHomeDir(), DomainSocketBaseName) return filepath.Join(GetWaveDataDir(), DomainSocketBaseName)
} }
func GetWaveHomeDir() string { func GetWaveDataDir() string {
homeVar := os.Getenv(WaveHomeVarName) retVal, found := os.LookupEnv(WaveDataHomeEnvVar)
if homeVar != "" { if !found {
return ExpandHomeDirSafe(homeVar) panic.Panic(WaveDataHomeEnvVar + " not set")
} }
if IsDevMode() { return retVal
return ExpandHomeDirSafe(DevWaveHome)
}
return ExpandHomeDirSafe(DefaultWaveHome)
} }
func EnsureWaveHomeDir() error { func GetWaveConfigDir() string {
return CacheEnsureDir(GetWaveHomeDir(), "wavehome", 0700, "wave home directory") retVal, found := os.LookupEnv(WaveConfigHomeEnvVar)
if !found {
panic.Panic(WaveConfigHomeEnvVar + " not set")
}
return retVal
}
func EnsureWaveDataDir() error {
return CacheEnsureDir(GetWaveDataDir(), "wavehome", 0700, "wave home directory")
} }
func EnsureWaveDBDir() error { func EnsureWaveDBDir() error {
return CacheEnsureDir(filepath.Join(GetWaveHomeDir(), WaveDBDir), "wavedb", 0700, "wave db directory") return CacheEnsureDir(filepath.Join(GetWaveDataDir(), WaveDBDir), "wavedb", 0700, "wave db directory")
}
func EnsureWaveConfigDir() error {
return CacheEnsureDir(GetWaveConfigDir(), "waveconfig", 0700, "wave config directory")
}
func EnsureWavePresetsDir() error {
return CacheEnsureDir(filepath.Join(GetWaveConfigDir(), "presets"), "wavepresets", 0700, "wave presets directory")
} }
func CacheEnsureDir(dirName string, cacheKey string, perm os.FileMode, dirDesc string) error { func CacheEnsureDir(dirName string, cacheKey string, perm os.FileMode, dirDesc string) error {

View File

@ -14,7 +14,7 @@ import (
"github.com/wavetermdev/waveterm/pkg/wps" "github.com/wavetermdev/waveterm/pkg/wps"
) )
var configDirAbsPath = filepath.Join(wavebase.GetWaveHomeDir(), wavebase.ConfigDir) var configDirAbsPath = wavebase.GetWaveConfigDir()
var instance *Watcher var instance *Watcher
var once sync.Once var once sync.Once

View File

@ -16,7 +16,6 @@ import (
"strings" "strings"
"github.com/wavetermdev/waveterm/pkg/util/utilfn" "github.com/wavetermdev/waveterm/pkg/util/utilfn"
"github.com/wavetermdev/waveterm/pkg/wavebase"
"github.com/wavetermdev/waveterm/pkg/waveobj" "github.com/wavetermdev/waveterm/pkg/waveobj"
"github.com/wavetermdev/waveterm/pkg/wconfig/defaultconfig" "github.com/wavetermdev/waveterm/pkg/wconfig/defaultconfig"
) )
@ -498,14 +497,6 @@ func SetBaseConfigValue(toMerge waveobj.MetaMapType) error {
return WriteWaveHomeConfigFile(SettingsFile, m) return WriteWaveHomeConfigFile(SettingsFile, m)
} }
func EnsureWaveConfigDir() error {
return wavebase.CacheEnsureDir(configDirAbsPath, "waveconfig", 0700, "wave config directory")
}
func EnsureWavePresetsDir() error {
return wavebase.CacheEnsureDir(filepath.Join(configDirAbsPath, "presets"), "wavepresets", 0700, "wave presets directory")
}
type WidgetConfigType struct { type WidgetConfigType struct {
DisplayOrder float64 `json:"display:order,omitempty"` DisplayOrder float64 `json:"display:order,omitempty"`
Icon string `json:"icon,omitempty"` Icon string `json:"icon,omitempty"`

View File

@ -431,7 +431,7 @@ func MakeTCPListener(serviceName string) (net.Listener, error) {
} }
func MakeUnixListener() (net.Listener, error) { func MakeUnixListener() (net.Listener, error) {
serverAddr := wavebase.GetWaveHomeDir() + "/wave.sock" serverAddr := wavebase.GetWaveDataDir() + "/wave.sock"
os.Remove(serverAddr) // ignore error os.Remove(serverAddr) // ignore error
rtn, err := net.Listen("unix", serverAddr) rtn, err := net.Listen("unix", serverAddr)
if err != nil { if err != nil {

View File

@ -42,7 +42,7 @@ func InitWStore() error {
} }
func GetDBName() string { func GetDBName() string {
waveHome := wavebase.GetWaveHomeDir() waveHome := wavebase.GetWaveDataDir()
return filepath.Join(waveHome, wavebase.WaveDBDir, WStoreDBName) return filepath.Join(waveHome, wavebase.WaveDBDir, WStoreDBName)
} }

View File

@ -5297,6 +5297,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"env-paths@npm:^3.0.0":
version: 3.0.0
resolution: "env-paths@npm:3.0.0"
checksum: 10c0/76dec878cee47f841103bacd7fae03283af16f0702dad65102ef0a556f310b98a377885e0f32943831eb08b5ab37842a323d02529f3dfd5d0a40ca71b01b435f
languageName: node
linkType: hard
"err-code@npm:^2.0.2": "err-code@npm:^2.0.2":
version: 2.0.3 version: 2.0.3
resolution: "err-code@npm:2.0.3" resolution: "err-code@npm:2.0.3"
@ -11685,6 +11692,7 @@ __metadata:
electron-builder: "npm:^25.1.7" electron-builder: "npm:^25.1.7"
electron-updater: "npm:6.3.9" electron-updater: "npm:6.3.9"
electron-vite: "npm:^2.3.0" electron-vite: "npm:^2.3.0"
env-paths: "npm:^3.0.0"
eslint: "npm:^9.12.0" eslint: "npm:^9.12.0"
eslint-config-prettier: "npm:^9.1.0" eslint-config-prettier: "npm:^9.1.0"
fast-average-color: "npm:^9.4.0" fast-average-color: "npm:^9.4.0"