mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
* fix: MacOS MDM deployment script * fix: Handle shell alias for bash on macos * fix: Code review fixes * fix: Code review fixes * feat: Add support for global config file * feat: Add support for global config file * fix: Code review fixes * fix: Avoid blocking CLI for analytics flush
129 lines
3.3 KiB
Go
129 lines
3.3 KiB
Go
package alias
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
type bashShell struct{}
|
|
|
|
var _ Shell = &bashShell{}
|
|
|
|
// bashLoginFiles are the login startup files in the order bash reads them.
|
|
var bashLoginFiles = []string{".bash_profile", ".bash_login", ".profile"}
|
|
|
|
func NewBashShell() (*bashShell, error) {
|
|
return &bashShell{}, nil
|
|
}
|
|
|
|
func (b bashShell) Source(rcPath string) string {
|
|
return defaultShellSource(rcPath)
|
|
}
|
|
|
|
func (b bashShell) PathExport(binDir string) string {
|
|
return defaultPathExport(binDir)
|
|
}
|
|
|
|
func (b bashShell) Name() string {
|
|
return "bash"
|
|
}
|
|
|
|
func (b bashShell) CandidateRcFiles(homeDir string) []string {
|
|
files := []string{filepath.Join(homeDir, ".bashrc")}
|
|
for _, name := range bashLoginFiles {
|
|
files = append(files, filepath.Join(homeDir, name))
|
|
}
|
|
|
|
return files
|
|
}
|
|
|
|
func (b bashShell) InstallRcFiles(homeDir string, create bool) ([]string, error) {
|
|
return bashInstallRcFiles(homeDir, create, runtime.GOOS)
|
|
}
|
|
|
|
// bashInstallRcFiles resolves where bash should load PMG. bash reads .bashrc for
|
|
// interactive non-login shells and a login file (.bash_profile, .bash_login, or
|
|
// .profile) for login shells such as macOS Terminal, so the lines may need to
|
|
// land in both. goos is a parameter for testability.
|
|
func bashInstallRcFiles(homeDir string, create bool, goos string) ([]string, error) {
|
|
bashrc := filepath.Join(homeDir, ".bashrc")
|
|
bashrcExists := fileExists(bashrc)
|
|
login := firstExistingFile(homeDir, bashLoginFiles)
|
|
|
|
var files []string
|
|
if bashrcExists {
|
|
files = append(files, bashrc)
|
|
}
|
|
|
|
// macOS Terminal starts bash as a login shell, which does not read .bashrc.
|
|
// Create .bash_profile so the lines reach login shells too.
|
|
if login == "" && create && goos == "darwin" {
|
|
login = filepath.Join(homeDir, ".bash_profile")
|
|
if err := ensureFile(login); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Skip the login file when it already sources .bashrc, to avoid loading the
|
|
// lines twice.
|
|
if login != "" && (!bashrcExists || !referencesBashrc(login)) {
|
|
files = append(files, login)
|
|
}
|
|
|
|
if len(files) > 0 {
|
|
return files, nil
|
|
}
|
|
|
|
if !create {
|
|
return nil, nil
|
|
}
|
|
|
|
// Nothing exists yet: create the canonical file for this OS.
|
|
target := bashrc
|
|
if goos == "darwin" {
|
|
target = filepath.Join(homeDir, ".bash_profile")
|
|
}
|
|
|
|
if err := ensureFile(target); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return []string{target}, nil
|
|
}
|
|
|
|
// bashrcSourceRe matches a real sourcing of a bashrc file: a `source` or `.`
|
|
// command whose argument ends in `.bashrc` (for example `source ~/.bashrc` or
|
|
// `. "$HOME/.bashrc"`). Requiring the command keyword avoids matching mere
|
|
// mentions in comments or unrelated commands.
|
|
var bashrcSourceRe = regexp.MustCompile(`(^|[\s;&|()])(source|\.)\s+\S*\.bashrc($|[\s;'"&|)])`)
|
|
|
|
// referencesBashrc reports whether the file at path actually sources a bashrc
|
|
// file. It skips comment lines and inline comments so a commented mention does
|
|
// not wrongly suppress wiring the login file.
|
|
func referencesBashrc(path string) bool {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
for _, raw := range strings.Split(string(data), "\n") {
|
|
line := strings.TrimSpace(raw)
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
|
|
if i := strings.Index(line, "#"); i >= 0 {
|
|
line = line[:i]
|
|
}
|
|
|
|
if bashrcSourceRe.MatchString(line) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|