github.com/chrislusf/greenpack@v3.7.1-0.20170911073826-ad5bd10b7c47+incompatible/main.go (about)

     1  // greenpack is a code generation tool for
     2  // creating methods to serialize and de-serialize
     3  // Go data structures to and from Greenpack (a
     4  // schema-based serialization format that is derived
     5  // from MessagePack2).
     6  //
     7  // This package is targeted at the `go generate` tool.
     8  // To use it, include the following directive in a
     9  // go source file with types requiring source generation:
    10  //
    11  //     //go:generate greenpack
    12  //
    13  // The go generate tool should set the proper environment variables for
    14  // the generator to execute without any command-line flags. However, the
    15  // following options are supported, if you need them (See greenpack -h):
    16  //
    17  //   $ greenpack -h
    18  //
    19  //   Usage of greenpack:
    20  //
    21  //   -fast-strings
    22  //     	for speed when reading a string in a message that won't be
    23  //      reused, this flag means we'll use unsafe to cast the string
    24  //      header and avoid allocation.
    25  //
    26  //   -file go generate
    27  //     	input file (or directory); default is $GOFILE, which
    28  //      is set by the go generate command.
    29  //
    30  //   -genid
    31  //     	generate a fresh random greenSchemaId64 value to
    32  //      include in your Go source schema
    33  //
    34  //   -io
    35  //     	create Encode and Decode methods (default true)
    36  //
    37  //   -marshal
    38  //     	create Marshal and Unmarshal methods (default true)
    39  //
    40  //  -method-prefix string
    41  //    	(optional) prefix that will be pre-prended to
    42  //      the front of generated method names; useful when
    43  //      you need to avoid namespace collisions, but the
    44  //      generated tests will break/the msgp package
    45  //      interfaces won't be satisfied.
    46  //
    47  //  -no-embedded-schema
    48  //      don't embed the schema in the generated files
    49  //
    50  //  -no-structnames-onwire
    51  //    	don't embed the name of the struct in the
    52  //      serialized greenpack. Skipping the embedded
    53  //      struct names saves time and space and matches
    54  //      what protocol buffers/thrift/capnproto/msgpack do.
    55  //      You must know the type on the wire you expect;
    56  //      or embed a type tag in one universal wrapper
    57  //      struct. Embedded struct names are a feature
    58  //      of Greenpack to help with dynamic language
    59  //      bindings.
    60  //
    61  //   -o string
    62  //     	output file (default is {input_file}_gen.go
    63  //
    64  //   -schema-to-go string
    65  //     	(standalone functionality) path to schema in msgpack2
    66  //      format; we will convert it to Go, write the Go on stdout,
    67  //      and exit immediately
    68  //
    69  //   -tests
    70  //     	create tests and benchmarks (default true)
    71  //
    72  //   -unexported
    73  //     	also process unexported types
    74  //
    75  //   -write-schema string
    76  // 		write schema header to this file; - for stdout
    77  //
    78  //
    79  // For more information, please read README.md, and the wiki at github.com/glycerine/greenpack
    80  //
    81  package main
    82  
    83  import (
    84  	"flag"
    85  	"fmt"
    86  	"os"
    87  	"path/filepath"
    88  	"strings"
    89  
    90  	"github.com/glycerine/greenpack/cfg"
    91  	"github.com/glycerine/greenpack/gen"
    92  	"github.com/glycerine/greenpack/parse"
    93  	"github.com/glycerine/greenpack/printer"
    94  )
    95  
    96  func main() {
    97  	myflags := flag.NewFlagSet("greenpack", flag.ExitOnError)
    98  	c := &cfg.GreenConfig{}
    99  	c.DefineFlags(myflags)
   100  
   101  	err := myflags.Parse(os.Args[1:])
   102  	err = c.ValidateConfig()
   103  	if err != nil {
   104  		fmt.Printf("greenpack command line flag error: '%s'\n", err)
   105  		os.Exit(1)
   106  	}
   107  
   108  	if c.ShowVersion {
   109  		fmt.Println(GetCodeVersion(os.Args[0]))
   110  		os.Exit(0)
   111  	}
   112  
   113  	// GOFILE is set by go generate
   114  	if c.GoFile == "" {
   115  		c.GoFile = os.Getenv("GOFILE")
   116  		if c.GoFile == "" {
   117  			fmt.Println("No file to parse.")
   118  			os.Exit(1)
   119  		}
   120  	}
   121  	gen.SetFilename(c.GoFile)
   122  
   123  	var mode gen.Method
   124  	if c.Encode {
   125  		mode |= (gen.Encode | gen.Decode | gen.Size | gen.FieldsEmpty)
   126  	}
   127  	if c.Marshal {
   128  		mode |= (gen.Marshal | gen.Unmarshal | gen.Size | gen.FieldsEmpty)
   129  	}
   130  	if c.Tests {
   131  		mode |= gen.Test
   132  	}
   133  
   134  	if mode&^gen.Test == 0 {
   135  		fmt.Println("No methods to generate; -io=false && -marshal=false")
   136  		os.Exit(1)
   137  	}
   138  
   139  	if err := Run(mode, c); err != nil {
   140  		fmt.Println(err.Error())
   141  		os.Exit(1)
   142  	}
   143  }
   144  
   145  // Run writes all methods using the associated file or path, e.g.
   146  //
   147  //	err := msgp.Run("path/to/myfile.go", gen.Size|gen.Marshal|gen.Unmarshal|gen.Test, false)
   148  //
   149  func Run(mode gen.Method, c *cfg.GreenConfig) error {
   150  	if mode&^gen.Test == 0 {
   151  		return nil
   152  	}
   153  	fmt.Println("======== Greenpack Code Generator  =======")
   154  	fmt.Printf(">>> Input: \"%s\"\n", c.GoFile)
   155  	var fs *parse.FileSet
   156  	var err error
   157  	//if c.NoLoad {
   158  	fs, err = parse.FileNoLoad(c)
   159  	//} else {
   160  	//	fs, err = parse.File(c)
   161  	//}
   162  	if err != nil {
   163  		return err
   164  	}
   165  
   166  	if len(fs.Identities) == 0 {
   167  		fmt.Println("No types requiring code generation were found!")
   168  		return nil
   169  	}
   170  
   171  	return printer.PrintFile(newFilename(c.Out, c.GoFile, fs.Package), fs, mode, c, c.GoFile)
   172  }
   173  
   174  // picks a new file name based on input flags and input filename(s).
   175  func newFilename(out, old, pkg string) string {
   176  	if out != "" {
   177  		if pre := strings.TrimPrefix(out, old); len(pre) > 0 &&
   178  			!strings.HasSuffix(out, ".go") {
   179  			return filepath.Join(old, out)
   180  		}
   181  		return out
   182  	}
   183  
   184  	if fi, err := os.Stat(old); err == nil && fi.IsDir() {
   185  		old = filepath.Join(old, pkg)
   186  	}
   187  	// new file name is old file name + _gen.go
   188  	return strings.TrimSuffix(old, ".go") + "_gen.go"
   189  }
   190  
   191  func fileExists(name string) bool {
   192  	fi, err := os.Stat(name)
   193  	if err != nil {
   194  		return false
   195  	}
   196  	if fi.IsDir() {
   197  		return false
   198  	}
   199  	return true
   200  }