mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
8971e2feba
Adds electron-builder, which we will use to package and distribute our application, same as in the existing app. Replaces explicit port assignments with dynamic ones, which are then stored into environment variables. Adds a ~/.w2-dev folder for use when running a dev build. The build-helper pipeline from the old repo is included here too, but it is not updated yet so it will fail. Also removes some redundant utility functions and cleans up some let vs. const usage. The packaging can be run using the `package:prod` and `package:dev` tasks. --------- Co-authored-by: sawka <mike.sawka@gmail.com>
180 lines
4.0 KiB
Go
180 lines
4.0 KiB
Go
// Copyright 2024, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package wavebase
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/alexflint/go-filemutex"
|
|
)
|
|
|
|
const WaveVersion = "v0.1.0"
|
|
const DefaultWaveHome = "~/.w2"
|
|
const DevWaveHome = "~/.w2-dev"
|
|
const WaveHomeVarName = "WAVETERM_HOME"
|
|
const WaveDevVarName = "WAVETERM_DEV"
|
|
const WaveLockFile = "waveterm.lock"
|
|
const DomainSocketBaseName = "wave.sock"
|
|
|
|
var baseLock = &sync.Mutex{}
|
|
var ensureDirCache = map[string]bool{}
|
|
|
|
func IsDevMode() bool {
|
|
pdev := os.Getenv(WaveDevVarName)
|
|
return pdev != ""
|
|
}
|
|
|
|
func GetHomeDir() string {
|
|
homeVar, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return "/"
|
|
}
|
|
return homeVar
|
|
}
|
|
|
|
func ExpandHomeDir(pathStr string) string {
|
|
if pathStr != "~" && !strings.HasPrefix(pathStr, "~/") {
|
|
return pathStr
|
|
}
|
|
homeDir := GetHomeDir()
|
|
if pathStr == "~" {
|
|
return homeDir
|
|
}
|
|
return filepath.Join(homeDir, pathStr[2:])
|
|
}
|
|
|
|
func ReplaceHomeDir(pathStr string) string {
|
|
homeDir := GetHomeDir()
|
|
if pathStr == homeDir {
|
|
return "~"
|
|
}
|
|
if strings.HasPrefix(pathStr, homeDir+"/") {
|
|
return "~" + pathStr[len(homeDir):]
|
|
}
|
|
return pathStr
|
|
}
|
|
|
|
func GetDomainSocketName() string {
|
|
return filepath.Join(GetWaveHomeDir(), DomainSocketBaseName)
|
|
}
|
|
|
|
func GetWaveHomeDir() string {
|
|
homeVar := os.Getenv(WaveHomeVarName)
|
|
if homeVar != "" {
|
|
return ExpandHomeDir(homeVar)
|
|
}
|
|
if IsDevMode() {
|
|
return ExpandHomeDir(DevWaveHome)
|
|
}
|
|
return ExpandHomeDir(DefaultWaveHome)
|
|
}
|
|
|
|
func EnsureWaveHomeDir() error {
|
|
return CacheEnsureDir(GetWaveHomeDir(), "wavehome", 0700, "wave home directory")
|
|
}
|
|
|
|
func CacheEnsureDir(dirName string, cacheKey string, perm os.FileMode, dirDesc string) error {
|
|
baseLock.Lock()
|
|
ok := ensureDirCache[cacheKey]
|
|
baseLock.Unlock()
|
|
if ok {
|
|
return nil
|
|
}
|
|
err := TryMkdirs(dirName, perm, dirDesc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
baseLock.Lock()
|
|
ensureDirCache[cacheKey] = true
|
|
baseLock.Unlock()
|
|
return nil
|
|
}
|
|
|
|
func TryMkdirs(dirName string, perm os.FileMode, dirDesc string) error {
|
|
info, err := os.Stat(dirName)
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
err = os.MkdirAll(dirName, perm)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot make %s %q: %w", dirDesc, dirName, err)
|
|
}
|
|
info, err = os.Stat(dirName)
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("error trying to stat %s: %w", dirDesc, err)
|
|
}
|
|
if !info.IsDir() {
|
|
return fmt.Errorf("%s %q must be a directory", dirDesc, dirName)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var osLangOnce = &sync.Once{}
|
|
var osLang string
|
|
|
|
func determineLang() string {
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
|
defer cancelFn()
|
|
if runtime.GOOS == "darwin" {
|
|
out, err := exec.CommandContext(ctx, "defaults", "read", "-g", "AppleLocale").CombinedOutput()
|
|
if err != nil {
|
|
log.Printf("error executing 'defaults read -g AppleLocale': %v\n", err)
|
|
return ""
|
|
}
|
|
strOut := string(out)
|
|
truncOut := strings.Split(strOut, "@")[0]
|
|
return strings.TrimSpace(truncOut) + ".UTF-8"
|
|
} else if runtime.GOOS == "win32" {
|
|
out, err := exec.CommandContext(ctx, "Get-Culture", "|", "select", "-exp", "Name").CombinedOutput()
|
|
if err != nil {
|
|
log.Printf("error executing 'Get-Culture | select -exp Name': %v\n", err)
|
|
return ""
|
|
}
|
|
return strings.TrimSpace(string(out)) + ".UTF-8"
|
|
} else {
|
|
// this is specifically to get the wavesrv LANG so waveshell
|
|
// on a remote uses the same LANG
|
|
return os.Getenv("LANG")
|
|
}
|
|
}
|
|
|
|
func DetermineLang() string {
|
|
osLangOnce.Do(func() {
|
|
osLang = determineLang()
|
|
})
|
|
return osLang
|
|
}
|
|
|
|
func DetermineLocale() string {
|
|
truncated := strings.Split(DetermineLang(), ".")[0]
|
|
if truncated == "" {
|
|
return "C"
|
|
}
|
|
return strings.Replace(truncated, "_", "-", -1)
|
|
}
|
|
|
|
func AcquireWaveLock() (*filemutex.FileMutex, error) {
|
|
homeDir := GetWaveHomeDir()
|
|
lockFileName := filepath.Join(homeDir, WaveLockFile)
|
|
log.Printf("[base] acquiring lock on %s\n", lockFileName)
|
|
m, err := filemutex.New(lockFileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = m.TryLock()
|
|
return m, err
|
|
|
|
}
|