| @@ -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("") | |||||
| } | } | ||||