Merge branch 'master' of github.com:TuneLab/go-truss into add_version_tag

This commit is contained in:
Ian Molee 2016-12-06 14:47:00 -08:00
Родитель 62f22cecba 375fce470a
Коммит 9f6da34c52
6 изменённых файлов: 89 добавлений и 101 удалений

Просмотреть файл

@ -6,7 +6,6 @@ import (
"fmt"
"go/build"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
@ -28,6 +27,7 @@ import (
var (
pbPackageFlag = flag.String("pbout", "", "The go package path where the protoc-gen-go .pb.go structs will be written.")
svcPackageFlag = flag.String("svcout", "", "The go package path where the generated service directory will be written.")
verboseFlag = flag.Bool("v", false, "Verbose output with stack traces for errors.")
)
const (
@ -41,8 +41,6 @@ var (
)
func init() {
log.SetLevel(log.InfoLevel)
buildinfo := new(bytes.Buffer)
if Version != "" && Version != noVersion {
buildinfo.WriteString("version: ")
@ -69,6 +67,11 @@ func init() {
flag.Usage()
os.Exit(1)
}
log.SetLevel(log.InfoLevel)
if *verboseFlag {
log.SetLevel(log.DebugLevel)
}
}
func main() {
@ -81,8 +84,8 @@ func main() {
genFiles, err := generateCode(cfg, dt, sd)
exitIfError(errors.Wrap(err, "cannot generate service"))
for _, f := range genFiles {
err := writeGenFile(f, cfg.ServicePath)
for path, file := range genFiles {
err := writeGenFile(file, path, cfg.ServicePath)
if err != nil {
exitIfError(errors.Wrap(err, "cannot to write output"))
}
@ -249,9 +252,9 @@ func parseServiceDefinition(cfg *truss.Config) (deftree.Deftree, *svcdef.Svcdef,
return dt, sd, nil
}
// generateCode returns a []truss.NamedReadWriter that represents a gokit
// generateCode returns a map[string]io.Reader that represents a gokit
// service with documentation
func generateCode(cfg *truss.Config, dt deftree.Deftree, sd *svcdef.Svcdef) ([]truss.NamedReadWriter, error) {
func generateCode(cfg *truss.Config, dt deftree.Deftree, sd *svcdef.Svcdef) (map[string]io.Reader, error) {
conf := ggkconf.Config{
PBPackage: cfg.PBPackage,
GoPackage: cfg.ServicePackage,
@ -265,33 +268,45 @@ func generateCode(cfg *truss.Config, dt deftree.Deftree, sd *svcdef.Svcdef) ([]t
genDocFiles := gendoc.GenerateDocs(dt)
genFiles := append(genGokitFiles, genDocFiles...)
return genFiles, nil
return combineFiles(genGokitFiles, genDocFiles), nil
}
// writeGenFile writes a truss.NamedReadWriter to the filesystem
// to be contained within serviceDir
func writeGenFile(f truss.NamedReadWriter, serviceDir string) error {
// combineFiles takes any number of map[string]io.Reader and combines them into one.
func combineFiles(group ...map[string]io.Reader) map[string]io.Reader {
final := make(map[string]io.Reader)
for _, g := range group {
for path, file := range g {
if final[path] != nil {
log.WithField("path", path).
Warn("truss generated two files with same path, outputting final one specified")
}
final[path] = file
}
}
return final
}
// writeGenFile writes a file at relPath relative to serviceDir to the filesystem
func writeGenFile(file io.Reader, relPath, serviceDir string) error {
// the serviceDir contains /NAME-service so we want to write to the
// directory above
outDir := filepath.Dir(serviceDir)
// i.e. NAME-service/generated/endpoint.go
name := f.Name()
fullPath := filepath.Join(outDir, name)
fullPath := filepath.Join(outDir, relPath)
err := os.MkdirAll(filepath.Dir(fullPath), 0777)
if err != nil {
return err
}
file, err := os.Create(fullPath)
outFile, err := os.Create(fullPath)
if err != nil {
return errors.Wrapf(err, "cannot create file %v", fullPath)
}
_, err = io.Copy(file, f)
_, err = io.Copy(outFile, file)
if err != nil {
return errors.Wrapf(err, "cannot write to %v", fullPath)
}
@ -325,60 +340,51 @@ func cleanProtofilePath(rawPaths []string) ([]string, error) {
func exitIfError(err error) {
if errors.Cause(err) != nil {
defer os.Exit(1)
if *verboseFlag {
fmt.Printf("%+v\n", err)
return
}
fmt.Printf("%v\n", err)
}
}
// readPreviousGeneration returns a []truss.NamedReadWriter for all files serviceDir
func readPreviousGeneration(serviceDir string) ([]truss.NamedReadWriter, error) {
// readPreviousGeneration returns a map[string]io.Reader representing the files in serviceDir
func readPreviousGeneration(serviceDir string) (map[string]io.Reader, error) {
if fileExists(serviceDir) != true {
return nil, nil
}
var files []truss.NamedReadWriter
dir, _ := filepath.Split(serviceDir)
sfs := simpleFileConstructor{
dir: dir,
files: files,
}
err := filepath.Walk(serviceDir, sfs.makeSimpleFile)
if err != nil {
return nil, errors.Wrapf(err, "cannot fully walk directory %v", sfs.dir)
}
files := make(map[string]io.Reader)
return sfs.files, nil
}
addFileToFiles := func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
// simpleFileConstructor has function makeSimpleFile of type filepath.WalkFunc
// This allows for filepath.Walk to be called with makeSimpleFile and build a truss.SimpleFile
// for all files in a direcotry
type simpleFileConstructor struct {
dir string
files []truss.NamedReadWriter
}
file, ioErr := os.Open(path)
if ioErr != nil {
return errors.Wrapf(ioErr, "cannot read file: %v", path)
}
// trim the prefix of the path to the proto files from the full path to the file
relPath, err := filepath.Rel(dir, path)
if err != nil {
return err
}
files[relPath] = file
// makeSimpleFile is of type filepath.WalkFunc
// makeSimpleFile constructs a truss.SimpleFile and stores it in SimpleFileConstructor.files
func (sfs *simpleFileConstructor) makeSimpleFile(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
byteContent, ioErr := ioutil.ReadFile(path)
if ioErr != nil {
return errors.Wrapf(ioErr, "cannot read file: %v", path)
err := filepath.Walk(serviceDir, addFileToFiles)
if err != nil {
return nil, errors.Wrapf(err, "cannot fully walk directory %v", dir)
}
// trim the prefix of the path to the proto files from the full path to the file
name := strings.TrimPrefix(path, sfs.dir)
var file truss.SimpleFile
file.Path = name
file.Write(byteContent)
sfs.files = append(sfs.files, &file)
return nil
return files, nil
}
// fileExists checks if a file at the given path exists. Returns true if the

Просмотреть файл

@ -3,14 +3,16 @@
package gendoc
import (
"io"
"strings"
"github.com/TuneLab/go-truss/deftree"
"github.com/TuneLab/go-truss/truss"
)
// GenerateDocs accepts a deftree that represents an ast of a group of
// protofiles and returns a []truss.SimpleFile that represents a relative
// protofiles and returns map[string]io.Reader that represents a relative
// filestructure of generated docs
func GenerateDocs(dt deftree.Deftree) []truss.NamedReadWriter {
func GenerateDocs(dt deftree.Deftree) map[string]io.Reader {
response := ""
microDef, ok := dt.(*deftree.MicroserviceDefinition)
@ -20,13 +22,8 @@ func GenerateDocs(dt deftree.Deftree) []truss.NamedReadWriter {
response = "Error, could not cast Deftree to MicroserviceDefinition"
}
var file truss.SimpleFile
file.Path = dt.GetName() + "-service/docs/docs.md"
file.Write([]byte(response))
var files []truss.NamedReadWriter
files = append(files, &file)
files := make(map[string]io.Reader)
files[dt.GetName()+"-service/docs/docs.md"] = strings.NewReader(response)
return files
}

Просмотреть файл

@ -2,6 +2,7 @@
package generator
import (
"bytes"
"go/format"
"io"
"io/ioutil"
@ -16,37 +17,27 @@ import (
templFiles "github.com/TuneLab/go-truss/gengokit/template"
"github.com/TuneLab/go-truss/svcdef"
"github.com/TuneLab/go-truss/truss"
)
// GenerateGokit returns a gokit service generated from a service definition (svcdef),
// the package to the root of the generated service goPackage, the package
// to the .pb.go service struct files (goPBPackage) and any prevously generated files.
func GenerateGokit(sd *svcdef.Svcdef, conf gengokit.Config) ([]truss.NamedReadWriter, error) {
func GenerateGokit(sd *svcdef.Svcdef, conf gengokit.Config) (map[string]io.Reader, error) {
data, err := gengokit.NewData(sd, conf)
if err != nil {
return nil, errors.Wrap(err, "cannot create template data")
}
prevFiles := make(map[string]io.Reader, len(conf.PreviousFiles))
for _, f := range conf.PreviousFiles {
prevFiles[f.Name()] = f
}
codeGenFiles := make(map[string]io.Reader)
var codeGenFiles []truss.NamedReadWriter
for _, templFP := range templFiles.AssetNames() {
actualFP := templatePathToActual(templFP, sd.PkgName)
prev := prevFiles[actualFP]
file, err := generateResponseFile(data, prev, templFP)
for _, templPath := range templFiles.AssetNames() {
actualPath := templatePathToActual(templPath, sd.PkgName)
file, err := generateResponseFile(templPath, data, conf.PreviousFiles[actualPath])
if err != nil {
return nil, errors.Wrap(err, "cannot render template")
}
if file == nil {
continue
}
codeGenFiles = append(codeGenFiles, file)
codeGenFiles[actualPath] = file
}
return codeGenFiles, nil
@ -54,9 +45,10 @@ func GenerateGokit(sd *svcdef.Svcdef, conf gengokit.Config) ([]truss.NamedReadWr
// generateResponseFile contains logic to choose how to render a template file
// based on path and if that file was generated previously. It accepts a
// template path to render, a data to apply to the template,
// and . It returns a truss.NamedReadWriter representing the generated file.
func generateResponseFile(data *gengokit.Data, prevFile io.Reader, templFP string) (truss.NamedReadWriter, error) {
// template path to render, a templateExecutor to apply to the template, and a
// map of paths to files for the previous generation. It returns a
// io.Reader representing the generated file.
func generateResponseFile(templFP string, data *gengokit.Data, prevFile io.Reader) (io.Reader, error) {
var genCode io.Reader
var err error
@ -100,15 +92,7 @@ func generateResponseFile(data *gengokit.Data, prevFile io.Reader, templFP strin
// writing to disk
formattedCode := formatCode(codeBytes)
var resp truss.SimpleFile
// Set the path to the file and write the code to the file
resp.Path = actualFP
if _, err = resp.Write(formattedCode); err != nil {
return nil, err
}
return &resp, nil
return bytes.NewReader(formattedCode), nil
}
// templatePathToActual accepts a templateFilePath and the packageName of the

Просмотреть файл

@ -230,7 +230,7 @@ func TestAllTemplates(t *testing.T) {
for _, templFP := range templateFileAssets.AssetNames() {
var prev io.Reader
firstCode, err := testGenerateResponseFile(data1, prev, templFP)
firstCode, err := testGenerateResponseFile(templFP, data1, prev)
if err != nil {
t.Fatalf("%s failed to format on first generation\n\nERROR:\n\n%s\n\nCODE:\n\n%s", templFP, err, firstCode)
}
@ -238,7 +238,7 @@ func TestAllTemplates(t *testing.T) {
// store the file to pass back to testGenerateResponseFile for second generation
prev = strings.NewReader(firstCode)
secondCode, err := testGenerateResponseFile(data1, prev, templFP)
secondCode, err := testGenerateResponseFile(templFP, data1, prev)
if err != nil {
t.Fatalf("%s failed to format on second identical generation\n\nERROR: %s\nCODE:\n\n%s",
templFP, err, secondCode)
@ -252,7 +252,7 @@ func TestAllTemplates(t *testing.T) {
prev = strings.NewReader(secondCode)
// pass in data2 created from def2
addRPCCode, err := testGenerateResponseFile(data2, prev, templFP)
addRPCCode, err := testGenerateResponseFile(templFP, data2, prev)
if err != nil {
t.Fatalf("%s failed to format on third generation with 1 rpc added\n\nERROR: %s\nCODE:\n\n%s",
templFP, err, addRPCCode)
@ -262,7 +262,7 @@ func TestAllTemplates(t *testing.T) {
prev = strings.NewReader(addRPCCode)
// pass in data1 create from def1
_, err = testGenerateResponseFile(data1, prev, templFP)
_, err = testGenerateResponseFile(templFP, data1, prev)
if err != nil {
t.Fatalf("%s failed to format on fourth generation with 1 rpc removed\n\nERROR: %s\nCODE:\n\n%s",
templFP, err, addRPCCode)
@ -281,8 +281,8 @@ func diff(a, b string) string {
// string which it returns as this logic needs to be repeated in tests. In
// addition this function will return an error if the code fails to format,
// while generateResponseFile will not.
func testGenerateResponseFile(data *gengokit.Data, prev io.Reader, templFP string) (string, error) {
code, err := generateResponseFile(data, prev, templFP)
func testGenerateResponseFile(templPath string, data *gengokit.Data, prev io.Reader) (string, error) {
code, err := generateResponseFile(templPath, data, prev)
if err != nil {
return "", err
}

Просмотреть файл

@ -12,7 +12,6 @@ import (
"github.com/TuneLab/go-truss/gengokit/clientarggen"
"github.com/TuneLab/go-truss/gengokit/httptransport"
"github.com/TuneLab/go-truss/svcdef"
"github.com/TuneLab/go-truss/truss"
)
type Renderable interface {
@ -23,7 +22,7 @@ type Config struct {
GoPackage string
PBPackage string
PreviousFiles []truss.NamedReadWriter
PreviousFiles map[string]io.Reader
}
// FuncMap contains a series of utility functions to be passed into

Просмотреть файл

@ -1,5 +1,7 @@
package truss
import "io"
// Config defines the inputs to a truss service generation
type Config struct {
// The first path in $GOPATH
@ -15,5 +17,5 @@ type Config struct {
// The paths to each of the .proto files truss is being run against
DefPaths []string
// The files of a previously generated service, may be nil
PrevGen []NamedReadWriter
PrevGen map[string]io.Reader
}