Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix --strace with relative replace in vendor #90

Merged
merged 1 commit into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:

- name: Binary Install
continue-on-error: false
run: curl -fsSL https://github.com/xhd2015/xgo/raw/master/install.sh | env INSTALL_TO_BIN=true bash -x
run: curl -fsSL https://github.com/xhd2015/xgo/raw/master/script/install/install.sh | env INSTALL_TO_BIN=true bash -x

- name: Check Binary Install
continue-on-error: false
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ func TestPatchFunc(t *testing.T) {
NOTE: `Mock` and `Patch` supports top-level variables and consts, see [runtime/mock/MOCK_VAR_CONST.md](runtime/mock/MOCK_VAR_CONST.md).

## Trace
> Trace might be the most powerful tool provided by xgo, this blog have a more thorough example: https://blog.xhd2015.xyz/posts/xgo-trace_a-powerful-visualization-tool-in-go
> Trace might be the most powerful tool provided by xgo, this blog has a more thorough example: https://blog.xhd2015.xyz/posts/xgo-trace_a-powerful-visualization-tool-in-go

It is painful when debugging with a deep call stack.

Expand Down
3 changes: 2 additions & 1 deletion cmd/xgo/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ Examples:
xgo build -o main -gcflags="all=-N -l" ./ build current module with debug flags
xgo run ./ run current module
xgo test ./... test all test cases of current module
xgo test -run TestSomething --strace ./ test and collect stack trace
xgo tool trace TestSomething.json view collected stack trace
xgo exec go version print instrumented go version
xgo tool trace TestSomething.json view test trace

See https://github.com/xhd2015/xgo for documentation.

Expand Down
6 changes: 3 additions & 3 deletions cmd/xgo/runtime_gen/core/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"os"
)

const VERSION = "1.0.27"
const REVISION = "6ab4a77013b73241451df46df0614dfaceb37a52+1"
const NUMBER = 201
const VERSION = "1.0.28"
const REVISION = "2eaf6cf94cd17d2888d6708cb76d194b334c8957+1"
const NUMBER = 202

// these fields will be filled by compiler
const XGO_VERSION = ""
Expand Down
93 changes: 80 additions & 13 deletions cmd/xgo/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,29 +262,43 @@ func loadDependency(goroot string, goBinary string, goVersion *goinfo.GoVersion,
goModReplace := make(map[string]string)
if vendorDir != "" {
var hasReplace bool
editArgs := []string{"mod", "edit"}

// read vendor/modules.txt,
vendorInfo, err := goinfo.ParseVendor(vendorDir)
if err != nil {
return nil, err
}
replacedModules := make([]string, 0, len(vendorInfo.VendorList))
// get all modules, convert all deps to replace
for _, mod := range vendorInfo.VendorList {
modInfo, ok := vendorInfo.VendorMeta[mod]
if !ok {
continue
}
// modInfo is completely optional
modInfo := vendorInfo.VendorMeta[mod]
modPath := mod.Path
if modInfo.Replacement.Path != "" {
if modInfo.Replacement.Path != "" &&
!isLocalReplace(modInfo.Replacement.Path) { // !isLocalReplace, see https://github.com/xhd2015/xgo/issues/87#issuecomment-2074722912
modPath = modInfo.Replacement.Path
}
vendorModPath := filepath.Join(vendorDir, modPath)
vendorModFile := filepath.Join(vendorModPath, "go.mod")
replaceModFile := filepath.Join(tmpProjectDir, vendorModFile)
// replace goMod => vendor=>

editArgs = append(editArgs, fmt.Sprintf("-replace=%s=%s", modPath, vendorModPath))
// NOTE: if replace without require, go will automatically add
// version v0.0.0-00010101000000-000000000000
// https://stackoverflow.com/questions/58012771/go-mod-fails-to-find-version-v0-0-0-00010101000000-000000000000-of-a-dependency
//
// to suppress this message, always add require
version := mod.Version
if version == "" {
version = "v0.0.0-00010101000000-000000000000"
}
requireCmd := fmt.Sprintf("-require=%s@%s", modPath, version)

// logDebug("replace %s -> %s", modPath, vendorModPath)
replacedModules = append(replacedModules,
requireCmd,
fmt.Sprintf("-replace=%s=%s", modPath, vendorModPath),
)
hasReplace = true
// create placeholder go.mod for each module
modGoVersion := modInfo.GoVersion
Expand All @@ -297,6 +311,7 @@ func loadDependency(goroot string, goBinary string, goVersion *goinfo.GoVersion,
}
goModReplace[vendorModFile] = replaceModFile
}
logDebug("num replaced modules: %d", len(replacedModules)/2)

if hasReplace {
if false {
Expand All @@ -313,13 +328,19 @@ func loadDependency(goroot string, goBinary string, goVersion *goinfo.GoVersion,
// force use -mod=mod
mod = "mod" // force use mod after replaced vendor
modfile = tmpGoMod
editArgs = append(editArgs, tmpGoMod)
err = cmd.Env([]string{
"GOROOT=" + goroot,
}).Run(goBinary, editArgs...)
if err != nil {
return nil, err
for _, replaceModuleGroup := range splitArgsBatch(replacedModules, 100) {
editArgs := make([]string, 0, 3+len(replaceModuleGroup))
editArgs = append(editArgs, "mod", "edit")
editArgs = append(editArgs, replaceModuleGroup...)
editArgs = append(editArgs, tmpGoMod)
err = cmd.Env([]string{
"GOROOT=" + goroot,
}).Run(goBinary, editArgs...)
if err != nil {
return nil, err
}
}

}
}

Expand All @@ -344,6 +365,52 @@ func loadDependency(goroot string, goBinary string, goVersion *goinfo.GoVersion,
}, nil
}

// system may have limit on single go command
func splitArgsBatch(args []string, limit int) [][]string {
if len(args) <= limit {
return [][]string{args}
}
n := len(args) / limit
remain := len(args) - n*limit
bcap := n
if remain > 0 {
bcap++
}
groups := make([][]string, bcap)
off := 0
for i := 0; i < n; i++ {
group := make([]string, limit)
for j := 0; j < limit; j++ {
group[j] = args[off]
off++
}
groups[i] = group
}
if remain > 0 {
group := make([]string, remain)
for i := 0; i < remain; i++ {
group[i] = args[off]
off++
}
groups[bcap-1] = group
}
return groups
}

func isLocalReplace(modPath string) bool {
// ./ or ../
if modPath == "." || modPath == ".." {
return true
}
if strings.HasPrefix(modPath, "./") {
return true
}
if strings.HasPrefix(modPath, "../") {
return true
}
return false
}

func createOverlayFile(tmpProjectDir string, replace map[string]string) (string, error) {
overlay := Overlay{Replace: replace}
overlayData, err := json.Marshal(overlay)
Expand Down
6 changes: 3 additions & 3 deletions cmd/xgo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package main

import "fmt"

const VERSION = "1.0.27"
const REVISION = "6ab4a77013b73241451df46df0614dfaceb37a52+1"
const NUMBER = 201
const VERSION = "1.0.28"
const REVISION = "2eaf6cf94cd17d2888d6708cb76d194b334c8957+1"
const NUMBER = 202

func getRevision() string {
revSuffix := ""
Expand Down
6 changes: 3 additions & 3 deletions runtime/core/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"os"
)

const VERSION = "1.0.27"
const REVISION = "6ab4a77013b73241451df46df0614dfaceb37a52+1"
const NUMBER = 201
const VERSION = "1.0.28"
const REVISION = "2eaf6cf94cd17d2888d6708cb76d194b334c8957+1"
const NUMBER = 202

// these fields will be filled by compiler
const XGO_VERSION = ""
Expand Down
2 changes: 1 addition & 1 deletion runtime/test/trace_without_dep_vendor/hook_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//go:build ignore
// +build ignore

package trace_without_dep
package trace_without_dep_vendor

import (
"os"
Expand Down
2 changes: 1 addition & 1 deletion runtime/test/trace_without_dep_vendor/trace_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package trace_without_dep
package trace_without_dep_vendor

import (
"testing"
Expand Down
7 changes: 7 additions & 0 deletions runtime/test/trace_without_dep_vendor_replace/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/xhd2015/xgo/runtime/test/trace_without_dep_vendor_replace

go 1.14

require github.com/xhd2015/xgo/runtime/test/trace_without_dep_vendor_replace/lib v1.0.0

replace github.com/xhd2015/xgo/runtime/test/trace_without_dep_vendor_replace/lib => ./lib
25 changes: 25 additions & 0 deletions runtime/test/trace_without_dep_vendor_replace/hook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//go:build ignore
// +build ignore

package trace_without_dep_vendor_replace

import (
"os"
"testing"
)

const traceFile = "TestGreet.json"

func TestPreCheck(t *testing.T) {
err := os.RemoveAll(traceFile)
if err != nil {
t.Fatal(err)
}
}

func TestPostCheck(t *testing.T) {
_, err := os.Stat(traceFile)
if err != nil {
t.Fatalf("expect %s, actual: %v", traceFile, err)
}
}
3 changes: 3 additions & 0 deletions runtime/test/trace_without_dep_vendor_replace/lib/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/xhd2015/xgo/runtime/test/trace_without_dep_vendor_replace/lib2

go 1.14
5 changes: 5 additions & 0 deletions runtime/test/trace_without_dep_vendor_replace/lib/lib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package lib

func Greet(s string) string {
return "hello " + s
}
14 changes: 14 additions & 0 deletions runtime/test/trace_without_dep_vendor_replace/trace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package trace_without_dep_vendor_replace

import (
"testing"

"github.com/xhd2015/xgo/runtime/test/trace_without_dep_vendor_replace/lib"
)

func TestGreet(t *testing.T) {
result := lib.Greet("world")
if result != "hello world" {
t.Fatalf("result: %s", result)
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# github.com/xhd2015/xgo/runtime/test/trace_without_dep_vendor_replace/lib v1.0.0 => ./lib
## explicit
github.com/xhd2015/xgo/runtime/test/trace_without_dep_vendor_replace/lib
# github.com/xhd2015/xgo/runtime/test/trace_without_dep_vendor_replace/lib => ./lib
4 changes: 4 additions & 0 deletions script/install/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ curl --fail --location --progress-bar --output "${tmp_dir}/${file}" "$uri" || er
)

if [[ "$INSTALL_TO_BIN" == "true" ]];then
# install fails if target already exists
if [[ -f /usr/local/bin/xgo ]];then
mv /usr/local/bin/{xgo,xgo_backup}
fi
install "$bin_dir/xgo" /usr/local/bin
else
if [[ -f ~/.bash_profile ]];then
Expand Down
6 changes: 6 additions & 0 deletions script/run-test/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ var extraSubTests = []*TestCase{
dir: "runtime/test/trace_without_dep_vendor",
flags: []string{"--strace"},
},
{
// see https://github.com/xhd2015/xgo/issues/87
name: "trace_without_dep_vendor_replace",
dir: "runtime/test/trace_without_dep_vendor_replace",
flags: []string{"--strace"},
},
{
name: "trap_with_overlay",
dir: "runtime/test/trap_with_overlay",
Expand Down
36 changes: 35 additions & 1 deletion support/goinfo/vendor_parse_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package goinfo

import "testing"
import (
"os"
"strings"
"testing"
)

func TestParseVendorInfo(t *testing.T) {
// NOTE: in vendor, replacing module have no
Expand Down Expand Up @@ -29,3 +33,33 @@ git.some/x1/y1/mark
}
t.Logf("%v", info)
}

func TestDebugParseCustomVendor(t *testing.T) {
t.Skipf("debug only")

debugPkg := "test"
file := os.Getenv("TEST_DEBUG_FILE")

vendorInfo, err := ParseVendor(file)
if err != nil {
t.Fatal(err)
}

for _, mod := range vendorInfo.VendorList {
if strings.HasPrefix(debugPkg, mod.Path) {
t.Logf("VendorList found mod: %s %s", mod.Path, mod.Version)
}
}
for _, mod := range vendorInfo.VendorReplaced {
if strings.HasPrefix(debugPkg, mod.Path) {
t.Logf("VendorReplaced found mod: %s %s", mod.Path, mod.Version)
}
}
for mod, meta := range vendorInfo.VendorMeta {
if strings.HasPrefix(debugPkg, mod.Path) {
t.Logf("VendorMeta found mod: %s %s, meta: %+v", mod.Path, mod.Version, meta)
}
}
modVersion := vendorInfo.VendorVersion[debugPkg]
t.Logf("VendorVersion: %s", modVersion)
}
Loading