Merge branch 'master' of github.com:TuneLab/go-truss into add_version_tag
This commit is contained in:
Коммит
9f6da34c52
|
@ -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
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче