cli/github/project.go
2019-10-03 22:20:31 -05:00

181 lines
3.5 KiB
Go

package github
import (
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/github/gh/git"
"github.com/github/gh/utils"
)
type Project struct {
Name string
Owner string
Host string
Protocol string
}
func (p Project) String() string {
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
}
func (p *Project) SameAs(other *Project) bool {
return strings.ToLower(p.Owner) == strings.ToLower(other.Owner) &&
strings.ToLower(p.Name) == strings.ToLower(other.Name) &&
strings.ToLower(p.Host) == strings.ToLower(other.Host)
}
func (p *Project) WebURL(name, owner, path string) string {
if owner == "" {
owner = p.Owner
}
if name == "" {
name = p.Name
}
ownerWithName := fmt.Sprintf("%s/%s", owner, name)
if strings.Contains(ownerWithName, ".wiki") {
ownerWithName = strings.TrimSuffix(ownerWithName, ".wiki")
if path != "wiki" {
if strings.HasPrefix(path, "commits") {
path = "_history"
} else if path != "" {
path = fmt.Sprintf("_%s", path)
}
if path != "" {
path = utils.ConcatPaths("wiki", path)
} else {
path = "wiki"
}
}
}
url := fmt.Sprintf("%s://%s", p.Protocol, utils.ConcatPaths(p.Host, ownerWithName))
if path != "" {
url = utils.ConcatPaths(url, path)
}
return url
}
func (p *Project) GitURL(name, owner string, isSSH bool) (url string) {
if name == "" {
name = p.Name
}
if owner == "" {
owner = p.Owner
}
host := rawHost(p.Host)
if preferredProtocol() == "https" {
url = fmt.Sprintf("https://%s/%s/%s.git", host, owner, name)
} else if isSSH || preferredProtocol() == "ssh" {
url = fmt.Sprintf("git@%s:%s/%s.git", host, owner, name)
} else {
url = fmt.Sprintf("git://%s/%s/%s.git", host, owner, name)
}
return url
}
// Remove the scheme from host when the host url is absolute.
func rawHost(host string) string {
u, err := url.Parse(host)
utils.Check(err)
if u.IsAbs() {
return u.Host
} else {
return u.Path
}
}
func preferredProtocol() string {
userProtocol := os.Getenv("HUB_PROTOCOL")
if userProtocol == "" {
userProtocol, _ = git.Config("hub.protocol")
}
return userProtocol
}
func NewProjectFromURL(url *url.URL) (p *Project, err error) {
if !knownGitHubHostsInclude(url.Host) {
err = &GithubHostError{url}
return
}
parts := strings.SplitN(url.Path, "/", 4)
if len(parts) <= 2 {
err = fmt.Errorf("Invalid GitHub URL: %s", url)
return
}
name := strings.TrimSuffix(parts[2], ".git")
p = newProject(parts[1], name, url.Host, url.Scheme)
return
}
func NewProject(owner, name, host string) *Project {
return newProject(owner, name, host, "")
}
func newProject(owner, name, host, protocol string) *Project {
if strings.Contains(owner, "/") {
result := strings.SplitN(owner, "/", 2)
owner = result[0]
if name == "" {
name = result[1]
}
} else if strings.Contains(name, "/") {
result := strings.SplitN(name, "/", 2)
if owner == "" {
owner = result[0]
}
name = result[1]
}
if host == "" {
host = DefaultGitHubHost()
}
if host == "ssh.github.com" {
host = GitHubHost
}
if protocol != "http" && protocol != "https" {
protocol = ""
}
if protocol == "" {
h := CurrentConfig().Find(host)
if h != nil {
protocol = h.Protocol
}
}
if protocol == "" {
protocol = "https"
}
if owner == "" {
h := CurrentConfig().Find(host)
if h != nil {
owner = h.User
}
}
return &Project{
Name: name,
Owner: owner,
Host: host,
Protocol: protocol,
}
}
func SanitizeProjectName(name string) string {
name = filepath.Base(name)
return strings.Replace(name, " ", "-", -1)
}