-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
148 lines (123 loc) · 3.58 KB
/
main.go
File metadata and controls
148 lines (123 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package main
import (
"flag"
"fmt"
"net/url"
"os"
"os/exec"
"runtime"
"strings"
)
const VERSION = "0.1.0"
var Usage = func() {
fmt.Fprintf(os.Stderr, "This utility is meant to be called as a git subcommand `git browser`\n")
fmt.Fprintf(os.Stderr, "It will build the correct URL for your githost that will open\n")
fmt.Fprintf(os.Stderr, "in your default browser automatically.")
flag.PrintDefaults()
}
func main() {
showOnlyFlg := flag.Bool("s", false, "show: print the URL to stdout, don't open a browser")
branchFlg := flag.Bool("b", false, "branch: use current branch")
remoteFlg := flag.String("r", "origin", "remote: choose a remote to open")
versionFlg := flag.Bool("v", false, "version: print the current version an exit")
flag.Usage = Usage
flag.Parse()
if *versionFlg {
fmt.Printf("%s\n", VERSION)
os.Exit(0)
}
// this will fail if no remote or not a git repo
remote := gitRemote(*remoteFlg)
browserUrl := parseRemote(remote)
if *branchFlg {
branch := gitCurrentBranch()
browserUrl = makeBranchUrl(browserUrl, branch)
}
if *showOnlyFlg {
fmt.Printf("%s\n", browserUrl)
} else {
openBrowser(browserUrl)
}
}
func gitRemote(remoteName string) string {
cmd := exec.Command("git", "remote", "get-url", remoteName)
out, err := cmd.Output()
if err != nil {
fmt.Printf("Error: `git remote` call failed: %v", err)
os.Exit(1)
}
outStr := string(out)
return strings.TrimRight(outStr, "\n")
}
func gitCurrentBranch() string {
cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
out, err := cmd.Output()
if err != nil {
fmt.Printf("Error: failed getting current branch: %v", err)
os.Exit(1)
}
outStr := string(out)
return strings.TrimRight(outStr, "\n")
}
func parseRemote(remoteUrl string) string {
// sample ssh clone remote url
// git@github.com:<some-profile/<some-repo>.git
// sample https clone remote url
// https://github.com/<some-profile/<some-repo>.git
// should turn into
// https://github.com/<some-profile/<some-repo>
remoteUrl = strings.TrimSuffix(remoteUrl, ".git")
if strings.HasPrefix(remoteUrl, "http") {
// http(s) clone, nothing else to do
} else if strings.HasPrefix(remoteUrl, "git@") {
remoteUrl = strings.Replace(remoteUrl, ":", "/", -1)
remoteUrl = strings.TrimPrefix(remoteUrl, "git@")
remoteUrl = "https://" + remoteUrl
}
return remoteUrl
}
func codeHostFromUrl(remoteUrl string) string {
// it's a bit unclear about when this will actually return
// an err. it's posslbe to just return an empty string for .Host
url, err := url.Parse(remoteUrl)
if err != nil {
fmt.Printf("Error: failed parsing remoteUrl: %v", err)
os.Exit(1)
}
return url.Host
}
func makeBranchUrl(remoteUrl string, branch string) string {
codehost := codeHostFromUrl(remoteUrl)
var urlFmtString string
switch codehost {
case "github.com":
urlFmtString = "%s/tree/%s"
case "gitlab.com":
urlFmtString = "%s/-/tree/%s"
case "bitbucket.org":
urlFmtString = "%s/src/%s/"
default:
// just return the remoteURL if we don't recognize the code host
return remoteUrl
}
// this should not have a trailing / but make sure so the
// fmt strings don't double up the /
remoteUrl = strings.TrimSuffix(remoteUrl, "/")
return fmt.Sprintf(urlFmtString, remoteUrl, branch)
}
func openBrowser(url string) {
var cmd []string
switch runtime.GOOS {
case "linux":
cmd = []string{"xdg-open"}
case "darwin":
cmd = []string{"open"}
case "windows":
cmd = []string{"cmd", "/c", "start"}
default:
fmt.Printf("Error: unable to start a browser session")
os.Exit(1)
}
openCmd := exec.Command(cmd[0], append(cmd[1:], url)...)
openCmd.Start()
}