diff --git a/commands/extensions.go b/commands/extensions.go new file mode 100644 index 0000000..cc043cd --- /dev/null +++ b/commands/extensions.go @@ -0,0 +1,82 @@ +package commands + +import ( + "hjbdev/pvm/common" + "hjbdev/pvm/theme" + "os" + "path/filepath" + "regexp" + "strings" +) + +func Extensions(args []string) { + if len(args) < 2 { + theme.Error("You must specify an action and an extension.") + theme.Info("Usage: pvm extensions ") + return + } + + // determine which version is currently selected + currentVersion := common.GetCurrentVersionFolder() + + if currentVersion == "" { + theme.Error("You do not have an active PHP version.") + theme.Info("Select a PHP version with `pvm use ` first.") + } + + command := args[0] + ext := args[1] + + if command != "enable" && command != "disable" { + theme.Error("Invalid action. Must be 'enable' or 'disable'.") + return + } + + homeDir, err := os.UserHomeDir() + + if err != nil { + panic(err) + } + + // check if the version exists + if _, err := os.Stat(homeDir + "/.pvm/versions/" + currentVersion); os.IsNotExist(err) { + theme.Error("The specified version does not exist.") + return + } + + extensions := strings.Split(ext, ",") + + for _, extension := range extensions { + handleExtension(extension, command, homeDir, currentVersion) + } +} + +func handleExtension(ext string, command string, homeDir string, currentVersion string) { + ini := common.ReadPhpIni(homeDir + "/.pvm/versions/" + currentVersion + "/php.ini") + splitIni := regexp.MustCompile(`\r?\n`).Split(ini, -1) + extensionStatus, lineNumber := common.GetExtensionStatus(ini, ext) + + if extensionStatus == common.ExtensionEnabled { + if command == "enable" { + theme.Success("Extension " + ext + " is already enabled.") + } else { + disabledLine := ";" + splitIni[lineNumber] + splitIni[lineNumber] = disabledLine + newIni := strings.Join(splitIni, "\n") + os.WriteFile(filepath.Join(homeDir, ".pvm", "versions", currentVersion, "php.ini"), []byte(newIni), 0644) + theme.Success("Extension " + ext + " enabled.") + } + } else if extensionStatus == common.ExtensionDisabled { + if command == "enable" { + enabledLine := strings.Replace(splitIni[lineNumber], ";", "", 1) + splitIni[lineNumber] = enabledLine + newIni := strings.Join(splitIni, "\n") + os.WriteFile(filepath.Join(homeDir, ".pvm", "versions", currentVersion, "php.ini"), []byte(newIni), 0644) + theme.Success("Extension " + ext + " enabled.") + } else { + theme.Success("Extension " + ext + " is already disabled.") + } + } else { + theme.Error("Extension " + ext + " not found in php.ini") + } +} diff --git a/commands/help.go b/commands/help.go index 8d4db06..f121de1 100644 --- a/commands/help.go +++ b/commands/help.go @@ -14,6 +14,7 @@ func Help(notFoundError bool) { } fmt.Println("Available Commands:") + fmt.Println(" extensions") fmt.Println(" help") fmt.Println(" install") fmt.Println(" list") diff --git a/commands/list.go b/commands/list.go index da23cb0..abb334e 100644 --- a/commands/list.go +++ b/commands/list.go @@ -1,9 +1,11 @@ package commands import ( + "hjbdev/pvm/common" "hjbdev/pvm/theme" "log" "os" + "github.com/fatih/color" ) @@ -35,8 +37,14 @@ func List() { theme.Title("Installed PHP versions") + currentVersion := common.GetCurrentVersionFolder() + // print all folders for _, version := range versions { - color.White(" " + version.Name()) + if version.Name() == currentVersion { + color.White(" " + version.Name() + " (current)") + } else { + color.White(" " + version.Name()) + } } } diff --git a/commands/use.go b/commands/use.go index 40beba8..fb81ca9 100644 --- a/commands/use.go +++ b/commands/use.go @@ -11,6 +11,12 @@ import ( "strings" ) +type VersionMeta struct { + Name string + Number common.Version + Folder os.DirEntry +} + func Use(args []string) { threadSafe := true @@ -56,7 +62,7 @@ func Use(args []string) { log.Fatalln(err) } - var selectedVersion *versionMeta + var selectedVersion *VersionMeta // loop over all found installed versions for i, version := range versions { safe := true @@ -65,9 +71,10 @@ func Use(args []string) { } foundVersion := common.GetVersion(version.Name(), safe, "") if threadSafe == foundVersion.ThreadSafe && strings.HasPrefix(foundVersion.String(), args[0]) { - selectedVersion = &versionMeta{ - number: foundVersion, - folder: versions[i], + selectedVersion = &VersionMeta{ + Name: version.Name(), + Number: foundVersion, + Folder: versions[i], } } } @@ -79,9 +86,9 @@ func Use(args []string) { requestedVersion := common.GetVersion(args[0], threadSafe, "") if requestedVersion.Minor == -1 { - theme.Warning(fmt.Sprintf("No minor version specified, assumed newest minor version %s.", selectedVersion.number.String())) + theme.Warning(fmt.Sprintf("No minor version specified, assumed newest minor version %s.", selectedVersion.Number.String())) } else if requestedVersion.Patch == -1 { - theme.Warning(fmt.Sprintf("No patch version specified, assumed newest patch version %s.", selectedVersion.number.String())) + theme.Warning(fmt.Sprintf("No patch version specified, assumed newest patch version %s.", selectedVersion.Number.String())) } // remove old php bat script @@ -108,7 +115,7 @@ func Use(args []string) { os.Remove(shPathCGI) } - versionFolderPath := filepath.Join(homeDir, ".pvm", "versions", selectedVersion.folder.Name()) + versionFolderPath := filepath.Join(homeDir, ".pvm", "versions", selectedVersion.Folder.Name()) versionPath := filepath.Join(versionFolderPath, "php.exe") versionPathCGI := filepath.Join(versionFolderPath, "php-cgi.exe") @@ -184,10 +191,7 @@ func Use(args []string) { } // end of ext directory link creation - theme.Success(fmt.Sprintf("Using PHP %s", selectedVersion.number)) -} + os.WriteFile(filepath.Join(homeDir, ".pvm", "version"), []byte(selectedVersion.Name), 0755) -type versionMeta struct { - number common.Version - folder os.DirEntry + theme.Success(fmt.Sprintf("Using PHP %s", selectedVersion.Number)) } diff --git a/common/helpers.go b/common/helpers.go index 510b53e..d148705 100644 --- a/common/helpers.go +++ b/common/helpers.go @@ -2,8 +2,11 @@ package common import ( "fmt" + "os" + "path/filepath" "regexp" "strconv" + "strings" ) type Version struct { @@ -52,3 +55,62 @@ func GetVersion(text string, safe bool, url string) Version { Url: url, } } + +func GetCurrentVersionFolder() string { + homeDir, err := os.UserHomeDir() + + if err != nil { + return "" + } + + content, err := os.ReadFile(filepath.Join(homeDir, ".pvm", "version")) + + if err != nil { + return "" + } + + return string(content) +} + +func ReadPhpIni(path string) string { + file, err := os.ReadFile(path) + + if err != nil { + panic(err) + } + + return string(file) +} + +type ExtensionStatus int + +const ( + ExtensionEnabled ExtensionStatus = 1 + ExtensionDisabled ExtensionStatus = 2 + ExtensionNotFound ExtensionStatus = 3 +) + +func GetExtensionStatus(ini string, extension string) (ExtensionStatus, int) { + lines := regexp.MustCompile(`\r?\n`).Split(ini, -1) + + for index, line := range lines { + extensionMatches := regexp.MustCompile(`extension\s*=\s*["']?([^"']+)["']?`).FindStringSubmatch(line) + + if len(extensionMatches) == 0 { + continue + } + + if extensionMatches[1] == extension { + fullLine := lines[index] + noWhitespace := strings.TrimSpace(fullLine) + + if strings.HasPrefix(noWhitespace, ";") { + return ExtensionDisabled, index + } else { + return ExtensionEnabled, index + } + } + } + + return ExtensionNotFound, -1 +} diff --git a/main.go b/main.go index 0a32770..8ea126d 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,8 @@ func main() { commands.Install(args) case "use": commands.Use(args[1:]) + case "extensions": + commands.Extensions(args[1:]) default: commands.Help(true) }