fix: branch name '/' replace

This commit is contained in:
liruichen_wsl 2024-03-08 19:00:02 +08:00
parent f88485e4e3
commit 4563969f29

View File

@ -14,77 +14,77 @@
package build package build
import ( import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/RickLeee/goc/v2/pkg/build/internal/tool" "github.com/RickLeee/goc/v2/pkg/build/internal/tool"
"github.com/RickLeee/goc/v2/pkg/build/internal/websocket" "github.com/RickLeee/goc/v2/pkg/build/internal/websocket"
"github.com/RickLeee/goc/v2/pkg/log" "github.com/RickLeee/goc/v2/pkg/log"
) )
// Inject injects cover variables for all the .go files in the target directory // Inject injects cover variables for all the .go files in the target directory
func (b *Build) Inject() { func (b *Build) Inject() {
log.StartWait("injecting cover variables") log.StartWait("injecting cover variables")
var seen = make(map[string]*PackageCover) var seen = make(map[string]*PackageCover)
// 所有插桩变量定义声明 // 所有插桩变量定义声明
allDecl := "" allDecl := ""
pkgs := b.Pkgs pkgs := b.Pkgs
for _, pkg := range pkgs { for _, pkg := range pkgs {
if pkg.Name == "main" { if pkg.Name == "main" {
// 该 main 二进制所关联的所有插桩变量的元信息 // 该 main 二进制所关联的所有插桩变量的元信息
// 每个 main 之间是不相关的,需要重新定义 // 每个 main 之间是不相关的,需要重新定义
allMainCovers := make([]*PackageCover, 0) allMainCovers := make([]*PackageCover, 0)
// 注入 main package // 注入 main package
mainCover, mainDecl := b.addCounters(pkg) mainCover, mainDecl := b.addCounters(pkg)
// 收集插桩变量的定义和元信息 // 收集插桩变量的定义和元信息
allDecl += mainDecl allDecl += mainDecl
allMainCovers = append(allMainCovers, mainCover) allMainCovers = append(allMainCovers, mainCover)
// 向 main package 的依赖注入插桩变量 // 向 main package 的依赖注入插桩变量
for _, dep := range pkg.Deps { for _, dep := range pkg.Deps {
if packageCover, ok := seen[dep]; ok { if packageCover, ok := seen[dep]; ok {
allMainCovers = append(allMainCovers, packageCover) allMainCovers = append(allMainCovers, packageCover)
continue continue
} }
// 依赖需要忽略 Go 标准库和 go.mod 引入的第三方 // 依赖需要忽略 Go 标准库和 go.mod 引入的第三方
if depPkg, ok := pkgs[dep]; ok { if depPkg, ok := pkgs[dep]; ok {
// 注入依赖的 package // 注入依赖的 package
packageCover, depDecl := b.addCounters(depPkg) packageCover, depDecl := b.addCounters(depPkg)
// 收集插桩变量的定义和元信息 // 收集插桩变量的定义和元信息
allDecl += depDecl allDecl += depDecl
allMainCovers = append(allMainCovers, packageCover) allMainCovers = append(allMainCovers, packageCover)
// 避免重复访问 // 避免重复访问
seen[dep] = packageCover seen[dep] = packageCover
} }
} }
// 为每个 main 包注入 websocket handler // 为每个 main 包注入 websocket handler
b.injectGocAgent(b.getPkgTmpDir(pkg.Dir), allMainCovers) b.injectGocAgent(b.getPkgTmpDir(pkg.Dir), allMainCovers)
if b.Mode == "watch" { if b.Mode == "watch" {
log.Donef("inject main package [%v] with rpcagent and watchagent", pkg.ImportPath) log.Donef("inject main package [%v] with rpcagent and watchagent", pkg.ImportPath)
} else { } else {
log.Donef("inject main package [%v] with rpcagent", pkg.ImportPath) log.Donef("inject main package [%v] with rpcagent", pkg.ImportPath)
} }
} }
} }
// 在工程根目录注入所有插桩变量的声明+定义 // 在工程根目录注入所有插桩变量的声明+定义
b.injectGlobalCoverVarFile(allDecl) b.injectGlobalCoverVarFile(allDecl)
// 添加自定义 websocket 依赖 // 添加自定义 websocket 依赖
// 用户代码可能有 gorrila/websocket 的依赖,为避免依赖冲突,以及可能的 replace/vendor // 用户代码可能有 gorrila/websocket 的依赖,为避免依赖冲突,以及可能的 replace/vendor
// 这里直接注入一份完整的 gorrila/websocket 实现 // 这里直接注入一份完整的 gorrila/websocket 实现
websocket.AddCustomWebsocketDep(b.GlobalCoverVarImportPathDir) websocket.AddCustomWebsocketDep(b.GlobalCoverVarImportPathDir)
log.Donef("websocket library injected") log.Donef("websocket library injected")
log.StopWait() log.StopWait()
log.Donef("global cover variables injected") log.Donef("global cover variables injected")
} }
// addCounters is different from official go tool cover // addCounters is different from official go tool cover
@ -95,20 +95,20 @@ func (b *Build) Inject() {
// //
// 3. return the declarations as string // 3. return the declarations as string
func (b *Build) addCounters(pkg *Package) (*PackageCover, string) { func (b *Build) addCounters(pkg *Package) (*PackageCover, string) {
mode := b.Mode mode := b.Mode
gobalCoverVarImportPath := b.GlobalCoverVarImportPath gobalCoverVarImportPath := b.GlobalCoverVarImportPath
coverVarMap := declareCoverVars(pkg) coverVarMap := declareCoverVars(pkg)
decl := "" decl := ""
for file, coverVar := range coverVarMap { for file, coverVar := range coverVarMap {
decl += "\n" + tool.Annotate(filepath.Join(b.getPkgTmpDir(pkg.Dir), file), mode, coverVar.Var, coverVar.File, gobalCoverVarImportPath) + "\n" decl += "\n" + tool.Annotate(filepath.Join(b.getPkgTmpDir(pkg.Dir), file), mode, coverVar.Var, coverVar.File, gobalCoverVarImportPath) + "\n"
} }
return &PackageCover{ return &PackageCover{
Package: pkg, Package: pkg,
Vars: coverVarMap, Vars: coverVarMap,
}, decl }, decl
} }
// getPkgTmpDir gets corresponding pkg dir in temporary project // getPkgTmpDir gets corresponding pkg dir in temporary project
@ -119,12 +119,12 @@ func (b *Build) addCounters(pkg *Package) (*PackageCover, string) {
// 在原工程目录已经做了一次 go list -json在临时目录没有必要再做一遍直接转换一下就能得到 // 在原工程目录已经做了一次 go list -json在临时目录没有必要再做一遍直接转换一下就能得到
// 临时目录中的 pkg.Dir。 // 临时目录中的 pkg.Dir。
func (b *Build) getPkgTmpDir(pkgDir string) string { func (b *Build) getPkgTmpDir(pkgDir string) string {
relDir, err := filepath.Rel(b.CurModProjectDir, pkgDir) relDir, err := filepath.Rel(b.CurModProjectDir, pkgDir)
if err != nil { if err != nil {
log.Fatalf("go json -list meta info wrong: %v", err) log.Fatalf("go json -list meta info wrong: %v", err)
} }
return filepath.Join(b.TmpModProjectDir, relDir) return filepath.Join(b.TmpModProjectDir, relDir)
} }
// injectGocAgent inject handlers like following // injectGocAgent inject handlers like following
@ -141,143 +141,144 @@ func (b *Build) getPkgTmpDir(pkgDir string) string {
// 11111_22222_bridge.go 仅仅用于引用 11111_22222_package, where package contains ws agent main logic. // 11111_22222_bridge.go 仅仅用于引用 11111_22222_package, where package contains ws agent main logic.
// 使用 bridge.go 文件是为了避免插桩逻辑中的变量名污染 main 包 // 使用 bridge.go 文件是为了避免插桩逻辑中的变量名污染 main 包
func (b *Build) injectGocAgent(where string, covers []*PackageCover) { func (b *Build) injectGocAgent(where string, covers []*PackageCover) {
if len(covers) == 0 { if len(covers) == 0 {
return return
} }
if len(covers[0].Vars) == 0 { if len(covers[0].Vars) == 0 {
return return
} }
injectPkgName := "goc-cover-agent-apis-auto-generated-11111-22222-package" injectPkgName := "goc-cover-agent-apis-auto-generated-11111-22222-package"
injectBridgeName := "goc-cover-agent-apis-auto-generated-11111-22222-bridge.go" injectBridgeName := "goc-cover-agent-apis-auto-generated-11111-22222-bridge.go"
wherePkg := filepath.Join(where, injectPkgName) wherePkg := filepath.Join(where, injectPkgName)
err := os.MkdirAll(wherePkg, os.ModePerm) err := os.MkdirAll(wherePkg, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("fail to generate %v directory: %v", injectPkgName, err) log.Fatalf("fail to generate %v directory: %v", injectPkgName, err)
} }
// create bridge file // create bridge file
whereBridge := filepath.Join(where, injectBridgeName) whereBridge := filepath.Join(where, injectBridgeName)
f1, err := os.Create(whereBridge) f1, err := os.Create(whereBridge)
if err != nil { if err != nil {
log.Fatalf("fail to create cover bridge file in temporary project: %v", err) log.Fatalf("fail to create cover bridge file in temporary project: %v", err)
} }
defer f1.Close() defer f1.Close()
tmplBridgeData := struct { tmplBridgeData := struct {
CoverImportPath string CoverImportPath string
}{ }{
// covers[0] is the main package // covers[0] is the main package
CoverImportPath: covers[0].Package.ImportPath + "/" + injectPkgName, CoverImportPath: covers[0].Package.ImportPath + "/" + injectPkgName,
} }
if err := coverBridgeTmpl.Execute(f1, tmplBridgeData); err != nil { if err := coverBridgeTmpl.Execute(f1, tmplBridgeData); err != nil {
log.Fatalf("fail to generate cover bridge in temporary project: %v", err) log.Fatalf("fail to generate cover bridge in temporary project: %v", err)
} }
// create ws agent files // create ws agent files
dest := filepath.Join(wherePkg, "rpcagent.go") dest := filepath.Join(wherePkg, "rpcagent.go")
f2, err := os.Create(dest) f2, err := os.Create(dest)
if err != nil { if err != nil {
log.Fatalf("fail to create cover agent file in temporary project: %v", err) log.Fatalf("fail to create cover agent file in temporary project: %v", err)
} }
defer f2.Close() defer f2.Close()
var _coverMode string var _coverMode string
if b.Mode == "watch" { if b.Mode == "watch" {
_coverMode = "cover" _coverMode = "cover"
} else { } else {
_coverMode = b.Mode _coverMode = b.Mode
} }
var commitID string var commitID string
cmd := exec.Command("git", "rev-parse", "--short=8", "HEAD") cmd := exec.Command("git", "rev-parse", "--short=8", "HEAD")
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {
log.Errorf("git describe Error:", err) log.Errorf("git describe Error:", err)
} else { } else {
commitID = strings.TrimRight(string(output), "\n") commitID = strings.TrimRight(string(output), "\n")
} }
var branch string var branch string
cmd = exec.Command("git", "branch", "--contains", commitID, "-r") cmd = exec.Command("git", "branch", "--contains", commitID, "-r")
br, err := cmd.Output() br, err := cmd.Output()
if err != nil { if err != nil {
log.Errorf("get git branch Error:", err) log.Errorf("get git branch Error:", err)
} else { } else {
log.Infof("[goc][info] raw branch: %v ", br) log.Infof("[goc][info] raw branch: %v ", br)
branch = strings.Replace(string(br), "\n", "", -1) branch = strings.Replace(string(br), "\n", "", -1)
branch = strings.TrimLeft(branch, "heads/") branch = strings.TrimLeft(branch, "heads/")
branch = strings.Trim(branch, " ") branch = strings.Trim(branch, " ")
} branch = strings.Replace(branch, "/", "-", -1)
log.Infof("[goc][info] branch: %v --- commitID: %v", branch, commitID) }
tmplData := struct { log.Infof("[goc][info] branch: %v --- commitID: %v", branch, commitID)
Covers []*PackageCover tmplData := struct {
GlobalCoverVarImportPath string Covers []*PackageCover
Package string GlobalCoverVarImportPath string
Host string Package string
Mode string Host string
CommitID string Mode string
Branch string CommitID string
}{ Branch string
Covers: covers, }{
GlobalCoverVarImportPath: b.GlobalCoverVarImportPath, Covers: covers,
Package: injectPkgName, GlobalCoverVarImportPath: b.GlobalCoverVarImportPath,
Host: b.Host, Package: injectPkgName,
Mode: _coverMode, Host: b.Host,
Branch: branch, Mode: _coverMode,
CommitID: commitID, Branch: branch,
} CommitID: commitID,
}
if err := coverMainTmpl.Execute(f2, tmplData); err != nil { if err := coverMainTmpl.Execute(f2, tmplData); err != nil {
log.Fatalf("fail to generate cover agent handlers in temporary project: %v", err) log.Fatalf("fail to generate cover agent handlers in temporary project: %v", err)
} }
// 写入 watch // 写入 watch
if b.Mode != "watch" { if b.Mode != "watch" {
return return
} }
f, err := os.Create(filepath.Join(wherePkg, "watchagent.go")) f, err := os.Create(filepath.Join(wherePkg, "watchagent.go"))
if err != nil { if err != nil {
log.Fatalf("fail to create watchagent file: %v", err) log.Fatalf("fail to create watchagent file: %v", err)
} }
tmplwatchData := struct { tmplwatchData := struct {
Random string Random string
Host string Host string
GlobalCoverVarImportPath string GlobalCoverVarImportPath string
}{ }{
Random: filepath.Base(b.TmpModProjectDir), Random: filepath.Base(b.TmpModProjectDir),
Host: b.Host, Host: b.Host,
GlobalCoverVarImportPath: b.GlobalCoverVarImportPath, GlobalCoverVarImportPath: b.GlobalCoverVarImportPath,
} }
if err := coverWatchTmpl.Execute(f, tmplwatchData); err != nil { if err := coverWatchTmpl.Execute(f, tmplwatchData); err != nil {
log.Fatalf("fail to generate watchagent in temporary project: %v", err) log.Fatalf("fail to generate watchagent in temporary project: %v", err)
} }
} }
// injectGlobalCoverVarFile 写入所有插桩变量的全局定义至一个单独的文件 // injectGlobalCoverVarFile 写入所有插桩变量的全局定义至一个单独的文件
func (b *Build) injectGlobalCoverVarFile(decl string) { func (b *Build) injectGlobalCoverVarFile(decl string) {
globalCoverVarPackage := path.Base(b.GlobalCoverVarImportPath) globalCoverVarPackage := path.Base(b.GlobalCoverVarImportPath)
globalCoverDef := filepath.Join(b.TmpModProjectDir, globalCoverVarPackage) globalCoverDef := filepath.Join(b.TmpModProjectDir, globalCoverVarPackage)
b.GlobalCoverVarImportPathDir = globalCoverDef b.GlobalCoverVarImportPathDir = globalCoverDef
err := os.MkdirAll(globalCoverDef, os.ModePerm) err := os.MkdirAll(globalCoverDef, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("fail to create global cover definition package dir: %v", err) log.Fatalf("fail to create global cover definition package dir: %v", err)
} }
coverFile, err := os.Create(filepath.Join(globalCoverDef, "cover.go")) coverFile, err := os.Create(filepath.Join(globalCoverDef, "cover.go"))
if err != nil { if err != nil {
log.Fatalf("fail to create global cover definition file: %v", err) log.Fatalf("fail to create global cover definition file: %v", err)
} }
defer coverFile.Close() defer coverFile.Close()
packageName := "package coverdef\n\n" packageName := "package coverdef\n\n"
random := filepath.Base(b.TmpModProjectDir) random := filepath.Base(b.TmpModProjectDir)
varWatchDef := fmt.Sprintf(` varWatchDef := fmt.Sprintf(`
var WatchChannel_%v = make(chan *blockInfo, 1024) var WatchChannel_%v = make(chan *blockInfo, 1024)
var WatchEnabled_%v = false var WatchEnabled_%v = false
@ -310,8 +311,8 @@ func UploadCoverChangeEvent_%v(name string, pos []uint32, i int, stmts uint16) {
`, random, random, random, random, random, random) `, random, random, random, random, random, random)
_, err = coverFile.WriteString(packageName + varWatchDef + decl) _, err = coverFile.WriteString(packageName + varWatchDef + decl)
if err != nil { if err != nil {
log.Fatalf("fail to write to global cover definition file: %v", err) log.Fatalf("fail to write to global cover definition file: %v", err)
} }
} }