From 44a19287083a9861cf6d8fd46d746161a4456290 Mon Sep 17 00:00:00 2001 From: Zxilly Date: Fri, 26 Jan 2024 22:17:31 +0800 Subject: [PATCH 1/5] feat: support path handle on multi platform --- .github/workflows/go.yml | 15 ++++++----- file.go | 7 +++-- goroot.go | 31 ++++++++++++--------- goroot_test.go | 4 ++- package.go | 44 +++++++++++++++++------------- package_test.go | 58 ++++++++++++++++++++-------------------- slow_test.go | 8 +++--- utils.go | 30 +++++++++++++++++++++ utils_windows.go | 31 +++++++++++++++++++++ 9 files changed, 151 insertions(+), 77 deletions(-) create mode 100644 utils.go create mode 100644 utils_windows.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 836ad5c..f0b4238 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -1,4 +1,4 @@ -name: build +name: Build and tests on: push: @@ -7,16 +7,18 @@ on: branches: [ develop, master ] jobs: - - build: - runs-on: ubuntu-latest + build_and_tests: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ">=1.21.0" @@ -24,6 +26,7 @@ jobs: run: go build -o a - name: Test + shell: bash run: go test -timeout 1800s -v -race -coverprofile=coverage.txt -covermode=atomic -tags slow_test - name: Codecov diff --git a/file.go b/file.go index 48d5bbe..2cbfc6f 100644 --- a/file.go +++ b/file.go @@ -25,7 +25,6 @@ import ( "fmt" "io" "os" - "path/filepath" "sort" "sync" ) @@ -237,7 +236,7 @@ func (f *GoFile) enumPackages() error { p, ok := packages[n.PackageName()] if !ok { p = &Package{ - Filepath: filepath.Dir(n.BaseName()), + Filepath: "", // to be filled later by dir(PCToLine()) Functions: make([]*Function, 0), Methods: make([]*Method, 0), } @@ -261,7 +260,7 @@ func (f *GoFile) enumPackages() error { if !ok && needFilepath { fp, _, _ := tab.PCToLine(m.Offset) - p.Filepath = filepath.Dir(fp) + p.Filepath = osAwarePathDir(fp) } } else { f := &Function{ @@ -274,7 +273,7 @@ func (f *GoFile) enumPackages() error { if !ok && needFilepath { fp, _, _ := tab.PCToLine(f.Offset) - p.Filepath = filepath.Dir(fp) + p.Filepath = osAwarePathDir(fp) } } } diff --git a/goroot.go b/goroot.go index cd88bfb..63107e9 100644 --- a/goroot.go +++ b/goroot.go @@ -19,6 +19,7 @@ package gore import ( "bytes" + "errors" "fmt" "reflect" "strings" @@ -28,7 +29,7 @@ import ( ) func tryFromGOROOT(f *GoFile) (string, error) { - // Check for non supported architectures. + // Check for non-supported architectures. if f.FileInfo.Arch != Arch386 && f.FileInfo.Arch != ArchAMD64 { return "", nil } @@ -59,9 +60,9 @@ pkgLoop: } } - // Check if the functions was found + // Check if the functions were found if fcn == nil { - // If we can't find the function there is nothing to do. + // If we can't find the function, there is nothing to do. return "", ErrNoGoRootFound } // Get the raw hex. @@ -92,13 +93,13 @@ pkgLoop: } arg := inst.Args[1].(x86asm.Mem) - // First assume that the address is a direct addressing. + // First, assume that the address is a direct addressing. addr := arg.Disp if arg.Base == x86asm.EIP || arg.Base == x86asm.RIP { // If the addressing is based on the instruction pointer, fix the address. addr = addr + int64(fcn.Offset) + int64(s) } else if arg.Base == 0 && arg.Disp > 0 { - // In order to support x32 direct addressing + // To support x32 direct addressing } else { continue } @@ -182,7 +183,7 @@ pkgLoop: } addr = addr + fcn.Offset + uint64(s) } else if arg.Base == 0 && arg.Disp > 0 { - // In order to support x32 direct addressing + // To support x32 direct addressing } else { continue } @@ -208,7 +209,7 @@ pkgLoop: } func tryFromTimeInit(f *GoFile) (string, error) { - // Check for non supported architectures. + // Check for non-supported architectures. if f.FileInfo.Arch != Arch386 && f.FileInfo.Arch != ArchAMD64 { return "", nil } @@ -239,7 +240,7 @@ pkgLoop: } } - // Check if the functions was found + // Check if the functions were found if fcn == nil { // If we can't find the function there is nothing to do. return "", ErrNoGoRootFound @@ -276,13 +277,13 @@ pkgLoop: } arg := inst.Args[1].(x86asm.Mem) - // First assume that the address is a direct addressing. + // First, assume that the address is a direct addressing. addr := arg.Disp if arg.Base == x86asm.EIP || arg.Base == x86asm.RIP { // If the addressing is based on the instruction pointer, fix the address. addr = addr + int64(fcn.Offset) + int64(s) } else if arg.Base == 0 && arg.Disp > 0 { - // In order to support x32 direct addressing + // To support x32 direct addressing } else { continue } @@ -332,7 +333,7 @@ func findGoRootPath(f *GoFile) (string, error) { if goroot != "" { return goroot, nil } - if err != nil && err != ErrNoGoRootFound { + if err != nil && !errors.Is(err, ErrNoGoRootFound) { return "", err } @@ -340,11 +341,11 @@ func findGoRootPath(f *GoFile) (string, error) { if goroot != "" { return goroot, nil } - if err != nil && err != ErrNoGoRootFound { + if err != nil && !errors.Is(err, ErrNoGoRootFound) { return "", err } - // Try determine from std lib package paths. + // Try to determine from std lib package paths. pkg, err := f.GetSTDLib() if err != nil { return "", fmt.Errorf("error when getting standard library packages: %w", err) @@ -358,6 +359,10 @@ func findGoRootPath(f *GoFile) (string, error) { if strings.HasSuffix(v.Filepath, subpath) { return strings.TrimSuffix(v.Filepath, subpath), nil } + subpathWin := fmt.Sprintf("\\src\\%s", v.Name) + if strings.HasSuffix(v.Filepath, subpathWin) { + return strings.TrimSuffix(v.Filepath, subpathWin), nil + } } return "", ErrNoGoRootFound diff --git a/goroot_test.go b/goroot_test.go index 6449669..7f0eccb 100644 --- a/goroot_test.go +++ b/goroot_test.go @@ -32,7 +32,9 @@ func TestExtractGoRoot(t *testing.T) { // Golden folder does not exist t.Skip("No golden files") } - var expectGoRoot string = "/usr/local/go" + + const expectGoRoot = "/usr/local/go" + for _, test := range goldFiles { t.Run("get goroot form "+test, func(t *testing.T) { r := require.New(t) diff --git a/package.go b/package.go index 68f651b..6c29090 100644 --- a/package.go +++ b/package.go @@ -19,7 +19,6 @@ package gore import ( "fmt" - "path/filepath" "runtime/debug" "sort" "strings" @@ -50,7 +49,7 @@ func (f *GoFile) GetSourceFiles(p *Package) []*SourceFile { getSourceFile := func(fileName string) *SourceFile { sf, ok := tmp[fileName] if !ok { - return &SourceFile{Name: filepath.Base(fileName)} + return &SourceFile{Name: osAwarePathBase(fileName)} } return sf } @@ -118,8 +117,8 @@ type PackageClassifier interface { func NewPathPackageClassifier(mainPkgFilepath string) *PathPackageClassifier { return &PathPackageClassifier{ mainFilepath: mainPkgFilepath, mainFolders: []string{ - filepath.Dir(mainPkgFilepath), - mainPkgFilepath, + osAwarePathDir(mainPkgFilepath), + osAwarePathClean(mainPkgFilepath), }, } } @@ -160,11 +159,11 @@ func (c *PathPackageClassifier) Classify(pkg *Package) PackageClass { return ClassVendor } - parentFolder := filepath.Dir(pkg.Filepath) + parentFolder := osAwarePathDir(pkg.Filepath) if strings.HasPrefix(pkg.Filepath, c.mainFilepath+"/vendor/") || - strings.HasPrefix(pkg.Filepath, filepath.Dir(c.mainFilepath)+"/vendor/") || - strings.HasPrefix(pkg.Filepath, filepath.Dir(filepath.Dir(c.mainFilepath))+"/vendor/") { + strings.HasPrefix(pkg.Filepath, osAwarePathDir(c.mainFilepath)+"/vendor/") || + strings.HasPrefix(pkg.Filepath, osAwarePathDir(osAwarePathDir(c.mainFilepath))+"/vendor/") { return ClassVendor } @@ -186,14 +185,13 @@ func (c *PathPackageClassifier) Classify(pkg *Package) PackageClass { } } - // If the path does not contain the "vendor" in path but has the main package folder name, assume part of main. + // If the path does not contain the "vendor" in a path but has the main package folder name, assume part of main. if !strings.Contains(pkg.Filepath, "vendor/") && - (filepath.Base(filepath.Dir(pkg.Filepath)) == filepath.Base(c.mainFilepath)) { + (osAwarePathBase(osAwarePathDir(pkg.Filepath)) == osAwarePathBase(c.mainFilepath)) { return ClassMain } - // Special case for entry point package. - if pkg.Name == "" && filepath.Base(pkg.Filepath) == "runtime" { + if pkg.Name == "" && osAwarePathBase(pkg.Filepath) == "runtime" { return ClassSTD } @@ -203,12 +201,12 @@ func (c *PathPackageClassifier) Classify(pkg *Package) PackageClass { } // Check if it's the main parent package. - if pkg.Name != "" && !strings.Contains(pkg.Name, "/") && strings.Contains(c.mainFilepath, pkg.Name) { + if pkg.Name != "" && (!strings.Contains(pkg.Name, "/") && strings.Contains(c.mainFilepath, pkg.Name)) { return ClassMain } // At this point, if the main package has a file path of "command-line-arguments" and we haven't figured out - // what class it is. We assume it being part of the main package. + // what class it is. We assume it is part of the main package. if c.mainFilepath == "command-line-arguments" { return ClassMain } @@ -220,23 +218,31 @@ func (c *PathPackageClassifier) Classify(pkg *Package) PackageClass { // Otherwise, false is retuned. func IsStandardLibrary(pkg string) bool { _, ok := stdPkgs[pkg] - return ok + if ok { + return true + } + + // Detect regexp.(*onePassInst).regexp/syntax type packages + tmp := strings.Split(pkg, ".")[0] + if len(tmp) < len(pkg) && IsStandardLibrary(tmp) { + return true + } + + return false } func isGeneratedPackage(pkg *Package) bool { - // Detect regexp.(*onePassInst).regexp/syntax type packages - tmp := strings.Split(pkg.Name, ".")[0] - if len(tmp) < len(pkg.Name) && IsStandardLibrary(tmp) { + if pkg.Filepath == "" { return true } // Special case for no package name and path of ".". - if pkg.Name == "" && pkg.Filepath == "." { + if pkg.Name == "" && pkg.Filepath == "" { return true } // Some internal stuff, classify it as Generated - if pkg.Filepath == "." && (pkg.Name == "__x86" || pkg.Name == "__i686") { + if pkg.Filepath == "" && (pkg.Name == "__x86" || pkg.Name == "__i686") { return true } diff --git a/package_test.go b/package_test.go index d16efd0..744ccd0 100644 --- a/package_test.go +++ b/package_test.go @@ -59,21 +59,21 @@ func TestClassifyPackage(t *testing.T) { {"crypto/sha512", "C:/Go/src/crypto/sha512", ClassSTD}, {"crypto/subtle", "C:/Go/src/crypto/subtle", ClassSTD}, {"crypto/tls", "C:/Go/src/crypto/tls", ClassSTD}, - {"crypto/tls.(*Config).(crypto/tls", "C:/Go/src/crypto/tls", ClassGenerated}, + {"crypto/tls.(*Config).(crypto/tls", "C:/Go/src/crypto/tls", ClassSTD}, {"crypto/x509", "C:/Go/src/crypto/x509", ClassSTD}, {"crypto/x509/pkix", "C:/Go/src/crypto/x509/pkix", ClassSTD}, {"encoding/asn1", "C:/Go/src/encoding/asn1", ClassSTD}, {"encoding/base64", "C:/Go/src/encoding/base64", ClassSTD}, {"encoding/binary", "C:/Go/src/encoding/binary", ClassSTD}, {"encoding/hex", "C:/Go/src/encoding/hex", ClassSTD}, - {"encoding/json.(*arrayEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassGenerated}, + {"encoding/json.(*arrayEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassSTD}, {"encoding/json", "C:/Go/src/encoding/json", ClassSTD}, - {"encoding/json.(*condAddrEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassGenerated}, - {"encoding/json.(floatEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassGenerated}, - {"encoding/json.(*mapEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassGenerated}, - {"encoding/json.(*ptrEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassGenerated}, - {"encoding/json.(*sliceEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassGenerated}, - {"encoding/json.(*structEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassGenerated}, + {"encoding/json.(*condAddrEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassSTD}, + {"encoding/json.(floatEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassSTD}, + {"encoding/json.(*mapEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassSTD}, + {"encoding/json.(*ptrEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassSTD}, + {"encoding/json.(*sliceEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassSTD}, + {"encoding/json.(*structEncoder).(encoding/json", "C:/Go/src/encoding/json", ClassSTD}, {"encoding/pem", "C:/Go/src/encoding/pem", ClassSTD}, {"errors", "C:/Go/src/errors", ClassSTD}, {"fmt", "C:/Go/src/fmt", ClassSTD}, @@ -98,11 +98,11 @@ func TestClassifyPackage(t *testing.T) { {"golang.org/x/crypto/ssh", "C:/Users/h/CloudStation/Projects/0/ly/lady/vendor/src/golang.org/x/crypto/ssh", ClassVendor}, {"golang.org/x/net/publicsuffix", "C:/Users/h/CloudStation/Projects/0/ly/lady/vendor/src/golang.org/x/net/publicsuffix", ClassVendor}, {"gopkg.in/vmihailenco/msgpack%2ev2", "C:/Users/h/CloudStation/Projects/0/ly/lady/vendor/src/gopkg.in/vmihailenco/msgpack.v2", ClassVendor}, - {"go.(*struct { net/http", ".", ClassGenerated}, - {"go.struct { net/http", ".", ClassGenerated}, - {"go.(*struct { sync.Mutex; table [64]math/big", ".", ClassGenerated}, - {"go.(*struct { sync.RWMutex; m map[reflect.Type][]encoding/json", ".", ClassGenerated}, - {"go.(*struct { sync.RWMutex; m map[reflect.Type]encoding/json", ".", ClassGenerated}, + {"go.(*struct { net/http", ".", ClassSTD}, + {"go.struct { net/http", ".", ClassSTD}, + {"go.(*struct { sync.Mutex; table [64]math/big", ".", ClassSTD}, + {"go.(*struct { sync.RWMutex; m map[reflect.Type][]encoding/json", ".", ClassSTD}, + {"go.(*struct { sync.RWMutex; m map[reflect.Type]encoding/json", ".", ClassSTD}, {"hash", "C:/Go/src/hash", ClassSTD}, {"hash/crc32", "C:/Go/src/hash/crc32", ClassSTD}, {"internal/golang.org/x/net/http2/hpack", "C:/Go/src/internal/golang.org/x/net/http2/hpack", ClassSTD}, @@ -122,31 +122,31 @@ func TestClassifyPackage(t *testing.T) { {"net", "C:/Go/src/runtime", ClassSTD}, {"net/http", "C:/Go/src/net/http", ClassSTD}, {"net/http/cookiejar", "C:/Go/src/net/http/cookiejar", ClassSTD}, - {"net/http.(*envOnce).(net/http", "C:/Go/src/net/http", ClassGenerated}, - {"net/http.(*http2clientConnReadLoop).(net/http", "C:/Go/src/net/http", ClassGenerated}, - {"net/http.(*http2clientStream).(net/http", "C:/Go/src/net/http", ClassGenerated}, - {"net/http.(*http2responseWriterState).(net/http", "C:/Go/src/net/http", ClassGenerated}, - {"net/http.(*http2serverConn).(net/http", "C:/Go/src/net/http", ClassGenerated}, - {"net/http.(*http2stream).(net/http", "C:/Go/src/net/http", ClassGenerated}, - {"net/http.(*http2Transport).(net/http", "C:/Go/src/net/http", ClassGenerated}, + {"net/http.(*envOnce).(net/http", "C:/Go/src/net/http", ClassSTD}, + {"net/http.(*http2clientConnReadLoop).(net/http", "C:/Go/src/net/http", ClassSTD}, + {"net/http.(*http2clientStream).(net/http", "C:/Go/src/net/http", ClassSTD}, + {"net/http.(*http2responseWriterState).(net/http", "C:/Go/src/net/http", ClassSTD}, + {"net/http.(*http2serverConn).(net/http", "C:/Go/src/net/http", ClassSTD}, + {"net/http.(*http2stream).(net/http", "C:/Go/src/net/http", ClassSTD}, + {"net/http.(*http2Transport).(net/http", "C:/Go/src/net/http", ClassSTD}, {"net/http/httputil", "C:/Go/src/net/http/httputil", ClassSTD}, {"net/http/internal", "C:/Go/src/net/http/internal", ClassSTD}, - {"net/http.(*persistConn).(net/http", "C:/Go/src/net/http", ClassGenerated}, - {"net/http.(*response).(net/http", "C:/Go/src/net/http", ClassGenerated}, - {"net/http.(*Server).(net/http", "C:/Go/src/net/http", ClassGenerated}, - {"net/http.(*Transport).(net/http", "C:/Go/src/net/http", ClassGenerated}, + {"net/http.(*persistConn).(net/http", "C:/Go/src/net/http", ClassSTD}, + {"net/http.(*response).(net/http", "C:/Go/src/net/http", ClassSTD}, + {"net/http.(*Server).(net/http", "C:/Go/src/net/http", ClassSTD}, + {"net/http.(*Transport).(net/http", "C:/Go/src/net/http", ClassSTD}, {"net/textproto", "C:/Go/src/net/textproto", ClassSTD}, {"net/url", "C:/Go/src/net/url", ClassSTD}, {"os", "C:/Go/src/runtime", ClassSTD}, {"os/exec", "C:/Go/src/os/exec", ClassSTD}, - {"os/exec.(*closeOnce).(os/exec", "C:/Go/src/os/exec", ClassGenerated}, + {"os/exec.(*closeOnce).(os/exec", "C:/Go/src/os/exec", ClassSTD}, {"os/user", "C:/Go/src/os/user", ClassSTD}, {"path", "C:/Go/src/path", ClassSTD}, {"path/filepath", "C:/Go/src/path/filepath", ClassSTD}, {"redis", "C:/Users/h/CloudStation/Projects/0/ly/lady/src/redis", ClassMain}, {"reflect", "C:/Go/src/runtime", ClassSTD}, {"regexp", "C:/Go/src/regexp", ClassSTD}, - {"regexp.(*onePassInst).regexp/syntax", ".", ClassGenerated}, + {"regexp.(*onePassInst).regexp/syntax", ".", ClassSTD}, {"regexp/syntax", "C:/Go/src/regexp/syntax", ClassSTD}, {"runtime", "C:/Go/src/runtime", ClassSTD}, {"runtime/debug", "C:/Go/src/runtime", ClassSTD}, @@ -160,8 +160,8 @@ func TestClassifyPackage(t *testing.T) { {"syscall", "C:/Go/src/runtime", ClassSTD}, {"text/template", "C:/Go/src/text/template", ClassSTD}, {"text/template/parse", "C:/Go/src/text/template/parse", ClassSTD}, - {"text/template.(*Template).text/template/parse", ".", ClassGenerated}, - {"text/template.Template.text/template/parse", ".", ClassGenerated}, + {"text/template.(*Template).text/template/parse", ".", ClassSTD}, + {"text/template.Template.text/template/parse", ".", ClassSTD}, {"time", "C:/Go/src/runtime", ClassSTD}, {"type", "C:/Users/h/CloudStation/Projects/0/ly/lady/src/lady", ClassGenerated}, {"type..eq.[0]github.com/shirou/gopsutil/net", "C:/Users/h/CloudStation/Projects/0/ly/lady/vendor/src/github.com/shirou/gopsutil/net", ClassGenerated}, @@ -461,7 +461,7 @@ func TestCommandLineArgumentsPagkageDetection(t *testing.T) { }{ {"x_cgo_sys_thread_creater", ".", ClassSTD}, {"_cgo_sys_thread_star", ".", ClassSTD}, - {"", ".", ClassGenerated}, + {"", "", ClassGenerated}, {"gopackage", "gopackage", ClassMain}, {"gopackage/subpackage", "gopackage/subpackage", ClassMain}, } diff --git a/slow_test.go b/slow_test.go index 3fe870b..a1cfb39 100644 --- a/slow_test.go +++ b/slow_test.go @@ -14,7 +14,6 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . - //go:build slow_test // +build slow_test @@ -22,7 +21,6 @@ package gore import ( "fmt" - "io/ioutil" "os" "os/exec" "path/filepath" @@ -448,13 +446,13 @@ func buildTestResource(body, goos, arch string, pie bool) (string, string) { panic("No go tool chain found: " + err.Error()) } - tmpdir, err := ioutil.TempDir("", "TestGORE") + tmpdir, err := os.MkdirTemp("", "gore-test") if err != nil { panic(err) } src := filepath.Join(tmpdir, "a.go") - err = ioutil.WriteFile(src, []byte(body), 0644) + err = os.WriteFile(src, []byte(body), 0644) if err != nil { panic(err) } @@ -475,7 +473,7 @@ func buildTestResource(body, goos, arch string, pie bool) (string, string) { gopath = tmpdir } - cmd.Env = append(cmd.Env, "GOCACHE="+tmpdir, "GOARCH="+arch, "GOOS="+goos, "GOPATH="+gopath, "PATH="+os.Getenv("PATH")) + cmd.Env = append(cmd.Env, "GOCACHE="+tmpdir, "GOARCH="+arch, "GOOS="+goos, "GOPATH="+gopath, "GOTMPDIR="+gopath, "PATH="+os.Getenv("PATH")) out, err := cmd.CombinedOutput() if err != nil { panic("building test executable failed: " + string(out)) diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..fa0d6d6 --- /dev/null +++ b/utils.go @@ -0,0 +1,30 @@ +//go:build !windows +// +build !windows + +package gore + +import ( + "path/filepath" + "strings" +) + +func osAwarePathDir(s string) string { + if strings.Contains(s, "/") { + return filepath.Dir(s) + } + return s +} + +func osAwarePathBase(s string) string { + if strings.Contains(s, "/") { + return filepath.Base(s) + } + return s +} + +func osAwarePathClean(s string) string { + if strings.Contains(s, "/") { + return filepath.Clean(s) + } + return s +} diff --git a/utils_windows.go b/utils_windows.go new file mode 100644 index 0000000..5c2bf34 --- /dev/null +++ b/utils_windows.go @@ -0,0 +1,31 @@ +//go:build windows +// +build windows + +package gore + +import ( + "path/filepath" + "strings" +) + +func osAwarePathDir(s string) string { + if strings.Contains(s, "/") { + return strings.ReplaceAll(filepath.Dir(s), "\\", "/") + } + return s + +} + +func osAwarePathBase(s string) string { + if strings.Contains(s, "/") { + return strings.ReplaceAll(filepath.Base(s), "\\", "/") + } + return s +} + +func osAwarePathClean(s string) string { + if strings.Contains(s, "/") { + return strings.ReplaceAll(filepath.Clean(s), "\\", "/") + } + return s +} From 2f43fb5f70ad84cd093bb27b4753cd06520a0e9e Mon Sep 17 00:00:00 2001 From: Zxilly Date: Tue, 30 Jan 2024 19:13:13 +0800 Subject: [PATCH 2/5] test: add tests for utils --- utils_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ utils_windows.go | 1 - 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 utils_test.go diff --git a/utils_test.go b/utils_test.go new file mode 100644 index 0000000..e1c9bc2 --- /dev/null +++ b/utils_test.go @@ -0,0 +1,56 @@ +package gore + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestOsAwarePathDir(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {input: "path/to/file", expected: "path/to"}, + {input: "path/to/dir/", expected: "path/to/dir"}, + {input: "", expected: ""}, + } + + for _, test := range tests { + actual := osAwarePathDir(test.input) + assert.Equal(t, test.expected, actual) + } +} + +func TestOsAwarePathBase(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {input: "path/to/file", expected: "file"}, + {input: "path/to/dir/", expected: "dir"}, + {input: "", expected: ""}, + } + + for _, test := range tests { + actual := osAwarePathBase(test.input) + assert.Equal(t, test.expected, actual) + } +} + +func TestOsAwarePathClean(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {input: "path/to/file", expected: "path/to/file"}, + {input: "path/to/dir/", expected: "path/to/dir"}, + {input: "", expected: ""}, + {input: "path/./to/../file", expected: "path/file"}, + } + + for _, test := range tests { + actual := osAwarePathClean(test.input) + assert.Equal(t, test.expected, actual) + } +} diff --git a/utils_windows.go b/utils_windows.go index 5c2bf34..8d12dc5 100644 --- a/utils_windows.go +++ b/utils_windows.go @@ -13,7 +13,6 @@ func osAwarePathDir(s string) string { return strings.ReplaceAll(filepath.Dir(s), "\\", "/") } return s - } func osAwarePathBase(s string) string { From 9f79701e90a33ed3b59b0e9ddb43b1f2662fb0fb Mon Sep 17 00:00:00 2001 From: Zxilly Date: Wed, 31 Jan 2024 02:04:35 +0800 Subject: [PATCH 3/5] refactor: use std `path` instead --- file.go | 5 +++-- package.go | 17 ++++++++------- utils.go | 30 -------------------------- utils_test.go | 56 ------------------------------------------------ utils_windows.go | 30 -------------------------- 5 files changed, 12 insertions(+), 126 deletions(-) delete mode 100644 utils.go delete mode 100644 utils_test.go delete mode 100644 utils_windows.go diff --git a/file.go b/file.go index 2cbfc6f..ba79961 100644 --- a/file.go +++ b/file.go @@ -25,6 +25,7 @@ import ( "fmt" "io" "os" + "path" "sort" "sync" ) @@ -260,7 +261,7 @@ func (f *GoFile) enumPackages() error { if !ok && needFilepath { fp, _, _ := tab.PCToLine(m.Offset) - p.Filepath = osAwarePathDir(fp) + p.Filepath = path.Dir(fp) } } else { f := &Function{ @@ -273,7 +274,7 @@ func (f *GoFile) enumPackages() error { if !ok && needFilepath { fp, _, _ := tab.PCToLine(f.Offset) - p.Filepath = osAwarePathDir(fp) + p.Filepath = path.Dir(fp) } } } diff --git a/package.go b/package.go index 6c29090..32a0d25 100644 --- a/package.go +++ b/package.go @@ -19,6 +19,7 @@ package gore import ( "fmt" + "path" "runtime/debug" "sort" "strings" @@ -49,7 +50,7 @@ func (f *GoFile) GetSourceFiles(p *Package) []*SourceFile { getSourceFile := func(fileName string) *SourceFile { sf, ok := tmp[fileName] if !ok { - return &SourceFile{Name: osAwarePathBase(fileName)} + return &SourceFile{Name: path.Base(fileName)} } return sf } @@ -117,8 +118,8 @@ type PackageClassifier interface { func NewPathPackageClassifier(mainPkgFilepath string) *PathPackageClassifier { return &PathPackageClassifier{ mainFilepath: mainPkgFilepath, mainFolders: []string{ - osAwarePathDir(mainPkgFilepath), - osAwarePathClean(mainPkgFilepath), + path.Dir(mainPkgFilepath), + path.Clean(mainPkgFilepath), }, } } @@ -159,11 +160,11 @@ func (c *PathPackageClassifier) Classify(pkg *Package) PackageClass { return ClassVendor } - parentFolder := osAwarePathDir(pkg.Filepath) + parentFolder := path.Dir(pkg.Filepath) if strings.HasPrefix(pkg.Filepath, c.mainFilepath+"/vendor/") || - strings.HasPrefix(pkg.Filepath, osAwarePathDir(c.mainFilepath)+"/vendor/") || - strings.HasPrefix(pkg.Filepath, osAwarePathDir(osAwarePathDir(c.mainFilepath))+"/vendor/") { + strings.HasPrefix(pkg.Filepath, path.Dir(c.mainFilepath)+"/vendor/") || + strings.HasPrefix(pkg.Filepath, path.Dir(path.Dir(c.mainFilepath))+"/vendor/") { return ClassVendor } @@ -187,11 +188,11 @@ func (c *PathPackageClassifier) Classify(pkg *Package) PackageClass { // If the path does not contain the "vendor" in a path but has the main package folder name, assume part of main. if !strings.Contains(pkg.Filepath, "vendor/") && - (osAwarePathBase(osAwarePathDir(pkg.Filepath)) == osAwarePathBase(c.mainFilepath)) { + (path.Base(path.Dir(pkg.Filepath)) == path.Base(c.mainFilepath)) { return ClassMain } // Special case for entry point package. - if pkg.Name == "" && osAwarePathBase(pkg.Filepath) == "runtime" { + if pkg.Name == "" && path.Base(pkg.Filepath) == "runtime" { return ClassSTD } diff --git a/utils.go b/utils.go deleted file mode 100644 index fa0d6d6..0000000 --- a/utils.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build !windows -// +build !windows - -package gore - -import ( - "path/filepath" - "strings" -) - -func osAwarePathDir(s string) string { - if strings.Contains(s, "/") { - return filepath.Dir(s) - } - return s -} - -func osAwarePathBase(s string) string { - if strings.Contains(s, "/") { - return filepath.Base(s) - } - return s -} - -func osAwarePathClean(s string) string { - if strings.Contains(s, "/") { - return filepath.Clean(s) - } - return s -} diff --git a/utils_test.go b/utils_test.go deleted file mode 100644 index e1c9bc2..0000000 --- a/utils_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package gore - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestOsAwarePathDir(t *testing.T) { - tests := []struct { - input string - expected string - }{ - {input: "path/to/file", expected: "path/to"}, - {input: "path/to/dir/", expected: "path/to/dir"}, - {input: "", expected: ""}, - } - - for _, test := range tests { - actual := osAwarePathDir(test.input) - assert.Equal(t, test.expected, actual) - } -} - -func TestOsAwarePathBase(t *testing.T) { - tests := []struct { - input string - expected string - }{ - {input: "path/to/file", expected: "file"}, - {input: "path/to/dir/", expected: "dir"}, - {input: "", expected: ""}, - } - - for _, test := range tests { - actual := osAwarePathBase(test.input) - assert.Equal(t, test.expected, actual) - } -} - -func TestOsAwarePathClean(t *testing.T) { - tests := []struct { - input string - expected string - }{ - {input: "path/to/file", expected: "path/to/file"}, - {input: "path/to/dir/", expected: "path/to/dir"}, - {input: "", expected: ""}, - {input: "path/./to/../file", expected: "path/file"}, - } - - for _, test := range tests { - actual := osAwarePathClean(test.input) - assert.Equal(t, test.expected, actual) - } -} diff --git a/utils_windows.go b/utils_windows.go deleted file mode 100644 index 8d12dc5..0000000 --- a/utils_windows.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build windows -// +build windows - -package gore - -import ( - "path/filepath" - "strings" -) - -func osAwarePathDir(s string) string { - if strings.Contains(s, "/") { - return strings.ReplaceAll(filepath.Dir(s), "\\", "/") - } - return s -} - -func osAwarePathBase(s string) string { - if strings.Contains(s, "/") { - return strings.ReplaceAll(filepath.Base(s), "\\", "/") - } - return s -} - -func osAwarePathClean(s string) string { - if strings.Contains(s, "/") { - return strings.ReplaceAll(filepath.Clean(s), "\\", "/") - } - return s -} From 41e58e22df4514166d250b12a671523af3853f7c Mon Sep 17 00:00:00 2001 From: Zxilly Date: Wed, 31 Jan 2024 02:22:17 +0800 Subject: [PATCH 4/5] fix: add check for --- file.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/file.go b/file.go index ba79961..282a35a 100644 --- a/file.go +++ b/file.go @@ -258,11 +258,6 @@ func (f *GoFile) enumPackages() error { } p.Methods = append(p.Methods, m) - - if !ok && needFilepath { - fp, _, _ := tab.PCToLine(m.Offset) - p.Filepath = path.Dir(fp) - } } else { f := &Function{ Name: n.BaseName(), @@ -271,9 +266,13 @@ func (f *GoFile) enumPackages() error { PackageName: n.PackageName(), } p.Functions = append(p.Functions, f) + } - if !ok && needFilepath { - fp, _, _ := tab.PCToLine(f.Offset) + if needFilepath { + fp, _, _ := tab.PCToLine(n.Entry) + if fp == "" { + p.Filepath = fp + } else { p.Filepath = path.Dir(fp) } } From 1e2db0cf2dfae4a4155d2b08c091932432351c7c Mon Sep 17 00:00:00 2001 From: Zxilly Date: Wed, 31 Jan 2024 02:31:24 +0800 Subject: [PATCH 5/5] fix: add check for "" --- file.go | 5 +++-- package.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/file.go b/file.go index 282a35a..cbf2796 100644 --- a/file.go +++ b/file.go @@ -270,9 +270,10 @@ func (f *GoFile) enumPackages() error { if needFilepath { fp, _, _ := tab.PCToLine(n.Entry) - if fp == "" { + switch fp { + case "", "": p.Filepath = fp - } else { + default: p.Filepath = path.Dir(fp) } } diff --git a/package.go b/package.go index 32a0d25..2264381 100644 --- a/package.go +++ b/package.go @@ -237,7 +237,7 @@ func isGeneratedPackage(pkg *Package) bool { return true } - // Special case for no package name and path of ".". + // Special case for no package name and path of "". if pkg.Name == "" && pkg.Filepath == "" { return true }