github.com/pengwynn/gh@v1.0.1-0.20140118055701-14327ca3942e/github/project.go (about) 1 package github 2 3 import ( 4 "errors" 5 "fmt" 6 "github.com/jingweno/gh/git" 7 "github.com/jingweno/gh/utils" 8 "net/url" 9 "os" 10 "regexp" 11 "strings" 12 ) 13 14 type Project struct { 15 Name string 16 Owner string 17 Host string 18 } 19 20 func (p Project) String() string { 21 return fmt.Sprintf("%s/%s", p.Owner, p.Name) 22 } 23 24 func (p *Project) WebURL(name, owner, path string) string { 25 if owner == "" { 26 owner = p.Owner 27 } 28 if name == "" { 29 name = p.Name 30 } 31 32 ownerWithName := fmt.Sprintf("%s/%s", owner, name) 33 if strings.Contains(ownerWithName, ".wiki") { 34 ownerWithName = strings.TrimSuffix(ownerWithName, ".wiki") 35 if path != "wiki" { 36 if strings.HasPrefix(path, "commits") { 37 path = "_history" 38 } else if path != "" { 39 path = fmt.Sprintf("_%s", path) 40 } 41 42 if path != "" { 43 path = utils.ConcatPaths("wiki", path) 44 } else { 45 path = "wiki" 46 } 47 } 48 } 49 50 url := fmt.Sprintf("https://%s", utils.ConcatPaths(p.Host, ownerWithName)) 51 if path != "" { 52 url = utils.ConcatPaths(url, path) 53 } 54 55 return url 56 } 57 58 func (p *Project) GitURL(name, owner string, isSSH bool) (url string) { 59 if name == "" { 60 name = p.Name 61 } 62 if owner == "" { 63 owner = p.Owner 64 } 65 66 host := rawHost(p.Host) 67 68 if useHttpProtocol() { 69 url = fmt.Sprintf("https://%s/%s/%s.git", host, owner, name) 70 } else if isSSH { 71 url = fmt.Sprintf("git@%s:%s/%s.git", host, owner, name) 72 } else { 73 url = fmt.Sprintf("git://%s/%s/%s.git", host, owner, name) 74 } 75 76 return url 77 } 78 79 // Remove the scheme from host when the credential url is absolute. 80 func rawHost(host string) string { 81 u, err := url.Parse(host) 82 utils.Check(err) 83 84 if u.IsAbs() { 85 return u.Host 86 } else { 87 return u.Path 88 } 89 } 90 91 func useHttpProtocol() bool { 92 https := os.Getenv("GH_PROTOCOL") 93 if https == "" { 94 https, _ = git.Config("gh.protocol") 95 } 96 97 return https == "https" 98 } 99 100 func NewProjectFromURL(url *url.URL) (p *Project, err error) { 101 if !knownHosts().Include(url.Host) { 102 err = fmt.Errorf("Invalid GitHub URL: %s", url) 103 return 104 } 105 106 parts := strings.SplitN(url.Path, "/", 4) 107 if len(parts) <= 2 { 108 err = fmt.Errorf("Invalid GitHub URL: %s", url) 109 return 110 } 111 112 name := strings.TrimSuffix(parts[2], ".git") 113 p = NewProject(parts[1], name, url.Host) 114 115 return 116 } 117 118 func NewProject(owner, name, host string) *Project { 119 if strings.Contains(owner, "/") { 120 result := strings.SplitN(owner, "/", 2) 121 owner = result[0] 122 if name == "" { 123 name = result[1] 124 } 125 } else if strings.Contains(name, "/") { 126 result := strings.SplitN(name, "/", 2) 127 if owner == "" { 128 owner = result[0] 129 } 130 name = result[1] 131 } 132 133 if host == "" { 134 host = DefaultHost() 135 } 136 137 if owner == "" { 138 c := CurrentConfigs().PromptFor(host) 139 owner = c.User 140 } 141 142 if name == "" { 143 name, _ = utils.DirName() 144 } 145 146 return &Project{Name: name, Owner: owner, Host: host} 147 } 148 149 func parseOwnerAndName(remote string) (owner string, name string) { 150 url, err := mustMatchGitHubURL(remote) 151 utils.Check(err) 152 153 return url[1], url[2] 154 } 155 156 func MatchURL(url string) []string { 157 httpRegex := regexp.MustCompile("https://github\\.com/(.+)/(.+?)(\\.git|$)") 158 if httpRegex.MatchString(url) { 159 return httpRegex.FindStringSubmatch(url) 160 } 161 162 readOnlyRegex := regexp.MustCompile("git://.*github\\.com/(.+)/(.+?)(\\.git|$)") 163 if readOnlyRegex.MatchString(url) { 164 return readOnlyRegex.FindStringSubmatch(url) 165 } 166 167 sshRegex := regexp.MustCompile("git@github\\.com:(.+)/(.+?)(\\.git|$)") 168 if sshRegex.MatchString(url) { 169 return sshRegex.FindStringSubmatch(url) 170 } 171 172 return nil 173 } 174 175 func mustMatchGitHubURL(url string) ([]string, error) { 176 githubURL := MatchURL(url) 177 if githubURL == nil { 178 return nil, errors.New("The origin remote doesn't point to a GitHub repository: " + url) 179 } 180 181 return githubURL, nil 182 }