package util import ( "fmt" "io/fs" "os" "path" "path/filepath" "strings" "github.com/tal-tech/go-zero/tools/goctl/vars" ) const ( pkgSep = "/" goModeIdentifier = "go.mod" ) // JoinPackages calls strings.Join and returns func JoinPackages(pkgs ...string) string { return strings.Join(pkgs, pkgSep) } // MkdirIfNotExist makes directories if the input path is not exists func MkdirIfNotExist(dir string) error { if len(dir) == 0 { return nil } if _, err := os.Stat(dir); os.IsNotExist(err) { return os.MkdirAll(dir, os.ModePerm) } return nil } // PathFromGoSrc returns the path without slash where has been trim the prefix $GOPATH func PathFromGoSrc() (string, error) { dir, err := os.Getwd() if err != nil { return "", err } gopath := os.Getenv("GOPATH") parent := path.Join(gopath, "src", vars.ProjectName) pos := strings.Index(dir, parent) if pos < 0 { return "", fmt.Errorf("%s is not in GOPATH", dir) } // skip slash return dir[len(parent)+1:], nil } // FindGoModPath returns the path in project where has file go.mod, it maybe return empty string if // there is no go.mod file in project func FindGoModPath(dir string) (string, bool) { absDir, err := filepath.Abs(dir) if err != nil { return "", false } absDir = strings.ReplaceAll(absDir, `\`, `/`) var rootPath string tempPath := absDir hasGoMod := false for { if FileExists(filepath.Join(tempPath, goModeIdentifier)) { rootPath = strings.TrimPrefix(absDir[len(tempPath):], "/") hasGoMod = true break } if tempPath == filepath.Dir(tempPath) { break } tempPath = filepath.Dir(tempPath) if tempPath == string(filepath.Separator) { break } } if hasGoMod { return rootPath, true } return "", false } // FindProjectPath returns the parent directory where has file go.mod in project func FindProjectPath(loc string) (string, bool) { var dir string if strings.IndexByte(loc, '/') == 0 { dir = loc } else { wd, err := os.Getwd() if err != nil { return "", false } dir = filepath.Join(wd, loc) } for { if FileExists(filepath.Join(dir, goModeIdentifier)) { return dir, true } dir = filepath.Dir(dir) if dir == "/" { break } } return "", false } // ReadLink returns the destination of the named symbolic link recursively. func ReadLink(name string) (string, error) { name, err := filepath.Abs(name) if err != nil { return "", err } if _, err := os.Lstat(name); err != nil { return name, nil } // uncheck condition: ignore file path /var, maybe be temporary file path if name == "/" || name == "/var" { return name, nil } isLink, err := isLink(name) if err != nil { return "", err } if !isLink { dir, base := filepath.Split(name) dir = filepath.Clean(dir) dir, err := ReadLink(dir) if err != nil { return "", err } return filepath.Join(dir, base), nil } link, err := os.Readlink(name) if err != nil { return "", err } dir, base := filepath.Split(link) dir = filepath.Dir(dir) dir, err = ReadLink(dir) if err != nil { return "", err } return filepath.Join(dir, base), nil } func isLink(name string) (bool, error) { fi, err := os.Lstat(name) if err != nil { return false, err } return fi.Mode()&fs.ModeSymlink != 0, nil }