Skip to content

Commit

Permalink
feat: allow rule specifying Golang version (#257)
Browse files Browse the repository at this point in the history
  • Loading branch information
y1yang0 authored Dec 18, 2024
1 parent 7c42e21 commit 00b3ca4
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 63 deletions.
3 changes: 2 additions & 1 deletion pkg/data/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"ImportPath": "runtime",
"Function":"doInit",
"OnEnter": "reorderInitTasks(ts)",
"UseRaw": true
"UseRaw": true,
"GoVersion": "[1.21.0,)"
},
{
"ImportPath": "runtime",
Expand Down
43 changes: 31 additions & 12 deletions tool/preprocess/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ import (
"github.com/dave/dst"
)

const (
CompileFlagPattern = "-p"
CompileFlagGoVer = "-goversion"
)

type ruleMatcher struct {
availableRules map[string][]resource.InstRule
}
Expand Down Expand Up @@ -141,9 +146,10 @@ func findAvailableRules() []resource.InstRule {

// match gives compilation arguments and finds out all interested rules
// for it.
func (rm *ruleMatcher) match(importPath string,
candidates []string) *resource.RuleBundle {
func (rm *ruleMatcher) match(cmdArgs []string) *resource.RuleBundle {
importPath := findFlagValue(cmdArgs, CompileFlagPattern)
util.Assert(importPath != "", "sanity check")
util.Log("RunMatch: %v (%v)", importPath, cmdArgs)
availables := make([]resource.InstRule, len(rm.availableRules[importPath]))

// Okay, we are interested in these candidates, let's read it and match with
Expand All @@ -155,7 +161,12 @@ func (rm *ruleMatcher) match(importPath string,
}
parsedAst := make(map[string]*dst.File)
bundle := resource.NewRuleBundle(importPath)
for _, candidate := range candidates {

goVersion := findFlagValue(cmdArgs, CompileFlagGoVer)
util.Assert(goVersion != "", "sanity check")
util.Assert(strings.HasPrefix(goVersion, "go"), "sanity check")
goVersion = strings.Replace(goVersion, "go", "v", 1)
for _, candidate := range cmdArgs {
// It's not a go file, ignore silently
if !shared.IsGoFile(candidate) {
continue
Expand All @@ -176,6 +187,19 @@ func (rm *ruleMatcher) match(importPath string,
if !matched {
continue
}
// Check if the rule requires a specific Go version(range)
if rule.GetGoVersion() != "" {
matched, err = shared.MatchVersion(goVersion, rule.GetGoVersion())
if err != nil {
util.Log("Failed to match Go version %v between %v and %v",
err, file, rule)
continue
}
if !matched {
continue
}
}

// Check if it matches with file rule early as we try to avoid
// parsing the file content, which is time consuming
if _, ok := rule.(*resource.InstFileRule); ok {
Expand Down Expand Up @@ -247,22 +271,17 @@ func (rm *ruleMatcher) match(importPath string,
return bundle
}

func readImportPath(cmd []string) string {
var pkg string
func findFlagValue(cmd []string, flag string) string {
for i, v := range cmd {
if v == "-p" {
if v == flag {
return cmd[i+1]
}
}
return pkg
return ""
}

func runMatch(matcher *ruleMatcher, cmd string, ch chan *resource.RuleBundle) {
cmdArgs := shared.SplitCmds(cmd)
importPath := readImportPath(cmdArgs)
util.Assert(importPath != "", "sanity check")
util.Log("RunMatch: %v (%v)", importPath, cmdArgs)
bundle := matcher.match(importPath, cmdArgs)
bundle := matcher.match(shared.SplitCmds(cmd))
ch <- bundle
}

Expand Down
83 changes: 33 additions & 50 deletions tool/resource/ruledef.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (

type InstRule interface {
GetVersion() string // GetVersion returns the version of the rule
GetGoVersion() string // GetGoVersion returns the go version of the rule
GetImportPath() string // GetImportPath returns import path of the rule
GetPath() string // GetPath returns the local path of the rule
SetPath(path string) // SetPath sets the local path of the rule
Expand All @@ -46,18 +47,27 @@ type InstRule interface {
}

type InstBaseRule struct {
// Local path of the rule
// Local path of the rule, it desginates where we can found the hook code
Path string `json:"Path,omitempty"`
// Version of the rule, e.g. "[1.9.1,1.9.2)" or ""
// Version of the rule, e.g. "[1.9.1,1.9.2)" or "", it desginates the
// version range of rule, all other version will not be instrumented
Version string `json:"Version,omitempty"`
// Import path of the rule, e.g. "github.com/gin-gonic/gin"
// Go version of the rule, e.g. "[1.22.0,)" or "", it desginates the go
// version range of rule, all other go version will not be instrumented
GoVersion string `json:"GoVersion,omitempty"`
// Import path of the rule, e.g. "github.com/gin-gonic/gin", it desginates
// the import path of rule, all other import path will not be instrumented
ImportPath string `json:"ImportPath,omitempty"`
}

func (rule *InstBaseRule) GetVersion() string {
return rule.Version
}

func (rule *InstBaseRule) GetGoVersion() string {
return rule.GoVersion
}

func (rule *InstBaseRule) GetImportPath() string {
return rule.ImportPath
}
Expand Down Expand Up @@ -107,30 +117,6 @@ type InstFileRule struct {
Replace bool `json:"Replace,omitempty"`
}

func (rule *InstFuncRule) WithVersion(version string) *InstFuncRule {
rule.Version = version
return rule
}

func (rule *InstFuncRule) WithUseRaw(useRaw bool) *InstFuncRule {
rule.UseRaw = useRaw
return rule
}

func (rule *InstFuncRule) WithFileDeps(deps ...string) *InstFuncRule {
return rule
}

func (rule *InstFileRule) WithReplace(replace bool) *InstFileRule {
rule.Replace = replace
return rule
}

func (rule *InstFileRule) WithVersion(version string) *InstFileRule {
rule.Version = version
return rule
}

// String returns string representation of the rule
func (rule *InstFuncRule) String() string {
bs, _ := json.Marshal(rule)
Expand All @@ -146,39 +132,36 @@ func (rule *InstFileRule) String() string {
}

// Verify checks the rule is valid
func verifyRuleBase(rule *InstBaseRule) error {
if rule.Path == "" {
return fmt.Errorf("local path is empty")
func verifyRule(rule *InstBaseRule, checkPath bool) error {
if checkPath {
if rule.Path == "" {
return fmt.Errorf("local path is empty")
}
}
// Import path should not be empty
if rule.ImportPath == "" {
return fmt.Errorf("import path is empty")
}
if rule.Version != "" {
// If version is specified, it should be in the format of [start,end)
if !strings.Contains(rule.Version, "[") ||
!strings.Contains(rule.Version, ")") ||
!strings.Contains(rule.Version, ",") ||
strings.Contains(rule.Version, "v") {
return fmt.Errorf("invalid version format %s", rule.Version)
// If version is specified, it should be in the format of [start,end)
for _, v := range []string{rule.Version, rule.GoVersion} {
if v != "" {
if !strings.Contains(v, "[") ||
!strings.Contains(v, ")") ||
!strings.Contains(v, ",") ||
strings.Contains(v, "v") {
return fmt.Errorf("invalid version format %s", v)
}
}
}
return nil
}

func verifyRuleBase(rule *InstBaseRule) error {
return verifyRule(rule, false)
}

func verifyRuleBaseWithoutPath(rule *InstBaseRule) error {
if rule.ImportPath == "" {
return fmt.Errorf("import path is empty")
}
if rule.Version != "" {
// If version is specified, it should be in the format of [start,end)
if !strings.Contains(rule.Version, "[") ||
!strings.Contains(rule.Version, ")") ||
!strings.Contains(rule.Version, ",") ||
strings.Contains(rule.Version, "v") {
return fmt.Errorf("invalid version format %s", rule.Version)
}
}
return nil
return verifyRule(rule, true)
}

func (rule *InstFileRule) Verify() error {
Expand Down
4 changes: 4 additions & 0 deletions tool/util/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ package util
import (
"fmt"
"os"
"sync"
)

var logWriter *os.File = os.Stdout
var logMutex sync.Mutex

var Guarantee = Assert // More meaningful name:)

Expand All @@ -29,7 +31,9 @@ func SetLogTo(w *os.File) {

func Log(format string, args ...interface{}) {
template := "[" + GetRunPhase().String() + "] " + format + "\n"
logMutex.Lock()
fmt.Fprintf(logWriter, template, args...)
logMutex.Unlock()
}

func LogFatal(format string, args ...interface{}) {
Expand Down

0 comments on commit 00b3ca4

Please sign in to comment.