Browse Source

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 years ago
parent
commit
b1301ebcb1
3 changed files with 25 additions and 12 deletions
  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/parser"
 	"go/token"
+	"math/rand"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -71,7 +72,7 @@ func CodecGenTempWrite{{ .RandString }}() {
 	var t{{ $index }} {{ . }}
 	typs = append(typs, reflect.TypeOf(t{{ $index }}))
 {{ 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())
 	if err != nil {
 		fout.Write(out.Bytes())
@@ -91,7 +92,7 @@ func CodecGenTempWrite{{ .RandString }}() {
 // Tool then executes: "go run __frun__" which creates fout.
 // 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) {
 	// For each file, grab AST, find each type, and write a call to it.
 	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")
 		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).
 	// Also, ImportDir(...) must take an absolute path.
 	lastdir := filepath.Dir(outfile)
@@ -130,7 +138,7 @@ func Generate(outfile, buildTag, codecPkgPath string, useUnsafe bool, goRunTag s
 		CodecImportPath: codecPkgPath,
 		BuildTag:        buildTag,
 		UseUnsafe:       useUnsafe,
-		RandString:      strconv.FormatInt(time.Now().UnixNano(), 10),
+		RandString:      strconv.FormatInt(uid, 10),
 	}
 	tv.ImportPath = pkg.ImportPath
 	if tv.ImportPath == tv.CodecImportPath {
@@ -263,9 +271,9 @@ func main() {
 	rt := flag.String("rt", "", "tags for go run")
 	x := flag.Bool("x", false, "keep temp file")
 	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()
-	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 {
 		fmt.Fprintf(os.Stderr, "codecgen error: %v\n", err)
 		os.Exit(1)

+ 10 - 5
codec/gen.go

@@ -128,12 +128,14 @@ type genRunner struct {
 	xs string                    // top level variable/constant suffix
 	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
 // 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 {
 		return
 	}
@@ -148,8 +150,13 @@ func Gen(w io.Writer, buildTags, pkgName string, useUnsafe bool, typ ...reflect.
 		is:     make(map[reflect.Type]struct{}),
 		ts:     make(map[reflect.Type]struct{}),
 		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:
 	x.cp = reflect.TypeOf(x).PkgPath()
 	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.xs = strconv.FormatInt(x.rr.Int63n(9999), 10)
-
 	x.line("const (")
 	x.linef("codecSelferC_UTF8%s = %v", x.xs, int64(c_UTF8))
 	x.linef("codecSelferC_RAW%s = %v", x.xs, int64(c_RAW))

+ 2 - 2
codec/prebuild.sh

@@ -142,9 +142,9 @@ _codegenerators() {
     then
         true && \
             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 ... " && \
-            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 ... " && \
             msgp -tests=false -pkg=codec -o=values_msgp${zsfx} -file=$zfin && \
             echo "ffjson ... " && \