From 8df7498c33b14eb9e98b02d79ff48afa40d59e24 Mon Sep 17 00:00:00 2001 From: lyyyuna Date: Sun, 20 Jun 2021 21:14:21 +0800 Subject: [PATCH] goc build init version --- pkg/build/build.go | 58 ++++++++++++++++++++++++++++++++++++++--- pkg/build/goenv.go | 13 ++++++--- pkg/config/config.go | 24 +++++++++-------- pkg/cover/agent.tpl | 4 ++- pkg/cover/inject.go | 2 ++ pkg/flag/build_flags.go | 29 ++++++++++++++++++++- pkg/flag/packages.go | 12 ++++++--- 7 files changed, 117 insertions(+), 25 deletions(-) diff --git a/pkg/build/build.go b/pkg/build/build.go index 81b6cc4..b6c27b9 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -1,6 +1,10 @@ package build import ( + "os" + "os/exec" + + "github.com/qiniu/goc/v2/pkg/config" "github.com/qiniu/goc/v2/pkg/cover" "github.com/qiniu/goc/v2/pkg/flag" "github.com/qiniu/goc/v2/pkg/log" @@ -17,9 +21,13 @@ type Build struct { // consumes args, get package dirs, read project meta info. func NewBuild(cmd *cobra.Command, args []string) *Build { b := &Build{} + // 1. 解析 goc 命令行和 go 命令行 remainedArgs := flag.BuildCmdArgsParse(cmd, args) + // 2. 解析 go 包位置 flag.GetPackagesDir(remainedArgs) + // 3. 读取工程元信息:go.mod, pkgs list ... b.readProjectMetaInfo() + // 4. 展示元信息 b.displayProjectMetaInfo() return b @@ -31,12 +39,54 @@ func NewBuild(cmd *cobra.Command, args []string) *Build { // 2. inject cover variables and functions into the project, // 3. build the project in temp. func (b *Build) Build() { + // 1. 拷贝至临时目录 b.copyProjectToTmp() // defer b.clean() log.Donef("project copied to temporary directory") - - // inject cover vars + // 2. inject cover vars cover.Inject() - - // build in the temp project + // 3. build in the temp project + b.doBuildInTemp() +} + +func (b *Build) doBuildInTemp() { + goflags := config.GocConfig.Goflags + // 检查用户是否自定义了 -o + oSet := false + for _, flag := range goflags { + if flag == "-o" { + oSet = true + } + } + + // 如果没被设置就加一个至原命令执行的目录 + if !oSet { + goflags = append(goflags, "-o", config.GocConfig.CurWd) + } + + pacakges := config.GocConfig.TmpPkgDir + if config.GocConfig.ContainSpecialPattern { + pacakges = pacakges + "/..." + } + + goflags = append(goflags, pacakges) + + args := []string{"build"} + args = append(args, goflags...) + // go 命令行由 go build [-o output] [build flags] [packages] 组成 + cmd := exec.Command("go", args...) + cmd.Dir = config.GocConfig.TmpModProjectDir + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + log.Infof("go build cmd is: %v", cmd.Args) + if err := cmd.Start(); err != nil { + log.Fatalf("fail to execute go build: %v", err) + } + if err := cmd.Wait(); err != nil { + log.Fatalf("fail to execute go build: %v", err) + } + + // done + log.Donef("go build done") } diff --git a/pkg/build/goenv.go b/pkg/build/goenv.go index d6db963..910e8df 100644 --- a/pkg/build/goenv.go +++ b/pkg/build/goenv.go @@ -19,11 +19,10 @@ func (b *Build) readProjectMetaInfo() { // get gopath & gobin config.GocConfig.GOPATH = b.readGOPATH() config.GocConfig.GOBIN = b.readGOBIN() - // 获取当前目录及其依赖的 package list - config.GocConfig.Pkgs = b.listPackages(config.GocConfig.CurPkgDir) + // 获取 [packages] 及其依赖的 package list + pkgs := b.listPackages(config.GocConfig.CurPkgDir) // get mod info - pkgs := config.GocConfig.Pkgs for _, pkg := range pkgs { // check if go modules is enabled if pkg.Module == nil { @@ -36,6 +35,13 @@ func (b *Build) readProjectMetaInfo() { break } + // 如果包目录不是工程根目录,那再次 go list 一次,获取整个工程的包信息 + if config.GocConfig.CurPkgDir != config.GocConfig.CurModProjectDir { + config.GocConfig.Pkgs = b.listPackages(config.GocConfig.CurModProjectDir) + } else { + config.GocConfig.Pkgs = pkgs + } + // get tmp folder name config.GocConfig.TmpModProjectDir = filepath.Join(os.TempDir(), tmpFolderName(config.GocConfig.CurModProjectDir)) // get cur pkg dir in the corresponding tmp dir @@ -47,7 +53,6 @@ func (b *Build) readProjectMetaInfo() { // displayProjectMetaInfo prints basic infomation of this project to stdout func (b *Build) displayProjectMetaInfo() { - log.Infof("Project Infomation") log.Infof("GOPATH: %v", config.GocConfig.GOPATH) log.Infof("GOBIN: %v", config.GocConfig.GOBIN) log.Infof("Project Directory: %v", config.GocConfig.CurModProjectDir) diff --git a/pkg/config/config.go b/pkg/config/config.go index 2dfdcc3..aafc814 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -3,17 +3,19 @@ package config import "time" type gocConfig struct { - Debug bool - ImportPath string // import path of the project - CurPkgDir string - CurModProjectDir string - TmpModProjectDir string - TmpPkgDir string - BinaryName string - Pkgs map[string]*Package - GOPATH string - GOBIN string - IsMod bool // deprecated + Debug bool + CurWd string + Goflags []string + ImportPath string // import path of the project + CurPkgDir string + CurModProjectDir string + TmpModProjectDir string + TmpPkgDir string + ContainSpecialPattern bool // 参数中包含 ... + Pkgs map[string]*Package + GOPATH string + GOBIN string + IsMod bool // deprecated GlobalCoverVarImportPath string GlobalCoverVarImportPathDir string diff --git a/pkg/cover/agent.tpl b/pkg/cover/agent.tpl index 537c568..1b0fb5e 100644 --- a/pkg/cover/agent.tpl +++ b/pkg/cover/agent.tpl @@ -56,6 +56,7 @@ func init() { time.Sleep(waitDelay) continue } + log.Printf("[goc][Info] connected to goc server") rwc := &ReadWriteCloser{ws: ws} s := rpc.NewServer() @@ -65,6 +66,7 @@ func init() { // exit rpc server, close ws connection ws.Close() time.Sleep(waitDelay) + log.Printf("[goc][Error] connection to goc server broken", ) } } @@ -84,7 +86,7 @@ func (ga *GocAgent) GetProfile(req *ProfileReq, res *ProfileRes) error { } w := new(strings.Builder) - fmt.Fprint(w, "south north") + fmt.Fprint(w, "mode: {{.Mode}}\n") counters, blocks := loadValues() var active, total int64 diff --git a/pkg/cover/inject.go b/pkg/cover/inject.go index da15199..0d7002b 100644 --- a/pkg/cover/inject.go +++ b/pkg/cover/inject.go @@ -158,11 +158,13 @@ func injectGocAgent(where string, covers []*config.PackageCover) { GlobalCoverVarImportPath string Package string Host string + Mode string }{ Covers: covers, GlobalCoverVarImportPath: config.GocConfig.GlobalCoverVarImportPath, Package: injectPkgName, Host: config.GocConfig.Host, + Mode: config.GocConfig.Mode, } if err := coverMainTmpl.Execute(f, tmplData); err != nil { diff --git a/pkg/flag/build_flags.go b/pkg/flag/build_flags.go index 2d67896..7b5986e 100644 --- a/pkg/flag/build_flags.go +++ b/pkg/flag/build_flags.go @@ -2,7 +2,10 @@ package flag import ( "flag" + "os" + "path/filepath" + "github.com/qiniu/goc/v2/pkg/config" "github.com/qiniu/goc/v2/pkg/log" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -15,7 +18,8 @@ The [goc flags] can be placed in anywhere in the command line. However, other flags' order are same with the go official command. ` -// BuildCmdArgsParse parse both go flags and goc flags, it returns all non-flag arguments. +// BuildCmdArgsParse parse both go flags and goc flags, it rewrite go flags if +// necessary, and returns all non-flag arguments. // // 吞下 [packages] 之前所有的 flags. func BuildCmdArgsParse(cmd *cobra.Command, args []string) []string { @@ -52,6 +56,29 @@ func BuildCmdArgsParse(cmd *cobra.Command, args []string) []string { log.Fatalf("%v", err) } + // 找出设置的 go flag + curWd, err := os.Getwd() + if err != nil { + log.Fatalf("fail to get current working directory: %v", err) + } + config.GocConfig.CurWd = curWd + flags := make([]string, 0) + goFlagSets.Visit(func(f *flag.Flag) { + // 将用户指定 -o 改成绝对目录 + if f.Name == "o" { + outputDir := f.Value.String() + outputDir, err := filepath.Abs(outputDir) + if err != nil { + log.Fatalf("output flag is not valid: %v", err) + } + flags = append(flags, "-o", outputDir) + } else { + flags = append(flags, "-"+f.Name, f.Value.String()) + } + }) + + config.GocConfig.Goflags = flags + return goFlagSets.Args() } diff --git a/pkg/flag/packages.go b/pkg/flag/packages.go index 16ab904..491e404 100644 --- a/pkg/flag/packages.go +++ b/pkg/flag/packages.go @@ -38,7 +38,7 @@ func GetPackagesDir(patterns []string) { // 获取当前 [packages] 所在的目录位置,供后续插桩使用。 config.GocConfig.CurPkgDir = filepath.Dir(absp) // 获取二进制名字 - config.GocConfig.BinaryName = filepath.Base(absp) + // config.GocConfig.BinaryName = filepath.Base(absp) return } } @@ -51,8 +51,11 @@ func GetPackagesDir(patterns []string) { } config.GocConfig.CurPkgDir = coverWd - config.GocConfig.BinaryName = "" - return + + // 是否包含 ... + if strings.Contains(patterns[0], "...") { + config.GocConfig.ContainSpecialPattern = true + } } // goFilesPackage 对一组 go 文件解析,判断是否合法 @@ -97,7 +100,7 @@ func goFilesPackage(gofiles []string) error { return nil } -// getDirFromImportPaths return the import path's real directory +// getDirFromImportPaths return the import path's real abs directory // // 该函数接收到的只有 dir 或 import path,file 在上一步已被排除 // 只考虑 go modules 的情况 @@ -134,6 +137,7 @@ func getDirFromImportPaths(patterns []string) (string, error) { case strings.Contains(pattern, "..."): i := strings.Index(pattern, "...") dir, _ := filepath.Split(pattern[:i]) + dir, _ = filepath.Abs(dir) if _, err := os.Stat(dir); err != nil { return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern) }