1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2024 Datadog, Inc.
package utils
import (
"bytes"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
)
// This code is based on: https://github.com/mitchellh/go-homedir/blob/v1.1.0/homedir.go (MIT License)
// ExpandPath expands a file path that starts with '~' to the user's home directory.
// If the path does not start with '~', it is returned unchanged.
//
// Parameters:
//
// path - The file path to be expanded.
//
// Returns:
//
// The expanded file path, with '~' replaced by the user's home directory, if applicable.
func ExpandPath(path string) string {
if len(path) == 0 || path[0] != '~' {
return path
}
// If the second character is not '/' or '\', return the path unchanged
if len(path) > 1 && path[1] != '/' && path[1] != '\\' {
return path
}
homeFolder := getHomeDir()
if len(homeFolder) > 0 {
return filepath.Join(homeFolder, path[1:])
}
return path
}
// getHomeDir returns the home directory of the current user.
// The method used to determine the home directory depends on the operating system.
//
// On Windows, it prefers the HOME environment variable, then USERPROFILE, and finally combines HOMEDRIVE and HOMEPATH.
// On Unix-like systems, it prefers the HOME environment variable, and falls back to various shell commands
// to determine the home directory if necessary.
//
// Returns:
//
// The home directory of the current user.
func getHomeDir() string {
if runtime.GOOS == "windows" {
if home := os.Getenv("HOME"); home != "" {
// First prefer the HOME environment variable
return home
}
if userProfile := os.Getenv("USERPROFILE"); userProfile != "" {
// Prefer the USERPROFILE environment variable
return userProfile
}
homeDrive := os.Getenv("HOMEDRIVE")
homePath := os.Getenv("HOMEPATH")
return homeDrive + homePath
}
homeEnv := "HOME"
if runtime.GOOS == "plan9" {
// On plan9, environment variables are lowercase.
homeEnv = "home"
}
if home := os.Getenv(homeEnv); home != "" {
// Prefer the HOME environment variable
return home
}
var stdout bytes.Buffer
if runtime.GOOS == "darwin" {
// On macOS, use dscl to read the NFSHomeDirectory
cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`)
cmd.Stdout = &stdout
if err := cmd.Run(); err == nil {
result := strings.TrimSpace(stdout.String())
if result != "" {
return result
}
}
} else {
// On other Unix-like systems, use getent to read the passwd entry for the current user
cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
cmd.Stdout = &stdout
if err := cmd.Run(); err == nil {
if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
// The passwd entry is in the format: username:password:uid:gid:gecos:home:shell
passwdParts := strings.SplitN(passwd, ":", 7)
if len(passwdParts) > 5 {
return passwdParts[5]
}
}
}
}
// If all else fails, use the shell to determine the home directory
stdout.Reset()
cmd := exec.Command("sh", "-c", "cd && pwd")
cmd.Stdout = &stdout
if err := cmd.Run(); err == nil {
return strings.TrimSpace(stdout.String())
}
return ""
}
|