gobot.io/x/gobot@v1.16.0/cli/generate.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "strings" 8 "text/template" 9 10 "github.com/urfave/cli" 11 ) 12 13 type config struct { 14 Package string 15 Name string 16 UpperName string 17 FirstLetter string 18 Example string 19 dir string 20 } 21 22 func Generate() cli.Command { 23 return cli.Command{ 24 Name: "generate", 25 Usage: "Generate new Gobot adaptors, drivers, and platforms", 26 Action: func(c *cli.Context) { 27 valid := false 28 for _, s := range []string{"adaptor", "driver", "platform"} { 29 if s == c.Args().First() { 30 valid = true 31 } 32 } 33 if valid == false { 34 fmt.Println("Invalid/no subcommand supplied.") 35 fmt.Println("Usage:") 36 fmt.Println(" gobot generate adaptor <name> [package] # generate a new Gobot adaptor") 37 fmt.Println(" gobot generate driver <name> [package] # generate a new Gobot driver") 38 fmt.Println(" gobot generate platform <name> [package] # generate a new Gobot platform") 39 return 40 } 41 42 if len(c.Args()) < 2 { 43 fmt.Println("Please provide a one word name.") 44 return 45 } 46 47 name := strings.ToLower(c.Args()[1]) 48 packageName := name 49 if len(c.Args()) > 2 { 50 packageName = strings.ToLower(c.Args()[2]) 51 } 52 upperName := strings.ToUpper(string(name[0])) + string(name[1:]) 53 54 cfg := config{ 55 Package: packageName, 56 UpperName: upperName, 57 Name: name, 58 FirstLetter: string(name[0]), 59 dir: ".", 60 } 61 62 switch c.Args().First() { 63 case "adaptor": 64 if err := generateAdaptor(cfg); err != nil { 65 fmt.Println(err) 66 } 67 case "driver": 68 if err := generateDriver(cfg); err != nil { 69 fmt.Println(err) 70 } 71 case "platform": 72 pwd, err := os.Getwd() 73 if err != nil { 74 fmt.Println(err) 75 return 76 } 77 dir := pwd + "/" + cfg.Name 78 fmt.Println("Creating", dir) 79 if err := os.MkdirAll(dir, 0700); err != nil { 80 fmt.Println(err) 81 return 82 } 83 cfg.dir = dir 84 85 examplesDir := dir + "/examples" 86 fmt.Println("Creating", examplesDir) 87 if err := os.MkdirAll(examplesDir, 0700); err != nil { 88 fmt.Println(err) 89 return 90 } 91 92 if err := generatePlatform(cfg); err != nil { 93 fmt.Println(err) 94 } 95 } 96 }, 97 } 98 } 99 100 func generate(c config, file string, tmpl string) error { 101 fileLocation := c.dir + "/" + file 102 fmt.Println("Creating", fileLocation) 103 104 f, err := os.Create(fileLocation) 105 defer f.Close() 106 if err != nil { 107 return err 108 } 109 110 t, err := template.New("").Parse(tmpl) 111 if err != nil { 112 return err 113 } 114 115 return t.Execute(f, c) 116 } 117 118 func generateDriver(c config) error { 119 if err := generate(c, c.Name+"_driver.go", driver()); err != nil { 120 return err 121 } 122 123 return generate(c, c.Name+"_driver_test.go", driverTest()) 124 } 125 126 func generateAdaptor(c config) error { 127 if err := generate(c, c.Name+"_adaptor.go", adaptor()); err != nil { 128 return err 129 } 130 131 return generate(c, c.Name+"_adaptor_test.go", adaptorTest()) 132 } 133 134 func generatePlatform(c config) error { 135 if err := generateDriver(c); err != nil { 136 return err 137 } 138 if err := generateAdaptor(c); err != nil { 139 return err 140 } 141 142 dir := c.dir 143 exampleDir := dir + "/examples" 144 c.dir = exampleDir 145 146 if err := generate(c, "main.go", example()); err != nil { 147 return err 148 } 149 150 c.dir = dir 151 152 if exp, err := ioutil.ReadFile(exampleDir + "/main.go"); err != nil { 153 return err 154 } else { 155 c.Example = string(exp) 156 } 157 158 return generate(c, "README.md", readme()) 159 } 160 161 func adaptor() string { 162 return `package {{.Package}} 163 164 type {{.UpperName}}Adaptor struct { 165 name string 166 } 167 168 func New{{.UpperName}}Adaptor() *{{.UpperName}}Adaptor { 169 return &{{.UpperName}}Adaptor{ 170 name: "{{.UpperName}}", 171 } 172 } 173 174 func ({{.FirstLetter}} *{{.UpperName}}Adaptor) Name() string { return {{.FirstLetter}}.name } 175 176 func ({{.FirstLetter}} *{{.UpperName}}Adaptor) SetName(name string) { {{.FirstLetter}}.name = name } 177 178 func ({{.FirstLetter}} *{{.UpperName}}Adaptor) Connect() error { return nil } 179 180 func ({{.FirstLetter}} *{{.UpperName}}Adaptor) Finalize() error { return nil } 181 182 func ({{.FirstLetter}} *{{.UpperName}}Adaptor) Ping() string { return "pong" } 183 ` 184 } 185 186 func driver() string { 187 return `package {{.Package}} 188 189 import ( 190 "time" 191 192 "gobot.io/x/gobot" 193 ) 194 195 const Hello string = "hello" 196 197 type {{.UpperName}}Driver struct { 198 name string 199 connection gobot.Connection 200 interval time.Duration 201 halt chan bool 202 gobot.Eventer 203 gobot.Commander 204 } 205 206 func New{{.UpperName}}Driver(a *{{.UpperName}}Adaptor) *{{.UpperName}}Driver { 207 {{.FirstLetter}} := &{{.UpperName}}Driver{ 208 name: "{{.UpperName}}", 209 connection: a, 210 interval: 500*time.Millisecond, 211 halt: make(chan bool, 0), 212 Eventer: gobot.NewEventer(), 213 Commander: gobot.NewCommander(), 214 } 215 216 {{.FirstLetter}}.AddEvent(Hello) 217 218 {{.FirstLetter}}.AddCommand(Hello, func(params map[string]interface{}) interface{} { 219 return {{.FirstLetter}}.Hello() 220 }) 221 222 return {{.FirstLetter}} 223 } 224 225 func ({{.FirstLetter}} *{{.UpperName}}Driver) Name() string { return {{.FirstLetter}}.name } 226 227 func ({{.FirstLetter}} *{{.UpperName}}Driver) SetName(name string) { {{.FirstLetter}}.name = name } 228 229 func ({{.FirstLetter}} *{{.UpperName}}Driver) Connection() gobot.Connection { 230 return {{.FirstLetter}}.connection 231 } 232 233 func ({{.FirstLetter}} *{{.UpperName}}Driver) adaptor() *{{.UpperName}}Adaptor { 234 return {{.FirstLetter}}.Connection().(*{{.UpperName}}Adaptor) 235 } 236 237 func ({{.FirstLetter}} *{{.UpperName}}Driver) Hello() string { 238 return "hello from " + {{.FirstLetter}}.Name() + "!" 239 } 240 241 func ({{.FirstLetter}} *{{.UpperName}}Driver) Ping() string { 242 return {{.FirstLetter}}.adaptor().Ping() 243 } 244 245 func ({{.FirstLetter}} *{{.UpperName}}Driver) Start() error { 246 go func() { 247 for { 248 {{.FirstLetter}}.Publish({{.FirstLetter}}.Event(Hello), {{.FirstLetter}}.Hello()) 249 250 select { 251 case <- time.After({{.FirstLetter}}.interval): 252 case <- {{.FirstLetter}}.halt: 253 return 254 } 255 } 256 }() 257 return nil 258 } 259 260 func ({{.FirstLetter}} *{{.UpperName}}Driver) Halt() error { 261 {{.FirstLetter}}.halt <- true 262 return nil 263 } 264 265 ` 266 } 267 268 func example() string { 269 return ` 270 package main 271 272 import ( 273 "../" 274 "fmt" 275 "time" 276 277 "gobot.io/x/gobot" 278 ) 279 280 func main() { 281 gbot := gobot.NewMaster() 282 283 conn := {{.Package}}.New{{.UpperName}}Adaptor() 284 dev := {{.Package}}.New{{.UpperName}}Driver(conn) 285 286 work := func() { 287 dev.On(dev.Event({{.Package}}.Hello), func(data interface{}) { 288 fmt.Println(data) 289 }) 290 291 gobot.Every(1200*time.Millisecond, func() { 292 fmt.Println(dev.Ping()) 293 }) 294 } 295 296 robot := gobot.NewRobot( 297 "robot", 298 []gobot.Connection{conn}, 299 []gobot.Device{dev}, 300 work, 301 ) 302 303 gbot.AddRobot(robot) 304 gbot.Start() 305 } 306 ` 307 } 308 309 func driverTest() string { 310 return `package {{.Package}} 311 312 import ( 313 "testing" 314 "time" 315 316 "gobot.io/x/gobot" 317 "gobot.io/x/gobot/gobottest" 318 ) 319 320 var _ gobot.Driver = (*{{.UpperName}}Driver)(nil) 321 322 func Test{{.UpperName}}Driver(t *testing.T) { 323 d := New{{.UpperName}}Driver(New{{.UpperName}}Adaptor()) 324 325 gobottest.Assert(t, d.Name(), "{{.UpperName}}") 326 gobottest.Assert(t, d.Connection().Name(), "{{.UpperName}}") 327 328 ret := d.Command(Hello)(nil) 329 gobottest.Assert(t, ret.(string), "hello from {{.UpperName}}!") 330 331 gobottest.Assert(t, d.Ping(), "pong") 332 333 gobottest.Assert(t, len(d.Start()), 0) 334 335 time.Sleep(d.interval) 336 337 sem := make(chan bool, 0) 338 339 d.On(d.Event(Hello), func(data interface{}) { 340 sem <- true 341 }) 342 343 select { 344 case <-sem: 345 case <-time.After(600 * time.Millisecond): 346 t.Errorf("Hello Event was not published") 347 } 348 349 gobottest.Assert(t, len(d.Halt()), 0) 350 351 d.On(d.Event(Hello), func(data interface{}) { 352 sem <- true 353 }) 354 355 select { 356 case <-sem: 357 t.Errorf("Hello Event should not publish after Halt") 358 case <-time.After(600 * time.Millisecond): 359 } 360 } 361 362 ` 363 } 364 365 func adaptorTest() string { 366 return `package {{.Package}} 367 368 import ( 369 "testing" 370 371 "gobot.io/x/gobot" 372 "gobot.io/x/gobot/gobottest" 373 ) 374 375 var _ gobot.Adaptor = (*{{.UpperName}}Adaptor)(nil) 376 377 func Test{{.UpperName}}Adaptor(t *testing.T) { 378 a := New{{.UpperName}}Adaptor() 379 380 gobottest.Assert(t, a.Name(), "{{.UpperName}}") 381 382 gobottest.Assert(t, len(a.Connect()), 0) 383 384 gobottest.Assert(t, a.Ping(), "pong") 385 386 gobottest.Assert(t, len(a.Connect()), 0) 387 388 gobottest.Assert(t, len(a.Finalize()), 0) 389 } 390 ` 391 } 392 393 func readme() string { 394 return `# {{.Package}} 395 396 Gobot (http://gobot.io/) is a framework for robotics and physical computing using Go 397 398 This repository contains the Gobot adaptor and driver for {{.Package}}. 399 400 For more information about Gobot, check out the github repo at 401 https://gobot.io/x/gobot 402 403 ## Installing 404 ` + "```bash\ngo get path/to/repo/{{.Package}}\n```" + ` 405 406 ## Using 407 ` + "```go{{.Example}}\n```" + ` 408 409 ## Connecting 410 411 Explain how to connect to the device here... 412 413 ## License 414 415 Copyright (c) 2018 <Your Name Here>. Licensed under the <Insert license here> license. 416 ` 417 }