refactor cover method
This commit is contained in:
parent
4be6d34cad
commit
0fb0487dbb
@ -18,6 +18,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/qiniu/goc/pkg/build"
|
"github.com/qiniu/goc/pkg/build"
|
||||||
|
"github.com/qiniu/goc/pkg/cover"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ goc build -- -ldflags "-extldflags -static" -tags="embed kodo"
|
|||||||
}()
|
}()
|
||||||
// doCover with original buildFlags, with new GOPATH( tmp:original )
|
// doCover with original buildFlags, with new GOPATH( tmp:original )
|
||||||
// in the tmp directory
|
// in the tmp directory
|
||||||
doCover(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir)
|
cover.Execute(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir, mode, center)
|
||||||
// do install in the temporary directory
|
// do install in the temporary directory
|
||||||
gocBuild.Build()
|
gocBuild.Build()
|
||||||
return
|
return
|
||||||
|
@ -13,6 +13,9 @@ var (
|
|||||||
buildFlags string
|
buildFlags string
|
||||||
packages string
|
packages string
|
||||||
appArgs string
|
appArgs string
|
||||||
|
|
||||||
|
goRunExecFlag string
|
||||||
|
goRunArguments string
|
||||||
)
|
)
|
||||||
|
|
||||||
// addBasicFlags adds a
|
// addBasicFlags adds a
|
||||||
@ -41,6 +44,8 @@ func addRunFlags(cmdset *pflag.FlagSet) {
|
|||||||
addBuildFlags(cmdset)
|
addBuildFlags(cmdset)
|
||||||
cmdset.Lookup("packages").Usage = "specify the package name, only ., ./... and *.go are supported"
|
cmdset.Lookup("packages").Usage = "specify the package name, only ., ./... and *.go are supported"
|
||||||
cmdset.StringVar(&appArgs, "appargs", "", "specify the application's arguments")
|
cmdset.StringVar(&appArgs, "appargs", "", "specify the application's arguments")
|
||||||
|
cmdset.StringVar(&goRunExecFlag, "exec", "", "same as -exec flag in 'go run' command")
|
||||||
|
cmdset.StringVar(&goRunArguments, "arguments", "", "same as 'arguments' in 'go run' command")
|
||||||
// bind to viper
|
// bind to viper
|
||||||
viper.BindPFlags(cmdset)
|
viper.BindPFlags(cmdset)
|
||||||
}
|
}
|
||||||
|
170
cmd/cover.go
170
cmd/cover.go
@ -17,13 +17,10 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/qiniu/goc/pkg/cover"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qiniu/goc/pkg/cover"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,7 +49,7 @@ goc cover --center=http://127.0.0.1:7777 --target=/path/to/target --mode=atomic
|
|||||||
log.Fatalf("unknown -mode %v", mode)
|
log.Fatalf("unknown -mode %v", mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
doCover(buildFlags, "", target)
|
cover.Execute(buildFlags, "", target, mode, center)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,166 +58,3 @@ func init() {
|
|||||||
addCommonFlags(coverCmd.Flags())
|
addCommonFlags(coverCmd.Flags())
|
||||||
rootCmd.AddCommand(coverCmd)
|
rootCmd.AddCommand(coverCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCover(args string, newgopath string, target string) {
|
|
||||||
if !isDirExist(target) {
|
|
||||||
log.Fatalf("target directory %s not exist", target)
|
|
||||||
}
|
|
||||||
|
|
||||||
listArgs := []string{"-json"}
|
|
||||||
if len(args) != 0 {
|
|
||||||
listArgs = append(listArgs, args)
|
|
||||||
}
|
|
||||||
listArgs = append(listArgs, "./...")
|
|
||||||
pkgs := cover.ListPackages(target, strings.Join(listArgs, " "), newgopath)
|
|
||||||
|
|
||||||
var seen = make(map[string]*cover.PackageCover)
|
|
||||||
var seenCache = make(map[string]*cover.PackageCover)
|
|
||||||
for _, pkg := range pkgs {
|
|
||||||
if pkg.Name == "main" {
|
|
||||||
log.Printf("handle package: %v", pkg.ImportPath)
|
|
||||||
// inject the main package
|
|
||||||
mainCover, err := cover.AddCounters(pkg, mode, newgopath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to add counters for pkg %s, err: %v", pkg.ImportPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// new a testcover for this service
|
|
||||||
tc := cover.TestCover{
|
|
||||||
Mode: mode,
|
|
||||||
Center: center,
|
|
||||||
MainPkgCover: mainCover,
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle its dependency
|
|
||||||
var internalPkgCache = make(map[string][]*cover.PackageCover)
|
|
||||||
tc.CacheCover = make(map[string]*cover.PackageCover)
|
|
||||||
for _, dep := range pkg.Deps {
|
|
||||||
|
|
||||||
if packageCover, ok := seen[dep]; ok {
|
|
||||||
tc.DepsCover = append(tc.DepsCover, packageCover)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
//only focus package neither standard Go library nor dependency library
|
|
||||||
if depPkg, ok := pkgs[dep]; ok {
|
|
||||||
|
|
||||||
if findInternal(dep) {
|
|
||||||
|
|
||||||
//scan exist cache cover to tc.CacheCover
|
|
||||||
if cache, ok := seenCache[dep]; ok {
|
|
||||||
log.Printf("cache cover exist: %s", cache.Package.ImportPath)
|
|
||||||
tc.CacheCover[cache.Package.Dir] = cache
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// add counter for internal package
|
|
||||||
inPkgCover, err := cover.AddCounters(depPkg, mode, newgopath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to add counters for internal pkg %s, err: %v", depPkg.ImportPath, err)
|
|
||||||
}
|
|
||||||
parentDir := getInternalParent(depPkg.Dir)
|
|
||||||
parentImportPath := getInternalParent(depPkg.ImportPath)
|
|
||||||
|
|
||||||
//if internal parent dir or import is root path, ignore the dep. the dep is Go library nor dependency library
|
|
||||||
if parentDir == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if parentImportPath == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pkg := &cover.Package{
|
|
||||||
ImportPath: parentImportPath,
|
|
||||||
Dir: parentDir,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some internal package have same parent dir or import path
|
|
||||||
// Cache all vars by internal parent dir for all child internal counter vars
|
|
||||||
cacheCover := cover.AddCacheCover(pkg, inPkgCover)
|
|
||||||
if v, ok := tc.CacheCover[cacheCover.Package.Dir]; ok {
|
|
||||||
for cVar, val := range v.Vars {
|
|
||||||
cacheCover.Vars[cVar] = val
|
|
||||||
}
|
|
||||||
tc.CacheCover[cacheCover.Package.Dir] = cacheCover
|
|
||||||
} else {
|
|
||||||
tc.CacheCover[cacheCover.Package.Dir] = cacheCover
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache all internal vars to internal parent package
|
|
||||||
inCover := cover.CacheInternalCover(inPkgCover)
|
|
||||||
if v, ok := internalPkgCache[cacheCover.Package.Dir]; ok {
|
|
||||||
v = append(v, inCover)
|
|
||||||
internalPkgCache[cacheCover.Package.Dir] = v
|
|
||||||
} else {
|
|
||||||
var covers []*cover.PackageCover
|
|
||||||
covers = append(covers, inCover)
|
|
||||||
internalPkgCache[cacheCover.Package.Dir] = covers
|
|
||||||
}
|
|
||||||
seenCache[dep] = cacheCover
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
packageCover, err := cover.AddCounters(depPkg, mode, newgopath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to add counters for pkg %s, err: %v", depPkg.ImportPath, err)
|
|
||||||
}
|
|
||||||
tc.DepsCover = append(tc.DepsCover, packageCover)
|
|
||||||
seen[dep] = packageCover
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if errs := cover.InjectCacheCounters(internalPkgCache, tc.CacheCover); len(errs) > 0 {
|
|
||||||
log.Fatalf("failed to inject cache counters for package: %s, err: %v", pkg.ImportPath, errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// inject Http Cover APIs
|
|
||||||
var httpCoverApis = fmt.Sprintf("%s/http_cover_apis_auto_generated.go", pkg.Dir)
|
|
||||||
if err := cover.InjectCountersHandlers(tc, httpCoverApis); err != nil {
|
|
||||||
log.Fatalf("failed to inject counters for package: %s, err: %v", pkg.ImportPath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isDirExist(path string) bool {
|
|
||||||
s, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return s.IsDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refer: https://github.com/golang/go/blob/master/src/cmd/go/internal/load/pkg.go#L1334:6
|
|
||||||
// findInternal looks for the final "internal" path element in the given import path.
|
|
||||||
// If there isn't one, findInternal returns ok=false.
|
|
||||||
// Otherwise, findInternal returns ok=true and the index of the "internal".
|
|
||||||
func findInternal(path string) bool {
|
|
||||||
// Three cases, depending on internal at start/end of string or not.
|
|
||||||
// The order matters: we must return the index of the final element,
|
|
||||||
// because the final one produces the most restrictive requirement
|
|
||||||
// on the importer.
|
|
||||||
switch {
|
|
||||||
case strings.HasSuffix(path, "/internal"):
|
|
||||||
return true
|
|
||||||
case strings.Contains(path, "/internal/"):
|
|
||||||
return true
|
|
||||||
case path == "internal", strings.HasPrefix(path, "internal/"):
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInternalParent(path string) string {
|
|
||||||
switch {
|
|
||||||
case strings.HasSuffix(path, "/internal"):
|
|
||||||
return strings.Split(path, "/internal")[0]
|
|
||||||
case strings.Contains(path, "/internal/"):
|
|
||||||
return strings.Split(path, "/internal/")[0]
|
|
||||||
case path == "internal":
|
|
||||||
return ""
|
|
||||||
case strings.HasPrefix(path, "internal/"):
|
|
||||||
return strings.Split(path, "internal/")[0]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
@ -18,6 +18,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/qiniu/goc/pkg/build"
|
"github.com/qiniu/goc/pkg/build"
|
||||||
|
"github.com/qiniu/goc/pkg/cover"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'"
|
|||||||
}()
|
}()
|
||||||
// doCover with original buildFlags, with new GOPATH( tmp:original )
|
// doCover with original buildFlags, with new GOPATH( tmp:original )
|
||||||
// in the tmp directory
|
// in the tmp directory
|
||||||
doCover(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir)
|
cover.Execute(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir, mode, center)
|
||||||
// do install in the temporary directory
|
// do install in the temporary directory
|
||||||
gocBuild.Install()
|
gocBuild.Install()
|
||||||
},
|
},
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -33,6 +32,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -112,6 +113,125 @@ type PackageError struct {
|
|||||||
Err string // the error itself
|
Err string // the error itself
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Execute execute go tool cover for all the .go files in the target folder
|
||||||
|
func Execute(args, newGopath, target, mode, center string) {
|
||||||
|
if !isDirExist(target) {
|
||||||
|
log.Fatalf("target directory %s not exist", target)
|
||||||
|
}
|
||||||
|
|
||||||
|
listArgs := []string{"-json"}
|
||||||
|
if len(args) != 0 {
|
||||||
|
listArgs = append(listArgs, args)
|
||||||
|
}
|
||||||
|
listArgs = append(listArgs, "./...")
|
||||||
|
pkgs := ListPackages(target, strings.Join(listArgs, " "), newGopath)
|
||||||
|
|
||||||
|
var seen = make(map[string]*PackageCover)
|
||||||
|
var seenCache = make(map[string]*PackageCover)
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
if pkg.Name == "main" {
|
||||||
|
log.Printf("handle package: %v", pkg.ImportPath)
|
||||||
|
// inject the main package
|
||||||
|
mainCover, err := AddCounters(pkg, mode, newGopath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to add counters for pkg %s, err: %v", pkg.ImportPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// new a testcover for this service
|
||||||
|
tc := TestCover{
|
||||||
|
Mode: mode,
|
||||||
|
Center: center,
|
||||||
|
MainPkgCover: mainCover,
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle its dependency
|
||||||
|
var internalPkgCache = make(map[string][]*PackageCover)
|
||||||
|
tc.CacheCover = make(map[string]*PackageCover)
|
||||||
|
for _, dep := range pkg.Deps {
|
||||||
|
if packageCover, ok := seen[dep]; ok {
|
||||||
|
tc.DepsCover = append(tc.DepsCover, packageCover)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//only focus package neither standard Go library nor dependency library
|
||||||
|
if depPkg, ok := pkgs[dep]; ok {
|
||||||
|
if findInternal(dep) {
|
||||||
|
//scan exist cache cover to tc.CacheCover
|
||||||
|
if cache, ok := seenCache[dep]; ok {
|
||||||
|
log.Printf("cache cover exist: %s", cache.Package.ImportPath)
|
||||||
|
tc.CacheCover[cache.Package.Dir] = cache
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// add counter for internal package
|
||||||
|
inPkgCover, err := AddCounters(depPkg, mode, newGopath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to add counters for internal pkg %s, err: %v", depPkg.ImportPath, err)
|
||||||
|
}
|
||||||
|
parentDir := getInternalParent(depPkg.Dir)
|
||||||
|
parentImportPath := getInternalParent(depPkg.ImportPath)
|
||||||
|
|
||||||
|
//if internal parent dir or import is root path, ignore the dep. the dep is Go library nor dependency library
|
||||||
|
if parentDir == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if parentImportPath == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg := &Package{
|
||||||
|
ImportPath: parentImportPath,
|
||||||
|
Dir: parentDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some internal package have same parent dir or import path
|
||||||
|
// Cache all vars by internal parent dir for all child internal counter vars
|
||||||
|
cacheCover := AddCacheCover(pkg, inPkgCover)
|
||||||
|
if v, ok := tc.CacheCover[cacheCover.Package.Dir]; ok {
|
||||||
|
for cVar, val := range v.Vars {
|
||||||
|
cacheCover.Vars[cVar] = val
|
||||||
|
}
|
||||||
|
tc.CacheCover[cacheCover.Package.Dir] = cacheCover
|
||||||
|
} else {
|
||||||
|
tc.CacheCover[cacheCover.Package.Dir] = cacheCover
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache all internal vars to internal parent package
|
||||||
|
inCover := CacheInternalCover(inPkgCover)
|
||||||
|
if v, ok := internalPkgCache[cacheCover.Package.Dir]; ok {
|
||||||
|
v = append(v, inCover)
|
||||||
|
internalPkgCache[cacheCover.Package.Dir] = v
|
||||||
|
} else {
|
||||||
|
var covers []*PackageCover
|
||||||
|
covers = append(covers, inCover)
|
||||||
|
internalPkgCache[cacheCover.Package.Dir] = covers
|
||||||
|
}
|
||||||
|
seenCache[dep] = cacheCover
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
packageCover, err := AddCounters(depPkg, mode, newGopath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to add counters for pkg %s, err: %v", depPkg.ImportPath, err)
|
||||||
|
}
|
||||||
|
tc.DepsCover = append(tc.DepsCover, packageCover)
|
||||||
|
seen[dep] = packageCover
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs := InjectCacheCounters(internalPkgCache, tc.CacheCover); len(errs) > 0 {
|
||||||
|
log.Fatalf("failed to inject cache counters for package: %s, err: %v", pkg.ImportPath, errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inject Http Cover APIs
|
||||||
|
var httpCoverApis = fmt.Sprintf("%s/http_cover_apis_auto_generated.go", pkg.Dir)
|
||||||
|
if err := InjectCountersHandlers(tc, httpCoverApis); err != nil {
|
||||||
|
log.Fatalf("failed to inject counters for package: %s, err: %v", pkg.ImportPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ListPackages list all packages under specific via go list command
|
// ListPackages list all packages under specific via go list command
|
||||||
// The argument newgopath is if you need to go list in a different GOPATH
|
// The argument newgopath is if you need to go list in a different GOPATH
|
||||||
func ListPackages(dir string, args string, newgopath string) map[string]*Package {
|
func ListPackages(dir string, args string, newgopath string) map[string]*Package {
|
||||||
@ -167,6 +287,48 @@ func AddCounters(pkg *Package, mode, newgopath string) (*PackageCover, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isDirExist(path string) bool {
|
||||||
|
s, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refer: https://github.com/golang/go/blob/master/src/cmd/go/internal/load/pkg.go#L1334:6
|
||||||
|
// findInternal looks for the final "internal" path element in the given import path.
|
||||||
|
// If there isn't one, findInternal returns ok=false.
|
||||||
|
// Otherwise, findInternal returns ok=true and the index of the "internal".
|
||||||
|
func findInternal(path string) bool {
|
||||||
|
// Three cases, depending on internal at start/end of string or not.
|
||||||
|
// The order matters: we must return the index of the final element,
|
||||||
|
// because the final one produces the most restrictive requirement
|
||||||
|
// on the importer.
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(path, "/internal"):
|
||||||
|
return true
|
||||||
|
case strings.Contains(path, "/internal/"):
|
||||||
|
return true
|
||||||
|
case path == "internal", strings.HasPrefix(path, "internal/"):
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInternalParent(path string) string {
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(path, "/internal"):
|
||||||
|
return strings.Split(path, "/internal")[0]
|
||||||
|
case strings.Contains(path, "/internal/"):
|
||||||
|
return strings.Split(path, "/internal/")[0]
|
||||||
|
case path == "internal":
|
||||||
|
return ""
|
||||||
|
case strings.HasPrefix(path, "internal/"):
|
||||||
|
return strings.Split(path, "internal/")[0]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func buildCoverCmd(file string, coverVar *FileVar, pkg *Package, mode, newgopath string) *exec.Cmd {
|
func buildCoverCmd(file string, coverVar *FileVar, pkg *Package, mode, newgopath string) *exec.Cmd {
|
||||||
// to construct: go tool cover -mode=atomic -o dest src (note: dest==src)
|
// to construct: go tool cover -mode=atomic -o dest src (note: dest==src)
|
||||||
var newArgs = []string{"tool", "cover"}
|
var newArgs = []string{"tool", "cover"}
|
||||||
|
Loading…
Reference in New Issue
Block a user