Skip to content

Commit

Permalink
refactor: Refactor EnvKeys to make configuring multiple PATHs smoother (
Browse files Browse the repository at this point in the history
#97)

* refactor: Refactor EnvKeys to make configuring multiple PATHs smoother

When the plugin configures multiple PATHs, there is no need to care about the specific OS delimiter, be it ; or :, just pass multiple PATHs and vfox will configure and de-duplicate them in order.

* doc: update
  • Loading branch information
aooohan authored Mar 11, 2024
1 parent 982ef93 commit f103a47
Show file tree
Hide file tree
Showing 18 changed files with 132 additions and 109 deletions.
20 changes: 12 additions & 8 deletions cmd/commands/activate.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,19 @@ func activateCmd(ctx *cli.Context) error {
if err != nil {
return err
}
envKeys[env.HookFlag] = &name
originPath := os.Getenv("PATH")
envKeys[env.PathFlag] = &originPath
exportEnvs := make(env.Vars)
for k, v := range envKeys.Variables {
exportEnvs[k] = v
}

sdkPaths := envKeys["PATH"]
if sdkPaths != nil {
paths := manager.EnvManager.Paths([]string{*sdkPaths, originPath})
exportEnvs[env.HookFlag] = &name
originPath := os.Getenv("PATH")
exportEnvs[env.PathFlag] = &originPath

envKeys["PATH"] = &paths
sdkPaths := envKeys.Paths
if len(sdkPaths) != 0 {
paths := manager.EnvManager.Paths(append(sdkPaths[:], originPath))
exportEnvs["PATH"] = &paths
}

path := manager.PathMeta.ExecutablePath
Expand All @@ -64,7 +68,7 @@ func activateCmd(ctx *cli.Context) error {
if s == nil {
return fmt.Errorf("unknow target shell %s", name)
}
exportStr := s.Export(envKeys)
exportStr := s.Export(exportEnvs)
str, err := s.Activate()
if err != nil {
return err
Expand Down
29 changes: 12 additions & 17 deletions cmd/commands/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var Env = &cli.Command{

func envCmd(ctx *cli.Context) error {
if ctx.IsSet("json") {
type SDKs map[string]map[string]string
type SDKs map[string]map[string]*string
data := struct {
IsHookEnv bool `json:"is_hook_env"`
Paths []string `json:"paths"`
Expand All @@ -66,17 +66,8 @@ func envCmd(ctx *cli.Context) error {
for k, v := range manager.Record.Export() {
if lookupSdk, err := manager.LookupSdk(k); err == nil {
if keys, err := lookupSdk.EnvKeys(internal.Version(v)); err == nil {
newEnv := make(map[string]string)
for key, value := range keys {
if key == "PATH" {
data.Paths = append(data.Paths, *value)
} else {
newEnv[key] = *value
}
}
if len(newEnv) > 0 {
data.SDKs[lookupSdk.Plugin.Name] = newEnv
}
data.SDKs[lookupSdk.Plugin.Name] = keys.Variables
data.Paths = append(data.Paths, keys.Paths...)
}
}
}
Expand Down Expand Up @@ -108,14 +99,18 @@ func envCmd(ctx *cli.Context) error {
return err
}

sdkPaths := envKeys["PATH"]
if sdkPaths != nil {
exportEnvs := make(env.Vars)
for k, v := range envKeys.Variables {
exportEnvs[k] = v
}
sdkPaths := envKeys.Paths
if len(sdkPaths) != 0 {
originPath := os.Getenv(env.PathFlag)
paths := manager.EnvManager.Paths([]string{*sdkPaths, originPath})
envKeys["PATH"] = &paths
paths := manager.EnvManager.Paths(append(sdkPaths[:], originPath))
exportEnvs["PATH"] = &paths
}

exportStr := s.Export(envKeys)
exportStr := s.Export(exportEnvs)
fmt.Println(exportStr)
return nil
}
Expand Down
5 changes: 5 additions & 0 deletions docs/plugins/create/howto.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,14 @@ function PLUGIN:EnvKeys(ctx)
key = "JAVA_HOME",
value = mainPath
},
--- NOTE: If you need to set multiple PATH paths, just pass multiple PATHs, vfox will automatically deduplicate and set them in the order of configuration
{
key = "PATH",
value = mainPath .. "/bin"
},
{
key = "PATH",
value = mainPath .. "/bin2"
}
}
end
Expand Down
5 changes: 5 additions & 0 deletions docs/zh-hans/plugins/create/howto.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,14 @@ function PLUGIN:EnvKeys(ctx)
key = "JAVA_HOME",
value = mainPath
},
--- 注意, 如果需要设置多个PATH路径, 只需要传递多个PATH即可,vfox将会自动去重并按配置顺序设置
{
key = "PATH",
value = mainPath .. "/bin"
},
{
key = "PATH",
value = mainPath .. "/bin2"
}
}
end
Expand Down
16 changes: 13 additions & 3 deletions internal/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,21 @@ import (

type Manager interface {
Flush() error
Load(key, value string) error
Load(envs *Envs) error
Get(key string) (string, bool)
Remove(key string) error
Remove(envs *Envs) error
Paths(paths []string) string
io.Closer
}

type Envs map[string]*string
// Vars is a map of environment variables
type Vars map[string]*string

// Paths is a slice of PATH.
type Paths []string

// Envs is a struct that contains environment variables and PATH.
type Envs struct {
Variables Vars
Paths Paths
}
36 changes: 17 additions & 19 deletions internal/env/macos_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,28 @@ func (m *macosEnvManager) Close() error {
return nil
}

func (m *macosEnvManager) Load(key, value string) error {
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{}{}
func (m *macosEnvManager) Load(envs *Envs) error {
for k, v := range envs.Variables {
m.envMap[k] = *v
}
for _, path := range envs.Paths {
if _, ok := m.pathMap[path]; ok {
continue
}
} else {
m.envMap[key] = value
m.paths = append(m.paths, path)
m.pathMap[path] = struct{}{}
}
return nil
}
func (m *macosEnvManager) Remove(key string) error {
if key == "PATH" {
return fmt.Errorf("can not remove PATH variable")
func (m *macosEnvManager) Remove(envs *Envs) error {
for k, _ := range envs.Variables {
if k == "PATH" {
return fmt.Errorf("can not remove PATH variable")
}
delete(m.envMap, k)
m.deletedEnvMap[k] = struct{}{}
}
array := strings.Split(key, ":")
for _, k := range array {
for _, k := range envs.Paths {
if _, ok := m.pathMap[k]; ok {
delete(m.pathMap, k)
var newPaths []string
Expand All @@ -74,9 +75,6 @@ func (m *macosEnvManager) Remove(key string) error {
}
m.paths = newPaths
m.deletedPathMap[k] = struct{}{}
} else {
delete(m.envMap, key)
m.deletedEnvMap[key] = struct{}{}
}
}
return nil
Expand Down
37 changes: 17 additions & 20 deletions internal/env/windows_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ package env

import (
"errors"
"fmt"
"os"
"strings"
"syscall"
Expand Down Expand Up @@ -118,18 +117,8 @@ func (w *windowsEnvManager) Flush() (err error) {
return
}

func (w *windowsEnvManager) Load(key, value string) error {
if key == "PATH" {
keys := strings.Split(value, ";")
for _, k := range keys {
_, ok := w.pathMap[k]
if !ok {
w.pathMap[k] = struct{}{}
w.paths = append(w.paths, k)
}
}

} else {
func (w *windowsEnvManager) Load(envs *Envs) error {
for k, v := range envs.Variables {
err := os.Setenv(key, value)
if err != nil {
return err
Expand All @@ -139,6 +128,13 @@ func (w *windowsEnvManager) Load(key, value string) error {
return err
}
}
for _, path := range envs.Paths {
_, ok := w.pathMap[k]
if !ok {
w.pathMap[k] = struct{}{}
w.paths = append(w.paths, k)
}
}
return nil
}

Expand All @@ -150,12 +146,15 @@ func (w *windowsEnvManager) Get(key string) (string, bool) {
return val, true
}

func (w *windowsEnvManager) Remove(key string) error {
if key == "PATH" {
return fmt.Errorf("can not remove PATH variable")
func (w *windowsEnvManager) Remove(envs *Envs) error {
for k, _ := range envs.Variables {
if key == "PATH" {
return fmt.Errorf("can not remove PATH variable")
}
_ = w.key.DeleteValue(k)
}
keys := strings.Split(key, ";")
for _, k := range keys {

for _, k := range envs.Paths {
if _, ok := w.pathMap[k]; ok {
delete(w.pathMap, k)
var newPaths []string
Expand All @@ -166,8 +165,6 @@ func (w *windowsEnvManager) Remove(key string) error {
}
w.paths = newPaths
w.deletedPathMap[k] = struct{}{}
} else {
_ = w.key.DeleteValue(k)
}
}
return nil
Expand Down
24 changes: 9 additions & 15 deletions internal/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,27 +52,21 @@ type Manager struct {
Config *config.Config
}

func (m *Manager) EnvKeys() (env.Envs, error) {
shellEnvs := make(env.Envs)
var paths []string
func (m *Manager) EnvKeys() (*env.Envs, error) {
shellEnvs := &env.Envs{
Variables: make(env.Vars),
Paths: make(env.Paths, 0),
}
for k, v := range m.Record.Export() {
if lookupSdk, err := m.LookupSdk(k); err == nil {
if keys, err := lookupSdk.EnvKeys(Version(v)); err == nil {
for key, value := range keys {
if key == "PATH" {
paths = append(paths, *value)
} else {
shellEnvs[key] = value
}
if ek, err := lookupSdk.EnvKeys(Version(v)); err == nil {
for key, value := range ek.Variables {
shellEnvs.Variables[key] = value
}
shellEnvs.Paths = append(shellEnvs.Paths, ek.Paths...)
}
}
}
if len(paths) != 0 {
pathStr := m.EnvManager.Paths(paths[:])
shellEnvs["PATH"] = &pathStr
} else {
}
return shellEnvs, nil
}

Expand Down
16 changes: 13 additions & 3 deletions internal/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
_ "embed"
"errors"
"fmt"
"github.com/version-fox/vfox/internal/util"
"path/filepath"
"regexp"
"strings"
Expand Down Expand Up @@ -206,7 +207,7 @@ func (l *LuaPlugin) PostInstall(rootPath string, sdks []*Info) error {
return nil
}

func (l *LuaPlugin) EnvKeys(sdkPackage *Package) (env.Envs, error) {
func (l *LuaPlugin) EnvKeys(sdkPackage *Package) (*env.Envs, error) {
L := l.vm.Instance
mainInfo := sdkPackage.Main

Expand Down Expand Up @@ -237,18 +238,27 @@ func (l *LuaPlugin) EnvKeys(sdkPackage *Package) (env.Envs, error) {
return nil, fmt.Errorf("no environment variables provided")
}

envKeys := make(env.Envs)
envKeys := &env.Envs{
Variables: make(env.Vars),
}

var items []*EnvKeysHookResultItem
err = luai.Unmarshal(table, &items)
if err != nil {
return nil, err
}

pathSet := util.NewSortedSet[string]()
for _, item := range items {
envKeys[item.Key] = &item.Value
if item.Key == "PATH" {
pathSet.Add(item.Value)
} else {
envKeys.Variables[item.Key] = &item.Value
}
}

envKeys.Paths = pathSet.Slice()

return envKeys, nil
}

Expand Down
15 changes: 9 additions & 6 deletions internal/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,20 @@ func TestPlugin(t *testing.T) {
t.Fatal(err)
}

javaHome := keys["JAVA_HOME"]
javaHome := keys.Variables["JAVA_HOME"]
if *javaHome == "" {
t.Errorf("expected JAVA_HOME to be set, got '%s'", *javaHome)
}
path := keys["PATH"]
if *path == "" {
t.Errorf("expected PATH to be set, got '%s'", *path)
path := keys.Paths
if len(path) != 2 {
t.Errorf("expected 2 paths, got %d", len(path))
}

if !strings.HasSuffix(*path, "/bin") {
t.Errorf("expected PATH to end with '/bin', got '%s'", *path)
if !strings.HasSuffix(path[0], "/bin") {
t.Errorf("expected PATH to end with '/bin', got '%s'", path[0])
}
if !strings.HasSuffix(path[1], "/bin2") {
t.Errorf("expected PATH to end with '/bin', got '%s'", path[1])
}
})

Expand Down
Loading

0 comments on commit f103a47

Please sign in to comment.