Skip to content

Commit

Permalink
bugfix: simplify unix-like env manager to accept PATH value from plug…
Browse files Browse the repository at this point in the history
…in which include many paths.
  • Loading branch information
aooohan committed Mar 4, 2024
1 parent c5c96f4 commit 571fa66
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 160 deletions.
40 changes: 0 additions & 40 deletions internal/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,43 +30,3 @@ type Manager interface {
}

type Envs map[string]*string

type KV struct {
Key string
Value string
}

type Store struct {
envMap map[string]string
deletedEnvMap map[string]struct{}
// $PATH
pathMap map[string]struct{}
deletedPathMap map[string]struct{}
}

func (s *Store) Add(kv *KV) {
if kv.Key == "PATH" {
s.pathMap[kv.Value] = struct{}{}
} else {
s.envMap[kv.Key] = kv.Value
}
}

func (s *Store) Remove(key string) {
if _, ok := s.pathMap[key]; ok {
delete(s.pathMap, key)
s.deletedPathMap[key] = struct{}{}
} else {
delete(s.envMap, key)
s.deletedEnvMap[key] = struct{}{}
}
}

func NewStore() *Store {
return &Store{
envMap: make(map[string]string),
pathMap: make(map[string]struct{}),
deletedPathMap: make(map[string]struct{}),
deletedEnvMap: make(map[string]struct{}),
}
}
172 changes: 52 additions & 120 deletions internal/env/macos_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@
package env

import (
"bufio"
"fmt"
"os"
"strings"
)

type macosEnvManager struct {
// ~/.version_fox/env.sh
vfEnvPath string
store *Store
envMap map[string]string
deletedEnvMap map[string]struct{}
// $PATH
paths []string
pathMap map[string]struct{}
deletedPathMap map[string]struct{}
}

func (m *macosEnvManager) Paths(paths []string) string {
Expand All @@ -40,166 +42,96 @@ func (m *macosEnvManager) Close() error {
}

func (m *macosEnvManager) Load(key, value string) error {
// TODO check PATH which include many values
m.store.Add(&KV{
Key: key,
Value: value,
})
if key == "PATH" {
pathArray := strings.Split(value, ":")
for _, path := range pathArray {
if _, ok := m.pathMap[path]; ok {
continue
}
m.paths = append(m.paths, path)
m.pathMap[path] = struct{}{}
}
} else {
m.envMap[key] = value
}
return nil
}
func (m *macosEnvManager) Remove(key string) error {
if key == "PATH" {
return fmt.Errorf("can not remove PATH variable")
}
m.store.Remove(key)
array := strings.Split(key, ":")
for _, k := range array {
if _, ok := m.pathMap[k]; ok {
delete(m.pathMap, k)
var newPaths []string
for _, v := range m.paths {
if v != k {
newPaths = append(newPaths, v)
}
}
m.paths = newPaths
m.deletedPathMap[k] = struct{}{}
} else {
delete(m.envMap, key)
m.deletedEnvMap[key] = struct{}{}
}
}
return nil
}

func (m *macosEnvManager) Flush() error {
for k, v := range m.store.envMap {
for k, _ := range m.deletedEnvMap {
if err := os.Unsetenv(k); err != nil {
return err
}
}
for k, v := range m.envMap {
if err := os.Setenv(k, v); err != nil {
return err
}
}
var newPaths []string
for path := range m.store.pathMap {
for path := range m.pathMap {
newPaths = append(newPaths, path)
}
oldPaths := strings.Split(os.Getenv("PATH"), ":")
for _, path := range oldPaths {
if strings.Contains(path, ".version-fox") {
if _, ok := m.deletedPathMap[path]; ok {
continue
}
if _, ok := m.pathMap[path]; ok {
continue
}
newPaths = append(newPaths, path)
}
return os.Setenv("PATH", strings.Join(newPaths, ":"))
//file, err := os.OpenFile(m.vfEnvPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
//if err != nil {
// fmt.Printf("Failed to open the file %s, err:%s\n", m.vfEnvPath, err.Error())
// return err
//}
//defer file.Close()
//for k, v := range m.store.envMap {
// str := fmt.Sprintf("export %s=%s\n", k, v)
// if _, err := file.WriteString(str); err != nil {
// fmt.Printf("Failed to flush env variable to file,value: err:%s\n", err.Error())
// return err
// }
//}
//
//pathValue := fmt.Sprintf("export PATH=%s\n", m.pathEnvValue())
//if _, err := file.WriteString(pathValue); err != nil {
// fmt.Printf("Failed to flush PATH variable to file, err:%s\n", err.Error())
// return err
//}
//return nil
}

func (m *macosEnvManager) Get(key string) (string, bool) {
if key == "PATH" {
return m.pathEnvValue(), true
} else {
s, ok := m.store.envMap[key]
s, ok := m.envMap[key]
return s, ok
}
}

func (m *macosEnvManager) pathEnvValue() string {
var pathValues []string
for k, _ := range m.store.pathMap {
for k, _ := range m.pathMap {
pathValues = append(pathValues, k)
}
pathValues = append(pathValues, "$PATH")
return strings.Join(pathValues, ":")
}

func (m *macosEnvManager) loadEnvFile() error {
file, err := os.Open(m.vfEnvPath)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "export") {
line = strings.TrimPrefix(line, "export")
line = strings.TrimSpace(line)
kv := strings.Split(line, "=")
if len(kv) == 2 {
key := kv[0]
value := kv[1]
if key == "PATH" {
pathArray := strings.Split(value, ":")
for _, path := range pathArray {
if path == "$PATH" {
continue
}
m.store.Add(&KV{
Key: "PATH",
Value: path,
})
}
} else {
m.store.Add(&KV{
Key: key,
Value: value,
})
}
}
}
}
if err := scanner.Err(); err != nil {
return err
}
return nil
}

func NewEnvManager(vfConfigPath string) (Manager, error) {
//envPath := filepath.Join(vfConfigPath, "env.sh")
//if !util.FileExists(envPath) {
// _, _ = os.Create(envPath)
//}
manager := &macosEnvManager{
//vfEnvPath: envPath,
store: NewStore(),
envMap: make(map[string]string),
pathMap: make(map[string]struct{}),
deletedPathMap: make(map[string]struct{}),
deletedEnvMap: make(map[string]struct{}),
}
//err := manager.loadEnvFile()
//if err != nil {
// fmt.Printf("Failed to load env file: %s, err:%s\n", manager.vfEnvPath, err.Error())
//}
//if err := appendEnvSourceIfNotExist(manager.shellInfo.ConfigPath, manager.vfEnvPath); err != nil {
// return nil, err
//}
return manager, nil
}

func appendEnvSourceIfNotExist(parentEnvPath, childEnvPath string) error {
shellConfigFile, err := os.Open(parentEnvPath)
if err != nil {
return err
}
defer shellConfigFile.Close()
command := fmt.Sprintf("source %s", childEnvPath)
stat, _ := os.Stat(parentEnvPath)
if stat.Size() > 0 {
scanner := bufio.NewScanner(shellConfigFile)
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, command) {
return nil
}
}
if err := scanner.Err(); err != nil {
return err
}
}

file, err := os.OpenFile(parentEnvPath, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString("\n" + command + "\n")
return err
}

0 comments on commit 571fa66

Please sign in to comment.