enhance error handling

This commit is contained in:
lyyyuna 2020-06-18 16:20:54 +08:00
parent 4c7721b0e8
commit b02d49c2be
16 changed files with 143 additions and 81 deletions

View File

@ -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()

View File

@ -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)

View File

@ -11,8 +11,8 @@ 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
goRunArguments string goRunArguments 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")

View File

@ -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()

View File

@ -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)

View File

@ -42,6 +42,6 @@ goc list [flags]
} }
func init() { func init() {
listCmd.Flags().StringVarP(&center, "center", "", "http://127.0.0.1:7777", "cover profile host center") addBasicFlags(listCmd.Flags())
rootCmd.AddCommand(listCmd) rootCmd.AddCommand(listCmd)
} }

View File

@ -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 "", ""
},
})
} }
}, },
} }

View File

@ -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)
}
}, },
} }

View File

@ -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
} }

View File

@ -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()

View File

@ -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")
) )

View File

@ -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

View File

@ -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")

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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