1package commands
2
3import (
4	"fmt"
5	"regexp"
6	"strings"
7
8	"github.com/github/hub/git"
9	"github.com/github/hub/github"
10	"github.com/github/hub/utils"
11)
12
13var cmdRemote = &Command{
14	Run:          remote,
15	GitExtension: true,
16	Usage: `
17remote add [-p] [<OPTIONS>] <USER>[/<REPOSITORY>]
18remote set-url [-p] [<OPTIONS>] <NAME> <USER>[/<REPOSITORY>]
19`,
20	Long: `Add a git remote for a GitHub repository.
21
22## Options:
23	-p
24		(Deprecated) Use the ''ssh:'' protocol instead of ''git:'' for the remote URL.
25		The writeable ''ssh:'' protocol is automatically used for own repos, GitHub
26		Enterprise remotes, and private or pushable repositories.
27
28	<USER>[/<REPOSITORY>]
29		If <USER> is "origin", that value will be substituted for your GitHub
30		username. <REPOSITORY> defaults to the name of the current working directory.
31
32## Examples:
33		$ hub remote add jingweno
34		> git remote add jingweno git://github.com/jingweno/REPO.git
35
36		$ hub remote add origin
37		> git remote add origin git@github.com:USER/REPO.git
38
39## See also:
40
41hub-fork(1), hub(1), git-remote(1)
42`,
43}
44
45func init() {
46	CmdRunner.Use(cmdRemote)
47}
48
49/*
50 */
51func remote(command *Command, args *Args) {
52	if !args.IsParamsEmpty() && (args.FirstParam() == "add" || args.FirstParam() == "set-url") {
53		transformRemoteArgs(args)
54	}
55}
56
57func transformRemoteArgs(args *Args) {
58	ownerWithName := args.LastParam()
59
60	re := regexp.MustCompile(fmt.Sprintf(`^%s(/%s)?$`, OwnerRe, NameRe))
61	if !re.MatchString(ownerWithName) {
62		return
63	}
64	owner := ownerWithName
65	name := ""
66	if strings.Contains(ownerWithName, "/") {
67		parts := strings.SplitN(ownerWithName, "/", 2)
68		owner, name = parts[0], parts[1]
69	}
70
71	localRepo, err := github.LocalRepo()
72	utils.Check(err)
73
74	var host string
75	mainProject, err := localRepo.MainProject()
76	if err == nil {
77		host = mainProject.Host
78	}
79
80	if name == "" {
81		if mainProject != nil {
82			name = mainProject.Name
83		} else {
84			dirName, err := git.WorkdirName()
85			utils.Check(err)
86			name = github.SanitizeProjectName(dirName)
87		}
88	}
89
90	var hostConfig *github.Host
91	if host == "" {
92		hostConfig, err = github.CurrentConfig().DefaultHost()
93	} else {
94		hostConfig, err = github.CurrentConfig().PromptForHost(host)
95	}
96	if err != nil {
97		utils.Check(github.FormatError("adding remote", err))
98	}
99	host = hostConfig.Host
100
101	p := utils.NewArgsParser()
102	p.RegisterValue("-t")
103	p.RegisterValue("-m")
104	params, _ := p.Parse(args.Params)
105	if len(params) > 3 {
106		return
107	}
108
109	for i, pi := range p.PositionalIndices {
110		if i == 1 && strings.Contains(params[i], "/") {
111			args.ReplaceParam(pi, owner)
112		} else if i == 2 {
113			args.RemoveParam(pi)
114		}
115	}
116	if len(params) == 2 && owner == "origin" {
117		owner = hostConfig.User
118	}
119
120	if strings.EqualFold(owner, hostConfig.User) {
121		owner = hostConfig.User
122	}
123
124	project := github.NewProject(owner, name, host)
125
126	isPrivate := parseRemotePrivateFlag(args) || owner == hostConfig.User || project.Host != github.GitHubHost
127	if !isPrivate {
128		gh := github.NewClient(project.Host)
129		repo, err := gh.Repository(project)
130		if err != nil {
131			if strings.Contains(err.Error(), "HTTP 404") {
132				err = fmt.Errorf("Error: repository %s/%s doesn't exist", project.Owner, project.Name)
133			}
134			utils.Check(err)
135		}
136		isPrivate = repo.Private || repo.Permissions.Push
137	}
138
139	url := project.GitURL("", "", isPrivate)
140	args.AppendParams(url)
141}
142
143func parseRemotePrivateFlag(args *Args) bool {
144	if i := args.IndexOfParam("-p"); i != -1 {
145		args.RemoveParam(i)
146		return true
147	}
148
149	return false
150}
151