From 19b2cd8e909bd6211b13686b281cb418befbc767 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Wed, 30 Sep 2020 21:46:02 +0000 Subject: [PATCH] tools: add a function to canonicalize paths We have several different places in our code that need to canonicalize paths. In our case, that usually involves resolving a Cygwin path to a native Windows path, turning the path absolute, and calling filepath.EvalSymlinks. Let's add a function that does exactly that and call it from the places in the git package where we do this already. We pass an additional argument to indicate whether it's acceptable if the path is missing, and if so, we return an absolute but uncanonicalized path in that case. This is useful for canonicalizing Git environment variables which may or may not point to a valid location; we want Git, not us, to make the decision about whether a missing path is a problem in such a case. --- git/git.go | 34 +++++----------------------------- tools/filetools.go | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/git/git.go b/git/git.go index 5b8d9b7f..4acfca57 100644 --- a/git/git.go +++ b/git/git.go @@ -747,20 +747,11 @@ func GitAndRootDirs() (string, string, error) { paths := strings.Split(output, "\n") pathLen := len(paths) - for i := 0; i < pathLen; i++ { - if paths[i] != "" { - paths[i], err = tools.TranslateCygwinPath(paths[i]) - if err != nil { - return "", "", fmt.Errorf("error translating cygwin path: %s", err) - } - } - } - if pathLen == 0 { return "", "", fmt.Errorf("bad git rev-parse output: %q", output) } - absGitDir, err := canonicalizeDir(paths[0]) + absGitDir, err := tools.CanonicalizePath(paths[0], false) if err != nil { return "", "", fmt.Errorf("error converting %q to absolute: %s", paths[0], err) } @@ -769,21 +760,10 @@ func GitAndRootDirs() (string, string, error) { return absGitDir, "", nil } - absRootDir, err := canonicalizeDir(paths[1]) + absRootDir, err := tools.CanonicalizePath(paths[1], false) return absGitDir, absRootDir, err } -func canonicalizeDir(path string) (string, error) { - if len(path) > 0 { - path, err := filepath.Abs(path) - if err != nil { - return "", err - } - return filepath.EvalSymlinks(path) - } - return "", nil -} - func RootDir() (string, error) { cmd := gitNoLFS("rev-parse", "--show-toplevel") out, err := cmd.Output() @@ -796,7 +776,7 @@ func RootDir() (string, error) { if err != nil { return "", err } - return canonicalizeDir(path) + return tools.CanonicalizePath(path, false) } func GitDir() (string, error) { @@ -809,11 +789,7 @@ func GitDir() (string, error) { return "", fmt.Errorf("failed to call git rev-parse --git-dir: %v %v: %v", err, string(out), buf.String()) } path := strings.TrimSpace(string(out)) - path, err = tools.TranslateCygwinPath(path) - if err != nil { - return "", err - } - return canonicalizeDir(path) + return tools.CanonicalizePath(path, false) } func GitCommonDir() (string, error) { @@ -836,7 +812,7 @@ func GitCommonDir() (string, error) { if err != nil { return "", err } - return canonicalizeDir(path) + return tools.CanonicalizePath(path, false) } // GetAllWorkTreeHEADs returns the refs that all worktrees are using as HEADs diff --git a/tools/filetools.go b/tools/filetools.go index 742c0257..2d18ab24 100644 --- a/tools/filetools.go +++ b/tools/filetools.go @@ -478,3 +478,27 @@ func ExecutablePermissions(perms os.FileMode) os.FileMode { // Copy read bits to executable bits. return perms | ((perms & 0444) >> 2) } + +// CanonicalizePath takes a path and produces a canonical absolute path, +// performing any OS- or environment-specific path transformations (within the +// limitations of the Go standard library). If the path is empty, it returns +// the empty path with no error. If missingOk is true, then if the +// canonicalized path does not exist, an absolute path is given instead. +func CanonicalizePath(path string, missingOk bool) (string, error) { + path, err := TranslateCygwinPath(path) + if err != nil { + return "", err + } + if len(path) > 0 { + path, err := filepath.Abs(path) + if err != nil { + return "", err + } + result, err := filepath.EvalSymlinks(path) + if err != nil && os.IsNotExist(err) && missingOk { + return path, nil + } + return result, err + } + return "", nil +}