@@ -13,6 +13,9 @@ import ( | |||||
"strings" | "strings" | ||||
"time" | "time" | ||||
"code.gitea.io/gitea/modules/setting" | |||||
"golang.org/x/net/proxy" | |||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
"code.gitea.io/gitea/modules/migrations/base" | "code.gitea.io/gitea/modules/migrations/base" | ||||
"code.gitea.io/gitea/modules/structs" | "code.gitea.io/gitea/modules/structs" | ||||
@@ -98,13 +101,41 @@ func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *Gith | |||||
) | ) | ||||
client = oauth2.NewClient(downloader.ctx, ts) | client = oauth2.NewClient(downloader.ctx, ts) | ||||
} else { | } else { | ||||
client = &http.Client{ | |||||
Transport: &http.Transport{ | |||||
Proxy: func(req *http.Request) (*url.URL, error) { | |||||
req.SetBasicAuth(userName, password) | |||||
return nil, nil | |||||
if setting.Migrations.Proxy != "" { | |||||
contextDialer, err := getProxyDialContext() | |||||
if err != nil { | |||||
log.Warn("Failed to use proxy for Github.", err) | |||||
client = &http.Client{ | |||||
Transport: &http.Transport{ | |||||
Proxy: func(req *http.Request) (*url.URL, error) { | |||||
req.SetBasicAuth(userName, password) | |||||
return nil, nil | |||||
}, | |||||
}, | |||||
} | |||||
} else { | |||||
client = &http.Client{ | |||||
Transport: &http.Transport{ | |||||
Proxy: func(req *http.Request) (*url.URL, error) { | |||||
req.SetBasicAuth(userName, password) | |||||
return nil, nil | |||||
}, | |||||
DialContext: contextDialer.DialContext, | |||||
}, | |||||
} | |||||
} | |||||
} else { | |||||
client = &http.Client{ | |||||
Transport: &http.Transport{ | |||||
Proxy: func(req *http.Request) (*url.URL, error) { | |||||
req.SetBasicAuth(userName, password) | |||||
return nil, nil | |||||
}, | |||||
}, | }, | ||||
}, | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -112,6 +143,25 @@ func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *Gith | |||||
return &downloader | return &downloader | ||||
} | } | ||||
func getProxyDialContext() (proxy.ContextDialer, error) { | |||||
authInfo := &proxy.Auth{ | |||||
setting.Migrations.Username, | |||||
setting.Migrations.Password, | |||||
} | |||||
dialSocksProxy, err := proxy.SOCKS5("tcp", setting.Migrations.Proxy, authInfo, proxy.Direct) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
if contextDialer, ok := dialSocksProxy.(proxy.ContextDialer); ok { | |||||
return contextDialer, nil | |||||
} else { | |||||
return nil, fmt.Errorf("It is not a valiad dialer.") | |||||
} | |||||
} | |||||
// SetContext set context | // SetContext set context | ||||
func (g *GithubDownloaderV3) SetContext(ctx context.Context) { | func (g *GithubDownloaderV3) SetContext(ctx context.Context) { | ||||
g.ctx = ctx | g.ctx = ctx | ||||
@@ -6,6 +6,7 @@ package repository | |||||
import ( | import ( | ||||
"fmt" | "fmt" | ||||
"net/url" | |||||
"os" | "os" | ||||
"path" | "path" | ||||
"strings" | "strings" | ||||
@@ -54,29 +55,34 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt | |||||
repo.NumWatches = 1 | repo.NumWatches = 1 | ||||
} | } | ||||
migrateTimeout := time.Duration(setting.Git.Timeout.Migrate) * time.Second | |||||
migrateTimeout := getMigrateTimeout(opts.CloneAddr) | |||||
var err error | var err error | ||||
if err = os.RemoveAll(repoPath); err != nil { | if err = os.RemoveAll(repoPath); err != nil { | ||||
return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err) | return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err) | ||||
} | } | ||||
log.Info("clone begin:" + opts.CloneAddr) | |||||
if err = git.Clone(opts.CloneAddr, repoPath, git.CloneRepoOptions{ | if err = git.Clone(opts.CloneAddr, repoPath, git.CloneRepoOptions{ | ||||
Mirror: true, | Mirror: true, | ||||
Quiet: true, | Quiet: true, | ||||
Timeout: migrateTimeout, | Timeout: migrateTimeout, | ||||
}); err != nil { | }); err != nil { | ||||
log.Warn("clone err") | |||||
return repo, fmt.Errorf("Clone: %v", err) | return repo, fmt.Errorf("Clone: %v", err) | ||||
} | } | ||||
log.Info("clone end:" + opts.CloneAddr) | |||||
if opts.Wiki { | if opts.Wiki { | ||||
log.Info("test wiki path begin") | |||||
wikiPath := models.WikiPath(u.Name, opts.RepoName) | wikiPath := models.WikiPath(u.Name, opts.RepoName) | ||||
wikiRemotePath := wikiRemoteURL(opts.CloneAddr) | wikiRemotePath := wikiRemoteURL(opts.CloneAddr) | ||||
log.Info("test wiki path end") | |||||
if len(wikiRemotePath) > 0 { | if len(wikiRemotePath) > 0 { | ||||
if err := os.RemoveAll(wikiPath); err != nil { | if err := os.RemoveAll(wikiPath); err != nil { | ||||
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | ||||
} | } | ||||
log.Info("wiki clone begin") | |||||
if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{ | if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{ | ||||
Mirror: true, | Mirror: true, | ||||
Quiet: true, | Quiet: true, | ||||
@@ -88,6 +94,7 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt | |||||
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | ||||
} | } | ||||
} | } | ||||
log.Info("wiki clone end") | |||||
} | } | ||||
} | } | ||||
@@ -137,9 +144,20 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt | |||||
repo, err = CleanUpMigrateInfo(repo) | repo, err = CleanUpMigrateInfo(repo) | ||||
} | } | ||||
log.Info("clone all end:" + opts.CloneAddr) | |||||
return repo, err | return repo, err | ||||
} | } | ||||
func getMigrateTimeout(urlClone string) time.Duration { | |||||
u, err := url.Parse(urlClone) | |||||
if err == nil && strings.EqualFold(u.Host, "github.com") { | |||||
return time.Duration(setting.Git.Timeout.GitHubMigrate) * time.Second | |||||
} | |||||
return time.Duration(setting.Git.Timeout.Migrate) * time.Second | |||||
} | |||||
// cleanUpMigrateGitConfig removes mirror info which prevents "push --all". | // cleanUpMigrateGitConfig removes mirror info which prevents "push --all". | ||||
// This also removes possible user credentials. | // This also removes possible user credentials. | ||||
func cleanUpMigrateGitConfig(configPath string) error { | func cleanUpMigrateGitConfig(configPath string) error { | ||||
@@ -27,12 +27,13 @@ var ( | |||||
EnableAutoGitWireProtocol bool | EnableAutoGitWireProtocol bool | ||||
PullRequestPushMessage bool | PullRequestPushMessage bool | ||||
Timeout struct { | Timeout struct { | ||||
Default int | |||||
Migrate int | |||||
Mirror int | |||||
Clone int | |||||
Pull int | |||||
GC int `ini:"GC"` | |||||
Default int | |||||
Migrate int | |||||
GitHubMigrate int | |||||
Mirror int | |||||
Clone int | |||||
Pull int | |||||
GC int `ini:"GC"` | |||||
} `ini:"git.timeout"` | } `ini:"git.timeout"` | ||||
}{ | }{ | ||||
DisableDiffHighlight: false, | DisableDiffHighlight: false, | ||||
@@ -45,19 +46,21 @@ var ( | |||||
EnableAutoGitWireProtocol: true, | EnableAutoGitWireProtocol: true, | ||||
PullRequestPushMessage: true, | PullRequestPushMessage: true, | ||||
Timeout: struct { | Timeout: struct { | ||||
Default int | |||||
Migrate int | |||||
Mirror int | |||||
Clone int | |||||
Pull int | |||||
GC int `ini:"GC"` | |||||
Default int | |||||
Migrate int | |||||
GitHubMigrate int | |||||
Mirror int | |||||
Clone int | |||||
Pull int | |||||
GC int `ini:"GC"` | |||||
}{ | }{ | ||||
Default: int(git.DefaultCommandExecutionTimeout / time.Second), | |||||
Migrate: 600, | |||||
Mirror: 300, | |||||
Clone: 300, | |||||
Pull: 300, | |||||
GC: 60, | |||||
Default: int(git.DefaultCommandExecutionTimeout / time.Second), | |||||
Migrate: 900, | |||||
GitHubMigrate: 1800, | |||||
Mirror: 1200, | |||||
Clone: 300, | |||||
Pull: 300, | |||||
GC: 60, | |||||
}, | }, | ||||
} | } | ||||
) | ) | ||||
@@ -9,6 +9,9 @@ var ( | |||||
Migrations = struct { | Migrations = struct { | ||||
MaxAttempts int | MaxAttempts int | ||||
RetryBackoff int | RetryBackoff int | ||||
Proxy string | |||||
Username string | |||||
Password string | |||||
}{ | }{ | ||||
MaxAttempts: 3, | MaxAttempts: 3, | ||||
RetryBackoff: 3, | RetryBackoff: 3, | ||||
@@ -19,4 +22,7 @@ func newMigrationsService() { | |||||
sec := Cfg.Section("migrations") | sec := Cfg.Section("migrations") | ||||
Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts) | Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts) | ||||
Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff) | Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff) | ||||
Migrations.Proxy = sec.Key("Proxy").MustString("") | |||||
Migrations.Username = sec.Key("Username").MustString("") | |||||
Migrations.Password = sec.Key("Password").MustString("") | |||||
} | } |