Skip to content

Commit 4ad38af

Browse files
Merge pull request #85 from SasSwart/development
V0.0.17
2 parents f62567a + fb3779f commit 4ad38af

File tree

18 files changed

+436
-633
lines changed

18 files changed

+436
-633
lines changed

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION := v0.0.0
1+
VERSION := 0.0.0
22

33
all: linux_amd64.zip
44

@@ -8,7 +8,7 @@ linux_amd64.zip: build/linux_amd64 LICENSE
88
build/linux_amd64: build/linux_amd64/can build/linux_amd64/templates
99

1010
build/linux_amd64/can:
11-
echo '${VERSION}' > ./config/version.txt
11+
echo -n '${VERSION}' > ./config/version.txt
1212
go build -o ./build/linux_amd64/ ./...
1313

1414
build/linux_amd64/templates:
@@ -24,3 +24,6 @@ test:
2424
test_coverage:
2525
go test ./openapi -coverprofile=coverage.out
2626
go tool cover -html=coverage.out
27+
28+
install: build/linux_amd64
29+
cp build/linux_amd64/can ~/bin/can

cmd/can/main.go

Lines changed: 171 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,197 @@
11
package main
22

33
import (
4+
"bytes"
45
"fmt"
56
"github.com/sasswart/gin-in-a-can/config"
67
"github.com/sasswart/gin-in-a-can/openapi"
78
"github.com/sasswart/gin-in-a-can/render"
89
golang "github.com/sasswart/gin-in-a-can/render/go"
910
"github.com/sasswart/gin-in-a-can/tree"
11+
"io"
1012
"os"
13+
"path/filepath"
14+
"sync"
15+
16+
"github.com/spf13/cobra"
1117
)
1218

19+
var canCmd = &cobra.Command{
20+
Use: "can",
21+
Short: "Generate code based on OpenAPI specifications",
22+
}
23+
24+
var generateCmd = &cobra.Command{
25+
Use: "generate",
26+
Short: "Generate files",
27+
Run: func(cmd *cobra.Command, args []string) {
28+
absCfgPath, err := filepath.Abs(config.ConfigFilePath)
29+
if err != nil {
30+
fmt.Printf("could not resolve relative config path: %v\n", err)
31+
return
32+
}
33+
config.ConfigFilePath = absCfgPath
34+
35+
configFileReader, err := os.Open(absCfgPath)
36+
if err != nil {
37+
fmt.Printf("failed to open config file: %v", err)
38+
os.Exit(1)
39+
}
40+
41+
configs := config.ReadConfigs(configFileReader)
42+
43+
generate(configs)
44+
},
45+
}
46+
47+
var cleanCmd = &cobra.Command{
48+
Use: "clean",
49+
Short: "Remove generated files",
50+
Run: func(cmd *cobra.Command, args []string) {
51+
absCfgPath, err := filepath.Abs(config.ConfigFilePath)
52+
if err != nil {
53+
fmt.Printf("could not resolve relative config path: %v\n", err)
54+
return
55+
}
56+
config.ConfigFilePath = absCfgPath
57+
58+
configFileReader, err := os.Open(absCfgPath)
59+
if err != nil {
60+
fmt.Printf("failed to open config file: %v", err)
61+
os.Exit(1)
62+
}
63+
64+
configs := config.ReadConfigs(configFileReader)
65+
66+
clean(configs)
67+
},
68+
}
69+
70+
var versionCmd = &cobra.Command{
71+
Use: "version",
72+
Short: "Print the version number",
73+
Run: func(cmd *cobra.Command, args []string) {
74+
fmt.Printf("Can: v%s\n", config.SemVer)
75+
},
76+
}
77+
1378
func main() {
14-
fmt.Printf("can %s\n", config.SemVer)
15-
cfg := mustLoadConfig()
79+
canCmd.PersistentFlags().StringVarP(
80+
&config.ConfigFilePath,
81+
"configFile",
82+
"c",
83+
"./can.yml",
84+
"config file (default is ./can.yml)")
85+
86+
canCmd.PersistentFlags().BoolVarP(
87+
&config.Debug,
88+
"debug",
89+
"d",
90+
false,
91+
"Enable Debug logging")
92+
93+
canCmd.PersistentFlags().BoolVarP(
94+
&config.Dryrun,
95+
"dry-run",
96+
"r",
97+
false,
98+
"Print actions instead of applying them to disk")
99+
100+
canCmd.AddCommand(generateCmd)
101+
canCmd.AddCommand(cleanCmd)
102+
canCmd.AddCommand(versionCmd)
103+
104+
if err := canCmd.Execute(); err != nil {
105+
fmt.Println(err)
106+
os.Exit(1)
107+
}
108+
}
109+
110+
func clean(configs <-chan []byte) {
111+
wg := sync.WaitGroup{}
112+
for configBytes := range configs {
113+
114+
wg.Add(1)
115+
116+
go func(configBytes []byte) {
117+
defer wg.Done()
118+
119+
if len(configBytes) == 0 {
120+
if config.Debug {
121+
fmt.Println("Skipping empty config")
122+
}
123+
return
124+
}
125+
126+
configReader := bytes.NewReader(configBytes)
127+
cfg := mustLoadConfig(configReader)
128+
129+
if config.Dryrun {
130+
fmt.Printf("Would delete %s\n", cfg.GetOutputDir())
131+
return
132+
}
133+
134+
err := os.RemoveAll(cfg.GetOutputDir())
135+
if err != nil {
136+
fmt.Println(err)
137+
}
138+
139+
}(configBytes)
140+
}
141+
wg.Wait()
142+
}
143+
144+
func generate(configs <-chan []byte) {
145+
wg := sync.WaitGroup{}
146+
for configBytes := range configs {
147+
148+
wg.Add(1)
149+
150+
go func(configBytes []byte) {
151+
defer wg.Done()
152+
153+
if len(configBytes) == 0 {
154+
if config.Debug {
155+
fmt.Println("Skipping empty config")
156+
}
157+
return
158+
}
159+
160+
configReader := bytes.NewReader(configBytes)
161+
cfg := mustLoadConfig(configReader)
162+
163+
err := executeJobForConfig(cfg)
164+
if err != nil {
165+
fmt.Println(err)
166+
}
167+
}(configBytes)
168+
}
169+
wg.Wait()
170+
}
171+
172+
func executeJobForConfig(cfg config.Data) error {
173+
fmt.Printf("Executing job: %s\n", cfg.Name)
174+
16175
if config.Debug {
17176
fmt.Printf("Reading API specification from \"%s\"\n", cfg.GetOpenAPIFilepath())
18177
}
19178
apiSpec := mustLoadOpenApiFile(cfg.GetOpenAPIFilepath())
20179

21180
engine := render.NewEngine(cfg)
22181

23-
// Setup appropriate renderer via the `strategy` design pattern
24-
mustSetStrategy(&engine, cfg.Template.Strategy)
182+
err := setStrategy(&engine, cfg.Template.Strategy)
183+
if err != nil {
184+
return err
185+
}
25186

26187
apiSpec.SetMetadata(tree.Metadata{
27188
"package": cfg.Template.BasePackageName,
28189
})
29190

30191
if _, err := tree.Traverse(apiSpec, engine.Render); err != nil {
31-
fmt.Println(err.Error())
32-
os.Exit(1)
33-
}
34-
}
35-
36-
func mustSetStrategy(engine *render.Engine, strategy string) {
37-
err := setStrategy(engine, strategy)
38-
if err != nil {
39-
fmt.Println(err.Error())
40-
os.Exit(1)
192+
return err
41193
}
194+
return nil
42195
}
43196

44197
func mustLoadOpenApiFile(path string) *openapi.OpenAPI {
@@ -52,6 +205,8 @@ func mustLoadOpenApiFile(path string) *openapi.OpenAPI {
52205
}
53206

54207
// setStrategy creates and applies the renderer for the given strategy. An error is returned if the strategy is invalid
208+
// TODO: A "strategy" is really just a renderer. This function should be a factory that returns a renderer, which then
209+
// gets applied to the engine where this is called.
55210
func setStrategy(e *render.Engine, strategy string) error {
56211
var r render.Renderer
57212
switch strategy {
@@ -64,9 +219,9 @@ func setStrategy(e *render.Engine, strategy string) error {
64219
return fmt.Errorf("%s render strategy not implemented yet", strategy)
65220
}
66221

67-
func mustLoadConfig() config.Data {
222+
func mustLoadConfig(reader io.Reader) config.Data {
68223
cfg := config.Data{}
69-
err := cfg.Load()
224+
err := cfg.Load(reader)
70225
if err != nil {
71226
fmt.Println(err.Error())
72227
os.Exit(1)

0 commit comments

Comments
 (0)