enhance error handling
This commit is contained in:
parent
4c7721b0e8
commit
b02d49c2be
14
cmd/build.go
14
cmd/build.go
@ -17,7 +17,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/qiniu/goc/pkg/build"
|
"github.com/qiniu/goc/pkg/build"
|
||||||
"github.com/qiniu/goc/pkg/cover"
|
"github.com/qiniu/goc/pkg/cover"
|
||||||
@ -28,7 +28,7 @@ var buildCmd = &cobra.Command{
|
|||||||
Use: "build",
|
Use: "build",
|
||||||
Short: "Do cover for all go files and execute go build command",
|
Short: "Do cover for all go files and execute go build command",
|
||||||
Long: `
|
Long: `
|
||||||
First of all, this build command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target in this temporary directory, finally go build command will be executed and binaries generated to their original place.
|
Build command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target, binaries will be generated to their original place.
|
||||||
`,
|
`,
|
||||||
Example: `
|
Example: `
|
||||||
# Build the current binary with cover variables injected. The binary will be generated in the current folder.
|
# Build the current binary with cover variables injected. The binary will be generated in the current folder.
|
||||||
@ -44,7 +44,7 @@ goc build --output /to/this/path
|
|||||||
goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'"
|
goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'"
|
||||||
`,
|
`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
runBuild()
|
runBuild(args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,14 +52,14 @@ var buildOutput string
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
addBuildFlags(buildCmd.Flags())
|
addBuildFlags(buildCmd.Flags())
|
||||||
buildCmd.Flags().StringVar(&buildOutput, "output", "", "it forces build to write the resulting executable or object to the named output file or directory")
|
buildCmd.Flags().StringVar(&buildOutput, "output", "", "it forces build to write the resulting executable to the named output file")
|
||||||
rootCmd.AddCommand(buildCmd)
|
rootCmd.AddCommand(buildCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runBuild() {
|
func runBuild(args []string) {
|
||||||
gocBuild, err := build.NewBuild(buildFlags, packages, buildOutput)
|
gocBuild, err := build.NewBuild(buildFlags, args, buildOutput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Fail to NewBuild: %v", err)
|
log.Fatalf("Fail to build: %v", err)
|
||||||
}
|
}
|
||||||
// remove temporary directory if needed
|
// remove temporary directory if needed
|
||||||
defer gocBuild.Clean()
|
defer gocBuild.Clean()
|
||||||
|
@ -17,13 +17,14 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var baseDir string
|
var baseDir string
|
||||||
@ -42,8 +43,9 @@ func TestGeneratedBinary(t *testing.T) {
|
|||||||
os.Setenv("GOPATH", gopath)
|
os.Setenv("GOPATH", gopath)
|
||||||
os.Setenv("GO111MODULE", "on")
|
os.Setenv("GO111MODULE", "on")
|
||||||
|
|
||||||
buildFlags, packages, buildOutput = "", ".", ""
|
buildFlags, buildOutput = "", ""
|
||||||
runBuild()
|
args := []string{"."}
|
||||||
|
runBuild(args)
|
||||||
|
|
||||||
obj := filepath.Join(".", "simple-project")
|
obj := filepath.Join(".", "simple-project")
|
||||||
fInfo, err := os.Lstat(obj)
|
fInfo, err := os.Lstat(obj)
|
||||||
|
@ -11,7 +11,7 @@ var (
|
|||||||
mode string
|
mode string
|
||||||
debugGoc bool
|
debugGoc bool
|
||||||
buildFlags string
|
buildFlags string
|
||||||
packages string
|
// packages string
|
||||||
appArgs string
|
appArgs string
|
||||||
|
|
||||||
goRunExecFlag string
|
goRunExecFlag string
|
||||||
@ -35,14 +35,12 @@ func addCommonFlags(cmdset *pflag.FlagSet) {
|
|||||||
|
|
||||||
func addBuildFlags(cmdset *pflag.FlagSet) {
|
func addBuildFlags(cmdset *pflag.FlagSet) {
|
||||||
addCommonFlags(cmdset)
|
addCommonFlags(cmdset)
|
||||||
cmdset.StringVar(&packages, "packages", ".", "specify the package name, only . and ./... are supported")
|
|
||||||
// bind to viper
|
// bind to viper
|
||||||
viper.BindPFlags(cmdset)
|
viper.BindPFlags(cmdset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRunFlags(cmdset *pflag.FlagSet) {
|
func addRunFlags(cmdset *pflag.FlagSet) {
|
||||||
addBuildFlags(cmdset)
|
addBuildFlags(cmdset)
|
||||||
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(&goRunExecFlag, "exec", "", "same as -exec flag in 'go run' command")
|
||||||
cmdset.StringVar(&goRunArguments, "arguments", "", "same as 'arguments' in 'go run' command")
|
cmdset.StringVar(&goRunArguments, "arguments", "", "same as 'arguments' in 'go run' command")
|
||||||
|
@ -27,7 +27,7 @@ var installCmd = &cobra.Command{
|
|||||||
Use: "install",
|
Use: "install",
|
||||||
Short: "Do cover for all go files and execute go install command",
|
Short: "Do cover for all go files and execute go install command",
|
||||||
Long: `
|
Long: `
|
||||||
First of all, this install command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target in this temporary directory, finally go install command will be executed and binaries generated to their original place.
|
Install command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target, binaries will be generated to their original place.
|
||||||
`,
|
`,
|
||||||
Example: `
|
Example: `
|
||||||
# Install all binaries with cover variables injected. The binary will be installed in $GOPATH/bin or $HOME/go/bin if directory existed.
|
# Install all binaries with cover variables injected. The binary will be installed in $GOPATH/bin or $HOME/go/bin if directory existed.
|
||||||
@ -40,7 +40,7 @@ goc install --center=http://127.0.0.1:7777
|
|||||||
goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'"
|
goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'"
|
||||||
`,
|
`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
runInstall()
|
runInstall(args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,10 +49,10 @@ func init() {
|
|||||||
rootCmd.AddCommand(installCmd)
|
rootCmd.AddCommand(installCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runInstall() {
|
func runInstall(args []string) {
|
||||||
gocBuild, err := build.NewInstall(buildFlags, packages)
|
gocBuild, err := build.NewInstall(buildFlags, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Fail to NewInstall: %v", err)
|
log.Fatalf("Fail to install: %v", err)
|
||||||
}
|
}
|
||||||
// remove temporary directory if needed
|
// remove temporary directory if needed
|
||||||
defer gocBuild.Clean()
|
defer gocBuild.Clean()
|
||||||
|
@ -17,13 +17,14 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInstalledBinaryForMod(t *testing.T) {
|
func TestInstalledBinaryForMod(t *testing.T) {
|
||||||
@ -36,8 +37,9 @@ func TestInstalledBinaryForMod(t *testing.T) {
|
|||||||
os.Setenv("GOPATH", gopath)
|
os.Setenv("GOPATH", gopath)
|
||||||
os.Setenv("GO111MODULE", "on")
|
os.Setenv("GO111MODULE", "on")
|
||||||
|
|
||||||
buildFlags, packages, buildOutput = "", ".", ""
|
buildFlags, buildOutput = "", ""
|
||||||
runInstall()
|
args := []string{"."}
|
||||||
|
runInstall(args)
|
||||||
|
|
||||||
obj := filepath.Join(gopath, "bin", "simple-project")
|
obj := filepath.Join(gopath, "bin", "simple-project")
|
||||||
fInfo, err := os.Lstat(obj)
|
fInfo, err := os.Lstat(obj)
|
||||||
@ -64,8 +66,9 @@ func TestInstalledBinaryForLegacy(t *testing.T) {
|
|||||||
os.Setenv("GOPATH", gopath)
|
os.Setenv("GOPATH", gopath)
|
||||||
os.Setenv("GO111MODULE", "off")
|
os.Setenv("GO111MODULE", "off")
|
||||||
|
|
||||||
buildFlags, packages, buildOutput = "", ".", ""
|
buildFlags, buildOutput = "", ""
|
||||||
runInstall()
|
args := []string{"."}
|
||||||
|
runInstall(args)
|
||||||
|
|
||||||
obj := filepath.Join(gopath, "bin", "simple_gopath_project")
|
obj := filepath.Join(gopath, "bin", "simple_gopath_project")
|
||||||
fInfo, err := os.Lstat(obj)
|
fInfo, err := os.Lstat(obj)
|
||||||
|
@ -42,6 +42,6 @@ goc list [flags]
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
listCmd.Flags().StringVarP(¢er, "center", "", "http://127.0.0.1:7777", "cover profile host center")
|
addBasicFlags(listCmd.Flags())
|
||||||
rootCmd.AddCommand(listCmd)
|
rootCmd.AddCommand(listCmd)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -49,7 +48,13 @@ Find more information at:
|
|||||||
})
|
})
|
||||||
if debugGoc == false {
|
if debugGoc == false {
|
||||||
// we only need log in debug mode
|
// we only need log in debug mode
|
||||||
log.SetOutput(ioutil.Discard)
|
log.SetLevel(log.FatalLevel)
|
||||||
|
log.SetFormatter(&log.TextFormatter{
|
||||||
|
DisableTimestamp: true,
|
||||||
|
CallerPrettyfier: func(f *runtime.Frame) (string, string) {
|
||||||
|
return "", ""
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,10 @@ It is exactly behave as 'go run .' in addition of some internal goc features.`,
|
|||||||
goc run .
|
goc run .
|
||||||
`,
|
`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
gocBuild, _ := build.NewBuild(buildFlags, packages, buildOutput)
|
gocBuild, err := build.NewBuild(buildFlags, args, buildOutput)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Fail to run: %v", err)
|
||||||
|
}
|
||||||
gocBuild.GoRunExecFlag = goRunExecFlag
|
gocBuild.GoRunExecFlag = goRunExecFlag
|
||||||
gocBuild.GoRunArguments = goRunArguments
|
gocBuild.GoRunArguments = goRunArguments
|
||||||
defer gocBuild.Clean()
|
defer gocBuild.Clean()
|
||||||
@ -53,7 +56,9 @@ goc run .
|
|||||||
// execute covers for the target source with original buildFlags and new GOPATH( tmp:original )
|
// execute covers for the target source with original buildFlags and new GOPATH( tmp:original )
|
||||||
cover.Execute(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir, mode, gocServer)
|
cover.Execute(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir, mode, gocServer)
|
||||||
|
|
||||||
gocBuild.Run()
|
if err := gocBuild.Run(); err != nil {
|
||||||
|
log.Fatalln("Fail to run: %v", err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,17 +53,23 @@ type Build struct {
|
|||||||
|
|
||||||
// NewBuild creates a Build struct which can build from goc temporary directory,
|
// NewBuild creates a Build struct which can build from goc temporary directory,
|
||||||
// and generate binary in current working directory
|
// and generate binary in current working directory
|
||||||
func NewBuild(buildflags string, packages string, outputDir string) (*Build, error) {
|
func NewBuild(buildflags string, args []string, outputDir string) (*Build, error) {
|
||||||
|
if len(args) > 1 {
|
||||||
|
log.Errorln(ErrTooManyArgs)
|
||||||
|
return nil, ErrTooManyArgs
|
||||||
|
}
|
||||||
// buildflags = buildflags + " -o " + outputDir
|
// buildflags = buildflags + " -o " + outputDir
|
||||||
b := &Build{
|
b := &Build{
|
||||||
BuildFlags: buildflags,
|
BuildFlags: buildflags,
|
||||||
Packages: packages,
|
Packages: strings.Join(args, " "),
|
||||||
}
|
}
|
||||||
if false == b.validatePackageForBuild() {
|
if false == b.validatePackageForBuild() {
|
||||||
log.Errorln(ErrWrongPackageTypeForBuild)
|
log.Errorln(ErrWrongPackageTypeForBuild)
|
||||||
return nil, ErrWrongPackageTypeForBuild
|
return nil, ErrWrongPackageTypeForBuild
|
||||||
}
|
}
|
||||||
b.MvProjectsToTmp()
|
if err := b.MvProjectsToTmp(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
dir, err := b.determineOutputDir(outputDir)
|
dir, err := b.determineOutputDir(outputDir)
|
||||||
b.Target = dir
|
b.Target = dir
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -90,13 +96,13 @@ func (b *Build) Build() error {
|
|||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Fail to execute: %v. The error is: %v", cmd.Args, err)
|
log.Errorf("Fail to execute: %v. The error is: %v", cmd.Args, err)
|
||||||
return fmt.Errorf("fail to execute: %v: %w", cmd.Args, err)
|
return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err)
|
||||||
}
|
}
|
||||||
if err = cmd.Wait(); err != nil {
|
if err = cmd.Wait(); err != nil {
|
||||||
log.Errorf("go build failed. The error is: %v", err)
|
log.Errorf("go build failed. The error is: %v", err)
|
||||||
return fmt.Errorf("go build faileds: %w", err)
|
return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err)
|
||||||
}
|
}
|
||||||
log.Println("Go build exit successful.")
|
log.Infoln("Go build exit successful.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +116,7 @@ func (b *Build) determineOutputDir(outputDir string) (string, error) {
|
|||||||
curWorkingDir, err := os.Getwd()
|
curWorkingDir, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Cannot get current working directory: %v", err)
|
log.Errorf("Cannot get current working directory: %v", err)
|
||||||
return "", fmt.Errorf("cannot get current working directory: %w", err)
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if outputDir == "" {
|
if outputDir == "" {
|
||||||
@ -125,21 +131,21 @@ func (b *Build) determineOutputDir(outputDir string) (string, error) {
|
|||||||
abs, err := filepath.Abs(outputDir)
|
abs, err := filepath.Abs(outputDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Fail to transform the path: %v to absolute path: %v", outputDir, err)
|
log.Errorf("Fail to transform the path: %v to absolute path: %v", outputDir, err)
|
||||||
return "", fmt.Errorf("fail to transform the path %v to absolute path: %w", outputDir, err)
|
return "", err
|
||||||
}
|
}
|
||||||
return abs, nil
|
return abs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validatePackageForBuild only allow . as package name
|
// validatePackageForBuild only allow . as package name
|
||||||
func (b *Build) validatePackageForBuild() bool {
|
func (b *Build) validatePackageForBuild() bool {
|
||||||
if b.Packages == "." {
|
if b.Packages == "." || b.Packages == "" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run excutes the main package in addition with the internal goc features
|
// Run excutes the main package in addition with the internal goc features
|
||||||
func (b *Build) Run() {
|
func (b *Build) Run() error {
|
||||||
cmd := exec.Command("/bin/bash", "-c", "go run "+b.BuildFlags+" "+b.GoRunExecFlag+" "+b.Packages+" "+b.GoRunArguments)
|
cmd := exec.Command("/bin/bash", "-c", "go run "+b.BuildFlags+" "+b.GoRunExecFlag+" "+b.Packages+" "+b.GoRunArguments)
|
||||||
cmd.Dir = b.TmpWorkingDir
|
cmd.Dir = b.TmpWorkingDir
|
||||||
|
|
||||||
@ -148,16 +154,19 @@ func (b *Build) Run() {
|
|||||||
cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH))
|
cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("go build cmd is: %v", cmd.Args)
|
log.Infof("go build cmd is: %v", cmd.Args)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Fail to start command: %v. The error is: %v", cmd.Args, err)
|
log.Errorf("Fail to start command: %v. The error is: %v", cmd.Args, err)
|
||||||
|
return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = cmd.Wait(); err != nil {
|
if err = cmd.Wait(); err != nil {
|
||||||
log.Fatalf("Fail to execute command: %v. The error is: %v", cmd.Args, err)
|
log.Errorf("Fail to go run: %v. The error is: %v", cmd.Args, err)
|
||||||
|
return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,11 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInvalidPackage(t *testing.T) {
|
func TestInvalidPackage(t *testing.T) {
|
||||||
@ -32,7 +33,7 @@ func TestInvalidPackage(t *testing.T) {
|
|||||||
os.Setenv("GOPATH", gopath)
|
os.Setenv("GOPATH", gopath)
|
||||||
os.Setenv("GO111MODULE", "on")
|
os.Setenv("GO111MODULE", "on")
|
||||||
|
|
||||||
_, err := NewBuild("", "example.com/simple-project", "")
|
_, err := NewBuild("", []string{"example.com/simple-project"}, "")
|
||||||
assert.Equal(t, err, ErrWrongPackageTypeForBuild, "the package name should be invalid")
|
assert.Equal(t, err, ErrWrongPackageTypeForBuild, "the package name should be invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,8 +45,8 @@ func TestBasicBuildForModProject(t *testing.T) {
|
|||||||
os.Setenv("GOPATH", gopath)
|
os.Setenv("GOPATH", gopath)
|
||||||
os.Setenv("GO111MODULE", "on")
|
os.Setenv("GO111MODULE", "on")
|
||||||
|
|
||||||
buildFlags, packages, buildOutput := "", ".", ""
|
buildFlags, args, buildOutput := "", []string{"."}, ""
|
||||||
gocBuild, err := NewBuild(buildFlags, packages, buildOutput)
|
gocBuild, err := NewBuild(buildFlags, args, buildOutput)
|
||||||
assert.Equal(t, err, nil, "should create temporary directory successfully")
|
assert.Equal(t, err, nil, "should create temporary directory successfully")
|
||||||
|
|
||||||
err = gocBuild.Build()
|
err = gocBuild.Build()
|
||||||
|
@ -9,6 +9,7 @@ var (
|
|||||||
ErrGocShouldExecInProject = errors.New("goc not executed in project directory")
|
ErrGocShouldExecInProject = errors.New("goc not executed in project directory")
|
||||||
ErrWrongPackageTypeForInstall = errors.New("packages only support \".\" and \"./...\"")
|
ErrWrongPackageTypeForInstall = errors.New("packages only support \".\" and \"./...\"")
|
||||||
ErrWrongPackageTypeForBuild = errors.New("packages only support \".\"")
|
ErrWrongPackageTypeForBuild = errors.New("packages only support \".\"")
|
||||||
|
ErrTooManyArgs = errors.New("too many args")
|
||||||
ErrWrongCallSequence = errors.New("function should be called in a specified sequence")
|
ErrWrongCallSequence = errors.New("function should be called in a specified sequence")
|
||||||
ErrNoplaceToInstall = errors.New("no go env")
|
ErrNoplaceToInstall = errors.New("no go env")
|
||||||
)
|
)
|
||||||
|
@ -20,21 +20,28 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewInstall creates a Build struct which can install from goc temporary directory
|
// NewInstall creates a Build struct which can install from goc temporary directory
|
||||||
func NewInstall(buildflags string, packages string) (*Build, error) {
|
func NewInstall(buildflags string, args []string) (*Build, error) {
|
||||||
|
if len(args) > 1 {
|
||||||
|
log.Errorf("Too many args")
|
||||||
|
return nil, ErrTooManyArgs
|
||||||
|
}
|
||||||
b := &Build{
|
b := &Build{
|
||||||
BuildFlags: buildflags,
|
BuildFlags: buildflags,
|
||||||
Packages: packages,
|
Packages: strings.Join(args, " "),
|
||||||
}
|
}
|
||||||
if false == b.validatePackageForInstall() {
|
if false == b.validatePackageForInstall() {
|
||||||
log.Errorln(ErrWrongPackageTypeForInstall)
|
log.Errorln(ErrWrongPackageTypeForInstall)
|
||||||
return nil, ErrWrongPackageTypeForInstall
|
return nil, ErrWrongPackageTypeForInstall
|
||||||
}
|
}
|
||||||
b.MvProjectsToTmp()
|
if err := b.MvProjectsToTmp(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,18 +68,18 @@ func (b *Build) Install() error {
|
|||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Fail to execute: %v. The error is: %v", cmd.Args, err)
|
log.Errorf("Fail to execute: %v. The error is: %v", cmd.Args, err)
|
||||||
return fmt.Errorf("fail to execute: %v: %w", cmd.Args, err)
|
return err
|
||||||
}
|
}
|
||||||
if err = cmd.Wait(); err != nil {
|
if err = cmd.Wait(); err != nil {
|
||||||
log.Errorf("go install failed. The error is: %v", err)
|
log.Errorf("go install failed. The error is: %v", err)
|
||||||
return fmt.Errorf("go install failed: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
log.Infof("Go install successful. Binary installed in: %v", whereToInstall)
|
log.Infof("Go install successful. Binary installed in: %v", whereToInstall)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Build) validatePackageForInstall() bool {
|
func (b *Build) validatePackageForInstall() bool {
|
||||||
if b.Packages == "." || b.Packages == "./..." {
|
if b.Packages == "." || b.Packages == "" || b.Packages == "./..." {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBasicInstallForModProject(t *testing.T) {
|
func TestBasicInstallForModProject(t *testing.T) {
|
||||||
@ -15,7 +16,7 @@ func TestBasicInstallForModProject(t *testing.T) {
|
|||||||
os.Setenv("GOPATH", gopath)
|
os.Setenv("GOPATH", gopath)
|
||||||
os.Setenv("GO111MODULE", "on")
|
os.Setenv("GO111MODULE", "on")
|
||||||
|
|
||||||
buildFlags, packages := "", "."
|
buildFlags, packages := "", []string{"."}
|
||||||
gocBuild, err := NewInstall(buildFlags, packages)
|
gocBuild, err := NewInstall(buildFlags, packages)
|
||||||
assert.Equal(t, err, nil, "should create temporary directory successfully")
|
assert.Equal(t, err, nil, "should create temporary directory successfully")
|
||||||
|
|
||||||
|
@ -29,15 +29,24 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *Build) MvProjectsToTmp() {
|
func (b *Build) MvProjectsToTmp() error {
|
||||||
listArgs := []string{"-json"}
|
listArgs := []string{"-json"}
|
||||||
if len(b.BuildFlags) != 0 {
|
if len(b.BuildFlags) != 0 {
|
||||||
listArgs = append(listArgs, b.BuildFlags)
|
listArgs = append(listArgs, b.BuildFlags)
|
||||||
}
|
}
|
||||||
listArgs = append(listArgs, "./...")
|
listArgs = append(listArgs, "./...")
|
||||||
b.Pkgs = cover.ListPackages(".", strings.Join(listArgs, " "), "")
|
var err error
|
||||||
|
b.Pkgs, err = cover.ListPackages(".", strings.Join(listArgs, " "), "")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
b.mvProjectsToTmp()
|
err = b.mvProjectsToTmp()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Fail to move the project to temporary directory")
|
||||||
|
return err
|
||||||
|
}
|
||||||
b.OriGOPATH = os.Getenv("GOPATH")
|
b.OriGOPATH = os.Getenv("GOPATH")
|
||||||
if b.IsMod == true {
|
if b.IsMod == true {
|
||||||
b.NewGOPATH = ""
|
b.NewGOPATH = ""
|
||||||
@ -53,8 +62,8 @@ func (b *Build) MvProjectsToTmp() {
|
|||||||
if b.Root == "" && b.IsMod == false {
|
if b.Root == "" && b.IsMod == false {
|
||||||
b.NewGOPATH = b.OriGOPATH
|
b.NewGOPATH = b.OriGOPATH
|
||||||
}
|
}
|
||||||
log.Printf("New GOPATH: %v", b.NewGOPATH)
|
log.Infof("New GOPATH: %v", b.NewGOPATH)
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Build) mvProjectsToTmp() error {
|
func (b *Build) mvProjectsToTmp() error {
|
||||||
@ -84,7 +93,7 @@ func (b *Build) mvProjectsToTmp() error {
|
|||||||
b.TmpWorkingDir, err = b.getTmpwd()
|
b.TmpWorkingDir, err = b.getTmpwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("fail to get workding directory in temporary directory: %v", err)
|
log.Errorf("fail to get workding directory in temporary directory: %v", err)
|
||||||
return fmt.Errorf("fail to get workding directory in temporary directory: %w", err)
|
return fmt.Errorf("getTmpwd failed with error: %w", err)
|
||||||
}
|
}
|
||||||
// issue #14
|
// issue #14
|
||||||
// if b.Root == "", then the project is non-standard project
|
// if b.Root == "", then the project is non-standard project
|
||||||
@ -109,7 +118,7 @@ func TmpFolderName(path string) string {
|
|||||||
sum := sha256.Sum256([]byte(path))
|
sum := sha256.Sum256([]byte(path))
|
||||||
h := fmt.Sprintf("%x", sum[:6])
|
h := fmt.Sprintf("%x", sum[:6])
|
||||||
|
|
||||||
return "goc-" + h
|
return "goc-build-" + h
|
||||||
}
|
}
|
||||||
|
|
||||||
// traversePkgsList travse the Build.Pkgs list
|
// traversePkgsList travse the Build.Pkgs list
|
||||||
@ -128,7 +137,7 @@ func (b *Build) traversePkgsList() (isMod bool, root string, err error) {
|
|||||||
isMod = true
|
isMod = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Error("should not reach here")
|
log.Error(ErrShouldNotReached)
|
||||||
err = ErrShouldNotReached
|
err = ErrShouldNotReached
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ func TestNewDirParseInLegacyProject(t *testing.T) {
|
|||||||
os.Setenv("GOPATH", gopath)
|
os.Setenv("GOPATH", gopath)
|
||||||
os.Setenv("GO111MODULE", "off")
|
os.Setenv("GO111MODULE", "off")
|
||||||
|
|
||||||
b, _ := NewInstall("", ".")
|
b, _ := NewInstall("", []string{"."})
|
||||||
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
|
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
|
||||||
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
|
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ func TestNewDirParseInLegacyProject(t *testing.T) {
|
|||||||
t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir)
|
t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
b, _ = NewBuild("", ".", "")
|
b, _ = NewBuild("", []string{"."}, "")
|
||||||
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
|
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
|
||||||
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
|
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ func TestNewDirParseInModProject(t *testing.T) {
|
|||||||
os.Setenv("GOPATH", gopath)
|
os.Setenv("GOPATH", gopath)
|
||||||
os.Setenv("GO111MODULE", "on")
|
os.Setenv("GO111MODULE", "on")
|
||||||
|
|
||||||
b, _ := NewInstall("", ".")
|
b, _ := NewInstall("", []string{"."})
|
||||||
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
|
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
|
||||||
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
|
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ func TestNewDirParseInModProject(t *testing.T) {
|
|||||||
t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir)
|
t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
b, _ = NewBuild("", ".", "")
|
b, _ = NewBuild("", []string{"."}, "")
|
||||||
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
|
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
|
||||||
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
|
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ func TestLegacyProjectNotInGoPATH(t *testing.T) {
|
|||||||
os.Setenv("GOPATH", gopath)
|
os.Setenv("GOPATH", gopath)
|
||||||
os.Setenv("GO111MODULE", "off")
|
os.Setenv("GO111MODULE", "off")
|
||||||
|
|
||||||
b, _ := NewBuild("", ".", "")
|
b, _ := NewBuild("", []string{"."}, "")
|
||||||
if b.OriGOPATH != b.NewGOPATH {
|
if b.OriGOPATH != b.NewGOPATH {
|
||||||
t.Fatalf("New GOPATH should be same with old GOPATH, for this kind of project. New: %v, old: %v", b.NewGOPATH, b.OriGOPATH)
|
t.Fatalf("New GOPATH should be same with old GOPATH, for this kind of project. New: %v, old: %v", b.NewGOPATH, b.OriGOPATH)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -37,6 +38,11 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrCoverPkgFailed = errors.New("fail to inject code to project")
|
||||||
|
ErrCoverListFailed = errors.New("fail to list package dependencies")
|
||||||
|
)
|
||||||
|
|
||||||
// TestCover is a collection of all counters
|
// TestCover is a collection of all counters
|
||||||
type TestCover struct {
|
type TestCover struct {
|
||||||
Mode string
|
Mode string
|
||||||
@ -114,9 +120,10 @@ type PackageError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Execute execute go tool cover for all the .go files in the target folder
|
//Execute execute go tool cover for all the .go files in the target folder
|
||||||
func Execute(args, newGopath, target, mode, center string) {
|
func Execute(args, newGopath, target, mode, center string) error {
|
||||||
if !isDirExist(target) {
|
if !isDirExist(target) {
|
||||||
log.Fatalf("target directory %s not exist", target)
|
log.Errorf("Target directory %s not exist", target)
|
||||||
|
return ErrCoverPkgFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
listArgs := []string{"-json"}
|
listArgs := []string{"-json"}
|
||||||
@ -124,7 +131,11 @@ func Execute(args, newGopath, target, mode, center string) {
|
|||||||
listArgs = append(listArgs, args)
|
listArgs = append(listArgs, args)
|
||||||
}
|
}
|
||||||
listArgs = append(listArgs, "./...")
|
listArgs = append(listArgs, "./...")
|
||||||
pkgs := ListPackages(target, strings.Join(listArgs, " "), newGopath)
|
pkgs, err := ListPackages(target, strings.Join(listArgs, " "), newGopath)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Fail to list all packages, the error: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var seen = make(map[string]*PackageCover)
|
var seen = make(map[string]*PackageCover)
|
||||||
var seenCache = make(map[string]*PackageCover)
|
var seenCache = make(map[string]*PackageCover)
|
||||||
@ -134,7 +145,8 @@ func Execute(args, newGopath, target, mode, center string) {
|
|||||||
// inject the main package
|
// inject the main package
|
||||||
mainCover, err := AddCounters(pkg, mode, newGopath)
|
mainCover, err := AddCounters(pkg, mode, newGopath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to add counters for pkg %s, err: %v", pkg.ImportPath, err)
|
log.Errorf("failed to add counters for pkg %s, err: %v", pkg.ImportPath, err)
|
||||||
|
return ErrCoverPkgFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
// new a testcover for this service
|
// new a testcover for this service
|
||||||
@ -158,7 +170,7 @@ func Execute(args, newGopath, target, mode, center string) {
|
|||||||
if hasInternalPath(dep) {
|
if hasInternalPath(dep) {
|
||||||
//scan exist cache cover to tc.CacheCover
|
//scan exist cache cover to tc.CacheCover
|
||||||
if cache, ok := seenCache[dep]; ok {
|
if cache, ok := seenCache[dep]; ok {
|
||||||
log.Printf("cache cover exist: %s", cache.Package.ImportPath)
|
log.Infof("cache cover exist: %s", cache.Package.ImportPath)
|
||||||
tc.CacheCover[cache.Package.Dir] = cache
|
tc.CacheCover[cache.Package.Dir] = cache
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -166,7 +178,8 @@ func Execute(args, newGopath, target, mode, center string) {
|
|||||||
// add counter for internal package
|
// add counter for internal package
|
||||||
inPkgCover, err := AddCounters(depPkg, mode, newGopath)
|
inPkgCover, err := AddCounters(depPkg, mode, newGopath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to add counters for internal pkg %s, err: %v", depPkg.ImportPath, err)
|
log.Errorf("failed to add counters for internal pkg %s, err: %v", depPkg.ImportPath, err)
|
||||||
|
return ErrCoverPkgFailed
|
||||||
}
|
}
|
||||||
parentDir := getInternalParent(depPkg.Dir)
|
parentDir := getInternalParent(depPkg.Dir)
|
||||||
parentImportPath := getInternalParent(depPkg.ImportPath)
|
parentImportPath := getInternalParent(depPkg.ImportPath)
|
||||||
@ -212,7 +225,8 @@ func Execute(args, newGopath, target, mode, center string) {
|
|||||||
|
|
||||||
packageCover, err := AddCounters(depPkg, mode, newGopath)
|
packageCover, err := AddCounters(depPkg, mode, newGopath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to add counters for pkg %s, err: %v", depPkg.ImportPath, err)
|
log.Errorf("failed to add counters for pkg %s, err: %v", depPkg.ImportPath, err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
tc.DepsCover = append(tc.DepsCover, packageCover)
|
tc.DepsCover = append(tc.DepsCover, packageCover)
|
||||||
seen[dep] = packageCover
|
seen[dep] = packageCover
|
||||||
@ -220,21 +234,25 @@ func Execute(args, newGopath, target, mode, center string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if errs := InjectCacheCounters(internalPkgCache, tc.CacheCover); len(errs) > 0 {
|
if errs := InjectCacheCounters(internalPkgCache, tc.CacheCover); len(errs) > 0 {
|
||||||
log.Fatalf("failed to inject cache counters for package: %s, err: %v", pkg.ImportPath, errs)
|
log.Errorf("failed to inject cache counters for package: %s, err: %v", pkg.ImportPath, errs)
|
||||||
|
return ErrCoverPkgFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
// inject Http Cover APIs
|
// inject Http Cover APIs
|
||||||
var httpCoverApis = fmt.Sprintf("%s/http_cover_apis_auto_generated.go", pkg.Dir)
|
var httpCoverApis = fmt.Sprintf("%s/http_cover_apis_auto_generated.go", pkg.Dir)
|
||||||
if err := InjectCountersHandlers(tc, httpCoverApis); err != nil {
|
if err := InjectCountersHandlers(tc, httpCoverApis); err != nil {
|
||||||
log.Fatalf("failed to inject counters for package: %s, err: %v", pkg.ImportPath, err)
|
log.Errorf("failed to inject counters for package: %s, err: %v", pkg.ImportPath, err)
|
||||||
|
return ErrCoverPkgFailed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, error) {
|
||||||
cmd := exec.Command("/bin/bash", "-c", "go list "+args)
|
cmd := exec.Command("/bin/bash", "-c", "go list "+args)
|
||||||
log.Printf("go list cmd is: %v", cmd.Args)
|
log.Printf("go list cmd is: %v", cmd.Args)
|
||||||
cmd.Dir = dir
|
cmd.Dir = dir
|
||||||
@ -243,7 +261,8 @@ func ListPackages(dir string, args string, newgopath string) map[string]*Package
|
|||||||
}
|
}
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("excute `go list -json ./...` command failed, err: %v, out: %v", err, string(out))
|
log.Errorf("excute `go list -json ./...` command failed, err: %v, out: %v", err, string(out))
|
||||||
|
return nil, ErrCoverListFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
dec := json.NewDecoder(bytes.NewReader(out))
|
dec := json.NewDecoder(bytes.NewReader(out))
|
||||||
@ -254,10 +273,12 @@ func ListPackages(dir string, args string, newgopath string) map[string]*Package
|
|||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
log.Fatalf("reading go list output: %v", err)
|
log.Errorf("reading go list output: %v", err)
|
||||||
|
return nil, ErrCoverListFailed
|
||||||
}
|
}
|
||||||
if pkg.Error != nil {
|
if pkg.Error != nil {
|
||||||
log.Fatalf("list package %s failed with output: %v", pkg.ImportPath, pkg.Error)
|
log.Errorf("list package %s failed with output: %v", pkg.ImportPath, pkg.Error)
|
||||||
|
return nil, ErrCoverPkgFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
// for _, err := range pkg.DepsErrors {
|
// for _, err := range pkg.DepsErrors {
|
||||||
@ -266,7 +287,7 @@ func ListPackages(dir string, args string, newgopath string) map[string]*Package
|
|||||||
|
|
||||||
pkgs[pkg.ImportPath] = &pkg
|
pkgs[pkg.ImportPath] = &pkg
|
||||||
}
|
}
|
||||||
return pkgs
|
return pkgs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCounters add counters for all go files under the package
|
// AddCounters add counters for all go files under the package
|
||||||
|
Loading…
Reference in New Issue
Block a user