github.com/echohead/hub@v2.2.1+incompatible/github/localrepo.go (about)

     1  package github
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/github/hub/git"
     8  )
     9  
    10  func LocalRepo() (repo *GitHubRepo, err error) {
    11  	repo = &GitHubRepo{}
    12  
    13  	_, err = git.Dir()
    14  	if err != nil {
    15  		err = fmt.Errorf("fatal: Not a git repository")
    16  		return
    17  	}
    18  
    19  	return
    20  }
    21  
    22  type GitHubRepo struct {
    23  	remotes []Remote
    24  }
    25  
    26  func (r *GitHubRepo) loadRemotes() error {
    27  	if r.remotes != nil {
    28  		return nil
    29  	}
    30  
    31  	remotes, err := Remotes()
    32  	if err != nil {
    33  		return err
    34  	}
    35  	r.remotes = remotes
    36  
    37  	return nil
    38  }
    39  
    40  func (r *GitHubRepo) RemoteByName(name string) (*Remote, error) {
    41  	r.loadRemotes()
    42  
    43  	for _, remote := range r.remotes {
    44  		if remote.Name == name {
    45  			return &remote, nil
    46  		}
    47  	}
    48  
    49  	return nil, fmt.Errorf("No git remote with name %s", name)
    50  }
    51  
    52  func (r *GitHubRepo) remotesForPublish(owner string) (remotes []Remote) {
    53  	r.loadRemotes()
    54  	remotesMap := make(map[string]Remote)
    55  
    56  	if owner != "" {
    57  		for _, remote := range r.remotes {
    58  			p, e := remote.Project()
    59  			if e == nil && strings.ToLower(p.Owner) == owner {
    60  				remotesMap[remote.Name] = remote
    61  			}
    62  		}
    63  	}
    64  
    65  	names := OriginNamesInLookupOrder
    66  	for _, name := range names {
    67  		if _, ok := remotesMap[name]; ok {
    68  			continue
    69  		}
    70  
    71  		remote, err := r.RemoteByName(name)
    72  		if err == nil {
    73  			remotesMap[remote.Name] = *remote
    74  		}
    75  	}
    76  
    77  	for i := len(names) - 1; i >= 0; i-- {
    78  		name := names[i]
    79  		if remote, ok := remotesMap[name]; ok {
    80  			remotes = append(remotes, remote)
    81  			delete(remotesMap, name)
    82  		}
    83  	}
    84  
    85  	// anything other than names has higher priority
    86  	for _, remote := range remotesMap {
    87  		remotes = append([]Remote{remote}, remotes...)
    88  	}
    89  
    90  	return
    91  }
    92  
    93  func (r *GitHubRepo) CurrentBranch() (branch *Branch, err error) {
    94  	head, err := git.Head()
    95  	if err != nil {
    96  		err = fmt.Errorf("Aborted: not currently on any branch.")
    97  		return
    98  	}
    99  
   100  	branch = &Branch{r, head}
   101  	return
   102  }
   103  
   104  func (r *GitHubRepo) MasterBranch() (branch *Branch) {
   105  	origin, e := r.RemoteByName("origin")
   106  	var name string
   107  	if e == nil {
   108  		name, _ = git.BranchAtRef("refs", "remotes", origin.Name, "HEAD")
   109  	}
   110  
   111  	if name == "" {
   112  		name = "refs/heads/master"
   113  	}
   114  
   115  	branch = &Branch{r, name}
   116  
   117  	return
   118  }
   119  
   120  func (r *GitHubRepo) RemoteBranchAndProject(owner string, preferUpstream bool) (branch *Branch, project *Project, err error) {
   121  	r.loadRemotes()
   122  
   123  	for _, remote := range r.remotes {
   124  		if p, err := remote.Project(); err == nil {
   125  			project = p
   126  			break
   127  		}
   128  	}
   129  
   130  	branch, err = r.CurrentBranch()
   131  	if err != nil {
   132  		return
   133  	}
   134  
   135  	if project != nil {
   136  		branch = branch.PushTarget(owner, preferUpstream)
   137  		if branch != nil && branch.IsRemote() {
   138  			remote, e := r.RemoteByName(branch.RemoteName())
   139  			if e == nil {
   140  				project, err = remote.Project()
   141  				if err != nil {
   142  					return
   143  				}
   144  			}
   145  		}
   146  	}
   147  
   148  	return
   149  }
   150  
   151  func (r *GitHubRepo) OriginRemote() (remote *Remote, err error) {
   152  	r.loadRemotes()
   153  
   154  	if len(r.remotes) > 0 {
   155  		remote = &r.remotes[0]
   156  	}
   157  
   158  	if remote == nil {
   159  		err = fmt.Errorf("Can't find git remote origin")
   160  	}
   161  
   162  	return
   163  }
   164  
   165  func (r *GitHubRepo) MainProject() (project *Project, err error) {
   166  	origin, err := r.OriginRemote()
   167  	if err != nil {
   168  		err = fmt.Errorf("Aborted: the origin remote doesn't point to a GitHub repository.")
   169  
   170  		return
   171  	}
   172  
   173  	project, err = origin.Project()
   174  	if err != nil {
   175  		err = fmt.Errorf("Aborted: the origin remote doesn't point to a GitHub repository.")
   176  	}
   177  
   178  	return
   179  }
   180  
   181  func (r *GitHubRepo) CurrentProject() (project *Project, err error) {
   182  	project, err = r.UpstreamProject()
   183  	if err != nil {
   184  		project, err = r.MainProject()
   185  	}
   186  
   187  	return
   188  }
   189  
   190  func (r *GitHubRepo) UpstreamProject() (project *Project, err error) {
   191  	currentBranch, err := r.CurrentBranch()
   192  	if err != nil {
   193  		return
   194  	}
   195  
   196  	upstream, err := currentBranch.Upstream()
   197  	if err != nil {
   198  		return
   199  	}
   200  
   201  	remote, err := r.RemoteByName(upstream.RemoteName())
   202  	if err != nil {
   203  		return
   204  	}
   205  
   206  	project, err = remote.Project()
   207  
   208  	return
   209  }