diff options
-rw-r--r-- | plumbing/transport/file/client.go | 19 | ||||
-rw-r--r-- | repository_windows_test.go | 40 |
2 files changed, 57 insertions, 2 deletions
diff --git a/plumbing/transport/file/client.go b/plumbing/transport/file/client.go index 38714e2..d921d0a 100644 --- a/plumbing/transport/file/client.go +++ b/plumbing/transport/file/client.go @@ -7,6 +7,7 @@ import ( "io" "os" "path/filepath" + "runtime" "strings" "github.com/go-git/go-git/v5/plumbing/transport" @@ -95,7 +96,23 @@ func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.Auth } } - return &command{cmd: execabs.Command(cmd, ep.Path)}, nil + return &command{cmd: execabs.Command(cmd, adjustPathForWindows(ep.Path))}, nil +} + +func isDriveLetter(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') +} + +// On Windows, the path that results from a file: URL has a leading slash. This +// has to be removed if there's a drive letter +func adjustPathForWindows(p string) string { + if runtime.GOOS != "windows" { + return p + } + if len(p) >= 3 && p[0] == '/' && isDriveLetter(p[1]) && p[2] == ':' { + return p[1:] + } + return p } type command struct { diff --git a/repository_windows_test.go b/repository_windows_test.go index bec0acd..e7c1ac7 100644 --- a/repository_windows_test.go +++ b/repository_windows_test.go @@ -1,9 +1,47 @@ package git -import "fmt" +import ( + "fmt" + "strings" + + "github.com/go-git/go-billy/v5/util" + "github.com/go-git/go-git/v5/storage/memory" + . "gopkg.in/check.v1" +) // preReceiveHook returns the bytes of a pre-receive hook script // that prints m before exiting successfully func preReceiveHook(m string) []byte { return []byte(fmt.Sprintf("#!C:/Program\\ Files/Git/usr/bin/sh.exe\nprintf '%s'\n", m)) } + +func (s *RepositorySuite) TestCloneFileUrlWindows(c *C) { + dir, clean := s.TemporalDir() + defer clean() + + r, err := PlainInit(dir, false) + c.Assert(err, IsNil) + + err = util.WriteFile(r.wt, "foo", nil, 0755) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + _, err = w.Add("foo") + c.Assert(err, IsNil) + + _, err = w.Commit("foo", &CommitOptions{ + Author: defaultSignature(), + Committer: defaultSignature(), + }) + c.Assert(err, IsNil) + + url := "file:///" + strings.ReplaceAll(dir, "\\", "/") + c.Assert(url, Matches, "file:///[A-Za-z]:/.*") + _, err = Clone(memory.NewStorage(), nil, &CloneOptions{ + URL: url, + }) + + c.Assert(err, IsNil) +} |