11package main
22
33import (
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+
1378func 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
44197func 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.
55210func 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