Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check for outdated minectl cli version #124

Merged
merged 1 commit into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,8 @@ Apache License, Version 2.0
- https://github.com/c-bata/go-prompt
- https://github.com/vultr/govultr
- https://github.com/Azure/azure-sdk-for-go
- https://github.com/blang/semver
- https://github.com/tcnksm/go-latest

### Legal Disclaimer 👮

Expand Down
10 changes: 5 additions & 5 deletions cmd/minectl/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package minectl

import (
"fmt"
"log"
"os"

"github.com/minectl/pkg/common"
Expand All @@ -24,7 +23,7 @@ var createCmd = &cobra.Command{
Short: "Create an Minecraft Server.",
Example: `mincetl create \
--filename server-do.yaml`,
RunE: runCreate,
RunE: RunFunc(runCreate),
SilenceUsage: true,
SilenceErrors: true,
}
Expand All @@ -39,15 +38,16 @@ func runCreate(cmd *cobra.Command, _ []string) error {
}
p, err := provisioner.NewProvisioner(filename)
if err != nil {
log.Fatal(err)
fmt.Println(err)
}
wait := true
if cmd.Flags().Changed("wait") {
wait, _ = cmd.Flags().GetBool("wait")
}
res, err := p.CreateServer(wait)
if err != nil {
log.Fatal(err)
fmt.Println(err)
return nil
}
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"ID", "NAME", "REGION", "TAGS", "IP"})
Expand All @@ -64,5 +64,5 @@ func runCreate(cmd *cobra.Command, _ []string) error {
common.PrintMixedGreen("⤴️ To upload a plugin type:\n\n %s",
fmt.Sprintf("minectl plugins -f %s --id %s --plugin <folder>/x.jar --destination /minecraft/plugins\n", filename, res.ID))
common.PrintMixedGreen("\n🔌 Connected to RCON type:\n\n %s", fmt.Sprintf("minectl rcon -f %s --id %s\n", filename, res.ID))
return err
return nil
}
7 changes: 5 additions & 2 deletions cmd/minectl/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var deleteCmd = &cobra.Command{
--filename server-do.yaml
--id xxx-xxx-xxx-xxx
`,
RunE: runDelete,
RunE: RunFunc(runDelete),
SilenceUsage: true,
SilenceErrors: true,
}
Expand All @@ -48,5 +48,8 @@ func runDelete(cmd *cobra.Command, _ []string) error {
return err
}
err = newProvisioner.DeleteServer()
return err
if err != nil {
return err
}
return nil
}
4 changes: 2 additions & 2 deletions cmd/minectl/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var listCmd = &cobra.Command{
Example: `mincetl list \
--provider civo \
--region LON1`,
RunE: runList,
RunE: RunFunc(runList),
SilenceUsage: true,
SilenceErrors: true,
}
Expand Down Expand Up @@ -62,7 +62,7 @@ func runList(cmd *cobra.Command, _ []string) error {
table.SetBorder(false)
table.Render()
} else {
fmt.Println("🤷 No server found")
return errors.New("🤷 No server found")
}
return nil
}
201 changes: 198 additions & 3 deletions cmd/minectl/minectl.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
package minectl

import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strings"

"github.com/Azure/go-autorest/autorest/to"

"github.com/blang/semver/v4"
"github.com/morikuni/aec"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/tcnksm/go-latest"
)

var (
Expand All @@ -18,10 +29,196 @@ func init() {
minectlCmd.AddCommand(versionCmd)
}

var updateCheckResult chan *string

var minectlCmd = &cobra.Command{
Use: "minectl",
Short: "Create Minecraft Server on different cloud provider.",
Run: runMineCtl,
CompletionOptions: cobra.CompletionOptions{
DisableDefaultCmd: false,
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
fmt.Println("PersistentPostRun")
},
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
var waitForUpdateCheck bool
defer func() {
if !waitForUpdateCheck {
close(updateCheckResult)
}
}()

updateCheckResult = make(chan *string)
waitForUpdateCheck = true
go func() {
updateCheckResult <- checkForUpdate()
close(updateCheckResult)
}()
return nil
},
PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
checkVersionMsg, ok := <-updateCheckResult
if ok && checkVersionMsg != nil {
fmt.Println()
fmt.Println(to.String(checkVersionMsg))
}
return nil
},
}

func isDevVersion(s semver.Version) bool {
if len(s.Pre) == 0 {
return false
}

devStrings := regexp.MustCompile(`alpha|beta|dev|rc`)
return !s.Pre[0].IsNum && devStrings.MatchString(s.Pre[0].VersionStr)
}

func isBrewInstall(exe string) (bool, error) {
if runtime.GOOS != "darwin" {
return false, nil
}

exePath, err := filepath.EvalSymlinks(exe)
if err != nil {
return false, err
}

brewBin, err := exec.LookPath("brew")
if err != nil {
return false, err
}

brewPrefixCmd := exec.Command(brewBin, "--prefix", "minectl")

var stdout bytes.Buffer
var stderr bytes.Buffer
brewPrefixCmd.Stdout = &stdout
brewPrefixCmd.Stderr = &stderr
if err = brewPrefixCmd.Run(); err != nil {
if ee, ok := err.(*exec.ExitError); ok {
ee.Stderr = stderr.Bytes()
}
return false, errors.Wrapf(err, "'brew --prefix minectl' failed")
}

brewPrefixCmdOutput := strings.TrimSpace(stdout.String())
if brewPrefixCmdOutput == "" {
return false, errors.New("trimmed output from 'brew --prefix minectl' is empty")
}

brewPrefixPath, err := filepath.EvalSymlinks(brewPrefixCmdOutput)
if err != nil {
return false, err
}

brewPrefixExePath := filepath.Join(brewPrefixPath, "minectl")
return exePath == brewPrefixExePath, nil
}

func runPostCommandHooks(c *cobra.Command, args []string) error {
if c.PostRunE != nil {
if err := c.PostRunE(c, args); err != nil {
return err
}
} else if c.PostRun != nil {
c.PostRun(c, args)
}
for p := c; p != nil; p = p.Parent() {
if p.PersistentPostRunE != nil {
if err := p.PersistentPostRunE(c, args); err != nil {
return err
}
break
} else if p.PersistentPostRun != nil {
p.PersistentPostRun(c, args)
break
}
}
return nil
}

func RunFunc(run func(cmd *cobra.Command, args []string) error) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
if res := run(cmd, args); res != nil {
fmt.Println(res)
if postRunErr := runPostCommandHooks(cmd, args); postRunErr != nil {
fmt.Println(res)
}
os.Exit(1)
}
os.Exit(0)
return nil
}
}

func getUpgradeCommand() string {
exe, err := os.Executable()
if err != nil {
return ""
}

isBrew, err := isBrewInstall(exe)
if err != nil {
fmt.Printf("error determining if the running executable was installed with brew: %s", err)
}
if isBrew {
return "$ brew upgrade minectl"
}

if runtime.GOOS != "windows" {
return "$ curl -sSL https://get.minectl.dev | sh"
}
return ""
}

func getUpgradeMessage(latest *semver.Version, current *semver.Version) *string {
cmd := getUpgradeCommand()
msg := fmt.Sprintf("A new version of minectl is available. To upgrade from version '%s' to '%s', ", current, latest)
if cmd != "" {
msg += "run \n " + cmd + "\n\nor "
}

msg += "visit https://github.com/dirien/minectl#installing-minectl- for manual instructions."
return &msg
}

func getCLIVersionInfo(current *semver.Version) (*semver.Version, error) {
githubTag := &latest.GithubTag{
Owner: "dirien",
Repository: "minectl",
}

res, err := latest.Check(githubTag, current.String())
if err != nil {
return nil, err
}
version, err := semver.New(res.Current)
if err != nil {
return nil, err
}
return version, nil
}

func checkForUpdate() *string {
curVer, err := semver.ParseTolerant(getVersion())
if err != nil {
fmt.Printf("error parsing current version: %s", err)
}
if isDevVersion(curVer) {
return nil
}
latestVer, err := getCLIVersionInfo(&curVer)
if err != nil {
return nil
}
if latestVer.GT(curVer) {
return getUpgradeMessage(latestVer, &curVer)
}

return nil
}

var versionCmd = &cobra.Command{
Expand All @@ -34,16 +231,14 @@ func getVersion() string {
if len(Version) != 0 {
return Version
}
return "dev"
return "0.1.0-dev"
}

func parseBaseCommand(_ *cobra.Command, _ []string) {
printLogo()

fmt.Println("Version:", getVersion())
fmt.Println("Git Commit:", GitCommit)
fmt.Println("Build date:", Date)
os.Exit(0)
}

func Execute(version, gitCommit, date string) error {
Expand Down
6 changes: 2 additions & 4 deletions cmd/minectl/plugins.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package minectl

import (
"log"

"github.com/minectl/pkg/provisioner"
"github.com/pkg/errors"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -39,7 +37,7 @@ var pluginCmd = &cobra.Command{
--id xxx-xxx-xxx-xxx
--plugin plugin.jar
--destination /minecraft/mods`,
RunE: runPlugin,
RunE: RunFunc(runPlugin),
SilenceUsage: true,
SilenceErrors: true,
}
Expand Down Expand Up @@ -71,7 +69,7 @@ func runPlugin(cmd *cobra.Command, _ []string) error {
}
p, err := provisioner.NewProvisioner(filename, id)
if err != nil {
log.Fatal(err)
return err
}
plugin, _ := cmd.Flags().GetString("plugin")
destination, _ := cmd.Flags().GetString("destination")
Expand Down
8 changes: 3 additions & 5 deletions cmd/minectl/rcon.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package minectl

import (
"log"

"github.com/minectl/pkg/provisioner"
"github.com/pkg/errors"
"github.com/spf13/cobra"
Expand All @@ -20,7 +18,7 @@ var rconCmd = &cobra.Command{
Example: `mincetl rcon \
--filename server-do.yaml \
--id xxxx`,
RunE: runRCON,
RunE: RunFunc(runRCON),
SilenceUsage: true,
SilenceErrors: true,
}
Expand All @@ -42,11 +40,11 @@ func runRCON(cmd *cobra.Command, _ []string) error {
}
p, err := provisioner.NewProvisioner(filename, id)
if err != nil {
log.Fatal(err)
return err
}
err = p.DoRCON()
if err != nil {
log.Fatal(err)
return err
}
return nil
}
Loading