Просмотр исходного кода

codecgen: Support GO15VENDOREXPERIMENT

We depended on PkgPath to return the import path.
However, with GO15VENDOREXPERIMENT, reflect.Type.PkgPath()
will now return the path relative to the GOPATH, including /vendor/
in the path. This is no longer the import path.

We now will strip the vendor prefix appropriately if GO15VENDOREXPERIMENT is set.

We put a HACK comment in there, so we know to look at it later if things change
in the go sdk.

Fixes #102
Ugorji Nwoke 10 лет назад
Родитель
Сommit
899e396156
1 измененных файлов с 33 добавлено и 12 удалено
  1. 33 12
      codec/gen.go

+ 33 - 12
codec/gen.go

@@ -12,6 +12,7 @@ import (
 	"io"
 	"io/ioutil"
 	"math/rand"
+	"os"
 	"reflect"
 	"regexp"
 	"sort"
@@ -165,7 +166,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, typ ...ref
 		is:     make(map[reflect.Type]struct{}),
 		tm:     make(map[reflect.Type]struct{}),
 		ts:     []reflect.Type{},
-		bp:     typ[0].PkgPath(),
+		bp:     genImportPath(typ[0]),
 		xs:     uid,
 	}
 	if x.xs == "" {
@@ -174,11 +175,11 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, typ ...ref
 	}
 
 	// gather imports first:
-	x.cp = reflect.TypeOf(x).PkgPath()
+	x.cp = genImportPath(reflect.TypeOf(x))
 	x.imn[x.cp] = genCodecPkg
 	for _, t := range typ {
-		// fmt.Printf("###########: PkgPath: '%v', Name: '%s'\n", t.PkgPath(), t.Name())
-		if t.PkgPath() != x.bp {
+		// fmt.Printf("###########: PkgPath: '%v', Name: '%s'\n", genImportPath(t), t.Name())
+		if genImportPath(t) != x.bp {
 			panic(genAllTypesSamePkgErr)
 		}
 		x.genRefPkgs(t)
@@ -346,9 +347,9 @@ func (x *genRunner) genRefPkgs(t reflect.Type) {
 	if _, ok := x.is[t]; ok {
 		return
 	}
-	// fmt.Printf(">>>>>>: PkgPath: '%v', Name: '%s'\n", t.PkgPath(), t.Name())
+	// fmt.Printf(">>>>>>: PkgPath: '%v', Name: '%s'\n", genImportPath(t), t.Name())
 	x.is[t] = struct{}{}
-	tpkg, tname := t.PkgPath(), t.Name()
+	tpkg, tname := genImportPath(t), t.Name()
 	if tpkg != "" && tpkg != x.bp && tpkg != x.cp && tname != "" && tname[0] >= 'A' && tname[0] <= 'Z' {
 		if _, ok := x.im[tpkg]; !ok {
 			x.im[tpkg] = t
@@ -438,10 +439,10 @@ func (x *genRunner) genTypeName(t reflect.Type) (n string) {
 func (x *genRunner) genTypeNamePrim(t reflect.Type) (n string) {
 	if t.Name() == "" {
 		return t.String()
-	} else if t.PkgPath() == "" || t.PkgPath() == x.tc.PkgPath() {
+	} else if genImportPath(t) == "" || genImportPath(t) == genImportPath(x.tc) {
 		return t.Name()
 	} else {
-		return x.imn[t.PkgPath()] + "." + t.Name()
+		return x.imn[genImportPath(t)] + "." + t.Name()
 		// return t.String() // best way to get the package name inclusive
 	}
 }
@@ -653,7 +654,7 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
 		x.linef("r.EncodeBuiltin(%s, %s)", vrtid, varname)
 	}
 	// only check for extensions if the type is named, and has a packagePath.
-	if t.PkgPath() != "" && t.Name() != "" {
+	if genImportPath(t) != "" && t.Name() != "" {
 		// first check if extensions are configued, before doing the interface conversion
 		x.linef("} else if z.HasExtensions() && z.EncExt(%s) {", varname)
 	}
@@ -1065,7 +1066,7 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
 		x.linef("r.DecodeBuiltin(%s, %s)", vrtid, varname)
 	}
 	// only check for extensions if the type is named, and has a packagePath.
-	if t.PkgPath() != "" && t.Name() != "" {
+	if genImportPath(t) != "" && t.Name() != "" {
 		// first check if extensions are configued, before doing the interface conversion
 		x.linef("} else if z.HasExtensions() && z.DecExt(%s) {", varname)
 	}
@@ -1523,6 +1524,26 @@ func (x *genV) MethodNamePfx(prefix string, prim bool) string {
 
 }
 
+var genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") == "1"
+
+// genImportPath returns import path of a non-predeclared named typed, or an empty string otherwise.
+//
+// This handles the misbehaviour that occurs when 1.5-style vendoring is enabled,
+// where PkgPath returns the full path, including the vendoring pre-fix that should have been stripped.
+// We strip it here.
+func genImportPath(t reflect.Type) (s string) {
+	s = t.PkgPath()
+	if genCheckVendor {
+		// HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later.
+		// if s contains /vendor/, then return everything after it.
+		const vendorStr = "/vendor/"
+		if i := strings.LastIndex(s, vendorStr); i >= 0 {
+			s = s[i+len(vendorStr):]
+		}
+	}
+	return
+}
+
 func genNonPtr(t reflect.Type) reflect.Type {
 	for t.Kind() == reflect.Ptr {
 		t = t.Elem()
@@ -1547,7 +1568,7 @@ func genMethodNameT(t reflect.Type, tRef reflect.Type) (n string) {
 	}
 	tstr := t.String()
 	if tn := t.Name(); tn != "" {
-		if tRef != nil && t.PkgPath() == tRef.PkgPath() {
+		if tRef != nil && genImportPath(t) == genImportPath(tRef) {
 			return ptrPfx + tn
 		} else {
 			if genQNameRegex.MatchString(tstr) {
@@ -1579,7 +1600,7 @@ func genMethodNameT(t reflect.Type, tRef reflect.Type) (n string) {
 		if t == intfTyp {
 			return ptrPfx + "Interface"
 		} else {
-			if tRef != nil && t.PkgPath() == tRef.PkgPath() {
+			if tRef != nil && genImportPath(t) == genImportPath(tRef) {
 				if t.Name() != "" {
 					return ptrPfx + t.Name()
 				} else {