Add minio-cli stub generator

This commit is contained in:
Harshavardhana 2014-12-18 02:18:02 -08:00
parent 2b3be86727
commit 5268a62166
9 changed files with 387 additions and 1 deletions

View File

@ -48,6 +48,7 @@ cover: build-erasure build-signify build-split build-crc32c build-cpu build-sha1
install: build-erasure
@godep go install github.com/minio-io/minio/cmd/minio && echo "Installed minio into ${GOPATH}/bin"
@godep go install github.com/minio-io/minio/cmd/minio-cli && echo "Install minio-cli into ${GOPATH}/bin"
save: restore
@godep save ./...

2
cmd/minio-cli/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
templates.go
minio-cli

32
cmd/minio-cli/README.md Normal file
View File

@ -0,0 +1,32 @@
## Introduction
`minio-cli` is option stub builder for ``minio`` project using [codegangsta/cli](https://github.com/codegangsta/cli),
The idea is to be able to do rapid prototyping and facilitate new contributors to the project
## Usage
You just need to set its application name and options:
```bash
$ minio-cli -options option1,option2,option3 [application]
```
Generates three files namely [application].go, [application]-options.go, [application].md
## Example
If you want to start to building `bucket` application which has subcommands `get`, `put`, `list`:
```bash
$ minio-cli -options get,put,list foo
$ ls foo/
foo-options.go foo.go foo.md
```
## Installation
```bash
$ go get github.com/minio-io/minio
$ make install
```

View File

@ -0,0 +1,89 @@
// this code is from gofmt, modified for our internal usage - http://golang.org/src/cmd/gofmt/gofmt.go
package main
import (
"bytes"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
if in == nil {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
in = f
}
src, err := ioutil.ReadAll(in)
if err != nil {
return err
}
fileSet := token.NewFileSet()
file, err := parser.ParseFile(fileSet, filename, src, parser.ParseComments)
if err != nil {
return err
}
ast.SortImports(fileSet, file)
var buf bytes.Buffer
tabWidth := 8
printerMode := printer.UseSpaces | printer.TabIndent
err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file)
if err != nil {
return err
}
res := buf.Bytes()
if !bytes.Equal(src, res) {
err = ioutil.WriteFile(filename, res, 0)
if err != nil {
return err
}
}
return nil
}
func isGofile(f os.FileInfo) bool {
name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}
func visitFile(pathName string, f os.FileInfo, err error) error {
if err == nil && isGofile(f) {
err = processFile(pathName, nil, os.Stdout, false)
}
if err != nil {
return err
}
return nil
}
func walkDir(pathName string) {
filepath.Walk(pathName, visitFile)
}
func GoFormat(pathName string) error {
dir, err := os.Stat(pathName)
if err != nil {
return err
}
if dir.IsDir() {
walkDir(pathName)
}
return nil
}

163
cmd/minio-cli/minio-cli.go Normal file
View File

@ -0,0 +1,163 @@
package main
import (
"flag"
"log"
"os"
"path"
"strings"
"text/template"
"time"
"github.com/minio-io/minio/pkgs/utils"
)
type source struct {
Name string
TempLate template.Template
}
const (
// Relative path from GOPATH default
TEMPLATEREPO = "/src/github.com/minio-io/minio/templates/"
)
type option struct {
Name string
Definename string
Functionname string
}
type application struct {
Name string
Usage string
Month string
Year int
Options []option
}
func (f source) generate(appName string, def application) error {
wr, err := os.Create(path.Join(appName, f.Name))
if err != nil {
return err
}
defer wr.Close()
return f.TempLate.Execute(wr, def)
}
func initApplication(appname, usage string, inputOptions []string) application {
year, month, _ := time.Now().Date()
return application{
Name: appname,
Usage: usage,
Month: month.String(),
Year: year,
Options: initOptions(inputOptions),
}
}
func initOptions(inputOptions []string) []option {
var options []option
if inputOptions[0] == "" {
return options
}
for _, name := range inputOptions {
option := option{
Name: name,
Definename: utils.FirstUpper(name),
Functionname: "do" + utils.FirstUpper(name),
}
options = append(options, option)
}
return options
}
func main() {
var flOptions, flUsage, flTemplatePath string
flag.StringVar(&flOptions, "options", "", "Comma-separated list of options to build")
flag.StringVar(&flUsage, "usage", "", "A one liner explains the purpose of the cli being built")
flag.StringVar(&flTemplatePath, "templatepath", "", "Non standard templates path")
flag.Parse()
inputOptions := strings.Split(flOptions, ",")
appname := flag.Arg(0)
if appname == "" {
log.Fatal("app name must not be blank\n")
}
if inputOptions[0] == "" {
log.Fatal("-options option1 should be specified with appname")
}
gopath := os.Getenv("GOPATH")
var mainTemplatePath, optionsTemplatePath, readmeTemplatePath string
if flTemplatePath == "" {
mainTemplatePath = path.Join(gopath, TEMPLATEREPO, "main.tmpl")
optionsTemplatePath = path.Join(gopath, TEMPLATEREPO, "options.tmpl")
readmeTemplatePath = path.Join(gopath, TEMPLATEREPO, "README.tmpl")
} else {
mainTemplatePath = path.Join(flTemplatePath, "main.tmpl")
optionsTemplatePath = path.Join(flTemplatePath, "options.tmpl")
readmeTemplatePath = path.Join(flTemplatePath, "README.tmpl")
}
if _, err := os.Stat(mainTemplatePath); err != nil {
log.Fatal(err)
}
if _, err := os.Stat(optionsTemplatePath); err != nil {
log.Fatal(err)
}
if _, err := os.Stat(readmeTemplatePath); err != nil {
log.Fatal(err)
}
var mainTemplate = template.Must(template.ParseFiles(mainTemplatePath))
var optionsTemplate = template.Must(template.ParseFiles(optionsTemplatePath))
var readmeTemplate = template.Must(template.ParseFiles(readmeTemplatePath))
if _, err := os.Stat(appname); err == nil {
// if exists, we overwrite by default
err = os.RemoveAll(appname)
utils.Assert(err)
}
err := os.Mkdir(appname, 0755)
utils.Assert(err)
application := initApplication(appname, flUsage, inputOptions)
optionsGo := source{
Name: appname + "-options.go",
TempLate: *optionsTemplate,
}
readmeMd := source{
Name: appname + ".md",
TempLate: *readmeTemplate,
}
mainGo := source{
Name: appname + ".go",
TempLate: *mainTemplate,
}
err = readmeMd.generate(appname, application)
utils.Assert(err)
mainGo.generate(appname, application)
utils.Assert(err)
optionsGo.generate(appname, application)
err = GoFormat(appname)
utils.Assert(err)
}

View File

@ -16,8 +16,22 @@
package utils
import "io/ioutil"
import (
"io/ioutil"
"log"
"strings"
)
func MakeTempTestDir() (string, error) {
return ioutil.TempDir("/tmp", "minio-test-")
}
func Assert(err error) {
if err != nil {
log.Fatal(err)
}
}
func FirstUpper(str string) string {
return strings.ToUpper(str[0:1]) + str[1:]
}

13
templates/README.tmpl Normal file
View File

@ -0,0 +1,13 @@
% MINIO(1) Minio Manual
% Minio community
% {{.Month}} {{.Year}}
# NAME
{{.Name}} - {{.Usage}}
# SYNOPSIS
# DESCRIPTION
# EXAMPLES
# AUTHORS

31
templates/main.tmpl Normal file
View File

@ -0,0 +1,31 @@
/*
* Mini Object Storage, (C) 2014 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"os"
"github.com/codegangsta/cli"
)
func main() {
app := cli.NewApp()
app.Name = "{{.Name}}"
app.Usage = "{{.Usage}}"
app.Commands = Options
app.Run(os.Args)
}

41
templates/options.tmpl Normal file
View File

@ -0,0 +1,41 @@
/*
* Mini Object Storage, (C) 2014 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"github.com/codegangsta/cli"
)
var Options = []cli.Command{
{{range .Options}}{{.Definename}},
{{end}}
}
{{range .Options}}
var {{.Definename}} = cli.Command{
Name: "{{.Name}}",
Usage: "",
Description: `
`,
Action: {{.Functionname}},
}
{{end}}
{{range .Options}}
func {{.Functionname}}(c *cli.Context) {
}
{{end}}