hybridgroup.gobot/cli/generate.go

418 lines
8.5 KiB
Go

package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
"text/template"
"github.com/urfave/cli"
)
type config struct {
Package string
Name string
UpperName string
FirstLetter string
Example string
dir string
}
func Generate() cli.Command {
return cli.Command{
Name: "generate",
Usage: "Generate new Gobot adaptors, drivers, and platforms",
Action: func(c *cli.Context) {
valid := false
for _, s := range []string{"adaptor", "driver", "platform"} {
if s == c.Args().First() {
valid = true
}
}
if !valid {
fmt.Println("Invalid/no subcommand supplied.")
fmt.Println("Usage:")
fmt.Println(" gobot generate adaptor <name> [package] # generate a new Gobot adaptor")
fmt.Println(" gobot generate driver <name> [package] # generate a new Gobot driver")
fmt.Println(" gobot generate platform <name> [package] # generate a new Gobot platform")
return
}
if len(c.Args()) < 2 {
fmt.Println("Please provide a one word name.")
return
}
name := strings.ToLower(c.Args()[1])
packageName := name
if len(c.Args()) > 2 {
packageName = strings.ToLower(c.Args()[2])
}
upperName := strings.ToUpper(string(name[0])) + string(name[1:])
cfg := config{
Package: packageName,
UpperName: upperName,
Name: name,
FirstLetter: string(name[0]),
dir: ".",
}
switch c.Args().First() {
case "adaptor":
if err := generateAdaptor(cfg); err != nil {
fmt.Println(err)
}
case "driver":
if err := generateDriver(cfg); err != nil {
fmt.Println(err)
}
case "platform":
pwd, err := os.Getwd()
if err != nil {
fmt.Println(err)
return
}
dir := pwd + "/" + cfg.Name
fmt.Println("Creating", dir)
if err := os.MkdirAll(dir, 0700); err != nil {
fmt.Println(err)
return
}
cfg.dir = dir
examplesDir := dir + "/examples"
fmt.Println("Creating", examplesDir)
if err := os.MkdirAll(examplesDir, 0700); err != nil {
fmt.Println(err)
return
}
if err := generatePlatform(cfg); err != nil {
fmt.Println(err)
}
}
},
}
}
func generate(c config, file string, tmpl string) error {
fileLocation := c.dir + "/" + file
fmt.Println("Creating", fileLocation)
f, err := os.Create(fileLocation)
defer f.Close() //nolint:staticcheck // for historical reasons
if err != nil {
return err
}
t, err := template.New("").Parse(tmpl)
if err != nil {
return err
}
return t.Execute(f, c)
}
func generateDriver(c config) error {
if err := generate(c, c.Name+"_driver.go", driver()); err != nil {
return err
}
return generate(c, c.Name+"_driver_test.go", driverTest())
}
func generateAdaptor(c config) error {
if err := generate(c, c.Name+"_adaptor.go", adaptor()); err != nil {
return err
}
return generate(c, c.Name+"_adaptor_test.go", adaptorTest())
}
func generatePlatform(c config) error {
if err := generateDriver(c); err != nil {
return err
}
if err := generateAdaptor(c); err != nil {
return err
}
dir := c.dir
exampleDir := dir + "/examples"
c.dir = exampleDir
if err := generate(c, "main.go", example()); err != nil {
return err
}
c.dir = dir
exp, err := ioutil.ReadFile(exampleDir + "/main.go")
if err != nil {
return err
}
c.Example = string(exp)
return generate(c, "README.md", readme())
}
func adaptor() string {
return `package {{.Package}}
type {{.UpperName}}Adaptor struct {
name string
}
func New{{.UpperName}}Adaptor() *{{.UpperName}}Adaptor {
return &{{.UpperName}}Adaptor{
name: "{{.UpperName}}",
}
}
func ({{.FirstLetter}} *{{.UpperName}}Adaptor) Name() string { return {{.FirstLetter}}.name }
func ({{.FirstLetter}} *{{.UpperName}}Adaptor) SetName(name string) { {{.FirstLetter}}.name = name }
func ({{.FirstLetter}} *{{.UpperName}}Adaptor) Connect() error { return nil }
func ({{.FirstLetter}} *{{.UpperName}}Adaptor) Finalize() error { return nil }
func ({{.FirstLetter}} *{{.UpperName}}Adaptor) Ping() string { return "pong" }
`
}
func driver() string {
return `package {{.Package}}
import (
"time"
"gobot.io/x/gobot/v2"
)
const Hello string = "hello"
type {{.UpperName}}Driver struct {
name string
connection gobot.Connection
interval time.Duration
halt chan bool
gobot.Eventer
gobot.Commander
}
func New{{.UpperName}}Driver(a *{{.UpperName}}Adaptor) *{{.UpperName}}Driver {
{{.FirstLetter}} := &{{.UpperName}}Driver{
name: "{{.UpperName}}",
connection: a,
interval: 500*time.Millisecond,
halt: make(chan bool, 0),
Eventer: gobot.NewEventer(),
Commander: gobot.NewCommander(),
}
{{.FirstLetter}}.AddEvent(Hello)
{{.FirstLetter}}.AddCommand(Hello, func(params map[string]interface{}) interface{} {
return {{.FirstLetter}}.Hello()
})
return {{.FirstLetter}}
}
func ({{.FirstLetter}} *{{.UpperName}}Driver) Name() string { return {{.FirstLetter}}.name }
func ({{.FirstLetter}} *{{.UpperName}}Driver) SetName(name string) { {{.FirstLetter}}.name = name }
func ({{.FirstLetter}} *{{.UpperName}}Driver) Connection() gobot.Connection {
return {{.FirstLetter}}.connection
}
func ({{.FirstLetter}} *{{.UpperName}}Driver) adaptor() *{{.UpperName}}Adaptor {
return {{.FirstLetter}}.Connection().(*{{.UpperName}}Adaptor)
}
func ({{.FirstLetter}} *{{.UpperName}}Driver) Hello() string {
return "hello from " + {{.FirstLetter}}.Name() + "!"
}
func ({{.FirstLetter}} *{{.UpperName}}Driver) Ping() string {
return {{.FirstLetter}}.adaptor().Ping()
}
func ({{.FirstLetter}} *{{.UpperName}}Driver) Start() error {
go func() {
for {
{{.FirstLetter}}.Publish({{.FirstLetter}}.Event(Hello), {{.FirstLetter}}.Hello())
select {
case <- time.After({{.FirstLetter}}.interval):
case <- {{.FirstLetter}}.halt:
return
}
}
}()
return nil
}
func ({{.FirstLetter}} *{{.UpperName}}Driver) Halt() error {
{{.FirstLetter}}.halt <- true
return nil
}
`
}
func example() string {
return `
package main
import (
"../"
"fmt"
"time"
"gobot.io/x/gobot/v2"
)
func main() {
gbot := gobot.NewMaster()
conn := {{.Package}}.New{{.UpperName}}Adaptor()
dev := {{.Package}}.New{{.UpperName}}Driver(conn)
work := func() {
dev.On(dev.Event({{.Package}}.Hello), func(data interface{}) {
fmt.Println(data)
})
gobot.Every(1200*time.Millisecond, func() {
fmt.Println(dev.Ping())
})
}
robot := gobot.NewRobot(
"robot",
[]gobot.Connection{conn},
[]gobot.Device{dev},
work,
)
gbot.AddRobot(robot)
gbot.Start()
}
`
}
func driverTest() string {
return `package {{.Package}}
import (
"testing"
"time"
"gobot.io/x/gobot/v2"
"gobot.io/x/gobot/v2/gobottest"
)
var _ gobot.Driver = (*{{.UpperName}}Driver)(nil)
func Test{{.UpperName}}Driver(t *testing.T) {
d := New{{.UpperName}}Driver(New{{.UpperName}}Adaptor())
gobottest.Assert(t, d.Name(), "{{.UpperName}}")
gobottest.Assert(t, d.Connection().Name(), "{{.UpperName}}")
ret := d.Command(Hello)(nil)
gobottest.Assert(t, ret.(string), "hello from {{.UpperName}}!")
gobottest.Assert(t, d.Ping(), "pong")
gobottest.Assert(t, len(d.Start()), 0)
time.Sleep(d.interval)
sem := make(chan bool, 0)
d.On(d.Event(Hello), func(data interface{}) {
sem <- true
})
select {
case <-sem:
case <-time.After(600 * time.Millisecond):
t.Errorf("Hello Event was not published")
}
gobottest.Assert(t, len(d.Halt()), 0)
d.On(d.Event(Hello), func(data interface{}) {
sem <- true
})
select {
case <-sem:
t.Errorf("Hello Event should not publish after Halt")
case <-time.After(600 * time.Millisecond):
}
}
`
}
func adaptorTest() string {
return `package {{.Package}}
import (
"testing"
"gobot.io/x/gobot/v2"
"gobot.io/x/gobot/v2/gobottest"
)
var _ gobot.Adaptor = (*{{.UpperName}}Adaptor)(nil)
func Test{{.UpperName}}Adaptor(t *testing.T) {
a := New{{.UpperName}}Adaptor()
gobottest.Assert(t, a.Name(), "{{.UpperName}}")
gobottest.Assert(t, len(a.Connect()), 0)
gobottest.Assert(t, a.Ping(), "pong")
gobottest.Assert(t, len(a.Connect()), 0)
gobottest.Assert(t, len(a.Finalize()), 0)
}
`
}
func readme() string {
return `# {{.Package}}
Gobot (http://gobot.io/) is a framework for robotics and physical computing using Go
This repository contains the Gobot adaptor and driver for {{.Package}}.
For more information about Gobot, check out the github repo at
https://gobot.io/x/gobot/v2
## Installing
` + "```bash\ngo get path/to/repo/{{.Package}}\n```" + `
## Using
` + "```go{{.Example}}\n```" + `
## Connecting
Explain how to connect to the device here...
## License
Copyright (c) 2018 <Your Name Here>. Licensed under the <Insert license here> license.
`
}