Skip to content

Commit

Permalink
Simple utility for calculating the directory for go repos to go
Browse files Browse the repository at this point in the history
  • Loading branch information
doozr committed May 31, 2018
1 parent b49effb commit 2c52f07
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Tag file
tags
118 changes: 118 additions & 0 deletions gosrcdir.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package main

import (
"errors"
"fmt"
"go/build"
"net/url"
"os"
"path"
"strings"
)

// parseStandardURL parses a standard URI formatted git URL
func parseStandardURL(repo string) (pathParts []string, err error) {
parsedURL, err := url.Parse(repo)
if err != nil {
return
}

if parsedURL.Host == "" {
err = errors.New("Missing host part")
return
}

pathParts = append(pathParts, parsedURL.Host)

for _, pathPart := range strings.Split(parsedURL.Path, "/") {
if pathPart == "" {
continue
}
pathParts = append(pathParts, pathPart)
}

return
}

// parseWeirdGitURL tries to make sense of a user@host:path format git URL
func parseWeirdGitURL(repo string) (pathParts []string, err error) {

hostIndex := strings.Index(repo, "@") + 1
pathIndex := strings.Index(repo, ":") + 1
repoPath := strings.Split(string(repo[pathIndex:]), "/")

// If there is no : then this is wrong
if pathIndex == 0 || len(repoPath) == 0 {
err = errors.New("Missing path part")
return
}

// if index of @ is -1 then host is the first thing
// if @ is after : then it's part of the path
if hostIndex > pathIndex {
hostIndex = 0
}

host := string(repo[hostIndex : pathIndex-1])
pathParts = append(pathParts, host)

for _, pathPart := range repoPath {
if pathPart == "" {
err = fmt.Errorf("Blank path segment")
return
}
pathParts = append(pathParts, pathPart)
}

return
}

// calculateSourcePath works out the local filesystem path to directory above a given repo
func calculateSourcePath(goPath string, repo string) (repoPath string, err error) {
pathParts, err := parseStandardURL(repo)
if err != nil {
pathParts, err = parseWeirdGitURL(repo)
if err != nil {
return
}
}

if len(pathParts) < 2 {
err = errors.New("Host and path required")
return
}

pathParts = append([]string{goPath, "src"}, pathParts[:len(pathParts)-1]...)
repoPath = path.Join(pathParts...)
return
}

func getGoPath() string {
goPath := os.Getenv("GOPATH")
if goPath != "" {
return goPath
}
return build.Default.GOPATH
}

func main() {
args := os.Args[1:]

// Require at least one repo
if len(args) == 0 {
os.Exit(1)
}

// Work out where GOPATH really is
goPath := getGoPath()

// Calculate path for all repos
for _, repo := range args {
repoPath, err := calculateSourcePath(goPath, repo)
if err != nil {
fmt.Fprintf(os.Stderr, "Cannot parse repo URL %s: %s\n", repo, err)
os.Exit(1)
}
fmt.Println(repoPath)
}
}
82 changes: 82 additions & 0 deletions gosrcdir_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"reflect"
"testing"
)

type ParseTest struct {
Name string
Repo string
}

func TestParsesStandardURL(t *testing.T) {
for _, test := range []ParseTest{
{"HTTPS", "https://[email protected]/path/to/repo"},
{"SSH", "ssh://[email protected]/path/to/repo"},
{"Empty path elements", "https://[email protected]//path//to//repo"},
} {
repoPath, err := parseStandardURL(test.Repo)
if err != nil {
t.Errorf("%s: Unexpected error %q", test.Name, err)
}

expectedPath := []string{"host.com", "path", "to", "repo"}
if !reflect.DeepEqual(repoPath, expectedPath) {
t.Errorf("%s: Expected %q, got %q", test.Name, expectedPath, repoPath)
}
}
}

func TestParsesWeirdGitURL(t *testing.T) {
for _, test := range []ParseTest{
{"with user", "[email protected]:path/to/repo"},
{"without user", "host.com:path/to/repo"},
} {
repoPath, err := parseWeirdGitURL(test.Repo)
if err != nil {
t.Errorf("%s: Unexpected error %q", test.Name, err)
}

expectedPath := []string{"host.com", "path", "to", "repo"}
if !reflect.DeepEqual(repoPath, expectedPath) {
t.Errorf("%s: Expected %q, got %q", test.Name, expectedPath, repoPath)
}
}
}

func TestIsIntolerantToEmptyPathElementsInWeirdURL(t *testing.T) {
_, err := parseWeirdGitURL("[email protected]:path/to//repo")
if err == nil {
t.Errorf("Expected error, got %q", err)
}
}

func TestSourcePath(t *testing.T) {
for _, test := range []ParseTest{
{"Standard URL", "https://[email protected]/path/to/repo"},
{"Weird URL", "[email protected]:path/to/repo"},
} {
repoPath, err := calculateSourcePath("/home/user", test.Repo)
if err != nil {
t.Errorf("%s: Unexpected error %q", test.Name, err)
}

expectedPath := "/home/user/src/host.com/path/to"
if repoPath != expectedPath {
t.Errorf("%sExpected %q, got %q", test.Name, expectedPath, repoPath)
}
}
}

func TestSourcePathErrorsIfMissingHostOrPath(t *testing.T) {
for _, test := range []ParseTest{
{"Standard URL", "https://[email protected]/"},
{"Weird URL", "[email protected]:"},
} {
_, err := calculateSourcePath("/home/user", "[email protected]:")
if err == nil {
t.Errorf("%s: Expected error, got %q", test.Name, err)
}
}
}

0 comments on commit 2c52f07

Please sign in to comment.