1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
package main
import (
"bytes"
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"github.com/cheekybits/genny/out"
"github.com/cheekybits/genny/parse"
)
/*
source | genny gen [-in=""] [-out=""] [-pkg=""] "KeyType=string,int ValueType=string,int"
*/
const (
_ = iota
exitcodeInvalidArgs
exitcodeInvalidTypeSet
exitcodeStdinFailed
exitcodeGenFailed
exitcodeGetFailed
exitcodeSourceFileInvalid
exitcodeDestFileFailed
)
func main() {
var (
in = flag.String("in", "", "file to parse instead of stdin")
out = flag.String("out", "", "file to save output to instead of stdout")
pkgName = flag.String("pkg", "", "package name for generated files")
prefix = "https://github.com/metabition/gennylib/raw/master/"
)
flag.Parse()
args := flag.Args()
if len(args) < 2 {
usage()
os.Exit(exitcodeInvalidArgs)
}
if strings.ToLower(args[0]) != "gen" && strings.ToLower(args[0]) != "get" {
usage()
os.Exit(exitcodeInvalidArgs)
}
// parse the typesets
var setsArg = args[1]
if strings.ToLower(args[0]) == "get" {
setsArg = args[2]
}
typeSets, err := parse.TypeSet(setsArg)
if err != nil {
fatal(exitcodeInvalidTypeSet, err)
}
outWriter := newWriter(*out)
if strings.ToLower(args[0]) == "get" {
if len(args) != 3 {
fmt.Println("not enough arguments to get")
usage()
os.Exit(exitcodeInvalidArgs)
}
r, err := http.Get(prefix + args[1])
if err != nil {
fatal(exitcodeGetFailed, err)
}
b, err := ioutil.ReadAll(r.Body)
if err != nil {
fatal(exitcodeGetFailed, err)
}
r.Body.Close()
br := bytes.NewReader(b)
err = gen(*in, *pkgName, br, typeSets, outWriter)
} else if len(*in) > 0 {
var file *os.File
file, err = os.Open(*in)
if err != nil {
fatal(exitcodeSourceFileInvalid, err)
}
defer file.Close()
err = gen(*in, *pkgName, file, typeSets, outWriter)
} else {
var source []byte
source, err = ioutil.ReadAll(os.Stdin)
if err != nil {
fatal(exitcodeStdinFailed, err)
}
reader := bytes.NewReader(source)
err = gen("stdin", *pkgName, reader, typeSets, outWriter)
}
// do the work
if err != nil {
fatal(exitcodeGenFailed, err)
}
}
func usage() {
fmt.Fprintln(os.Stderr, `usage: genny [{flags}] gen "{types}"
gen - generates type specific code from generic code.
get <package/file> - fetch a generic template from the online library and gen it.
{flags} - (optional) Command line flags (see below)
{types} - (required) Specific types for each generic type in the source
{types} format: {generic}={specific}[,another][ {generic2}={specific2}]
Examples:
Generic=Specific
Generic1=Specific1 Generic2=Specific2
Generic1=Specific1,Specific2 Generic2=Specific3,Specific4
Flags:`)
flag.PrintDefaults()
}
func newWriter(fileName string) io.Writer {
if fileName == "" {
return os.Stdout
}
lf := &out.LazyFile{FileName: fileName}
defer lf.Close()
return lf
}
func fatal(code int, a ...interface{}) {
fmt.Println(a...)
os.Exit(code)
}
// gen performs the generic generation.
func gen(filename, pkgName string, in io.ReadSeeker, typesets []map[string]string, out io.Writer) error {
var output []byte
var err error
output, err = parse.Generics(filename, pkgName, in, typesets)
if err != nil {
return err
}
out.Write(output)
return nil
}
|