Ver código fonte

codecgen: Allow users specify random integer for use in generated code.

This allows for deterministic output during codecgen runs.
It also reduces the number of diff lines in the version control system (e.g. git).

Do this by allowing users specify a -d parameter to codecgen, which is
used in genRunner x.xs and used in the names of temporary generated files.

Fixes #101
Ugorji Nwoke 10 anos atrás
pai
commit
b1301ebcb1
3 arquivos alterados com 25 adições e 12 exclusões
  1. 13 5
      codec/codecgen/gen.go
  2. 10 5
      codec/gen.go
  3. 2 2
      codec/prebuild.sh

+ 13 - 5
codec/codecgen/gen.go

@@ -14,6 +14,7 @@ import (
 	"go/build"
 	"go/build"
 	"go/parser"
 	"go/parser"
 	"go/token"
 	"go/token"
+	"math/rand"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
 	"path/filepath"
 	"path/filepath"
@@ -71,7 +72,7 @@ func CodecGenTempWrite{{ .RandString }}() {
 	var t{{ $index }} {{ . }}
 	var t{{ $index }} {{ . }}
 	typs = append(typs, reflect.TypeOf(t{{ $index }}))
 	typs = append(typs, reflect.TypeOf(t{{ $index }}))
 {{ end }}
 {{ end }}
-	{{ if not .CodecPkgFiles }}{{ .CodecPkgName }}.{{ end }}Gen(&out, "{{ .BuildTag }}", "{{ .PackageName }}", {{ .UseUnsafe }}, typs...)
+	{{ if not .CodecPkgFiles }}{{ .CodecPkgName }}.{{ end }}Gen(&out, "{{ .BuildTag }}", "{{ .PackageName }}", "{{ .RandString }}", {{ .UseUnsafe }}, typs...)
 	bout, err := format.Source(out.Bytes())
 	bout, err := format.Source(out.Bytes())
 	if err != nil {
 	if err != nil {
 		fout.Write(out.Bytes())
 		fout.Write(out.Bytes())
@@ -91,7 +92,7 @@ func CodecGenTempWrite{{ .RandString }}() {
 // Tool then executes: "go run __frun__" which creates fout.
 // Tool then executes: "go run __frun__" which creates fout.
 // fout contains Codec(En|De)codeSelf implementations for every type T.
 // fout contains Codec(En|De)codeSelf implementations for every type T.
 //
 //
-func Generate(outfile, buildTag, codecPkgPath string, useUnsafe bool, goRunTag string,
+func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, goRunTag string,
 	regexName *regexp.Regexp, deleteTempFile bool, infiles ...string) (err error) {
 	regexName *regexp.Regexp, deleteTempFile bool, infiles ...string) (err error) {
 	// For each file, grab AST, find each type, and write a call to it.
 	// For each file, grab AST, find each type, and write a call to it.
 	if len(infiles) == 0 {
 	if len(infiles) == 0 {
@@ -101,6 +102,13 @@ func Generate(outfile, buildTag, codecPkgPath string, useUnsafe bool, goRunTag s
 		err = errors.New("outfile and codec package path cannot be blank")
 		err = errors.New("outfile and codec package path cannot be blank")
 		return
 		return
 	}
 	}
+	if uid < 0 {
+		uid = -uid
+	}
+	if uid == 0 {
+		rr := rand.New(rand.NewSource(time.Now().UnixNano()))
+		uid = 101 + rr.Int63n(9777)
+	}
 	// We have to parse dir for package, before opening the temp file for writing (else ImportDir fails).
 	// We have to parse dir for package, before opening the temp file for writing (else ImportDir fails).
 	// Also, ImportDir(...) must take an absolute path.
 	// Also, ImportDir(...) must take an absolute path.
 	lastdir := filepath.Dir(outfile)
 	lastdir := filepath.Dir(outfile)
@@ -130,7 +138,7 @@ func Generate(outfile, buildTag, codecPkgPath string, useUnsafe bool, goRunTag s
 		CodecImportPath: codecPkgPath,
 		CodecImportPath: codecPkgPath,
 		BuildTag:        buildTag,
 		BuildTag:        buildTag,
 		UseUnsafe:       useUnsafe,
 		UseUnsafe:       useUnsafe,
-		RandString:      strconv.FormatInt(time.Now().UnixNano(), 10),
+		RandString:      strconv.FormatInt(uid, 10),
 	}
 	}
 	tv.ImportPath = pkg.ImportPath
 	tv.ImportPath = pkg.ImportPath
 	if tv.ImportPath == tv.CodecImportPath {
 	if tv.ImportPath == tv.CodecImportPath {
@@ -263,9 +271,9 @@ func main() {
 	rt := flag.String("rt", "", "tags for go run")
 	rt := flag.String("rt", "", "tags for go run")
 	x := flag.Bool("x", false, "keep temp file")
 	x := flag.Bool("x", false, "keep temp file")
 	u := flag.Bool("u", false, "Use unsafe, e.g. to avoid unnecessary allocation on []byte->string")
 	u := flag.Bool("u", false, "Use unsafe, e.g. to avoid unnecessary allocation on []byte->string")
-
+	d := flag.Int64("d", 0, "random identifier for use in generated code")
 	flag.Parse()
 	flag.Parse()
-	if err := Generate(*o, *t, *c, *u, *rt,
+	if err := Generate(*o, *t, *c, *d, *u, *rt,
 		regexp.MustCompile(*r), !*x, flag.Args()...); err != nil {
 		regexp.MustCompile(*r), !*x, flag.Args()...); err != nil {
 		fmt.Fprintf(os.Stderr, "codecgen error: %v\n", err)
 		fmt.Fprintf(os.Stderr, "codecgen error: %v\n", err)
 		os.Exit(1)
 		os.Exit(1)

+ 10 - 5
codec/gen.go

@@ -128,12 +128,14 @@ type genRunner struct {
 	xs string                    // top level variable/constant suffix
 	xs string                    // top level variable/constant suffix
 	hn string                    // fn helper type name
 	hn string                    // fn helper type name
 
 
-	rr *rand.Rand // random generator for file-specific types
+	// rr *rand.Rand // random generator for file-specific types
 }
 }
 
 
 // Gen will write a complete go file containing Selfer implementations for each
 // Gen will write a complete go file containing Selfer implementations for each
 // type passed. All the types must be in the same package.
 // type passed. All the types must be in the same package.
-func Gen(w io.Writer, buildTags, pkgName string, useUnsafe bool, typ ...reflect.Type) {
+//
+// Library users: *DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.*
+func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, typ ...reflect.Type) {
 	if len(typ) == 0 {
 	if len(typ) == 0 {
 		return
 		return
 	}
 	}
@@ -148,8 +150,13 @@ func Gen(w io.Writer, buildTags, pkgName string, useUnsafe bool, typ ...reflect.
 		is:     make(map[reflect.Type]struct{}),
 		is:     make(map[reflect.Type]struct{}),
 		ts:     make(map[reflect.Type]struct{}),
 		ts:     make(map[reflect.Type]struct{}),
 		bp:     typ[0].PkgPath(),
 		bp:     typ[0].PkgPath(),
-		rr:     rand.New(rand.NewSource(time.Now().UnixNano())),
+		xs:     uid,
+	}
+	if x.xs == "" {
+		rr := rand.New(rand.NewSource(time.Now().UnixNano()))
+		x.xs = strconv.FormatInt(rr.Int63n(9999), 10)
 	}
 	}
+
 	// gather imports first:
 	// gather imports first:
 	x.cp = reflect.TypeOf(x).PkgPath()
 	x.cp = reflect.TypeOf(x).PkgPath()
 	x.imn[x.cp] = genCodecPkg
 	x.imn[x.cp] = genCodecPkg
@@ -194,8 +201,6 @@ func Gen(w io.Writer, buildTags, pkgName string, useUnsafe bool, typ ...reflect.
 	x.line(")")
 	x.line(")")
 	x.line("")
 	x.line("")
 
 
-	x.xs = strconv.FormatInt(x.rr.Int63n(9999), 10)
-
 	x.line("const (")
 	x.line("const (")
 	x.linef("codecSelferC_UTF8%s = %v", x.xs, int64(c_UTF8))
 	x.linef("codecSelferC_UTF8%s = %v", x.xs, int64(c_UTF8))
 	x.linef("codecSelferC_RAW%s = %v", x.xs, int64(c_RAW))
 	x.linef("codecSelferC_RAW%s = %v", x.xs, int64(c_RAW))

+ 2 - 2
codec/prebuild.sh

@@ -142,9 +142,9 @@ _codegenerators() {
     then
     then
         true && \
         true && \
             echo "codecgen - !unsafe ... " && \
             echo "codecgen - !unsafe ... " && \
-            codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} $zfin && \
+            codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} -d 1978 $zfin && \
             echo "codecgen - unsafe ... " && \
             echo "codecgen - unsafe ... " && \
-            codecgen -u -rt codecgen -t 'x,codecgen,unsafe' -o values_codecgen_unsafe${zsfx} $zfin && \
+            codecgen -u -rt codecgen -t 'x,codecgen,unsafe' -o values_codecgen_unsafe${zsfx} -d 1978 $zfin && \
             echo "msgp ... " && \
             echo "msgp ... " && \
             msgp -tests=false -pkg=codec -o=values_msgp${zsfx} -file=$zfin && \
             msgp -tests=false -pkg=codec -o=values_msgp${zsfx} -file=$zfin && \
             echo "ffjson ... " && \
             echo "ffjson ... " && \