Skip to content

Commit

Permalink
feat(golang-rewrite): implement 'asdf env' command
Browse files Browse the repository at this point in the history
  • Loading branch information
Stratus3D committed Nov 27, 2024
1 parent 3120fa3 commit 25dadec
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 14 deletions.
144 changes: 132 additions & 12 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@ import (
"io"
"log"
"os"
osexec "os/exec"
"path/filepath"
"slices"
"strings"
"text/tabwriter"

"asdf/internal/config"
"asdf/internal/exec"
"asdf/internal/execenv"
"asdf/internal/execute"
"asdf/internal/help"
"asdf/internal/info"
"asdf/internal/installs"
"asdf/internal/paths"
"asdf/internal/plugins"
"asdf/internal/resolve"
"asdf/internal/shims"
Expand Down Expand Up @@ -59,6 +63,15 @@ func Execute(version string) {
return currentCommand(logger, tool)
},
},
{
Name: "env",
Action: func(cCtx *cli.Context) error {
shimmedCommand := cCtx.Args().Get(0)
args := cCtx.Args().Slice()

return envCommand(logger, shimmedCommand, args)
},
},
{
Name: "exec",
Action: func(cCtx *cli.Context) error {
Expand Down Expand Up @@ -335,6 +348,83 @@ func formatVersions(versions []string) string {
}
}

func envCommand(logger *log.Logger, shimmedCommand string, args []string) error {
command := "env"

if shimmedCommand == "" {
logger.Printf("usage: asdf env <command>")
return fmt.Errorf("usage: asdf env <command>")
}

if len(args) >= 2 {
command = args[1]
}

realArgs := []string{}
if len(args) > 2 {
realArgs = args[2:]
}

conf, err := config.LoadConfig()
if err != nil {
logger.Printf("error loading config: %s", err)
return err
}

_, plugin, version, err := getExecutable(logger, conf, shimmedCommand)
if err != nil {
return err
}

parsedVersion := toolversions.Parse(version)
execPaths, err := shims.ExecutablePaths(conf, plugin, parsedVersion)
if err != nil {
return err
}
callbackEnv := map[string]string{
"ASDF_INSTALL_TYPE": parsedVersion.Type,
"ASDF_INSTALL_VERSION": parsedVersion.Value,
"ASDF_INSTALL_PATH": installs.InstallPath(conf, plugin, parsedVersion),
"PATH": setPath(conf, execPaths),
}

var env map[string]string
var fname string

if parsedVersion.Type == "system" {
env = execute.SliceToMap(os.Environ())
newPath := paths.RemoveFromPath(env["PATH"], shims.Directory(conf))
env["PATH"] = newPath
var found bool
fname, found = shims.FindSystemExecutable(conf, command)
if !found {
fmt.Println("not found")
return err
}
} else {
env, err = execenv.Generate(plugin, callbackEnv)
if _, ok := err.(plugins.NoCallbackError); !ok && err != nil {
return err
}

fname, err = osexec.LookPath(command)
if err != nil {
return err
}
}

err = exec.Exec(fname, realArgs, execute.MapToSlice(env))
if err != nil {
fmt.Printf("err %#+v\n", err.Error())
}
return err
}

func setPath(conf config.Config, pathes []string) string {
currentPath := os.Getenv("PATH")
return strings.Join(pathes, ":") + ":" + paths.RemoveFromPath(currentPath, shims.Directory(conf))
}

func execCommand(logger *log.Logger, command string, args []string) error {
if command == "" {
logger.Printf("usage: asdf exec <command>")
Expand All @@ -347,16 +437,51 @@ func execCommand(logger *log.Logger, command string, args []string) error {
return err
}

currentDir, err := os.Getwd()
executable, plugin, version, err := getExecutable(logger, conf, command)
fmt.Printf("version %#+v\n", version)
fmt.Println("here")
if err != nil {
logger.Printf("unable to get current directory: %s", err)
return err
}

executable, found, err := shims.FindExecutable(conf, command, currentDir)
if len(args) > 1 {
args = args[1:]
} else {
args = []string{}
}

parsedVersion := toolversions.Parse(version)
fmt.Printf("parsedVersion %#+v\n", parsedVersion)
paths, err := shims.ExecutablePaths(conf, plugin, parsedVersion)
if err != nil {
return err
}
callbackEnv := map[string]string{
"ASDF_INSTALL_TYPE": parsedVersion.Type,
"ASDF_INSTALL_VERSION": parsedVersion.Value,
"ASDF_INSTALL_PATH": installs.InstallPath(conf, plugin, parsedVersion),
"PATH": setPath(conf, paths),
}

env, _ := execenv.Generate(plugin, callbackEnv)
return exec.Exec(executable, args, execute.MapToSlice(env))
}

func getExecutable(logger *log.Logger, conf config.Config, command string) (executable string, plugin plugins.Plugin, version string, err error) {
currentDir, err := os.Getwd()
if err != nil {
logger.Printf("unable to get current directory: %s", err)
return "", plugins.Plugin{}, "", err
}

executable, plugin, version, found, err := shims.FindExecutable(conf, command, currentDir)
if err != nil {

if _, ok := err.(shims.NoExecutableForPluginError); ok {
logger.Printf("No executable %s found for current version. Please select a different version or install %s manually for the current version", command, command)
os.Exit(1)
return "", plugin, version, err
}
shimPath := shims.Path(conf, command)
toolVersions, _ := shims.GetToolsAndVersionsFromShimFile(shimPath)

Expand All @@ -383,21 +508,16 @@ func execCommand(logger *log.Logger, command string, args []string) error {
}

os.Exit(126)
return err
return executable, plugins.Plugin{}, "", err
}

if !found {
logger.Print("executable not found")
os.Exit(126)
return fmt.Errorf("executable not found")
}
if len(args) > 1 {
args = args[1:]
} else {
args = []string{}
return executable, plugins.Plugin{}, "", fmt.Errorf("executable not found")
}

return exec.Exec(executable, args, os.Environ())
return executable, plugin, version, nil
}

func anyInstalled(conf config.Config, toolVersions []toolversions.ToolVersions) bool {
Expand Down Expand Up @@ -882,7 +1002,7 @@ func whichCommand(logger *log.Logger, command string) error {
return errors.New("must provide command")
}

path, _, err := shims.FindExecutable(conf, command, currentDir)
path, _, _, _, err := shims.FindExecutable(conf, command, currentDir)
if _, ok := err.(shims.UnknownCommandError); ok {
logger.Printf("unknown command: %s. Perhaps you have to reshim?", command)
return errors.New("command not found")
Expand Down
14 changes: 14 additions & 0 deletions internal/execute/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ func MapToSlice(env map[string]string) (slice []string) {
return slice
}

// SliceToMap converts an env map to env slice suitable for syscall.Exec
func SliceToMap(env []string) map[string]string {
envMap := map[string]string{}

for _, envVar := range env {
varValue := strings.Split(envVar, "=")
if len(varValue) == 2 {
envMap[varValue[0]] = varValue[1]
}
}

return envMap
}

func formatArgString(args []string) string {
var newArgs []string
for _, str := range args {
Expand Down
6 changes: 4 additions & 2 deletions internal/shims/shims.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func FindExecutable(conf config.Config, shimName, currentDirectory string) (stri
func FindSystemExecutable(conf config.Config, executableName string) (string, bool) {
currentPath := os.Getenv("PATH")
defer os.Setenv("PATH", currentPath)
os.Setenv("PATH", paths.RemoveFromPath(currentPath, shimsDirectory(conf)))
os.Setenv("PATH", paths.RemoveFromPath(currentPath, Directory(conf)))
executablePath, err := exec.LookPath(executableName)
return executablePath, err == nil
}
Expand Down Expand Up @@ -288,7 +288,9 @@ func Path(conf config.Config, shimName string) string {
return filepath.Join(conf.DataDir, shimDirName, shimName)
}

func shimsDirectory(conf config.Config) string {
// Directory returns the path to the shims directory for the current
// configuration.
func Directory(conf config.Config) string {
return filepath.Join(conf.DataDir, shimDirName)
}

Expand Down

0 comments on commit 25dadec

Please sign in to comment.