2020-12-11 09:07:29 +00:00
|
|
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a MIT-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"code.gitea.io/tea/modules/git"
|
|
|
|
"code.gitea.io/tea/modules/utils"
|
|
|
|
|
|
|
|
gogit "github.com/go-git/go-git/v5"
|
|
|
|
)
|
|
|
|
|
|
|
|
// InitCommand resolves the application context, and returns the active login, and if
|
|
|
|
// available the repo slug. It does this by reading the config file for logins, parsing
|
|
|
|
// the remotes of the .git repo specified in repoFlag or $PWD, and using overrides from
|
|
|
|
// command flags. If a local git repo can't be found, repo slug values are unset.
|
|
|
|
func InitCommand(repoFlag, loginFlag, remoteFlag string) (login *Login, owner string, reponame string) {
|
2020-12-12 13:28:37 +00:00
|
|
|
err := loadConfig()
|
2020-12-11 09:07:29 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var repoSlug string
|
|
|
|
var repoPath string // empty means PWD
|
|
|
|
var repoFlagPathExists bool
|
|
|
|
|
|
|
|
// check if repoFlag can be interpreted as path to local repo.
|
|
|
|
if len(repoFlag) != 0 {
|
|
|
|
repoFlagPathExists, err = utils.PathExists(repoFlag)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err.Error())
|
|
|
|
}
|
|
|
|
if repoFlagPathExists {
|
|
|
|
repoPath = repoFlag
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// try to read git repo & extract context, ignoring if PWD is not a repo
|
|
|
|
login, repoSlug, err = contextFromLocalRepo(repoPath, remoteFlag)
|
|
|
|
if err != nil && err != gogit.ErrRepositoryNotExists {
|
|
|
|
log.Fatal(err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
// if repoFlag is not a path, use it to override repoSlug
|
|
|
|
if len(repoFlag) != 0 && !repoFlagPathExists {
|
|
|
|
repoSlug = repoFlag
|
|
|
|
}
|
|
|
|
|
|
|
|
// override login from flag, or use default login if repo based detection failed
|
|
|
|
if len(loginFlag) != 0 {
|
|
|
|
login = GetLoginByName(loginFlag)
|
|
|
|
if login == nil {
|
|
|
|
log.Fatalf("Login name '%s' does not exist", loginFlag)
|
|
|
|
}
|
|
|
|
} else if login == nil {
|
|
|
|
if login, err = GetDefaultLogin(); err != nil {
|
|
|
|
log.Fatal(err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// parse reposlug (owner falling back to login owner if reposlug contains only repo name)
|
|
|
|
owner, reponame = utils.GetOwnerAndRepo(repoSlug, login.User)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-12-12 13:28:37 +00:00
|
|
|
// contextFromLocalRepo discovers login & repo slug from the default branch remote of the given local repo
|
2020-12-11 09:07:29 +00:00
|
|
|
func contextFromLocalRepo(repoValue, remoteValue string) (*Login, string, error) {
|
|
|
|
repo, err := git.RepoFromPath(repoValue)
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", err
|
|
|
|
}
|
|
|
|
gitConfig, err := repo.Config()
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no remote
|
|
|
|
if len(gitConfig.Remotes) == 0 {
|
|
|
|
return nil, "", errors.New("No remote(s) found in this Git repository")
|
|
|
|
}
|
|
|
|
|
|
|
|
// if only one remote exists
|
|
|
|
if len(gitConfig.Remotes) >= 1 && len(remoteValue) == 0 {
|
|
|
|
for remote := range gitConfig.Remotes {
|
|
|
|
remoteValue = remote
|
|
|
|
}
|
|
|
|
if len(gitConfig.Remotes) > 1 {
|
|
|
|
// if master branch is present, use it as the default remote
|
|
|
|
masterBranch, ok := gitConfig.Branches["master"]
|
|
|
|
if ok {
|
|
|
|
if len(masterBranch.Remote) > 0 {
|
|
|
|
remoteValue = masterBranch.Remote
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
remoteConfig, ok := gitConfig.Remotes[remoteValue]
|
|
|
|
if !ok || remoteConfig == nil {
|
|
|
|
return nil, "", errors.New("Remote " + remoteValue + " not found in this Git repository")
|
|
|
|
}
|
|
|
|
|
2020-12-12 13:28:37 +00:00
|
|
|
for _, l := range config.Logins {
|
2020-12-11 09:07:29 +00:00
|
|
|
for _, u := range remoteConfig.URLs {
|
|
|
|
p, err := git.ParseURL(strings.TrimSpace(u))
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", fmt.Errorf("Git remote URL parse failed: %s", err.Error())
|
|
|
|
}
|
|
|
|
if strings.EqualFold(p.Scheme, "http") || strings.EqualFold(p.Scheme, "https") {
|
|
|
|
if strings.HasPrefix(u, l.URL) {
|
|
|
|
ps := strings.Split(p.Path, "/")
|
|
|
|
path := strings.Join(ps[len(ps)-2:], "/")
|
|
|
|
return &l, strings.TrimSuffix(path, ".git"), nil
|
|
|
|
}
|
|
|
|
} else if strings.EqualFold(p.Scheme, "ssh") {
|
|
|
|
if l.GetSSHHost() == strings.Split(p.Host, ":")[0] {
|
|
|
|
return &l, strings.TrimLeft(strings.TrimSuffix(p.Path, ".git"), "/"), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, "", errors.New("No Gitea login found. You might want to specify --repo (and --login) to work outside of a repository")
|
|
|
|
}
|