@@ -1077,9 +1077,11 @@ func CleanUpMigrateInfo(repo *Repository) (*Repository, error) { | |||
} | |||
} | |||
if err := cleanUpMigrateGitConfig(repo.GitConfigPath()); err != nil { | |||
return repo, fmt.Errorf("cleanUpMigrateGitConfig: %v", err) | |||
_, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath) | |||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { | |||
return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err) | |||
} | |||
if repo.HasWiki() { | |||
if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil { | |||
return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %v", err) |
@@ -20,7 +20,6 @@ import ( | |||
"github.com/Unknwon/com" | |||
"github.com/go-xorm/xorm" | |||
"gopkg.in/ini.v1" | |||
) | |||
// MirrorQueue holds an UniqueQueue object of the mirror | |||
@@ -71,11 +70,18 @@ func (m *Mirror) ScheduleNextUpdate() { | |||
} | |||
func remoteAddress(repoPath string) (string, error) { | |||
cfg, err := ini.Load(GitConfigPath(repoPath)) | |||
cmd := git.NewCommand("remote", "get-url", "origin") | |||
result, err := cmd.RunInDir(repoPath) | |||
if err != nil { | |||
if strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { | |||
return "", nil | |||
} | |||
return "", err | |||
} | |||
return cfg.Section("remote \"origin\"").Key("url").Value(), nil | |||
if len(result) > 0 { | |||
return result[:len(result)-1], nil | |||
} | |||
return "", nil | |||
} | |||
func (m *Mirror) readAddress() { | |||
@@ -115,14 +121,15 @@ func (m *Mirror) FullAddress() string { | |||
// SaveAddress writes new address to Git repository config. | |||
func (m *Mirror) SaveAddress(addr string) error { | |||
configPath := m.Repo.GitConfigPath() | |||
cfg, err := ini.Load(configPath) | |||
if err != nil { | |||
return fmt.Errorf("Load: %v", err) | |||
repoPath := m.Repo.RepoPath() | |||
// Remove old origin | |||
_, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath) | |||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { | |||
return err | |||
} | |||
cfg.Section("remote \"origin\"").Key("url").SetValue(addr) | |||
return cfg.SaveToIndent(configPath, "\t") | |||
_, err = git.NewCommand("remote", "add", "origin", addr).RunInDir(repoPath) | |||
return err | |||
} | |||
// gitShortEmptySha Git short empty SHA |
@@ -567,7 +567,9 @@ mirror_prune_desc = Remove obsolete remote-tracking references | |||
mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable automatic sync. | |||
mirror_interval_invalid = The mirror interval is not valid. | |||
mirror_address = Clone From URL | |||
mirror_address_desc = Include any required authorization credentials in the URL. | |||
mirror_address_desc = Include any required authorization credentials in the URL. These must be url escaped as appropriate | |||
mirror_address_url_invalid = The provided url is invalid. You must escape all components of the url correctly. | |||
mirror_address_protocol_invalid = The provided url is invalid. Only http(s):// or git:// locations can be mirrored from. | |||
mirror_last_synced = Last Synchronized | |||
watchers = Watchers | |||
stargazers = Stargazers |
@@ -7,9 +7,13 @@ package repo | |||
import ( | |||
"errors" | |||
"net/url" | |||
"regexp" | |||
"strings" | |||
"time" | |||
"mvdan.cc/xurls/v2" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/auth" | |||
"code.gitea.io/gitea/modules/base" | |||
@@ -32,6 +36,8 @@ const ( | |||
tplProtectedBranch base.TplName = "repo/settings/protected_branch" | |||
) | |||
var validFormAddress *regexp.Regexp | |||
// Settings show a repository's settings page | |||
func Settings(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.settings") | |||
@@ -145,7 +151,38 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | |||
return | |||
} | |||
} | |||
if err := ctx.Repo.Mirror.SaveAddress(form.MirrorAddress); err != nil { | |||
// Validate the form.MirrorAddress | |||
u, err := url.Parse(form.MirrorAddress) | |||
if err != nil { | |||
ctx.Data["Err_MirrorAddress"] = true | |||
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form) | |||
return | |||
} | |||
if u.Opaque != "" || !(u.Scheme == "http" || u.Scheme == "https" || u.Scheme == "git") { | |||
ctx.Data["Err_MirrorAddress"] = true | |||
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, &form) | |||
return | |||
} | |||
// Now use xurls | |||
address := validFormAddress.FindString(form.MirrorAddress) | |||
if address != form.MirrorAddress && form.MirrorAddress != "" { | |||
ctx.Data["Err_MirrorAddress"] = true | |||
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form) | |||
return | |||
} | |||
if u.EscapedPath() == "" || u.Host == "" || !u.IsAbs() { | |||
ctx.Data["Err_MirrorAddress"] = true | |||
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form) | |||
return | |||
} | |||
address = u.String() | |||
if err := ctx.Repo.Mirror.SaveAddress(address); err != nil { | |||
ctx.ServerError("SaveAddress", err) | |||
return | |||
} | |||
@@ -682,3 +719,11 @@ func DeleteDeployKey(ctx *context.Context) { | |||
"redirect": ctx.Repo.RepoLink + "/settings/keys", | |||
}) | |||
} | |||
func init() { | |||
var err error | |||
validFormAddress, err = xurls.StrictMatchingScheme(`(https?)|(git)://`) | |||
if err != nil { | |||
panic(err) | |||
} | |||
} |
@@ -62,7 +62,7 @@ | |||
<label for="interval">{{.i18n.Tr "repo.mirror_interval"}}</label> | |||
<input id="interval" name="interval" value="{{.MirrorInterval}}"> | |||
</div> | |||
<div class="field"> | |||
<div class="field {{if .Err_MirrorAddress}}error{{end}}"> | |||
<label for="mirror_address">{{.i18n.Tr "repo.mirror_address"}}</label> | |||
<input id="mirror_address" name="mirror_address" value="{{.Mirror.FullAddress}}" required> | |||
<p class="help">{{.i18n.Tr "repo.mirror_address_desc"}}</p> |