2022-11-09 11:27:54 -08:00
|
|
|
package platform
|
2019-03-13 04:14:30 -07:00
|
|
|
|
|
|
|
import (
|
2021-12-19 07:42:39 -08:00
|
|
|
"bytes"
|
2020-11-19 19:12:20 -08:00
|
|
|
"context"
|
2022-08-02 22:25:42 -07:00
|
|
|
"encoding/json"
|
2021-01-05 11:12:52 -08:00
|
|
|
"errors"
|
2021-08-01 06:25:15 -07:00
|
|
|
"fmt"
|
2022-02-25 03:51:38 -08:00
|
|
|
"io"
|
2022-04-16 10:52:59 -07:00
|
|
|
"io/fs"
|
2020-11-19 19:12:20 -08:00
|
|
|
"net/http"
|
2022-07-17 12:11:23 -07:00
|
|
|
"net/http/httputil"
|
2019-03-13 04:14:30 -07:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
2020-10-01 11:57:02 -07:00
|
|
|
"path/filepath"
|
2019-03-13 04:14:30 -07:00
|
|
|
"runtime"
|
2022-04-05 04:32:32 -07:00
|
|
|
"strconv"
|
2019-03-13 04:14:30 -07:00
|
|
|
"strings"
|
2022-04-06 00:05:17 -07:00
|
|
|
"sync"
|
2020-12-31 00:39:02 -08:00
|
|
|
"time"
|
2019-03-13 04:14:30 -07:00
|
|
|
|
2023-01-05 12:57:38 -08:00
|
|
|
"github.com/jandedobbeleer/oh-my-posh/src/log"
|
|
|
|
"github.com/jandedobbeleer/oh-my-posh/src/platform/battery"
|
|
|
|
"github.com/jandedobbeleer/oh-my-posh/src/platform/cmd"
|
|
|
|
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
2022-12-28 08:30:48 -08:00
|
|
|
|
2023-02-19 07:24:52 -08:00
|
|
|
cpu "github.com/shirou/gopsutil/v3/cpu"
|
|
|
|
disk "github.com/shirou/gopsutil/v3/disk"
|
|
|
|
load "github.com/shirou/gopsutil/v3/load"
|
2021-11-13 14:46:06 -08:00
|
|
|
process "github.com/shirou/gopsutil/v3/process"
|
2019-03-13 04:14:30 -07:00
|
|
|
)
|
|
|
|
|
2020-11-12 00:43:32 -08:00
|
|
|
const (
|
2022-08-02 22:25:59 -07:00
|
|
|
UNKNOWN = "unknown"
|
|
|
|
WINDOWS = "windows"
|
|
|
|
DARWIN = "darwin"
|
|
|
|
LINUX = "linux"
|
2020-11-12 00:43:32 -08:00
|
|
|
)
|
|
|
|
|
2023-01-22 11:06:31 -08:00
|
|
|
func pid() string {
|
2022-11-19 13:35:13 -08:00
|
|
|
pid := os.Getenv("POSH_PID")
|
|
|
|
if len(pid) == 0 {
|
|
|
|
pid = strconv.Itoa(os.Getppid())
|
|
|
|
}
|
|
|
|
return pid
|
|
|
|
}
|
|
|
|
|
2022-05-05 23:41:58 -07:00
|
|
|
var (
|
2023-01-22 11:06:31 -08:00
|
|
|
TEMPLATECACHE = fmt.Sprintf("template_cache_%s", pid())
|
|
|
|
TOGGLECACHE = fmt.Sprintf("toggle_cache_%s", pid())
|
|
|
|
PROMPTCOUNTCACHE = fmt.Sprintf("prompt_count_cache_%s", pid())
|
2022-05-05 23:41:58 -07:00
|
|
|
)
|
|
|
|
|
2022-03-12 13:04:08 -08:00
|
|
|
type Flags struct {
|
|
|
|
ErrorCode int
|
|
|
|
Config string
|
|
|
|
Shell string
|
2022-04-20 10:16:02 -07:00
|
|
|
ShellVersion string
|
2022-03-12 13:04:08 -08:00
|
|
|
PWD string
|
|
|
|
PSWD string
|
|
|
|
ExecutionTime float64
|
|
|
|
Eval bool
|
|
|
|
StackCount int
|
|
|
|
Migrate bool
|
|
|
|
TerminalWidth int
|
2022-04-19 22:02:12 -07:00
|
|
|
Strict bool
|
2022-05-07 01:12:22 -07:00
|
|
|
Debug bool
|
2022-10-03 03:56:49 -07:00
|
|
|
Manual bool
|
2022-12-17 13:30:23 -08:00
|
|
|
Plain bool
|
2023-01-22 11:06:31 -08:00
|
|
|
Primary bool
|
|
|
|
PromptCount int
|
2023-02-05 00:06:26 -08:00
|
|
|
Cleared bool
|
2022-01-26 01:23:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
type CommandError struct {
|
|
|
|
Err string
|
|
|
|
ExitCode int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *CommandError) Error() string {
|
|
|
|
return e.Err
|
|
|
|
}
|
|
|
|
|
2022-01-23 12:37:51 -08:00
|
|
|
type FileInfo struct {
|
|
|
|
ParentFolder string
|
|
|
|
Path string
|
|
|
|
IsDir bool
|
2021-01-05 11:12:52 -08:00
|
|
|
}
|
|
|
|
|
2022-01-23 12:37:51 -08:00
|
|
|
type Cache interface {
|
|
|
|
Init(home string)
|
|
|
|
Close()
|
|
|
|
Get(key string) (string, bool)
|
2021-11-23 02:13:32 -08:00
|
|
|
// ttl in minutes
|
2022-01-23 12:37:51 -08:00
|
|
|
Set(key, value string, ttl int)
|
2021-09-21 11:22:59 -07:00
|
|
|
}
|
|
|
|
|
2021-12-14 23:49:32 -08:00
|
|
|
type HTTPRequestModifier func(request *http.Request)
|
|
|
|
|
2022-06-01 00:50:20 -07:00
|
|
|
type WindowsRegistryValueType string
|
2021-12-04 13:11:25 -08:00
|
|
|
|
|
|
|
const (
|
2022-06-01 00:50:20 -07:00
|
|
|
DWORD = "DWORD"
|
|
|
|
QWORD = "QWORD"
|
|
|
|
BINARY = "BINARY"
|
|
|
|
STRING = "STRING"
|
2021-12-04 13:11:25 -08:00
|
|
|
)
|
|
|
|
|
2022-01-23 12:37:51 -08:00
|
|
|
type WindowsRegistryValue struct {
|
2022-01-26 01:23:18 -08:00
|
|
|
ValueType WindowsRegistryValueType
|
2022-06-01 00:50:20 -07:00
|
|
|
DWord uint64
|
|
|
|
QWord uint64
|
|
|
|
String string
|
2021-12-04 13:11:25 -08:00
|
|
|
}
|
|
|
|
|
2022-09-12 03:55:57 -07:00
|
|
|
type NotImplemented struct{}
|
|
|
|
|
|
|
|
func (n *NotImplemented) Error() string {
|
|
|
|
return "not implemented"
|
|
|
|
}
|
|
|
|
|
|
|
|
type ConnectionType string
|
|
|
|
|
|
|
|
const (
|
|
|
|
ETHERNET ConnectionType = "ethernet"
|
|
|
|
WIFI ConnectionType = "wifi"
|
|
|
|
CELLULAR ConnectionType = "cellular"
|
|
|
|
BLUETOOTH ConnectionType = "bluetooth"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Connection struct {
|
|
|
|
Name string
|
|
|
|
Type ConnectionType
|
|
|
|
TransmitRate uint64
|
|
|
|
ReceiveRate uint64
|
|
|
|
SSID string // Wi-Fi only
|
2021-12-26 08:17:44 -08:00
|
|
|
}
|
|
|
|
|
2023-02-19 07:24:52 -08:00
|
|
|
type Memory struct {
|
|
|
|
PhysicalTotalMemory uint64
|
|
|
|
PhysicalAvailableMemory uint64
|
|
|
|
PhysicalFreeMemory uint64
|
|
|
|
PhysicalPercentUsed float64
|
|
|
|
SwapTotalMemory uint64
|
|
|
|
SwapFreeMemory uint64
|
|
|
|
SwapPercentUsed float64
|
|
|
|
}
|
|
|
|
|
|
|
|
type SystemInfo struct {
|
|
|
|
// mem
|
|
|
|
Memory
|
|
|
|
// cpu
|
|
|
|
Times float64
|
|
|
|
CPU []cpu.InfoStat
|
|
|
|
// load
|
|
|
|
Load1 float64
|
|
|
|
Load5 float64
|
|
|
|
Load15 float64
|
|
|
|
// disk
|
|
|
|
Disks map[string]disk.IOCountersStat
|
|
|
|
}
|
|
|
|
|
2022-11-20 04:59:32 -08:00
|
|
|
type SegmentsCache map[string]interface{}
|
|
|
|
|
2022-12-28 01:12:53 -08:00
|
|
|
func (s *SegmentsCache) Contains(key string) bool {
|
|
|
|
_, ok := (*s)[key]
|
2022-11-20 04:59:32 -08:00
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
2022-01-26 01:23:18 -08:00
|
|
|
type TemplateCache struct {
|
2022-04-20 10:16:02 -07:00
|
|
|
Root bool
|
|
|
|
PWD string
|
|
|
|
Folder string
|
|
|
|
Shell string
|
|
|
|
ShellVersion string
|
|
|
|
UserName string
|
|
|
|
HostName string
|
|
|
|
Code int
|
|
|
|
Env map[string]string
|
2023-02-19 11:21:33 -08:00
|
|
|
Var map[string]interface{}
|
2022-04-20 10:16:02 -07:00
|
|
|
OS string
|
|
|
|
WSL bool
|
2023-01-22 11:06:31 -08:00
|
|
|
PromptCount int
|
2022-11-20 04:59:32 -08:00
|
|
|
Segments SegmentsCache
|
2022-12-28 01:12:53 -08:00
|
|
|
|
|
|
|
sync.RWMutex
|
2022-05-05 23:41:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *TemplateCache) AddSegmentData(key string, value interface{}) {
|
2022-12-28 01:12:53 -08:00
|
|
|
t.Lock()
|
2022-05-05 23:41:58 -07:00
|
|
|
t.Segments[key] = value
|
2022-12-28 01:12:53 -08:00
|
|
|
t.Unlock()
|
2022-01-26 01:23:18 -08:00
|
|
|
}
|
|
|
|
|
2023-01-26 10:45:31 -08:00
|
|
|
func (t *TemplateCache) RemoveSegmentData(key string) {
|
|
|
|
t.Lock()
|
|
|
|
delete(t.Segments, key)
|
|
|
|
t.Unlock()
|
|
|
|
}
|
|
|
|
|
2022-01-01 11:09:52 -08:00
|
|
|
type Environment interface {
|
2022-01-23 12:37:51 -08:00
|
|
|
Getenv(key string) string
|
|
|
|
Pwd() string
|
|
|
|
Home() string
|
|
|
|
User() string
|
|
|
|
Root() bool
|
|
|
|
Host() (string, error)
|
|
|
|
GOOS() string
|
|
|
|
Shell() string
|
|
|
|
Platform() string
|
|
|
|
ErrorCode() int
|
2022-02-19 10:04:06 -08:00
|
|
|
PathSeparator() string
|
2022-01-23 12:37:51 -08:00
|
|
|
HasFiles(pattern string) bool
|
|
|
|
HasFilesInDir(dir, pattern string) bool
|
|
|
|
HasFolder(folder string) bool
|
|
|
|
HasParentFilePath(path string) (fileInfo *FileInfo, err error)
|
2022-02-13 23:41:33 -08:00
|
|
|
HasFileInParentDirs(pattern string, depth uint) bool
|
2022-04-19 20:51:00 -07:00
|
|
|
ResolveSymlink(path string) (string, error)
|
2022-04-06 00:05:17 -07:00
|
|
|
DirMatchesOneOf(dir string, regexes []string) bool
|
2022-05-15 22:27:50 -07:00
|
|
|
DirIsWritable(path string) bool
|
2022-04-19 20:51:00 -07:00
|
|
|
CommandPath(command string) string
|
2022-01-23 12:37:51 -08:00
|
|
|
HasCommand(command string) bool
|
|
|
|
FileContent(file string) string
|
2022-04-16 10:52:59 -07:00
|
|
|
LsDir(path string) []fs.DirEntry
|
2022-01-23 12:37:51 -08:00
|
|
|
RunCommand(command string, args ...string) (string, error)
|
|
|
|
RunShellCommand(shell, command string) string
|
|
|
|
ExecutionTime() float64
|
2022-03-12 13:04:08 -08:00
|
|
|
Flags() *Flags
|
2022-07-05 07:27:25 -07:00
|
|
|
BatteryState() (*battery.Info, error)
|
2022-03-05 23:41:02 -08:00
|
|
|
QueryWindowTitles(processName, windowTitleRegex string) (string, error)
|
2022-01-23 12:37:51 -08:00
|
|
|
WindowsRegistryKeyValue(path string) (*WindowsRegistryValue, error)
|
2022-07-17 12:11:23 -07:00
|
|
|
HTTPRequest(url string, body io.Reader, timeout int, requestModifiers ...HTTPRequestModifier) ([]byte, error)
|
2022-01-23 12:37:51 -08:00
|
|
|
IsWsl() bool
|
|
|
|
IsWsl2() bool
|
|
|
|
StackCount() int
|
|
|
|
TerminalWidth() (int, error)
|
|
|
|
CachePath() string
|
|
|
|
Cache() Cache
|
|
|
|
Close()
|
|
|
|
Logs() string
|
|
|
|
InWSLSharedDrive() bool
|
|
|
|
ConvertToLinuxPath(path string) string
|
|
|
|
ConvertToWindowsPath(path string) string
|
2022-09-12 03:55:57 -07:00
|
|
|
Connection(connectionType ConnectionType) (*Connection, error)
|
2022-01-23 12:37:51 -08:00
|
|
|
TemplateCache() *TemplateCache
|
2022-08-02 22:25:42 -07:00
|
|
|
LoadTemplateCache()
|
2023-01-22 11:06:31 -08:00
|
|
|
SetPromptCount()
|
2023-02-01 00:59:50 -08:00
|
|
|
CursorPosition() (row, col int)
|
2023-02-19 07:24:52 -08:00
|
|
|
SystemInfo() (*SystemInfo, error)
|
2023-01-16 11:58:43 -08:00
|
|
|
Debug(message string)
|
|
|
|
Error(err error)
|
|
|
|
Trace(start time.Time, args ...string)
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2021-02-11 04:19:47 -08:00
|
|
|
type commandCache struct {
|
2022-12-28 01:12:53 -08:00
|
|
|
commands *ConcurrentMap
|
2021-02-11 04:19:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *commandCache) set(command, path string) {
|
2022-12-28 01:12:53 -08:00
|
|
|
c.commands.Set(command, path)
|
2021-02-11 04:19:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *commandCache) get(command string) (string, bool) {
|
2022-12-28 01:12:53 -08:00
|
|
|
cacheCommand, found := c.commands.Get(command)
|
2021-09-21 22:53:59 -07:00
|
|
|
if !found {
|
|
|
|
return "", false
|
|
|
|
}
|
2022-07-05 07:27:25 -07:00
|
|
|
command, ok := cacheCommand.(string)
|
2021-09-23 13:57:38 -07:00
|
|
|
return command, ok
|
2021-02-11 04:19:47 -08:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
type Shell struct {
|
2022-04-06 00:05:17 -07:00
|
|
|
CmdFlags *Flags
|
|
|
|
Version string
|
2023-02-19 11:21:33 -08:00
|
|
|
Var map[string]interface{}
|
2022-04-06 00:05:17 -07:00
|
|
|
|
2022-11-21 02:10:50 -08:00
|
|
|
cwd string
|
|
|
|
cmdCache *commandCache
|
|
|
|
fileCache *fileCache
|
|
|
|
tmplCache *TemplateCache
|
|
|
|
networks []*Connection
|
2022-12-28 01:12:53 -08:00
|
|
|
|
|
|
|
sync.RWMutex
|
2021-08-01 06:25:15 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) Init() {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-03-12 13:04:08 -08:00
|
|
|
if env.CmdFlags == nil {
|
|
|
|
env.CmdFlags = &Flags{}
|
|
|
|
}
|
2022-05-07 23:17:48 -07:00
|
|
|
if env.CmdFlags.Debug {
|
2022-11-21 02:10:50 -08:00
|
|
|
log.Enable()
|
2022-05-07 23:17:48 -07:00
|
|
|
}
|
2022-01-18 12:25:18 -08:00
|
|
|
env.fileCache = &fileCache{}
|
2022-01-23 12:37:51 -08:00
|
|
|
env.fileCache.Init(env.CachePath())
|
2022-03-16 00:47:39 -07:00
|
|
|
env.resolveConfigPath()
|
2021-11-16 22:16:43 -08:00
|
|
|
env.cmdCache = &commandCache{
|
2022-12-28 01:12:53 -08:00
|
|
|
commands: NewConcurrentMap(),
|
2021-08-01 06:25:15 -07:00
|
|
|
}
|
2023-01-22 11:06:31 -08:00
|
|
|
env.SetPromptCount()
|
2021-08-01 06:25:15 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) resolveConfigPath() {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-03-16 00:47:39 -07:00
|
|
|
if len(env.CmdFlags.Config) == 0 {
|
|
|
|
env.CmdFlags.Config = env.Getenv("POSH_THEME")
|
2022-02-25 03:51:38 -08:00
|
|
|
}
|
2022-03-16 00:47:39 -07:00
|
|
|
if len(env.CmdFlags.Config) == 0 {
|
2023-02-02 22:53:03 -08:00
|
|
|
env.Debug("No config set, fallback to default config")
|
2022-10-12 05:59:37 -07:00
|
|
|
return
|
2021-12-30 06:39:30 -08:00
|
|
|
}
|
2022-03-23 23:25:29 -07:00
|
|
|
if strings.HasPrefix(env.CmdFlags.Config, "https://") {
|
2022-04-29 05:28:29 -07:00
|
|
|
if err := env.downloadConfig(env.CmdFlags.Config); err != nil {
|
|
|
|
// make it use default config when download fails
|
2023-02-02 22:53:03 -08:00
|
|
|
env.Error(err)
|
2022-04-29 05:28:29 -07:00
|
|
|
env.CmdFlags.Config = ""
|
2022-04-25 00:50:55 -07:00
|
|
|
return
|
|
|
|
}
|
2022-02-25 03:51:38 -08:00
|
|
|
}
|
2022-01-13 23:39:08 -08:00
|
|
|
// Cygwin path always needs the full path as we're on Windows but not really.
|
|
|
|
// Doing filepath actions will convert it to a Windows path and break the init script.
|
2022-08-02 22:25:59 -07:00
|
|
|
if env.Platform() == WINDOWS && env.Shell() == "bash" {
|
2023-02-02 22:53:03 -08:00
|
|
|
env.Debug("Cygwin detected, using full path for config")
|
2022-01-13 23:39:08 -08:00
|
|
|
return
|
|
|
|
}
|
2022-03-12 13:04:08 -08:00
|
|
|
configFile := env.CmdFlags.Config
|
2021-12-30 06:39:30 -08:00
|
|
|
if strings.HasPrefix(configFile, "~") {
|
|
|
|
configFile = strings.TrimPrefix(configFile, "~")
|
2022-01-23 12:37:51 -08:00
|
|
|
configFile = filepath.Join(env.Home(), configFile)
|
2021-12-30 06:39:30 -08:00
|
|
|
}
|
|
|
|
if !filepath.IsAbs(configFile) {
|
2022-11-02 03:48:19 -07:00
|
|
|
configFile = filepath.Join(env.Pwd(), configFile)
|
2021-12-30 06:39:30 -08:00
|
|
|
}
|
2022-03-12 13:04:08 -08:00
|
|
|
env.CmdFlags.Config = filepath.Clean(configFile)
|
2021-12-30 06:39:30 -08:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) downloadConfig(location string) error {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), location)
|
2023-01-12 06:10:17 -08:00
|
|
|
ext := filepath.Ext(location)
|
|
|
|
configPath := filepath.Join(env.CachePath(), "config.omp"+ext)
|
2022-07-17 12:11:23 -07:00
|
|
|
cfg, err := env.HTTPRequest(location, nil, 5000)
|
2022-03-16 00:47:39 -07:00
|
|
|
if err != nil {
|
2022-04-25 00:50:55 -07:00
|
|
|
return err
|
2022-03-16 00:47:39 -07:00
|
|
|
}
|
|
|
|
out, err := os.Create(configPath)
|
|
|
|
if err != nil {
|
2022-04-25 00:50:55 -07:00
|
|
|
return err
|
2022-03-16 00:47:39 -07:00
|
|
|
}
|
|
|
|
defer out.Close()
|
|
|
|
_, err = io.Copy(out, bytes.NewReader(cfg))
|
|
|
|
if err != nil {
|
2022-04-25 00:50:55 -07:00
|
|
|
return err
|
2022-03-16 00:47:39 -07:00
|
|
|
}
|
|
|
|
env.CmdFlags.Config = configPath
|
2022-04-25 00:50:55 -07:00
|
|
|
return nil
|
2022-03-16 00:47:39 -07:00
|
|
|
}
|
|
|
|
|
2023-01-16 11:58:43 -08:00
|
|
|
func (env *Shell) Trace(start time.Time, args ...string) {
|
|
|
|
log.Trace(start, args...)
|
2021-08-01 06:25:15 -07:00
|
|
|
}
|
|
|
|
|
2023-01-16 11:58:43 -08:00
|
|
|
func (env *Shell) Debug(message string) {
|
|
|
|
log.Debug(message)
|
2022-11-21 02:10:50 -08:00
|
|
|
}
|
|
|
|
|
2023-01-16 11:58:43 -08:00
|
|
|
func (env *Shell) Error(err error) {
|
|
|
|
log.Error(err)
|
2021-10-20 02:55:53 -07:00
|
|
|
}
|
|
|
|
|
2023-01-16 11:58:43 -08:00
|
|
|
func (env *Shell) debugF(fn func() string) {
|
|
|
|
log.DebugF(fn)
|
2022-04-05 04:32:32 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) Getenv(key string) string {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), key)
|
2021-11-10 10:34:26 -08:00
|
|
|
val := os.Getenv(key)
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(val)
|
2021-11-10 10:34:26 -08:00
|
|
|
return val
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) Pwd() string {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
|
|
|
defer env.Debug(env.cwd)
|
2020-10-12 00:04:37 -07:00
|
|
|
if env.cwd != "" {
|
|
|
|
return env.cwd
|
|
|
|
}
|
2020-10-08 10:23:20 -07:00
|
|
|
correctPath := func(pwd string) string {
|
2022-10-12 02:48:52 -07:00
|
|
|
if env.GOOS() != WINDOWS {
|
|
|
|
return pwd
|
2022-10-03 07:46:16 -07:00
|
|
|
}
|
2022-10-12 02:48:52 -07:00
|
|
|
// on Windows, and being case sensitive and not consistent and all, this gives silly issues
|
|
|
|
driveLetter := regex.GetCompiledRegex(`^[a-z]:`)
|
|
|
|
return driveLetter.ReplaceAllStringFunc(pwd, strings.ToUpper)
|
2020-10-08 10:23:20 -07:00
|
|
|
}
|
2022-03-12 13:04:08 -08:00
|
|
|
if env.CmdFlags != nil && env.CmdFlags.PWD != "" {
|
2022-10-12 02:48:52 -07:00
|
|
|
env.cwd = correctPath(env.CmdFlags.PWD)
|
2020-10-12 00:04:37 -07:00
|
|
|
return env.cwd
|
2020-10-08 10:23:20 -07:00
|
|
|
}
|
2020-10-02 12:50:13 -07:00
|
|
|
dir, err := os.Getwd()
|
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2020-10-02 12:50:13 -07:00
|
|
|
return ""
|
|
|
|
}
|
2020-10-12 00:04:37 -07:00
|
|
|
env.cwd = correctPath(dir)
|
|
|
|
return env.cwd
|
2020-10-02 12:50:13 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) HasFiles(pattern string) bool {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), pattern)
|
2022-01-23 12:37:51 -08:00
|
|
|
cwd := env.Pwd()
|
2022-11-02 07:04:20 -07:00
|
|
|
fileSystem := os.DirFS(cwd)
|
|
|
|
matches, err := fs.Glob(fileSystem, pattern)
|
2020-10-01 11:57:02 -07:00
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2020-10-01 11:57:02 -07:00
|
|
|
return false
|
|
|
|
}
|
2022-04-23 00:46:57 -07:00
|
|
|
for _, match := range matches {
|
2022-11-02 07:04:20 -07:00
|
|
|
file, err := fs.Stat(fileSystem, match)
|
|
|
|
if err != nil || file.IsDir() {
|
2022-04-23 00:46:57 -07:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
2020-10-01 11:57:02 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) HasFilesInDir(dir, pattern string) bool {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), pattern)
|
2022-11-02 07:04:20 -07:00
|
|
|
fileSystem := os.DirFS(dir)
|
|
|
|
matches, err := fs.Glob(fileSystem, pattern)
|
2020-12-01 11:43:30 -08:00
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2020-12-01 11:43:30 -08:00
|
|
|
return false
|
|
|
|
}
|
2022-04-05 04:32:32 -07:00
|
|
|
hasFilesInDir := len(matches) > 0
|
2023-01-16 11:58:43 -08:00
|
|
|
env.debugF(func() string { return strconv.FormatBool(hasFilesInDir) })
|
2022-04-05 04:32:32 -07:00
|
|
|
return hasFilesInDir
|
2020-12-01 11:43:30 -08:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) HasFileInParentDirs(pattern string, depth uint) bool {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), pattern, fmt.Sprint(depth))
|
2022-02-13 23:41:33 -08:00
|
|
|
currentFolder := env.Pwd()
|
|
|
|
|
|
|
|
for c := 0; c < int(depth); c++ {
|
|
|
|
if env.HasFilesInDir(currentFolder, pattern) {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug("true")
|
2022-02-13 23:41:33 -08:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if dir := filepath.Dir(currentFolder); dir != currentFolder {
|
|
|
|
currentFolder = dir
|
|
|
|
} else {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug("false")
|
2022-02-13 23:41:33 -08:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug("false")
|
2022-02-13 23:41:33 -08:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) HasFolder(folder string) bool {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), folder)
|
2022-04-23 00:46:57 -07:00
|
|
|
f, err := os.Stat(folder)
|
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug("false")
|
2022-04-23 00:46:57 -07:00
|
|
|
return false
|
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.debugF(func() string { return strconv.FormatBool(f.IsDir()) })
|
2022-04-23 00:46:57 -07:00
|
|
|
return f.IsDir()
|
2020-10-07 04:32:42 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) ResolveSymlink(path string) (string, error) {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), path)
|
2022-07-25 22:28:54 -07:00
|
|
|
link, err := filepath.EvalSymlinks(path)
|
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2022-07-25 22:28:54 -07:00
|
|
|
return "", err
|
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(link)
|
2022-07-25 22:28:54 -07:00
|
|
|
return link, nil
|
2022-04-19 20:51:00 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) FileContent(file string) string {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), file)
|
2022-04-06 00:57:33 -07:00
|
|
|
if !filepath.IsAbs(file) {
|
|
|
|
file = filepath.Join(env.Pwd(), file)
|
|
|
|
}
|
2022-06-01 00:50:20 -07:00
|
|
|
content, err := os.ReadFile(file)
|
2020-10-07 04:32:42 -07:00
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2020-10-07 04:32:42 -07:00
|
|
|
return ""
|
|
|
|
}
|
2022-04-05 04:32:32 -07:00
|
|
|
fileContent := string(content)
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(fileContent)
|
2022-04-05 04:32:32 -07:00
|
|
|
return fileContent
|
2020-10-07 04:32:42 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) LsDir(path string) []fs.DirEntry {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), path)
|
2022-04-16 10:52:59 -07:00
|
|
|
entries, err := os.ReadDir(path)
|
2021-09-04 11:32:55 -07:00
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2021-09-04 11:32:55 -07:00
|
|
|
return nil
|
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.debugF(func() string {
|
2022-04-16 10:52:59 -07:00
|
|
|
var entriesStr string
|
|
|
|
for _, entry := range entries {
|
|
|
|
entriesStr += entry.Name() + "\n"
|
2021-09-04 11:32:55 -07:00
|
|
|
}
|
2022-04-16 10:52:59 -07:00
|
|
|
return entriesStr
|
|
|
|
})
|
|
|
|
return entries
|
2021-09-04 11:32:55 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) PathSeparator() string {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2019-03-13 04:14:30 -07:00
|
|
|
return string(os.PathSeparator)
|
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) User() string {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2020-10-12 03:53:54 -07:00
|
|
|
user := os.Getenv("USER")
|
|
|
|
if user == "" {
|
|
|
|
user = os.Getenv("USERNAME")
|
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(user)
|
2020-10-12 03:53:54 -07:00
|
|
|
return user
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) Host() (string, error) {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2019-03-13 04:14:30 -07:00
|
|
|
hostName, err := os.Hostname()
|
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2019-03-13 04:14:30 -07:00
|
|
|
return "", err
|
|
|
|
}
|
2022-04-05 04:32:32 -07:00
|
|
|
hostName = cleanHostName(hostName)
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(hostName)
|
2022-04-05 04:32:32 -07:00
|
|
|
return hostName, nil
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) GOOS() string {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2019-03-13 04:14:30 -07:00
|
|
|
return runtime.GOOS
|
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) RunCommand(command string, args ...string) (string, error) {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), append([]string{command}, args...)...)
|
2022-07-05 07:27:25 -07:00
|
|
|
if cacheCommand, ok := env.cmdCache.get(command); ok {
|
|
|
|
command = cacheCommand
|
|
|
|
}
|
|
|
|
output, err := cmd.Run(command, args...)
|
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2022-07-05 07:27:25 -07:00
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(output)
|
2022-07-05 07:27:25 -07:00
|
|
|
return output, err
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) RunShellCommand(shell, command string) string {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-02-19 05:35:57 -08:00
|
|
|
if out, err := env.RunCommand(shell, "-c", command); err == nil {
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
return ""
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) CommandPath(command string) string {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), command)
|
2022-04-19 20:51:00 -07:00
|
|
|
if path, ok := env.cmdCache.get(command); ok {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(path)
|
2022-04-19 20:51:00 -07:00
|
|
|
return path
|
2021-01-05 04:05:37 -08:00
|
|
|
}
|
2020-12-27 23:33:58 -08:00
|
|
|
path, err := exec.LookPath(command)
|
2021-01-05 04:05:37 -08:00
|
|
|
if err == nil {
|
2021-02-11 04:19:47 -08:00
|
|
|
env.cmdCache.set(command, path)
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(path)
|
2022-04-19 20:51:00 -07:00
|
|
|
return path
|
2021-01-05 04:05:37 -08:00
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2022-04-19 20:51:00 -07:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) HasCommand(command string) bool {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), command)
|
2022-04-19 20:51:00 -07:00
|
|
|
if path := env.CommandPath(command); path != "" {
|
2022-02-07 09:50:52 -08:00
|
|
|
return true
|
|
|
|
}
|
2021-01-05 04:05:37 -08:00
|
|
|
return false
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) ErrorCode() int {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-03-12 13:04:08 -08:00
|
|
|
return env.CmdFlags.ErrorCode
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) ExecutionTime() float64 {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-03-12 13:04:08 -08:00
|
|
|
if env.CmdFlags.ExecutionTime < 0 {
|
2020-12-12 03:54:25 -08:00
|
|
|
return 0
|
|
|
|
}
|
2022-03-12 13:04:08 -08:00
|
|
|
return env.CmdFlags.ExecutionTime
|
2020-12-06 13:03:40 -08:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) Flags() *Flags {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-03-12 13:04:08 -08:00
|
|
|
return env.CmdFlags
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) Shell() string {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-03-12 13:04:08 -08:00
|
|
|
if env.CmdFlags.Shell != "" {
|
|
|
|
return env.CmdFlags.Shell
|
2020-12-27 05:59:40 -08:00
|
|
|
}
|
2020-09-15 04:44:53 -07:00
|
|
|
pid := os.Getppid()
|
2020-10-23 07:36:40 -07:00
|
|
|
p, _ := process.NewProcess(int32(pid))
|
|
|
|
name, err := p.Name()
|
2020-09-24 10:11:56 -07:00
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2022-08-02 22:25:59 -07:00
|
|
|
return UNKNOWN
|
2020-09-24 10:11:56 -07:00
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug("process name: " + name)
|
2022-09-18 10:34:37 -07:00
|
|
|
// this is used for when scoop creates a shim, see
|
2022-12-28 08:30:48 -08:00
|
|
|
// https://github.com/jandedobbeleer/oh-my-posh/issues/2806
|
2022-09-18 10:34:37 -07:00
|
|
|
executable, _ := os.Executable()
|
|
|
|
if name == "cmd.exe" || name == executable {
|
2020-11-02 09:43:10 -08:00
|
|
|
p, _ = p.Parent()
|
|
|
|
name, err = p.Name()
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug("parent process name: " + name)
|
2020-11-02 09:43:10 -08:00
|
|
|
}
|
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2022-08-02 22:25:59 -07:00
|
|
|
return UNKNOWN
|
2020-11-02 09:43:10 -08:00
|
|
|
}
|
2020-12-27 10:51:32 -08:00
|
|
|
// Cache the shell value to speed things up.
|
2022-04-29 05:28:29 -07:00
|
|
|
env.CmdFlags.Shell = strings.Trim(strings.TrimSuffix(name, ".exe"), " ")
|
2022-03-12 13:04:08 -08:00
|
|
|
return env.CmdFlags.Shell
|
2020-09-15 04:44:53 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) unWrapError(err error) error {
|
2022-08-03 22:06:55 -07:00
|
|
|
cause := err
|
|
|
|
for {
|
|
|
|
type nested interface{ Unwrap() error }
|
|
|
|
unwrap, ok := cause.(nested)
|
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
cause = unwrap.Unwrap()
|
|
|
|
}
|
|
|
|
return cause
|
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) HTTPRequest(targetURL string, body io.Reader, timeout int, requestModifiers ...HTTPRequestModifier) ([]byte, error) {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), targetURL)
|
2021-08-17 23:21:55 -07:00
|
|
|
ctx, cncl := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout))
|
2020-12-31 00:39:02 -08:00
|
|
|
defer cncl()
|
2022-07-17 12:11:23 -07:00
|
|
|
request, err := http.NewRequestWithContext(ctx, http.MethodGet, targetURL, body)
|
2020-11-19 19:12:20 -08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-12-14 23:49:32 -08:00
|
|
|
for _, modifier := range requestModifiers {
|
|
|
|
modifier(request)
|
|
|
|
}
|
2022-07-17 12:11:23 -07:00
|
|
|
if env.CmdFlags.Debug {
|
|
|
|
dump, _ := httputil.DumpRequestOut(request, true)
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(string(dump))
|
2022-07-17 12:11:23 -07:00
|
|
|
}
|
2020-11-19 19:12:20 -08:00
|
|
|
response, err := client.Do(request)
|
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2022-08-03 22:06:55 -07:00
|
|
|
return nil, env.unWrapError(err)
|
2020-11-19 19:12:20 -08:00
|
|
|
}
|
2022-04-24 08:01:15 -07:00
|
|
|
// anything inside the range [200, 299] is considered a success
|
2022-04-25 00:32:40 -07:00
|
|
|
if response.StatusCode < 200 || response.StatusCode >= 300 {
|
2022-04-24 08:01:15 -07:00
|
|
|
message := "HTTP status code " + strconv.Itoa(response.StatusCode)
|
|
|
|
err := errors.New(message)
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2022-04-24 08:01:15 -07:00
|
|
|
return nil, err
|
|
|
|
}
|
2020-11-19 19:12:20 -08:00
|
|
|
defer response.Body.Close()
|
2022-07-17 12:11:23 -07:00
|
|
|
responseBody, err := io.ReadAll(response.Body)
|
2020-11-19 19:12:20 -08:00
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2020-11-19 19:12:20 -08:00
|
|
|
return nil, err
|
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Debug(string(responseBody))
|
2022-07-17 12:11:23 -07:00
|
|
|
return responseBody, nil
|
2020-11-19 19:12:20 -08:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) HasParentFilePath(path string) (*FileInfo, error) {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now(), path)
|
2022-01-23 12:37:51 -08:00
|
|
|
currentFolder := env.Pwd()
|
2021-01-05 11:12:52 -08:00
|
|
|
for {
|
2022-11-02 07:57:30 -07:00
|
|
|
fileSystem := os.DirFS(currentFolder)
|
|
|
|
info, err := fs.Stat(fileSystem, path)
|
2021-01-05 11:12:52 -08:00
|
|
|
if err == nil {
|
2022-01-23 12:37:51 -08:00
|
|
|
return &FileInfo{
|
|
|
|
ParentFolder: currentFolder,
|
2022-11-02 07:57:30 -07:00
|
|
|
Path: filepath.Join(currentFolder, path),
|
2022-01-23 12:37:51 -08:00
|
|
|
IsDir: info.IsDir(),
|
2021-01-05 11:12:52 -08:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if dir := filepath.Dir(currentFolder); dir != currentFolder {
|
|
|
|
currentFolder = dir
|
|
|
|
continue
|
|
|
|
}
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2021-01-05 11:12:52 -08:00
|
|
|
return nil, errors.New("no match at root level")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) StackCount() int {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-03-12 13:04:08 -08:00
|
|
|
if env.CmdFlags.StackCount < 0 {
|
2021-04-12 01:58:03 -07:00
|
|
|
return 0
|
|
|
|
}
|
2022-03-12 13:04:08 -08:00
|
|
|
return env.CmdFlags.StackCount
|
2021-04-12 01:58:03 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) Cache() Cache {
|
2021-09-21 11:22:59 -07:00
|
|
|
return env.fileCache
|
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) Close() {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-08-02 22:25:42 -07:00
|
|
|
templateCache, err := json.Marshal(env.TemplateCache())
|
|
|
|
if err == nil {
|
|
|
|
env.fileCache.Set(TEMPLATECACHE, string(templateCache), 1440)
|
|
|
|
}
|
2022-01-23 12:37:51 -08:00
|
|
|
env.fileCache.Close()
|
2021-11-16 10:59:42 -08:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) LoadTemplateCache() {
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
2022-12-25 11:40:23 -08:00
|
|
|
val, OK := env.fileCache.Get(TEMPLATECACHE)
|
2022-08-02 22:25:42 -07:00
|
|
|
if !OK {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var templateCache TemplateCache
|
|
|
|
err := json.Unmarshal([]byte(val), &templateCache)
|
|
|
|
if err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(err)
|
2022-08-02 22:25:42 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
env.tmplCache = &templateCache
|
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) Logs() string {
|
2022-11-21 02:10:50 -08:00
|
|
|
return log.String()
|
2021-09-21 11:22:59 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) TemplateCache() *TemplateCache {
|
2022-12-28 01:12:53 -08:00
|
|
|
env.Lock()
|
2023-01-16 11:58:43 -08:00
|
|
|
defer env.Trace(time.Now())
|
|
|
|
defer env.Unlock()
|
2022-01-18 00:48:47 -08:00
|
|
|
if env.tmplCache != nil {
|
|
|
|
return env.tmplCache
|
|
|
|
}
|
2023-01-22 11:06:31 -08:00
|
|
|
|
2022-02-03 08:45:35 -08:00
|
|
|
tmplCache := &TemplateCache{
|
2022-04-20 10:16:02 -07:00
|
|
|
Root: env.Root(),
|
|
|
|
Shell: env.Shell(),
|
|
|
|
ShellVersion: env.CmdFlags.ShellVersion,
|
|
|
|
Code: env.ErrorCode(),
|
|
|
|
WSL: env.IsWsl(),
|
2022-12-28 01:12:53 -08:00
|
|
|
Segments: make(map[string]interface{}),
|
2023-01-22 11:06:31 -08:00
|
|
|
PromptCount: env.CmdFlags.PromptCount,
|
2022-01-18 00:48:47 -08:00
|
|
|
}
|
2022-02-03 08:45:35 -08:00
|
|
|
tmplCache.Env = make(map[string]string)
|
2023-02-19 11:21:33 -08:00
|
|
|
tmplCache.Var = make(map[string]interface{})
|
|
|
|
|
|
|
|
if env.Var != nil {
|
|
|
|
tmplCache.Var = env.Var
|
|
|
|
}
|
2023-01-22 11:06:31 -08:00
|
|
|
|
2022-01-18 00:48:47 -08:00
|
|
|
const separator = "="
|
|
|
|
values := os.Environ()
|
|
|
|
for value := range values {
|
2023-01-19 20:14:14 -08:00
|
|
|
key, val, valid := strings.Cut(values[value], separator)
|
|
|
|
if !valid {
|
2022-01-18 00:48:47 -08:00
|
|
|
continue
|
|
|
|
}
|
2023-01-19 20:14:14 -08:00
|
|
|
tmplCache.Env[key] = val
|
2022-01-18 00:48:47 -08:00
|
|
|
}
|
2023-01-22 11:06:31 -08:00
|
|
|
|
2022-08-31 02:55:23 -07:00
|
|
|
pwd := env.Pwd()
|
2022-08-31 22:44:27 -07:00
|
|
|
tmplCache.PWD = ReplaceHomeDirPrefixWithTilde(env, pwd)
|
2022-08-31 02:55:23 -07:00
|
|
|
tmplCache.Folder = Base(env, pwd)
|
2022-10-03 07:46:16 -07:00
|
|
|
if env.GOOS() == WINDOWS && strings.HasSuffix(tmplCache.Folder, ":") {
|
|
|
|
tmplCache.Folder += `\`
|
|
|
|
}
|
2023-01-22 11:06:31 -08:00
|
|
|
|
2022-02-03 08:45:35 -08:00
|
|
|
tmplCache.UserName = env.User()
|
2022-01-23 12:37:51 -08:00
|
|
|
if host, err := env.Host(); err == nil {
|
2022-02-03 08:45:35 -08:00
|
|
|
tmplCache.HostName = host
|
2022-01-18 00:48:47 -08:00
|
|
|
}
|
2023-01-22 11:06:31 -08:00
|
|
|
|
2022-01-23 12:37:51 -08:00
|
|
|
goos := env.GOOS()
|
2022-02-03 08:45:35 -08:00
|
|
|
tmplCache.OS = goos
|
2022-08-02 22:25:59 -07:00
|
|
|
if goos == LINUX {
|
2022-02-03 08:45:35 -08:00
|
|
|
tmplCache.OS = env.Platform()
|
2022-02-03 02:42:31 -08:00
|
|
|
}
|
2023-01-22 11:06:31 -08:00
|
|
|
|
2022-02-03 08:45:35 -08:00
|
|
|
env.tmplCache = tmplCache
|
|
|
|
return tmplCache
|
2022-01-18 00:48:47 -08:00
|
|
|
}
|
|
|
|
|
2022-11-09 11:27:54 -08:00
|
|
|
func (env *Shell) DirMatchesOneOf(dir string, regexes []string) (match bool) {
|
2022-04-27 12:24:31 -07:00
|
|
|
// sometimes the function panics inside golang, we want to silence that error
|
|
|
|
// and assume that there's no match. Not perfect, but better than crashing
|
|
|
|
// for the time being until we figure out what the actual root cause is
|
|
|
|
defer func() {
|
|
|
|
if err := recover(); err != nil {
|
2023-01-16 11:58:43 -08:00
|
|
|
env.Error(errors.New("panic"))
|
2022-04-27 12:24:31 -07:00
|
|
|
match = false
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
match = dirMatchesOneOf(dir, env.Home(), env.GOOS(), regexes)
|
|
|
|
return
|
2022-04-06 00:05:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func dirMatchesOneOf(dir, home, goos string, regexes []string) bool {
|
2023-01-26 06:56:47 -08:00
|
|
|
if len(regexes) == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-10-03 07:46:16 -07:00
|
|
|
if goos == WINDOWS {
|
|
|
|
dir = strings.ReplaceAll(dir, "\\", "/")
|
|
|
|
home = strings.ReplaceAll(home, "\\", "/")
|
|
|
|
}
|
2022-01-26 01:23:18 -08:00
|
|
|
|
|
|
|
for _, element := range regexes {
|
|
|
|
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
|
|
|
|
if strings.HasPrefix(normalizedElement, "~") {
|
2022-10-03 07:46:16 -07:00
|
|
|
normalizedElement = strings.Replace(normalizedElement, "~", home, 1)
|
2022-01-26 01:23:18 -08:00
|
|
|
}
|
|
|
|
pattern := fmt.Sprintf("^%s$", normalizedElement)
|
2022-08-02 22:25:59 -07:00
|
|
|
if goos == WINDOWS || goos == DARWIN {
|
2022-01-26 01:23:18 -08:00
|
|
|
pattern = "(?i)" + pattern
|
|
|
|
}
|
2022-10-03 07:46:16 -07:00
|
|
|
matched := regex.MatchString(pattern, dir)
|
2022-01-26 01:23:18 -08:00
|
|
|
if matched {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-01-22 11:06:31 -08:00
|
|
|
func (env *Shell) SetPromptCount() {
|
|
|
|
countStr := os.Getenv("POSH_PROMPT_COUNT")
|
|
|
|
if len(countStr) > 0 {
|
|
|
|
// this counter is incremented by the shell
|
|
|
|
count, err := strconv.Atoi(countStr)
|
|
|
|
if err == nil {
|
|
|
|
env.CmdFlags.PromptCount = count
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var count int
|
|
|
|
if val, found := env.Cache().Get(PROMPTCOUNTCACHE); found {
|
|
|
|
count, _ = strconv.Atoi(val)
|
|
|
|
}
|
|
|
|
// only write to cache if we're the primary prompt
|
|
|
|
if env.CmdFlags.Primary {
|
|
|
|
count++
|
|
|
|
env.Cache().Set(PROMPTCOUNTCACHE, strconv.Itoa(count), 1440)
|
|
|
|
}
|
|
|
|
env.CmdFlags.PromptCount = count
|
|
|
|
}
|
|
|
|
|
2023-02-01 00:59:50 -08:00
|
|
|
func (env *Shell) CursorPosition() (row, col int) {
|
|
|
|
if number, err := strconv.Atoi(env.Getenv("POSH_CURSOR_LINE")); err == nil {
|
|
|
|
row = number
|
|
|
|
}
|
|
|
|
if number, err := strconv.Atoi(env.Getenv("POSH_CURSOR_COLUMN")); err != nil {
|
|
|
|
col = number
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-19 07:24:52 -08:00
|
|
|
func (env *Shell) SystemInfo() (*SystemInfo, error) {
|
|
|
|
s := &SystemInfo{}
|
|
|
|
|
|
|
|
mem, err := env.Memory()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
s.Memory = *mem
|
|
|
|
|
|
|
|
loadStat, err := load.Avg()
|
|
|
|
if err == nil {
|
|
|
|
s.Load1 = loadStat.Load1
|
|
|
|
s.Load5 = loadStat.Load5
|
|
|
|
s.Load15 = loadStat.Load15
|
|
|
|
}
|
|
|
|
|
|
|
|
processorTimes, err := cpu.Percent(0, false)
|
|
|
|
if err == nil && len(processorTimes) > 0 {
|
|
|
|
s.Times = processorTimes[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
processors, err := cpu.Info()
|
|
|
|
if err == nil {
|
|
|
|
s.CPU = processors
|
|
|
|
}
|
|
|
|
|
|
|
|
diskIO, err := disk.IOCounters()
|
|
|
|
if err == nil {
|
|
|
|
s.Disks = diskIO
|
|
|
|
}
|
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
2022-10-03 07:46:16 -07:00
|
|
|
func IsPathSeparator(env Environment, c uint8) bool {
|
2022-08-31 22:44:27 -07:00
|
|
|
if c == '/' {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if env.GOOS() == WINDOWS && c == '\\' {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-01-26 01:23:18 -08:00
|
|
|
// Base returns the last element of path.
|
|
|
|
// Trailing path separators are removed before extracting the last element.
|
|
|
|
// If the path consists entirely of separators, Base returns a single separator.
|
|
|
|
func Base(env Environment, path string) string {
|
|
|
|
volumeName := filepath.VolumeName(path)
|
|
|
|
// Strip trailing slashes.
|
2022-10-03 07:46:16 -07:00
|
|
|
for len(path) > 0 && IsPathSeparator(env, path[len(path)-1]) {
|
2022-01-26 01:23:18 -08:00
|
|
|
path = path[0 : len(path)-1]
|
|
|
|
}
|
2022-10-03 07:46:16 -07:00
|
|
|
if len(path) == 0 {
|
|
|
|
return env.PathSeparator()
|
|
|
|
}
|
2022-01-26 01:23:18 -08:00
|
|
|
if volumeName == path {
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
// Throw away volume name
|
|
|
|
path = path[len(filepath.VolumeName(path)):]
|
|
|
|
// Find the last element
|
|
|
|
i := len(path) - 1
|
2022-10-03 07:46:16 -07:00
|
|
|
for i >= 0 && !IsPathSeparator(env, path[i]) {
|
2022-01-26 01:23:18 -08:00
|
|
|
i--
|
|
|
|
}
|
|
|
|
if i >= 0 {
|
|
|
|
path = path[i+1:]
|
|
|
|
}
|
|
|
|
// If empty now, it had only slashes.
|
2022-10-03 07:46:16 -07:00
|
|
|
if len(path) == 0 {
|
2022-02-19 10:04:06 -08:00
|
|
|
return env.PathSeparator()
|
2022-01-26 01:23:18 -08:00
|
|
|
}
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
|
2022-08-31 22:44:27 -07:00
|
|
|
func ReplaceHomeDirPrefixWithTilde(env Environment, path string) string {
|
2022-10-03 07:46:16 -07:00
|
|
|
home := env.Home()
|
|
|
|
// match Home directory exactly
|
|
|
|
if !strings.HasPrefix(path, home) {
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
rem := path[len(home):]
|
|
|
|
if len(rem) == 0 || IsPathSeparator(env, rem[0]) {
|
|
|
|
return "~" + rem
|
2022-08-31 22:44:27 -07:00
|
|
|
}
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
|
2019-03-13 04:14:30 -07:00
|
|
|
func cleanHostName(hostName string) string {
|
|
|
|
garbage := []string{
|
|
|
|
".lan",
|
|
|
|
".local",
|
2020-10-07 08:14:26 -07:00
|
|
|
".localdomain",
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
for _, g := range garbage {
|
2020-10-07 08:14:26 -07:00
|
|
|
if strings.HasSuffix(hostName, g) {
|
|
|
|
hostName = strings.Replace(hostName, g, "", 1)
|
|
|
|
}
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
return hostName
|
|
|
|
}
|
2021-10-02 22:27:18 -07:00
|
|
|
|
|
|
|
func returnOrBuildCachePath(path string) string {
|
|
|
|
// validate root path
|
|
|
|
if _, err := os.Stat(path); err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
// validate oh-my-posh folder, if non existent, create it
|
2022-02-28 03:55:16 -08:00
|
|
|
cachePath := filepath.Join(path, "oh-my-posh")
|
2021-10-02 22:27:18 -07:00
|
|
|
if _, err := os.Stat(cachePath); err == nil {
|
|
|
|
return cachePath
|
|
|
|
}
|
|
|
|
if err := os.Mkdir(cachePath, 0755); err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return cachePath
|
|
|
|
}
|