github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/client/cli/new/new.go (about) 1 // Package new generates micro service templates 2 package new 3 4 import ( 5 "fmt" 6 "go/build" 7 "os" 8 "path" 9 "path/filepath" 10 "runtime" 11 "strings" 12 "text/template" 13 "time" 14 15 tmpl "github.com/tickoalcantara12/micro/v3/client/cli/new/template" 16 "github.com/tickoalcantara12/micro/v3/cmd" 17 "github.com/tickoalcantara12/micro/v3/cmd/usage" 18 "github.com/urfave/cli/v2" 19 "github.com/xlab/treeprint" 20 ) 21 22 func protoComments(goDir, alias string) []string { 23 return []string{ 24 "\ndownload protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:\n", 25 "visit https://github.com/protocolbuffers/protobuf/releases", 26 "\ncompile the proto file " + alias + ".proto:\n", 27 "cd " + alias, 28 "make init", 29 "go mod vendor", 30 "make proto\n", 31 } 32 } 33 34 type config struct { 35 // foo 36 Alias string 37 // github.com/micro/foo 38 Dir string 39 // $GOPATH/src/github.com/micro/foo 40 GoDir string 41 // $GOPATH 42 GoPath string 43 // UseGoPath 44 UseGoPath bool 45 // Files 46 Files []file 47 // Comments 48 Comments []string 49 } 50 51 type file struct { 52 Path string 53 Tmpl string 54 } 55 56 func write(c config, file, tmpl string) error { 57 fn := template.FuncMap{ 58 "title": func(s string) string { 59 return strings.ReplaceAll(strings.Title(s), "-", "") 60 }, 61 "dehyphen": func(s string) string { 62 return strings.ReplaceAll(s, "-", "") 63 }, 64 "lower": func(s string) string { 65 return strings.ToLower(s) 66 }, 67 } 68 69 f, err := os.Create(file) 70 if err != nil { 71 return err 72 } 73 defer f.Close() 74 75 t, err := template.New("f").Funcs(fn).Parse(tmpl) 76 if err != nil { 77 return err 78 } 79 80 return t.Execute(f, c) 81 } 82 83 func create(c config) error { 84 // check if dir exists 85 if _, err := os.Stat(c.Dir); !os.IsNotExist(err) { 86 return fmt.Errorf("%s already exists", c.Dir) 87 } 88 89 // create usage report 90 u := usage.New("new") 91 // a single request/service 92 u.Metrics.Count["requests"] = uint64(1) 93 u.Metrics.Count["services"] = uint64(1) 94 // send report 95 go usage.Report(u) 96 97 // just wait 98 <-time.After(time.Millisecond * 250) 99 100 fmt.Printf("Creating service %s\n\n", c.Alias) 101 102 t := treeprint.New() 103 104 // write the files 105 for _, file := range c.Files { 106 f := filepath.Join(c.Dir, file.Path) 107 dir := filepath.Dir(f) 108 109 if _, err := os.Stat(dir); os.IsNotExist(err) { 110 if err := os.MkdirAll(dir, 0755); err != nil { 111 return err 112 } 113 } 114 115 addFileToTree(t, file.Path) 116 if err := write(c, f, file.Tmpl); err != nil { 117 return err 118 } 119 } 120 121 // print tree 122 fmt.Println(t.String()) 123 124 for _, comment := range c.Comments { 125 fmt.Println(comment) 126 } 127 128 // just wait 129 <-time.After(time.Millisecond * 250) 130 131 return nil 132 } 133 134 func addFileToTree(root treeprint.Tree, file string) { 135 split := strings.Split(file, "/") 136 curr := root 137 for i := 0; i < len(split)-1; i++ { 138 n := curr.FindByValue(split[i]) 139 if n != nil { 140 curr = n 141 } else { 142 curr = curr.AddBranch(split[i]) 143 } 144 } 145 if curr.FindByValue(split[len(split)-1]) == nil { 146 curr.AddNode(split[len(split)-1]) 147 } 148 } 149 150 func Run(ctx *cli.Context) error { 151 dir := ctx.Args().First() 152 if len(dir) == 0 { 153 fmt.Println("specify service name") 154 return nil 155 } 156 157 // check if the path is absolute, we don't want this 158 // we want to a relative path so we can install in GOPATH 159 if path.IsAbs(dir) { 160 fmt.Println("require relative path as service will be installed in GOPATH") 161 return nil 162 } 163 164 var goPath string 165 var goDir string 166 167 goPath = build.Default.GOPATH 168 169 // don't know GOPATH, runaway.... 170 if len(goPath) == 0 { 171 fmt.Println("unknown GOPATH") 172 return nil 173 } 174 175 // attempt to split path if not windows 176 if runtime.GOOS == "windows" { 177 goPath = strings.Split(goPath, ";")[0] 178 } else { 179 goPath = strings.Split(goPath, ":")[0] 180 } 181 goDir = filepath.Join(goPath, "src", path.Clean(dir)) 182 183 c := config{ 184 Alias: dir, 185 Comments: protoComments(goDir, dir), 186 Dir: dir, 187 GoDir: goDir, 188 GoPath: goPath, 189 UseGoPath: false, 190 Files: []file{ 191 {"main.go", tmpl.MainSRV}, 192 {"handler/" + dir + ".go", tmpl.HandlerSRV}, 193 {"proto/" + dir + ".proto", tmpl.ProtoSRV}, 194 {"Makefile", tmpl.Makefile}, 195 {"README.md", tmpl.Readme}, 196 {".gitignore", tmpl.GitIgnore}, 197 }, 198 } 199 200 // set gomodule 201 if os.Getenv("GO111MODULE") != "off" { 202 c.Files = append(c.Files, file{"go.mod", tmpl.Module}) 203 } 204 205 // create the files 206 return create(c) 207 } 208 209 func init() { 210 cmd.Register(&cli.Command{ 211 Name: "new", 212 Usage: "Create a service template", 213 Description: `'micro new' scaffolds a new service skeleton. Example: 'micro new helloworld && cd helloworld'`, 214 Action: Run, 215 }) 216 }