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  }