Skip to content

Commit

Permalink
print summary after code generation (webrpc#155)
Browse files Browse the repository at this point in the history
* print summary after code generation

* typo
  • Loading branch information
pkieltyka committed Nov 30, 2022
1 parent 042aa56 commit 67409a6
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 45 deletions.
62 changes: 41 additions & 21 deletions cmd/webrpc-gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ var flags = flag.NewFlagSet("webrpc-gen", flag.ExitOnError)
func main() {
versionFlag := flags.Bool("version", false, "print webrpc version and exit")
schemaFlag := flags.String("schema", "", "webrpc schema file (required)")
targetFlag := flags.String("target", "", fmt.Sprintf("target generator (required), ie. golang@v0.7.0"))
targetFlag := flags.String("target", "", "target generator (required), ie. golang or golang@v0.7.0")
outFlag := flags.String("out", "", "generated output file, default: stdout")
fmtFlag := flags.Bool("fmt", true, "format generated code")
refreshCacheFlag := flags.Bool("refreshCache", false, "refresh webrpc cache")
testFlag := flags.Bool("test", false, "test schema parsing (skips code-gen)")
silentFlag := flags.Bool("silent", false, "silence gen summary")

// Collect CLI -flags and custom template -options.
cliFlags, templateOpts, err := collectCliArgs(flags, os.Args[1:])
Expand All @@ -39,7 +40,7 @@ func main() {
fmt.Fprintf(os.Stderr, "\nTarget generator usage:\n")
templateHelp, err := gen.Generate(&schema.WebRPCSchema{}, *targetFlag, &gen.Config{TemplateOptions: templateOpts})
if err != nil {
fmt.Fprintln(os.Stderr, templateHelp)
fmt.Fprintln(os.Stderr, templateHelp.Code)
} else {
fmt.Fprintf(os.Stderr, "failed to render -help: %v\n", err)
}
Expand Down Expand Up @@ -90,43 +91,37 @@ func main() {
TemplateOptions: templateOpts,
}

protoGen, err := gen.Generate(schema, *targetFlag, config)
genOutput, err := gen.Generate(schema, *targetFlag, config)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}

// Write output to stdout
if *outFlag == "" || *outFlag == "stdout" {
fmt.Println(protoGen)
fmt.Println(genOutput.Code)
os.Exit(0)
}

// Write output to a file
outfile := *outFlag
cwd, err := os.Getwd()
err = writeOutfile(*outFlag, []byte(genOutput.Code))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
if outfile[0:1] != "/" {
outfile = filepath.Join(cwd, outfile)
}

outdir := filepath.Dir(outfile)
if _, err := os.Stat(outdir); os.IsNotExist(err) {
err := os.MkdirAll(outdir, 0755)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
// Print gen report
if *silentFlag {
os.Exit(0)
}

err = os.WriteFile(outfile, []byte(protoGen), 0644)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
fmt.Println("=========================")
fmt.Println("webrpc generated summary:")
fmt.Println("=========================")
fmt.Println("- schema:", *schemaFlag)
fmt.Println("- target:", genOutput.TmplVersion)
fmt.Println("- template source:", genOutput.TmplDir)
fmt.Println("- output file:", *outFlag)
}

func collectCliArgs(flags *flag.FlagSet, args []string) (cliFlags []string, templateOpts map[string]interface{}, err error) {
Expand Down Expand Up @@ -165,3 +160,28 @@ func collectCliArgs(flags *flag.FlagSet, args []string) (cliFlags []string, temp

return
}

func writeOutfile(outfile string, protoGen []byte) error {
cwd, err := os.Getwd()
if err != nil {
return err
}
if outfile[0:1] != "/" {
outfile = filepath.Join(cwd, outfile)
}

outdir := filepath.Dir(outfile)
if _, err := os.Stat(outdir); os.IsNotExist(err) {
err := os.MkdirAll(outdir, 0755)
if err != nil {
return err
}
}

err = os.WriteFile(outfile, []byte(protoGen), 0644)
if err != nil {
return err
}

return nil
}
29 changes: 22 additions & 7 deletions gen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,26 @@ type Config struct {
TemplateOptions map[string]interface{}
}

func Generate(proto *schema.WebRPCSchema, target string, config *Config) (string, error) {
type GenOutput struct {
Code string
*TemplateSource
}

func Generate(proto *schema.WebRPCSchema, target string, config *Config) (*GenOutput, error) {
genOutput := &GenOutput{}

target = getOldTarget(target)

tmpl, err := loadTemplates(proto, target, config)
tmpl, tmplSource, err := loadTemplates(proto, target, config)
if err != nil {
return "", err
return genOutput, err
}
genOutput.TemplateSource = tmplSource

// Generate deterministic schema hash of the proto file
schemaHash, err := proto.SchemaHash()
if err != nil {
return "", err
return genOutput, err
}

// Template vars
Expand All @@ -54,14 +62,21 @@ func Generate(proto *schema.WebRPCSchema, target string, config *Config) (string
var b bytes.Buffer
err = tmpl.ExecuteTemplate(&b, "main", vars)
if err != nil {
return "", err
return genOutput, err
}

if config.Format && isGolangTarget(target) {
return formatGoSource(b.Bytes())
genCode, err := formatGoSource(b.Bytes())
if err != nil {
return genOutput, err
}
genOutput.Code = genCode
return genOutput, nil
}

return b.String(), nil
genOutput.Code = b.String()

return genOutput, nil
}

func getWebrpcGenCommand() string {
Expand Down
60 changes: 43 additions & 17 deletions gen/template_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"hash/fnv"
"io/ioutil"
"log"
"net/http"
"os"
Expand All @@ -21,48 +20,61 @@ import (
"github.com/webrpc/webrpc/schema"
)

func loadTemplates(proto *schema.WebRPCSchema, target string, config *Config) (*template.Template, error) {
s, err := newTemplateSource(proto, target, config)
func loadTemplates(proto *schema.WebRPCSchema, target string, config *Config) (*template.Template, *TemplateSource, error) {
s, err := NewTemplateSource(proto, target, config)
if err != nil {
return nil, err
return nil, nil, err
}
tmpl, err := s.loadTemplates()
if err != nil {
return nil, nil, err
}
return s.loadTemplates()
return tmpl, s, nil
}

// period of time before we attempt to refetch from git source again.
// in case of a failure, we will use the local cache.
const (
templateCacheTime = 1 * time.Hour
templateCacheTimestampFilename = ".webrpc-gen-timestamp"
templateCacheInfoFilename = ".webrpc-gen-info"
)

type templateSource struct {
type TemplateSource struct {
tmpl *template.Template
proto *schema.WebRPCSchema
target string
config *Config

IsLocal bool
TmplDir string
TmplVersion string // git url and hash, or the local dir same as TmplDir
}

func newTemplateSource(proto *schema.WebRPCSchema, target string, config *Config) (*templateSource, error) {
func NewTemplateSource(proto *schema.WebRPCSchema, target string, config *Config) (*TemplateSource, error) {
tmpl := template.New(target).Funcs(templateFuncMap(proto, config.TemplateOptions))
return &templateSource{
return &TemplateSource{
tmpl: tmpl,
proto: proto,
target: target,
config: config,
}, nil
}

func (s *templateSource) loadTemplates() (*template.Template, error) {
func (s *TemplateSource) loadTemplates() (*template.Template, error) {
if isLocalDir(s.target) {
// from local directory
s.IsLocal = true
tmpl, err := s.tmpl.ParseGlob(filepath.Join(s.target, "/*.tmpl"))
if err != nil {
return nil, fmt.Errorf("failed to load templates from %s: %w", s.target, err)
}
s.TmplDir = s.target
s.TmplVersion = s.target
return tmpl, err
} else {
// from remote git or cache source
s.IsLocal = false
s.target = s.inferRemoteTarget(s.target)
tmpl, err := s.loadRemote()
if err != nil {
Expand All @@ -72,17 +84,20 @@ func (s *templateSource) loadTemplates() (*template.Template, error) {
}
}

func (s *templateSource) loadRemote() (*template.Template, error) {
func (s *TemplateSource) loadRemote() (*template.Template, error) {
var sourceFS http.FileSystem

cacheDir, cacheFS, cacheAvailable, cacheTS, err := s.openCacheDir()
if err != nil {
return nil, err
}
s.IsLocal = false
s.TmplDir = cacheDir

// cache is new, so lets fetch from git
if !cacheAvailable || s.config.RefreshCache || time.Now().Unix()-cacheTS > int64(templateCacheTime.Seconds()) {
sourceFS, err = gitfs.New(context.Background(), s.target) //, gitfs.OptPrefetch(true), gitfs.OptGlob("/*.tmpl"))
s.TmplVersion = s.target

if err != nil {
// error occured reading from git, if cache is available, use that instead
Expand All @@ -94,7 +109,7 @@ func (s *templateSource) loadRemote() (*template.Template, error) {

} else {
// using git remote source -- lets cache the files too
err := s.syncTemplates(sourceFS, cacheFS, cacheDir)
err := s.syncTemplates(s.target, sourceFS, cacheFS, cacheDir)
if err != nil {
// in case of error, just print a warning and carry on
log.Println("[warning] error syncing git templates to local cache:", err.Error())
Expand All @@ -108,6 +123,12 @@ func (s *templateSource) loadRemote() (*template.Template, error) {
sourceFS = cacheFS
}

// read template version info
if cacheAvailable && s.TmplVersion == "" {
tmplVersion, _ := os.ReadFile(filepath.Join(cacheDir, templateCacheInfoFilename))
s.TmplVersion = strings.TrimSpace(string(tmplVersion))
}

// parse the template files from the source
tmpl, err := vfstemplate.ParseGlob(sourceFS, s.tmpl, "/*.tmpl")
if err != nil {
Expand All @@ -117,7 +138,7 @@ func (s *templateSource) loadRemote() (*template.Template, error) {
return tmpl, nil
}

func (s *templateSource) syncTemplates(remoteFS, cacheFS http.FileSystem, cacheDir string) error {
func (s *TemplateSource) syncTemplates(target string, remoteFS, cacheFS http.FileSystem, cacheDir string) error {
filenames, err := vfspath.Glob(remoteFS, "/*.tmpl")
if err != nil {
return err
Expand All @@ -129,7 +150,7 @@ func (s *templateSource) syncTemplates(remoteFS, cacheFS http.FileSystem, cacheD
return err
}

err = ioutil.WriteFile(filepath.Join(cacheDir, filename), data, 0755)
err = os.WriteFile(filepath.Join(cacheDir, filename), data, 0755)
if err != nil {
return err
}
Expand All @@ -138,15 +159,20 @@ func (s *templateSource) syncTemplates(remoteFS, cacheFS http.FileSystem, cacheD
now := time.Now().Unix()
data := []byte(fmt.Sprintf("%d", now))

err = ioutil.WriteFile(filepath.Join(cacheDir, templateCacheTimestampFilename), data, 0755)
err = os.WriteFile(filepath.Join(cacheDir, templateCacheTimestampFilename), data, 0755)
if err != nil {
return err
}

err = os.WriteFile(filepath.Join(cacheDir, templateCacheInfoFilename), []byte(strings.TrimSpace(target)), 0755)
if err != nil {
return err
}

return nil
}

func (s *templateSource) openCacheDir() (string, http.FileSystem, bool, int64, error) {
func (s *TemplateSource) openCacheDir() (string, http.FileSystem, bool, int64, error) {
cacheDir, _ := s.getTmpCacheDir()
if cacheDir == "" {
// unable to find OS temp dir, but we don't error -- although
Expand Down Expand Up @@ -185,7 +211,7 @@ func (s *templateSource) openCacheDir() (string, http.FileSystem, bool, int64, e
return cacheDir, cacheFS, available, ts, nil
}

func (s *templateSource) getTmpCacheDir() (string, error) {
func (s *TemplateSource) getTmpCacheDir() (string, error) {
dir := os.TempDir()
if dir == "" {
return "", fmt.Errorf("unable to determine OS temp dir")
Expand All @@ -201,7 +227,7 @@ func (s *templateSource) getTmpCacheDir() (string, error) {
return filepath.Join(dir, "webrpc-cache", fmt.Sprintf("%d-%s", hash.Sum32(), name)), nil
}

func (s *templateSource) inferRemoteTarget(target string) string {
func (s *TemplateSource) inferRemoteTarget(target string) string {
// extra check to ensure its not a local dir
if isLocalDir(target) {
return target
Expand Down

0 comments on commit 67409a6

Please sign in to comment.