From 2bb75e9cca1d02d34f9eec25177cc8a3c93b18d8 Mon Sep 17 00:00:00 2001 From: Fabian Burth Date: Wed, 29 May 2024 10:12:25 +0200 Subject: [PATCH] documentation and bugfix in GetPackageNameForFunc --- pkg/utils/package.go | 47 ++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/pkg/utils/package.go b/pkg/utils/package.go index 7f84c6b6f9..fa9671849b 100644 --- a/pkg/utils/package.go +++ b/pkg/utils/package.go @@ -2,41 +2,49 @@ package utils import ( "fmt" + "reflect" + "runtime" + "strings" + "github.com/mandelsoft/filepath/pkg/filepath" "github.com/mandelsoft/goutils/general" "github.com/mandelsoft/vfs/pkg/osfs" "github.com/mandelsoft/vfs/pkg/vfs" "golang.org/x/mod/modfile" - "reflect" - "runtime" - "strings" ) +const GO_MOD = "go.mod" + +// GetRelativePathToProjectRoot calculates the relative path to a go projects root directory. +// It therefore assumes that the project root is the directory containing the go.mod file. +// The optional parameter i determines how many directories the function will step up through, attempting to find a +// go.mod file. If it cannot find a directory with a go.mod file within i iterations, the function throws an error. func GetRelativePathToProjectRoot(i ...int) (string, error) { iterations := general.OptionalDefaulted(20, i...) path := "." for count := 0; count < iterations; count++ { - if ok, err := vfs.FileExists(osfs.OsFs, filepath.Join(path, "go.mod")); err != nil || ok { + if ok, err := vfs.FileExists(osfs.OsFs, filepath.Join(path, GO_MOD)); err != nil || ok { if err != nil { - return "", fmt.Errorf("failed to check if go.mod exists: %v", err) + return "", fmt.Errorf("failed to check if %s exists: %w", GO_MOD, err) } return path, nil } if count == iterations { - return "", fmt.Errorf("could not find go.mod (within %d steps)", iterations) + return "", fmt.Errorf("could not find %s (within %d steps)", GO_MOD, iterations) } path = filepath.Join(path, "..") } return "", nil } +// GetModuleName returns a go modules module name by finding and parsing the go.mod file. func GetModuleName() (string, error) { pathToRoot, err := GetRelativePathToProjectRoot() if err != nil { return "", err } - pathToGoMod := filepath.Join(pathToRoot, "go.mod") + pathToGoMod := filepath.Join(pathToRoot, GO_MOD) // Read the content of the go.mod file data, err := vfs.ReadFile(osfs.OsFs, pathToGoMod) if err != nil { @@ -44,18 +52,29 @@ func GetModuleName() (string, error) { } // Parse the go.mod file - modFile, err := modfile.Parse("go.mod", data, nil) + modFile, err := modfile.Parse(GO_MOD, data, nil) if err != nil { - return "", fmt.Errorf("error parsing go.mod file: %w", err) + return "", fmt.Errorf("error parsing %s file: %w", GO_MOD, err) } // Print the module path return modFile.Module.Mod.Path, nil } -func GetPackageNameForFunc(i interface{}) (string, error) { +func GetPackageNameForFunc(i ...interface{}) (string, error) { + // if no function is passed, assume the package name should be determined for the caller of this function + pc, _, _, ok := runtime.Caller(1) + if !ok { + panic("unable to find caller") + } + // Get the function's pointer - ptr := reflect.ValueOf(i).Pointer() + var ptr uintptr + if len(i) > 0 { + ptr = reflect.ValueOf(general.Optional(i...)).Pointer() + } else { + ptr = pc + } // Retrieve the function's runtime information funcForPC := runtime.FuncForPC(ptr) if funcForPC == nil { @@ -68,10 +87,12 @@ func GetPackageNameForFunc(i interface{}) (string, error) { // Assuming the format: "package/path.functionName" lastSlashIndex := strings.LastIndex(fullFuncName, "/") if lastSlashIndex == -1 { - return "", fmt.Errorf("could not determine package name") + panic("unable to find package name") } - packagePath := fullFuncName[:lastSlashIndex] + funcIndex := strings.Index(fullFuncName[lastSlashIndex:], ".") + packagePath := fullFuncName[:lastSlashIndex+funcIndex] + return packagePath, nil }