diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2021-11-16 21:30:11 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-16 21:30:11 +0800 |
commit | 48ccd325a1b81a58ac6d1d5d94fc4e90974599ea (patch) | |
tree | e7bb31d69343dd9845a1b0df013b093c8720f14b /modules | |
parent | 447428f44659cee0e94e1c444f6291defac2bda2 (diff) | |
download | gitea-48ccd325a1b81a58ac6d1d5d94fc4e90974599ea.tar.gz gitea-48ccd325a1b81a58ac6d1d5d94fc4e90974599ea.zip |
Move some functions into services/repository (#17660)
Diffstat (limited to 'modules')
-rw-r--r-- | modules/cron/cron.go | 94 | ||||
-rw-r--r-- | modules/cron/setting.go | 87 | ||||
-rw-r--r-- | modules/cron/tasks.go | 169 | ||||
-rw-r--r-- | modules/cron/tasks_basic.go | 141 | ||||
-rw-r--r-- | modules/cron/tasks_extended.go | 165 | ||||
-rw-r--r-- | modules/repository/adopt.go | 295 | ||||
-rw-r--r-- | modules/repository/archive.go | 20 | ||||
-rw-r--r-- | modules/repository/fork.go | 171 | ||||
-rw-r--r-- | modules/repository/fork_test.go | 30 | ||||
-rw-r--r-- | modules/repository/init.go | 86 |
10 files changed, 0 insertions, 1258 deletions
diff --git a/modules/cron/cron.go b/modules/cron/cron.go deleted file mode 100644 index ae309bd866..0000000000 --- a/modules/cron/cron.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2014 The Gogs Authors. All rights reserved. -// Copyright 2019 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 cron - -import ( - "context" - "time" - - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/sync" - - "github.com/gogs/cron" -) - -var c = cron.New() - -// Prevent duplicate running tasks. -var taskStatusTable = sync.NewStatusTable() - -// NewContext begins cron tasks -// Each cron task is run within the shutdown context as a running server -// AtShutdown the cron server is stopped -func NewContext() { - initBasicTasks() - initExtendedTasks() - - lock.Lock() - for _, task := range tasks { - if task.IsEnabled() && task.DoRunAtStart() { - go task.Run() - } - } - - c.Start() - started = true - lock.Unlock() - graceful.GetManager().RunAtShutdown(context.Background(), func() { - c.Stop() - lock.Lock() - started = false - lock.Unlock() - }) - -} - -// TaskTableRow represents a task row in the tasks table -type TaskTableRow struct { - Name string - Spec string - Next time.Time - Prev time.Time - ExecTimes int64 -} - -// TaskTable represents a table of tasks -type TaskTable []*TaskTableRow - -// ListTasks returns all running cron tasks. -func ListTasks() TaskTable { - entries := c.Entries() - eMap := map[string]*cron.Entry{} - for _, e := range entries { - eMap[e.Description] = e - } - lock.Lock() - defer lock.Unlock() - tTable := make([]*TaskTableRow, 0, len(tasks)) - for _, task := range tasks { - spec := "-" - var ( - next time.Time - prev time.Time - ) - if e, ok := eMap[task.Name]; ok { - spec = e.Spec - next = e.Next - prev = e.Prev - } - task.lock.Lock() - tTable = append(tTable, &TaskTableRow{ - Name: task.Name, - Spec: spec, - Next: next, - Prev: prev, - ExecTimes: task.ExecTimes, - }) - task.lock.Unlock() - } - - return tTable -} diff --git a/modules/cron/setting.go b/modules/cron/setting.go deleted file mode 100644 index d55e5b60ad..0000000000 --- a/modules/cron/setting.go +++ /dev/null @@ -1,87 +0,0 @@ -// 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 cron - -import ( - "time" - - "code.gitea.io/gitea/models" - "github.com/unknwon/i18n" -) - -// Config represents a basic configuration interface that cron task -type Config interface { - IsEnabled() bool - DoRunAtStart() bool - GetSchedule() string - FormatMessage(name, status string, doer *models.User, args ...interface{}) string - DoNoticeOnSuccess() bool -} - -// BaseConfig represents the basic config for a Cron task -type BaseConfig struct { - Enabled bool - RunAtStart bool - Schedule string - NoSuccessNotice bool -} - -// OlderThanConfig represents a cron task with OlderThan setting -type OlderThanConfig struct { - BaseConfig - OlderThan time.Duration -} - -// UpdateExistingConfig represents a cron task with UpdateExisting setting -type UpdateExistingConfig struct { - BaseConfig - UpdateExisting bool -} - -// CleanupHookTaskConfig represents a cron task with settings to cleanup hook_task -type CleanupHookTaskConfig struct { - BaseConfig - CleanupType string - OlderThan time.Duration - NumberToKeep int -} - -// GetSchedule returns the schedule for the base config -func (b *BaseConfig) GetSchedule() string { - return b.Schedule -} - -// IsEnabled returns the enabled status for the config -func (b *BaseConfig) IsEnabled() bool { - return b.Enabled -} - -// DoRunAtStart returns whether the task should be run at the start -func (b *BaseConfig) DoRunAtStart() bool { - return b.RunAtStart -} - -// DoNoticeOnSuccess returns whether a success notice should be posted -func (b *BaseConfig) DoNoticeOnSuccess() bool { - return !b.NoSuccessNotice -} - -// FormatMessage returns a message for the task -func (b *BaseConfig) FormatMessage(name, status string, doer *models.User, args ...interface{}) string { - realArgs := make([]interface{}, 0, len(args)+2) - realArgs = append(realArgs, i18n.Tr("en-US", "admin.dashboard."+name)) - if doer == nil { - realArgs = append(realArgs, "(Cron)") - } else { - realArgs = append(realArgs, doer.Name) - } - if len(args) > 0 { - realArgs = append(realArgs, args...) - } - if doer == nil || (doer.ID == -1 && doer.Name == "(Cron)") { - return i18n.Tr("en-US", "admin.dashboard.cron."+status, realArgs...) - } - return i18n.Tr("en-US", "admin.dashboard.task."+status, realArgs...) -} diff --git a/modules/cron/tasks.go b/modules/cron/tasks.go deleted file mode 100644 index 56c363e0b8..0000000000 --- a/modules/cron/tasks.go +++ /dev/null @@ -1,169 +0,0 @@ -// 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 cron - -import ( - "context" - "fmt" - "reflect" - "sync" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/setting" -) - -var lock = sync.Mutex{} -var started = false -var tasks = []*Task{} -var tasksMap = map[string]*Task{} - -// Task represents a Cron task -type Task struct { - lock sync.Mutex - Name string - config Config - fun func(context.Context, *models.User, Config) error - ExecTimes int64 -} - -// DoRunAtStart returns if this task should run at the start -func (t *Task) DoRunAtStart() bool { - return t.config.DoRunAtStart() -} - -// IsEnabled returns if this task is enabled as cron task -func (t *Task) IsEnabled() bool { - return t.config.IsEnabled() -} - -// GetConfig will return a copy of the task's config -func (t *Task) GetConfig() Config { - if reflect.TypeOf(t.config).Kind() == reflect.Ptr { - // Pointer: - return reflect.New(reflect.ValueOf(t.config).Elem().Type()).Interface().(Config) - } - // Not pointer: - return reflect.New(reflect.TypeOf(t.config)).Elem().Interface().(Config) -} - -// Run will run the task incrementing the cron counter with no user defined -func (t *Task) Run() { - t.RunWithUser(&models.User{ - ID: -1, - Name: "(Cron)", - LowerName: "(cron)", - }, t.config) -} - -// RunWithUser will run the task incrementing the cron counter at the time with User -func (t *Task) RunWithUser(doer *models.User, config Config) { - if !taskStatusTable.StartIfNotRunning(t.Name) { - return - } - t.lock.Lock() - if config == nil { - config = t.config - } - t.ExecTimes++ - t.lock.Unlock() - defer func() { - taskStatusTable.Stop(t.Name) - if err := recover(); err != nil { - // Recover a panic within the - combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2)) - log.Error("PANIC whilst running task: %s Value: %v", t.Name, combinedErr) - } - }() - graceful.GetManager().RunWithShutdownContext(func(baseCtx context.Context) { - ctx, cancel := context.WithCancel(baseCtx) - defer cancel() - pm := process.GetManager() - pid := pm.Add(config.FormatMessage(t.Name, "process", doer), cancel) - defer pm.Remove(pid) - if err := t.fun(ctx, doer, config); err != nil { - if db.IsErrCancelled(err) { - message := err.(db.ErrCancelled).Message - if err := models.CreateNotice(models.NoticeTask, config.FormatMessage(t.Name, "aborted", doer, message)); err != nil { - log.Error("CreateNotice: %v", err) - } - return - } - if err := models.CreateNotice(models.NoticeTask, config.FormatMessage(t.Name, "error", doer, err)); err != nil { - log.Error("CreateNotice: %v", err) - } - return - } - if config.DoNoticeOnSuccess() { - if err := models.CreateNotice(models.NoticeTask, config.FormatMessage(t.Name, "finished", doer)); err != nil { - log.Error("CreateNotice: %v", err) - } - } - }) -} - -// GetTask gets the named task -func GetTask(name string) *Task { - lock.Lock() - defer lock.Unlock() - log.Info("Getting %s in %v", name, tasksMap[name]) - - return tasksMap[name] -} - -// RegisterTask allows a task to be registered with the cron service -func RegisterTask(name string, config Config, fun func(context.Context, *models.User, Config) error) error { - log.Debug("Registering task: %s", name) - _, err := setting.GetCronSettings(name, config) - if err != nil { - log.Error("Unable to register cron task with name: %s Error: %v", name, err) - return err - } - - task := &Task{ - Name: name, - config: config, - fun: fun, - } - lock.Lock() - locked := true - defer func() { - if locked { - lock.Unlock() - } - }() - if _, has := tasksMap[task.Name]; has { - log.Error("A task with this name: %s has already been registered", name) - return fmt.Errorf("duplicate task with name: %s", task.Name) - } - - if config.IsEnabled() { - // We cannot use the entry return as there is no way to lock it - if _, err = c.AddJob(name, config.GetSchedule(), task); err != nil { - log.Error("Unable to register cron task with name: %s Error: %v", name, err) - return err - } - } - - tasks = append(tasks, task) - tasksMap[task.Name] = task - if started && config.IsEnabled() && config.DoRunAtStart() { - lock.Unlock() - locked = false - task.Run() - } - - return nil -} - -// RegisterTaskFatal will register a task but if there is an error log.Fatal -func RegisterTaskFatal(name string, config Config, fun func(context.Context, *models.User, Config) error) { - if err := RegisterTask(name, config, fun); err != nil { - log.Fatal("Unable to register cron task %s Error: %v", name, err) - } -} diff --git a/modules/cron/tasks_basic.go b/modules/cron/tasks_basic.go deleted file mode 100644 index a42c031b36..0000000000 --- a/modules/cron/tasks_basic.go +++ /dev/null @@ -1,141 +0,0 @@ -// 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 cron - -import ( - "context" - "time" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/migrations" - repository_service "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/services/auth" - mirror_service "code.gitea.io/gitea/services/mirror" -) - -func registerUpdateMirrorTask() { - RegisterTaskFatal("update_mirrors", &BaseConfig{ - Enabled: true, - RunAtStart: false, - Schedule: "@every 10m", - NoSuccessNotice: true, - }, func(ctx context.Context, _ *models.User, _ Config) error { - return mirror_service.Update(ctx) - }) -} - -func registerRepoHealthCheck() { - type RepoHealthCheckConfig struct { - BaseConfig - Timeout time.Duration - Args []string `delim:" "` - } - RegisterTaskFatal("repo_health_check", &RepoHealthCheckConfig{ - BaseConfig: BaseConfig{ - Enabled: true, - RunAtStart: false, - Schedule: "@midnight", - }, - Timeout: 60 * time.Second, - Args: []string{}, - }, func(ctx context.Context, _ *models.User, config Config) error { - rhcConfig := config.(*RepoHealthCheckConfig) - return repository_service.GitFsck(ctx, rhcConfig.Timeout, rhcConfig.Args) - }) -} - -func registerCheckRepoStats() { - RegisterTaskFatal("check_repo_stats", &BaseConfig{ - Enabled: true, - RunAtStart: true, - Schedule: "@midnight", - }, func(ctx context.Context, _ *models.User, _ Config) error { - return models.CheckRepoStats(ctx) - }) -} - -func registerArchiveCleanup() { - RegisterTaskFatal("archive_cleanup", &OlderThanConfig{ - BaseConfig: BaseConfig{ - Enabled: true, - RunAtStart: true, - Schedule: "@midnight", - }, - OlderThan: 24 * time.Hour, - }, func(ctx context.Context, _ *models.User, config Config) error { - acConfig := config.(*OlderThanConfig) - return models.DeleteOldRepositoryArchives(ctx, acConfig.OlderThan) - }) -} - -func registerSyncExternalUsers() { - RegisterTaskFatal("sync_external_users", &UpdateExistingConfig{ - BaseConfig: BaseConfig{ - Enabled: true, - RunAtStart: false, - Schedule: "@midnight", - }, - UpdateExisting: true, - }, func(ctx context.Context, _ *models.User, config Config) error { - realConfig := config.(*UpdateExistingConfig) - return auth.SyncExternalUsers(ctx, realConfig.UpdateExisting) - }) -} - -func registerDeletedBranchesCleanup() { - RegisterTaskFatal("deleted_branches_cleanup", &OlderThanConfig{ - BaseConfig: BaseConfig{ - Enabled: true, - RunAtStart: true, - Schedule: "@midnight", - }, - OlderThan: 24 * time.Hour, - }, func(ctx context.Context, _ *models.User, config Config) error { - realConfig := config.(*OlderThanConfig) - models.RemoveOldDeletedBranches(ctx, realConfig.OlderThan) - return nil - }) -} - -func registerUpdateMigrationPosterID() { - RegisterTaskFatal("update_migration_poster_id", &BaseConfig{ - Enabled: true, - RunAtStart: true, - Schedule: "@midnight", - }, func(ctx context.Context, _ *models.User, _ Config) error { - return migrations.UpdateMigrationPosterID(ctx) - }) -} - -func registerCleanupHookTaskTable() { - RegisterTaskFatal("cleanup_hook_task_table", &CleanupHookTaskConfig{ - BaseConfig: BaseConfig{ - Enabled: true, - RunAtStart: false, - Schedule: "@midnight", - }, - CleanupType: "OlderThan", - OlderThan: 168 * time.Hour, - NumberToKeep: 10, - }, func(ctx context.Context, _ *models.User, config Config) error { - realConfig := config.(*CleanupHookTaskConfig) - return webhook.CleanupHookTaskTable(ctx, webhook.ToHookTaskCleanupType(realConfig.CleanupType), realConfig.OlderThan, realConfig.NumberToKeep) - }) -} - -func initBasicTasks() { - registerUpdateMirrorTask() - registerRepoHealthCheck() - registerCheckRepoStats() - registerArchiveCleanup() - registerSyncExternalUsers() - registerDeletedBranchesCleanup() - if !setting.Repository.DisableMigrations { - registerUpdateMigrationPosterID() - } - registerCleanupHookTaskTable() -} diff --git a/modules/cron/tasks_extended.go b/modules/cron/tasks_extended.go deleted file mode 100644 index 9a37c40faf..0000000000 --- a/modules/cron/tasks_extended.go +++ /dev/null @@ -1,165 +0,0 @@ -// 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 cron - -import ( - "context" - "time" - - "code.gitea.io/gitea/models" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/updatechecker" -) - -func registerDeleteInactiveUsers() { - RegisterTaskFatal("delete_inactive_accounts", &OlderThanConfig{ - BaseConfig: BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@annually", - }, - OlderThan: 0 * time.Second, - }, func(ctx context.Context, _ *models.User, config Config) error { - olderThanConfig := config.(*OlderThanConfig) - return models.DeleteInactiveUsers(ctx, olderThanConfig.OlderThan) - }) -} - -func registerDeleteRepositoryArchives() { - RegisterTaskFatal("delete_repo_archives", &BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@annually", - }, func(ctx context.Context, _ *models.User, _ Config) error { - return repo_module.DeleteRepositoryArchives(ctx) - }) -} - -func registerGarbageCollectRepositories() { - type RepoHealthCheckConfig struct { - BaseConfig - Timeout time.Duration - Args []string `delim:" "` - } - RegisterTaskFatal("git_gc_repos", &RepoHealthCheckConfig{ - BaseConfig: BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@every 72h", - }, - Timeout: time.Duration(setting.Git.Timeout.GC) * time.Second, - Args: setting.Git.GCArgs, - }, func(ctx context.Context, _ *models.User, config Config) error { - rhcConfig := config.(*RepoHealthCheckConfig) - return repo_module.GitGcRepos(ctx, rhcConfig.Timeout, rhcConfig.Args...) - }) -} - -func registerRewriteAllPublicKeys() { - RegisterTaskFatal("resync_all_sshkeys", &BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@every 72h", - }, func(_ context.Context, _ *models.User, _ Config) error { - return models.RewriteAllPublicKeys() - }) -} - -func registerRewriteAllPrincipalKeys() { - RegisterTaskFatal("resync_all_sshprincipals", &BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@every 72h", - }, func(_ context.Context, _ *models.User, _ Config) error { - return models.RewriteAllPrincipalKeys() - }) -} - -func registerRepositoryUpdateHook() { - RegisterTaskFatal("resync_all_hooks", &BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@every 72h", - }, func(ctx context.Context, _ *models.User, _ Config) error { - return repo_module.SyncRepositoryHooks(ctx) - }) -} - -func registerReinitMissingRepositories() { - RegisterTaskFatal("reinit_missing_repos", &BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@every 72h", - }, func(ctx context.Context, _ *models.User, _ Config) error { - return repo_module.ReinitMissingRepositories(ctx) - }) -} - -func registerDeleteMissingRepositories() { - RegisterTaskFatal("delete_missing_repos", &BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@every 72h", - }, func(ctx context.Context, user *models.User, _ Config) error { - return repo_module.DeleteMissingRepositories(ctx, user) - }) -} - -func registerRemoveRandomAvatars() { - RegisterTaskFatal("delete_generated_repository_avatars", &BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@every 72h", - }, func(ctx context.Context, _ *models.User, _ Config) error { - return models.RemoveRandomAvatars(ctx) - }) -} - -func registerDeleteOldActions() { - RegisterTaskFatal("delete_old_actions", &OlderThanConfig{ - BaseConfig: BaseConfig{ - Enabled: false, - RunAtStart: false, - Schedule: "@every 168h", - }, - OlderThan: 365 * 24 * time.Hour, - }, func(ctx context.Context, _ *models.User, config Config) error { - olderThanConfig := config.(*OlderThanConfig) - return models.DeleteOldActions(olderThanConfig.OlderThan) - }) -} - -func registerUpdateGiteaChecker() { - type UpdateCheckerConfig struct { - BaseConfig - HTTPEndpoint string - } - RegisterTaskFatal("update_checker", &UpdateCheckerConfig{ - BaseConfig: BaseConfig{ - Enabled: true, - RunAtStart: false, - Schedule: "@every 168h", - }, - HTTPEndpoint: "https://dl.gitea.io/gitea/version.json", - }, func(ctx context.Context, _ *models.User, config Config) error { - updateCheckerConfig := config.(*UpdateCheckerConfig) - return updatechecker.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint) - }) -} - -func initExtendedTasks() { - registerDeleteInactiveUsers() - registerDeleteRepositoryArchives() - registerGarbageCollectRepositories() - registerRewriteAllPublicKeys() - registerRewriteAllPrincipalKeys() - registerRepositoryUpdateHook() - registerReinitMissingRepositories() - registerDeleteMissingRepositories() - registerRemoveRandomAvatars() - registerDeleteOldActions() - registerUpdateGiteaChecker() -} diff --git a/modules/repository/adopt.go b/modules/repository/adopt.go deleted file mode 100644 index 3d895ac484..0000000000 --- a/modules/repository/adopt.go +++ /dev/null @@ -1,295 +0,0 @@ -// 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 repository - -import ( - "context" - "fmt" - "os" - "path/filepath" - "strings" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - "github.com/gobwas/glob" -) - -// AdoptRepository adopts a repository for the user/organization. -func AdoptRepository(doer, u *models.User, opts models.CreateRepoOptions) (*models.Repository, error) { - if !doer.IsAdmin && !u.CanCreateRepo() { - return nil, models.ErrReachLimitOfRepo{ - Limit: u.MaxRepoCreation, - } - } - - if len(opts.DefaultBranch) == 0 { - opts.DefaultBranch = setting.Repository.DefaultBranch - } - - repo := &models.Repository{ - OwnerID: u.ID, - Owner: u, - OwnerName: u.Name, - Name: opts.Name, - LowerName: strings.ToLower(opts.Name), - Description: opts.Description, - OriginalURL: opts.OriginalURL, - OriginalServiceType: opts.GitServiceType, - IsPrivate: opts.IsPrivate, - IsFsckEnabled: !opts.IsMirror, - CloseIssuesViaCommitInAnyBranch: setting.Repository.DefaultCloseIssuesViaCommitsInAnyBranch, - Status: opts.Status, - IsEmpty: !opts.AutoInit, - } - - if err := db.WithTx(func(ctx context.Context) error { - repoPath := models.RepoPath(u.Name, repo.Name) - isExist, err := util.IsExist(repoPath) - if err != nil { - log.Error("Unable to check if %s exists. Error: %v", repoPath, err) - return err - } - if !isExist { - return models.ErrRepoNotExist{ - OwnerName: u.Name, - Name: repo.Name, - } - } - - if err := models.CreateRepository(ctx, doer, u, repo, true); err != nil { - return err - } - if err := adoptRepository(ctx, repoPath, doer, repo, opts); err != nil { - return fmt.Errorf("createDelegateHooks: %v", err) - } - if err := repo.CheckDaemonExportOK(ctx); err != nil { - return fmt.Errorf("checkDaemonExportOK: %v", err) - } - - // Initialize Issue Labels if selected - if len(opts.IssueLabels) > 0 { - if err := models.InitializeLabels(ctx, repo.ID, opts.IssueLabels, false); err != nil { - return fmt.Errorf("InitializeLabels: %v", err) - } - } - - if stdout, err := git.NewCommand("update-server-info"). - SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)). - RunInDir(repoPath); err != nil { - log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err) - return fmt.Errorf("CreateRepository(git update-server-info): %v", err) - } - return nil - }); err != nil { - return nil, err - } - - return repo, nil -} - -// DeleteUnadoptedRepository deletes unadopted repository files from the filesystem -func DeleteUnadoptedRepository(doer, u *models.User, repoName string) error { - if err := models.IsUsableRepoName(repoName); err != nil { - return err - } - - repoPath := models.RepoPath(u.Name, repoName) - isExist, err := util.IsExist(repoPath) - if err != nil { - log.Error("Unable to check if %s exists. Error: %v", repoPath, err) - return err - } - if !isExist { - return models.ErrRepoNotExist{ - OwnerName: u.Name, - Name: repoName, - } - } - - if exist, err := models.IsRepositoryExist(u, repoName); err != nil { - return err - } else if exist { - return models.ErrRepoAlreadyExist{ - Uname: u.Name, - Name: repoName, - } - } - - return util.RemoveAll(repoPath) -} - -// ListUnadoptedRepositories lists all the unadopted repositories that match the provided query -func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, int, error) { - globUser, _ := glob.Compile("*") - globRepo, _ := glob.Compile("*") - - qsplit := strings.SplitN(query, "/", 2) - if len(qsplit) > 0 && len(query) > 0 { - var err error - globUser, err = glob.Compile(qsplit[0]) - if err != nil { - log.Info("Invalid glob expression '%s' (skipped): %v", qsplit[0], err) - } - if len(qsplit) > 1 { - globRepo, err = glob.Compile(qsplit[1]) - if err != nil { - log.Info("Invalid glob expression '%s' (skipped): %v", qsplit[1], err) - } - } - } - start := (opts.Page - 1) * opts.PageSize - end := start + opts.PageSize - - repoNamesToCheck := make([]string, 0, opts.PageSize) - - repoNames := make([]string, 0, opts.PageSize) - var ctxUser *models.User - - count := 0 - - // We're going to iterate by pagesize. - root := filepath.Clean(setting.RepoRootPath) - if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() || path == root { - return nil - } - - if !strings.ContainsRune(path[len(root)+1:], filepath.Separator) { - // Got a new user - - // Clean up old repoNamesToCheck - if len(repoNamesToCheck) > 0 { - repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{ - Actor: ctxUser, - Private: true, - ListOptions: db.ListOptions{ - Page: 1, - PageSize: opts.PageSize, - }, LowerNames: repoNamesToCheck}) - if err != nil { - return err - } - for _, name := range repoNamesToCheck { - found := false - repoLoopCatchup: - for i, repo := range repos { - if repo.LowerName == name { - found = true - repos = append(repos[:i], repos[i+1:]...) - break repoLoopCatchup - } - } - if !found { - if count >= start && count < end { - repoNames = append(repoNames, fmt.Sprintf("%s/%s", ctxUser.Name, name)) - } - count++ - } - } - repoNamesToCheck = repoNamesToCheck[:0] - } - - if !globUser.Match(info.Name()) { - return filepath.SkipDir - } - - ctxUser, err = models.GetUserByName(info.Name()) - if err != nil { - if models.IsErrUserNotExist(err) { - log.Debug("Missing user: %s", info.Name()) - return filepath.SkipDir - } - return err - } - return nil - } - - name := info.Name() - - if !strings.HasSuffix(name, ".git") { - return filepath.SkipDir - } - name = name[:len(name)-4] - if models.IsUsableRepoName(name) != nil || strings.ToLower(name) != name || !globRepo.Match(name) { - return filepath.SkipDir - } - if count < end { - repoNamesToCheck = append(repoNamesToCheck, name) - if len(repoNamesToCheck) >= opts.PageSize { - repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{ - Actor: ctxUser, - Private: true, - ListOptions: db.ListOptions{ - Page: 1, - PageSize: opts.PageSize, - }, LowerNames: repoNamesToCheck}) - if err != nil { - return err - } - for _, name := range repoNamesToCheck { - found := false - repoLoop: - for i, repo := range repos { - if repo.LowerName == name { - found = true - repos = append(repos[:i], repos[i+1:]...) - break repoLoop - } - } - if !found { - if count >= start && count < end { - repoNames = append(repoNames, fmt.Sprintf("%s/%s", ctxUser.Name, name)) - } - count++ - } - } - repoNamesToCheck = repoNamesToCheck[:0] - } - return filepath.SkipDir - } - count++ - return filepath.SkipDir - }); err != nil { - return nil, 0, err - } - - if len(repoNamesToCheck) > 0 { - repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{ - Actor: ctxUser, - Private: true, - ListOptions: db.ListOptions{ - Page: 1, - PageSize: opts.PageSize, - }, LowerNames: repoNamesToCheck}) - if err != nil { - return nil, 0, err - } - for _, name := range repoNamesToCheck { - found := false - repoLoop: - for i, repo := range repos { - if repo.LowerName == name { - found = true - repos = append(repos[:i], repos[i+1:]...) - break repoLoop - } - } - if !found { - if count >= start && count < end { - repoNames = append(repoNames, fmt.Sprintf("%s/%s", ctxUser.Name, name)) - } - count++ - } - } - } - return repoNames, count, nil -} diff --git a/modules/repository/archive.go b/modules/repository/archive.go deleted file mode 100644 index bea636c579..0000000000 --- a/modules/repository/archive.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2021 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 repository - -import ( - "context" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/storage" -) - -// DeleteRepositoryArchives deletes all repositories' archives. -func DeleteRepositoryArchives(ctx context.Context) error { - if err := models.DeleteAllRepoArchives(); err != nil { - return err - } - return storage.Clean(storage.RepoArchives) -} diff --git a/modules/repository/fork.go b/modules/repository/fork.go deleted file mode 100644 index df1dccc596..0000000000 --- a/modules/repository/fork.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2019 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 repository - -import ( - "context" - "fmt" - "strings" - "time" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" -) - -// ForkRepository forks a repository -func ForkRepository(doer, owner *models.User, opts models.ForkRepoOptions) (_ *models.Repository, err error) { - forkedRepo, err := opts.BaseRepo.GetUserFork(owner.ID) - if err != nil { - return nil, err - } - if forkedRepo != nil { - return nil, models.ErrForkAlreadyExist{ - Uname: owner.Name, - RepoName: opts.BaseRepo.FullName(), - ForkName: forkedRepo.FullName(), - } - } - - repo := &models.Repository{ - OwnerID: owner.ID, - Owner: owner, - OwnerName: owner.Name, - Name: opts.Name, - LowerName: strings.ToLower(opts.Name), - Description: opts.Description, - DefaultBranch: opts.BaseRepo.DefaultBranch, - IsPrivate: opts.BaseRepo.IsPrivate || opts.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate, - IsEmpty: opts.BaseRepo.IsEmpty, - IsFork: true, - ForkID: opts.BaseRepo.ID, - } - - oldRepoPath := opts.BaseRepo.RepoPath() - - needsRollback := false - rollbackFn := func() { - if !needsRollback { - return - } - - repoPath := models.RepoPath(owner.Name, repo.Name) - - if exists, _ := util.IsExist(repoPath); !exists { - return - } - - // As the transaction will be failed and hence database changes will be destroyed we only need - // to delete the related repository on the filesystem - if errDelete := util.RemoveAll(repoPath); errDelete != nil { - log.Error("Failed to remove fork repo") - } - } - - needsRollbackInPanic := true - defer func() { - panicErr := recover() - if panicErr == nil { - return - } - - if needsRollbackInPanic { - rollbackFn() - } - panic(panicErr) - }() - - err = db.WithTx(func(ctx context.Context) error { - if err = models.CreateRepository(ctx, doer, owner, repo, false); err != nil { - return err - } - - if err = models.IncrementRepoForkNum(ctx, opts.BaseRepo.ID); err != nil { - return err - } - - // copy lfs files failure should not be ignored - if err = models.CopyLFS(ctx, repo, opts.BaseRepo); err != nil { - return err - } - - needsRollback = true - - repoPath := models.RepoPath(owner.Name, repo.Name) - if stdout, err := git.NewCommandContext(ctx, - "clone", "--bare", oldRepoPath, repoPath). - SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", opts.BaseRepo.FullName(), repo.FullName())). - RunInDirTimeout(10*time.Minute, ""); err != nil { - log.Error("Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v", repo, opts.BaseRepo, stdout, err) - return fmt.Errorf("git clone: %v", err) - } - - if err := repo.CheckDaemonExportOK(ctx); err != nil { - return fmt.Errorf("checkDaemonExportOK: %v", err) - } - - if stdout, err := git.NewCommandContext(ctx, "update-server-info"). - SetDescription(fmt.Sprintf("ForkRepository(git update-server-info): %s", repo.FullName())). - RunInDir(repoPath); err != nil { - log.Error("Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v", repo, stdout, err) - return fmt.Errorf("git update-server-info: %v", err) - } - - if err = createDelegateHooks(repoPath); err != nil { - return fmt.Errorf("createDelegateHooks: %v", err) - } - return nil - }) - needsRollbackInPanic = false - if err != nil { - rollbackFn() - return nil, err - } - - // even if below operations failed, it could be ignored. And they will be retried - ctx := db.DefaultContext - if err := repo.UpdateSize(ctx); err != nil { - log.Error("Failed to update size for repository: %v", err) - } - if err := models.CopyLanguageStat(opts.BaseRepo, repo); err != nil { - log.Error("Copy language stat from oldRepo failed") - } - - return repo, nil -} - -// ConvertForkToNormalRepository convert the provided repo from a forked repo to normal repo -func ConvertForkToNormalRepository(repo *models.Repository) error { - err := db.WithTx(func(ctx context.Context) error { - repo, err := models.GetRepositoryByIDCtx(ctx, repo.ID) - if err != nil { - return err - } - - if !repo.IsFork { - return nil - } - - if err := models.DecrementRepoForkNum(ctx, repo.ForkID); err != nil { - log.Error("Unable to decrement repo fork num for old root repo %d of repository %-v whilst converting from fork. Error: %v", repo.ForkID, repo, err) - return err - } - - repo.IsFork = false - repo.ForkID = 0 - - if err := models.UpdateRepositoryCtx(ctx, repo, false); err != nil { - log.Error("Unable to update repository %-v whilst converting from fork. Error: %v", repo, err) - return err - } - - return nil - }) - - return err -} diff --git a/modules/repository/fork_test.go b/modules/repository/fork_test.go deleted file mode 100644 index 197d76b056..0000000000 --- a/modules/repository/fork_test.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2017 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 repository - -import ( - "testing" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/unittest" - "github.com/stretchr/testify/assert" -) - -func TestForkRepository(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - // user 13 has already forked repo10 - user := unittest.AssertExistsAndLoadBean(t, &models.User{ID: 13}).(*models.User) - repo := unittest.AssertExistsAndLoadBean(t, &models.Repository{ID: 10}).(*models.Repository) - - fork, err := ForkRepository(user, user, models.ForkRepoOptions{ - BaseRepo: repo, - Name: "test", - Description: "test", - }) - assert.Nil(t, fork) - assert.Error(t, err) - assert.True(t, models.IsErrForkAlreadyExist(err)) -} diff --git a/modules/repository/init.go b/modules/repository/init.go index 5a1ff7e98b..076dbf748e 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -196,92 +196,6 @@ func checkInitRepository(owner, name string) (err error) { return nil } -func adoptRepository(ctx context.Context, repoPath string, u *models.User, repo *models.Repository, opts models.CreateRepoOptions) (err error) { - isExist, err := util.IsExist(repoPath) - if err != nil { - log.Error("Unable to check if %s exists. Error: %v", repoPath, err) - return err - } - if !isExist { - return fmt.Errorf("adoptRepository: path does not already exist: %s", repoPath) - } - - if err := createDelegateHooks(repoPath); err != nil { - return fmt.Errorf("createDelegateHooks: %v", err) - } - - // Re-fetch the repository from database before updating it (else it would - // override changes that were done earlier with sql) - if repo, err = models.GetRepositoryByIDCtx(ctx, repo.ID); err != nil { - return fmt.Errorf("getRepositoryByID: %v", err) - } - - repo.IsEmpty = false - gitRepo, err := git.OpenRepository(repo.RepoPath()) - if err != nil { - return fmt.Errorf("openRepository: %v", err) - } - defer gitRepo.Close() - if len(opts.DefaultBranch) > 0 { - repo.DefaultBranch = opts.DefaultBranch - - if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { - return fmt.Errorf("setDefaultBranch: %v", err) - } - } else { - repo.DefaultBranch, err = gitRepo.GetDefaultBranch() - if err != nil { - repo.DefaultBranch = setting.Repository.DefaultBranch - if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { - return fmt.Errorf("setDefaultBranch: %v", err) - } - } - - repo.DefaultBranch = strings.TrimPrefix(repo.DefaultBranch, git.BranchPrefix) - } - branches, _, _ := gitRepo.GetBranches(0, 0) - found := false - hasDefault := false - hasMaster := false - hasMain := false - for _, branch := range branches { - if branch == repo.DefaultBranch { - found = true - break - } else if branch == setting.Repository.DefaultBranch { - hasDefault = true - } else if branch == "master" { - hasMaster = true - } else if branch == "main" { - hasMain = true - } - } - if !found { - if hasDefault { - repo.DefaultBranch = setting.Repository.DefaultBranch - } else if hasMaster { - repo.DefaultBranch = "master" - } else if hasMain { - repo.DefaultBranch = "main" - } else if len(branches) > 0 { - repo.DefaultBranch = branches[0] - } else { - repo.IsEmpty = true - repo.DefaultBranch = setting.Repository.DefaultBranch - } - - if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { - return fmt.Errorf("setDefaultBranch: %v", err) - } - } - - if err = models.UpdateRepositoryCtx(ctx, repo, false); err != nil { - return fmt.Errorf("updateRepository: %v", err) - } - - return nil -} - // InitRepository initializes README and .gitignore if needed. func initRepository(ctx context.Context, repoPath string, u *models.User, repo *models.Repository, opts models.CreateRepoOptions) (err error) { if err = checkInitRepository(repo.OwnerName, repo.Name); err != nil { |