Skip to content

Commit c5d038b

Browse files
committed
Improve CLI output
1 parent 0a68bce commit c5d038b

File tree

6 files changed

+107
-47
lines changed

6 files changed

+107
-47
lines changed

input/input.go renamed to cli/input.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package input
1+
package cli
22

33
import (
44
"errors"

cli/output.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package cli
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
)
7+
8+
func Info(format string, a ...any) {
9+
fmt.Printf("%s\n", fmt.Sprintf(format, a...))
10+
}
11+
12+
func Begin(format string, a ...any) {
13+
fmt.Printf(format, a...)
14+
}
15+
16+
func Finish() {
17+
fmt.Print(" done.\n")
18+
}
19+
20+
func Success(format string, a ...any) {
21+
fmt.Printf("\x1b[32m%s\x1b[0m\n", fmt.Sprintf(format, a...))
22+
}
23+
24+
func Warn(format string, a ...any) {
25+
fmt.Printf("\x1b[33mWARNING: %s\x1b[0m\n", fmt.Sprintf(format, a...))
26+
}
27+
28+
func Error(format string, a ...any) error {
29+
message := fmt.Sprintf(format, a...)
30+
fmt.Printf("\x1b[1;31mERROR: %s\x1b[0m\n", message)
31+
return errors.New(message)
32+
}

commands/new.go

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@ package commands
22

33
import (
44
"encoding/json"
5-
"errors"
6-
"fmt"
75
"io"
86
"net/http"
97
"os"
108
"path/filepath"
119
"strings"
1210

11+
"github.com/code-game-project/codegame-cli/cli"
1312
"github.com/code-game-project/codegame-cli/external"
14-
"github.com/code-game-project/codegame-cli/input"
1513
"github.com/ogier/pflag"
1614
)
1715

@@ -21,19 +19,19 @@ func New() error {
2119
project = strings.ToLower(pflag.Arg(1))
2220
} else {
2321
var err error
24-
project, err = input.Select("Which type of project would you like to create?", []string{"Game Server", "Game Client"}, []string{"server", "client"})
22+
project, err = cli.Select("Which type of project would you like to create?", []string{"Game Server", "Game Client"}, []string{"server", "client"})
2523
if err != nil {
2624
return err
2725
}
2826
}
2927

30-
projectName, err := input.Input("Project name:")
28+
projectName, err := cli.Input("Project name:")
3129
if err != nil {
3230
return err
3331
}
3432

3533
if _, err := os.Stat(projectName); err == nil {
36-
return fmt.Errorf("Project '%s' already exists.", projectName)
34+
return cli.Error("Project '%s' already exists.", projectName)
3735
}
3836

3937
err = os.MkdirAll(projectName, 0755)
@@ -43,20 +41,28 @@ func New() error {
4341

4442
switch project {
4543
case "server":
46-
return newServer(projectName)
44+
err = newServer(projectName)
4745
case "client":
48-
return newClient(projectName)
46+
err = newClient(projectName)
4947
default:
50-
return fmt.Errorf("Unknown project type: %s", project)
48+
err = cli.Error("Unknown project type: %s", project)
5149
}
50+
51+
if err != nil {
52+
os.RemoveAll(projectName)
53+
return err
54+
}
55+
56+
cli.Success("Successfully created project in '%s/'.", projectName)
57+
return nil
5258
}
5359

5460
func newServer(projectName string) error {
55-
return errors.New("Not implemented.")
61+
return cli.Error("Not implemented.")
5662
}
5763

5864
func newClient(projectName string) error {
59-
url, err := input.Input("Enter the URL of the game server:")
65+
url, err := cli.Input("Enter the URL of the game server:")
6066
if err != nil {
6167
return err
6268
}
@@ -85,7 +91,7 @@ func newClient(projectName string) error {
8591
language = strings.ToLower(pflag.Arg(2))
8692
} else {
8793
var err error
88-
language, err = input.Select("In which language do you want to write your project?", []string{"Go"}, []string{"go"})
94+
language, err = cli.Select("In which language do you want to write your project?", []string{"Go"}, []string{"go"})
8995
if err != nil {
9096
return err
9197
}
@@ -98,21 +104,19 @@ func newClient(projectName string) error {
98104

99105
err = external.CGGenEvents(eventsOutput, baseURL(url, ssl), cgeVersion, language)
100106
if err != nil {
101-
fmt.Fprintln(os.Stderr, "\x1b[31mFailed to generate event definitions:", err, "\x1b[0m")
107+
cli.Error("Failed to generate event definitions: %s", err)
102108
}
103109

104110
switch language {
105111
case "go":
106112
err = newClientGo(projectName, url, cgVersion)
107113
default:
108-
return fmt.Errorf("Unsupported language: %s", language)
114+
return cli.Error("Unsupported language: %s", language)
109115
}
110116
if err != nil {
111117
return err
112118
}
113119

114-
fmt.Printf("\x1b[32mSuccessfully created project in '%s'.\n\x1b[0m", projectName)
115-
116120
return nil
117121
}
118122

@@ -122,30 +126,30 @@ func getCodeGameInfo(baseURL string) (string, string, error) {
122126
CGVersion string `json:"cg_version"`
123127
}
124128
res, err := http.Get(baseURL + "/info")
125-
if err != nil {
126-
return "", "", err
129+
if err != nil || res.StatusCode != http.StatusOK {
130+
return "", "", cli.Error("Couldn't access /info endpoint.")
127131
}
128132
defer res.Body.Close()
129133

130134
var data response
131135
err = json.NewDecoder(res.Body).Decode(&data)
132136
if err != nil {
133-
return "", "", err
137+
return "", "", cli.Error("Couldn't decode /info data.")
134138
}
135139

136140
return data.Name, data.CGVersion, nil
137141
}
138142

139143
func getCGEVersion(baseURL string) (string, error) {
140144
res, err := http.Get(baseURL + "/events")
141-
if err != nil {
142-
return "", err
145+
if err != nil || res.StatusCode != http.StatusOK {
146+
return "", cli.Error("Couldn't access /events endpoint.")
143147
}
144148
defer res.Body.Close()
145149

146150
data, err := io.ReadAll(res.Body)
147151
if err != nil {
148-
return "", err
152+
return "", cli.Error("Couldn't read /events file.")
149153
}
150154
return parseCGEVersion([]rune(string(data))), nil
151155
}

commands/new_go.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99

1010
_ "embed"
1111

12+
"github.com/code-game-project/codegame-cli/cli"
1213
"github.com/code-game-project/codegame-cli/external"
13-
"github.com/code-game-project/codegame-cli/input"
1414
)
1515

1616
//go:embed templates/main.go.tmpl
@@ -27,20 +27,28 @@ func newClientGo(projectName, serverURL, cgVersion string) error {
2727
return err
2828
}
2929

30+
cli.Begin("Cleaning up...")
3031
err = external.ExecuteInDir(projectName, "go", "mod", "tidy")
3132
if err != nil {
3233
return err
3334
}
3435

35-
return external.ExecuteInDir(projectName, "goimports", "-w", "main.go")
36+
err = external.ExecuteInDir(projectName, "goimports", "-w", "main.go")
37+
if err != nil {
38+
cli.Warn("Failed to add import statements: %s", err)
39+
}
40+
cli.Finish()
41+
42+
return nil
3643
}
3744

3845
func createGoTemplate(projectName, serverURL string) error {
39-
module, err := input.Input("Project module path:")
46+
module, err := cli.Input("Project module path:")
4047
if err != nil {
4148
return err
4249
}
4350

51+
cli.Begin("Creating project template...")
4452
out, err := external.ExecuteInDirHidden(projectName, "go", "mod", "init", module)
4553
if err != nil {
4654
fmt.Println(out)
@@ -62,12 +70,16 @@ func createGoTemplate(projectName, serverURL string) error {
6270
URL string
6371
}
6472

65-
return tmpl.Execute(file, data{
73+
err = tmpl.Execute(file, data{
6674
URL: serverURL,
6775
})
76+
cli.Finish()
77+
return err
6878
}
6979

7080
func installGoLibrary(projectName, cgVersion string) error {
81+
cli.Begin("Fetching correct client library version...")
82+
7183
clientVersion := external.ClientVersionFromCGVersion("code-game-project", "go-client", cgVersion)
7284

7385
if clientVersion == "latest" {
@@ -88,10 +100,14 @@ func installGoLibrary(projectName, cgVersion string) error {
88100
path = fmt.Sprintf("github.com/code-game-project/go-client/v%s/cg", majorVersion)
89101
}
90102
path += "@" + tag
103+
cli.Finish()
91104

105+
cli.Begin("Installing dependencies...")
92106
out, err := external.ExecuteInDirHidden(projectName, "go", "get", path)
93107
if err != nil {
94-
fmt.Println(out)
108+
cli.Error(out)
109+
return err
95110
}
96-
return err
111+
cli.Finish()
112+
return nil
97113
}

external/external.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"runtime"
1313
"strconv"
1414
"strings"
15+
16+
"github.com/code-game-project/codegame-cli/cli"
1517
)
1618

1719
var ErrTagNotFound = errors.New("tag not found")
@@ -62,7 +64,7 @@ func GetUsername() string {
6264
return strings.TrimSpace(user.Username)
6365
}
6466

65-
fmt.Println("Make sure to replace <your-name> with your actual name.")
67+
cli.Info("Make sure to replace <your-name> with your actual name.")
6668
return "<your-name>"
6769
}
6870

@@ -75,14 +77,14 @@ func OpenBrowser(url string) error {
7577
case "darwin":
7678
return exec.Command("open", url).Start()
7779
default:
78-
return fmt.Errorf("unsupported platform")
80+
return fmt.Errorf("Unsupported platform.")
7981
}
8082
}
8183

8284
func GithubTagFromVersion(owner, repo, version string) (string, error) {
8385
res, err := http.Get(fmt.Sprintf("https://api.github.com/repos/%s/%s/tags", owner, repo))
84-
if err != nil {
85-
return "", err
86+
if err != nil || res.StatusCode != http.StatusOK {
87+
return "", cli.Error("Couldn't access git tags from 'github.com/%s/%s'.", owner, repo)
8688
}
8789
defer res.Body.Close()
8890
type response []struct {
@@ -91,7 +93,7 @@ func GithubTagFromVersion(owner, repo, version string) (string, error) {
9193
var data response
9294
err = json.NewDecoder(res.Body).Decode(&data)
9395
if err != nil {
94-
return "", err
96+
return "", cli.Error("Couldn't decode git tag data.")
9597
}
9698

9799
for _, tag := range data {
@@ -104,16 +106,16 @@ func GithubTagFromVersion(owner, repo, version string) (string, error) {
104106

105107
func ClientVersionFromCGVersion(owner, repo, cgVersion string) string {
106108
res, err := http.Get(fmt.Sprintf("https://raw.githubusercontent.com/%s/%s/main/versions.json", owner, repo))
107-
if err != nil {
108-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: Couldn't fetch versions.json. Using latest client library version.\n\x1b[0m")
109+
if err != nil || res.StatusCode != http.StatusOK {
110+
cli.Warn("Couldn't fetch versions.json. Using latest client library version.")
109111
return "latest"
110112
}
111113
defer res.Body.Close()
112114

113115
var versions map[string]string
114116
err = json.NewDecoder(res.Body).Decode(&versions)
115117
if err != nil {
116-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: Invalid versions.json. Using latest client library version.\n\x1b[0m")
118+
cli.Warn("Invalid versions.json. Using latest client library version.")
117119
return "latest"
118120
}
119121

@@ -124,7 +126,7 @@ func ClientVersionFromCGVersion(owner, repo, cgVersion string) string {
124126

125127
parts := strings.Split(cgVersion, ".")
126128
if len(parts) < 2 {
127-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: Invalid versions.json. Using latest client library version.\n\x1b[0m")
129+
cli.Warn("Invalid versions.json. Using latest client library version.")
128130
return "latest"
129131
}
130132
major := parts[0]
@@ -134,28 +136,28 @@ func ClientVersionFromCGVersion(owner, repo, cgVersion string) string {
134136
for v := range versions {
135137
clientParts := strings.Split(v, ".")
136138
if len(clientParts) < 2 {
137-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: Invalid versions.json. Using latest client library version.\n\x1b[0m")
139+
cli.Warn("Invalid versions.json. Using latest client library version.")
138140
return "latest"
139141
}
140142
clientMajor := clientParts[0]
141143
if major == clientMajor {
142144
minor, err := strconv.Atoi(clientParts[1])
143145
if err != nil {
144-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: Invalid versions.json. Using latest client library version.\n\x1b[0m")
146+
cli.Warn("Invalid versions.json. Using latest client library version.")
145147
return "latest"
146148
}
147149
compatibleMinorVersions = append(compatibleMinorVersions, minor)
148150
}
149151
}
150152
if len(compatibleMinorVersions) == 0 {
151-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: No compatible client library version found. Using latest client library version.\n\x1b[0m")
153+
cli.Warn("No compatible client library version found. Using latest client library version.")
152154
return "latest"
153155
}
154156

155157
minorStr := parts[1]
156158
minor, err := strconv.Atoi(minorStr)
157159
if err != nil {
158-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: Invalid versions.json. Using latest client library version.\n\x1b[0m")
160+
cli.Warn("Invalid versions.json. Using latest client library version.")
159161
return "latest"
160162
}
161163

@@ -168,7 +170,7 @@ func ClientVersionFromCGVersion(owner, repo, cgVersion string) string {
168170
}
169171
if closestMinor >= 0 {
170172
v := fmt.Sprintf("%s.%d", major, minor)
171-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: No exact version match found. Using client library version %s.\n\x1b[0m", v)
173+
cli.Warn("No exact version match found. Using client library version %s.", v)
172174
return v
173175
}
174176

@@ -181,10 +183,10 @@ func ClientVersionFromCGVersion(owner, repo, cgVersion string) string {
181183
}
182184
if closestMinor >= 0 {
183185
v := fmt.Sprintf("%s.%d", major, minor)
184-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: No exact version match found. Using client library version %s.\n\x1b[0m", v)
186+
cli.Warn("No exact version match found. Using client library version %s.")
185187
return v
186188
}
187189

188-
fmt.Fprintf(os.Stderr, "\x1b[33mWARNING: No compatible client library version found. Using latest client library version.\n\x1b[0m")
190+
cli.Warn("No compatible client library version found. Using latest client library version.")
189191
return "latest"
190192
}

0 commit comments

Comments
 (0)