diff options
author | zeripath <art27@cantab.net> | 2021-11-22 22:32:16 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-22 22:32:16 +0000 |
commit | 1dbc58f742febbe58df59d4ce4148d2dbec1a20f (patch) | |
tree | 4b73978cdcbdff2e88752d8bbfa21478856d4305 | |
parent | baed01f24753afb600a2984dcb9bcda0bb8502b6 (diff) | |
download | gitea-1dbc58f742febbe58df59d4ce4148d2dbec1a20f.tar.gz gitea-1dbc58f742febbe58df59d4ce4148d2dbec1a20f.zip |
More pleasantly handle broken or missing git repositories (#17747)
* More pleasantly handle broken or missing git repositories
In #17742 it was noted that there a completely invalid git repository underlying a
repo on gitea.com. This happened due to a problem during a migration however, it
is not beyond the realms of possibility that a corruption could occur to another
user.
This PR adds a check to RepoAssignment that will detect if a repository loading has
failed due to an absent git repository. It will then show a page suggesting the user
contacts the administrator or deletes the repository.
Fix #17742
Signed-off-by: Andrew Thornton <art27@cantab.net>
* Update options/locale/locale_en-US.ini
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
-rw-r--r-- | models/repo.go | 6 | ||||
-rw-r--r-- | modules/context/repo.go | 34 | ||||
-rw-r--r-- | options/locale/locale_en-US.ini | 1 | ||||
-rw-r--r-- | routers/private/serv.go | 8 | ||||
-rw-r--r-- | templates/repo/empty.tmpl | 6 | ||||
-rw-r--r-- | templates/repo/header.tmpl | 12 |
6 files changed, 63 insertions, 4 deletions
diff --git a/models/repo.go b/models/repo.go index 7944149a76..860c5c4813 100644 --- a/models/repo.go +++ b/models/repo.go @@ -146,6 +146,7 @@ const ( RepositoryReady RepositoryStatus = iota // a normal repository RepositoryBeingMigrated // repository is migrating RepositoryPendingTransfer // repository pending in ownership transfer state + RepositoryBroken // repository is in a permanently broken state ) // TrustModelType defines the types of trust model for this repository @@ -289,6 +290,11 @@ func (repo *Repository) IsBeingCreated() bool { return repo.IsBeingMigrated() } +// IsBroken indicates that repository is broken +func (repo *Repository) IsBroken() bool { + return repo.Status == RepositoryBroken +} + // AfterLoad is invoked from XORM after setting the values of all fields of this object. func (repo *Repository) AfterLoad() { // FIXME: use models migration to solve all at once. diff --git a/modules/context/repo.go b/modules/context/repo.go index c96d34f2fc..1f1a035267 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -522,14 +522,30 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { } } + isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink || ctx.Link == ctx.Repo.RepoLink+"/settings" || strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/") + // Disable everything when the repo is being created - if ctx.Repo.Repository.IsBeingCreated() { + if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() { ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch + if !isHomeOrSettings { + ctx.Redirect(ctx.Repo.RepoLink) + } return } gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName)) if err != nil { + if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") { + log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err) + ctx.Repo.Repository.Status = models.RepositoryBroken + ctx.Repo.Repository.IsEmpty = true + ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch + // Only allow access to base of repo or settings + if !isHomeOrSettings { + ctx.Redirect(ctx.Repo.RepoLink) + } + return + } ctx.ServerError("RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err) return } @@ -551,6 +567,17 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { tags, err := ctx.Repo.GitRepo.GetTags(0, 0) if err != nil { + if strings.Contains(err.Error(), "fatal: not a git repository ") { + log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err) + ctx.Repo.Repository.Status = models.RepositoryBroken + ctx.Repo.Repository.IsEmpty = true + ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch + // Only allow access to base of repo or settings + if !isHomeOrSettings { + ctx.Redirect(ctx.Repo.RepoLink) + } + return + } ctx.ServerError("GetTags", err) return } @@ -919,6 +946,11 @@ func UnitTypes() func(ctx *Context) { // IssueTemplatesFromDefaultBranch checks for issue templates in the repo's default branch func (ctx *Context) IssueTemplatesFromDefaultBranch() []api.IssueTemplate { var issueTemplates []api.IssueTemplate + + if ctx.Repo.Repository.IsEmpty { + return issueTemplates + } + if ctx.Repo.Commit == nil { var err error ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 6e39b4b03d..ca6cd66625 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -946,6 +946,7 @@ clone_this_repo = Clone this repository create_new_repo_command = Creating a new repository on the command line push_exist_repo = Pushing an existing repository from the command line empty_message = This repository does not contain any content. +broken_message = The git data underlying this repository cannot be read. Contact the administrator of this instance or delete this repository. code = Code code.desc = Access source code, files, commits and branches. diff --git a/routers/private/serv.go b/routers/private/serv.go index a7ef980d2d..329d80476a 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -162,6 +162,14 @@ func ServCommand(ctx *context.PrivateContext) { return } + if repo.IsBroken() { + ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{ + Results: results, + Err: "Repository is in a broken state", + }) + return + } + // We can shortcut at this point if the repo is a mirror if mode > models.AccessModeRead && repo.IsMirror { ctx.JSON(http.StatusForbidden, private.ErrServCommand{ diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl index 20563f59e6..6da9e28e16 100644 --- a/templates/repo/empty.tmpl +++ b/templates/repo/empty.tmpl @@ -10,7 +10,11 @@ {{.i18n.Tr "repo.archive.title"}} </div> {{end}} - {{if .CanWriteCode}} + {{if .Repository.IsBroken}} + <div class="ui segment center"> + {{.i18n.Tr "repo.broken_message"}} + </div> + {{else if .CanWriteCode}} <h4 class="ui top attached header"> {{.i18n.Tr "repo.quick_guide"}} </h4> diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 554456d230..4fb5e1941b 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -40,7 +40,7 @@ {{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{.BaseRepo.FullName}}</a></div>{{end}} {{if .IsGenerated}}<div class="fork-flag">{{$.i18n.Tr "repo.generated_from"}} <a href="{{.TemplateRepo.Link}}">{{.TemplateRepo.FullName}}</a></div>{{end}} </div> - {{if not .IsBeingCreated}} + {{if not (or .IsBeingCreated .IsBroken)}} <div class="repo-buttons"> {{if $.RepoTransfer}} <form method="post" action="{{$.RepoLink}}/action/accept_transfer?redirect_to={{$.RepoLink}}"> @@ -100,7 +100,7 @@ </div><!-- end container --> {{end}} <div class="ui tabs container"> - {{if not .Repository.IsBeingCreated}} + {{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}} <div class="ui tabular stackable menu navbar"> {{if .Permission.CanRead $.UnitTypeCode}} <a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL}}{{end}}"> @@ -172,6 +172,14 @@ </div> {{end}} </div> + {{else if .Permission.IsAdmin}} + <div class="ui tabular stackable menu navbar"> + <div class="right menu"> + <a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings"> + {{svg "octicon-tools"}} {{.i18n.Tr "repo.settings"}} + </a> + </div> + </div> {{end}} </div> <div class="ui tabs divider"></div> |