forked from Shiloh/githaven
d68a613ba8
Currently only SHA1 repositories are supported by Gitea. This adds support for alternate SHA256 with the additional aim of easier support for additional hash types in the future. Fixes: #13794 Limited by: https://github.com/go-git/go-git/issues/899 Depend on: #28138 <img width="776" alt="图片" src="https://github.com/go-gitea/gitea/assets/81045/5448c9a7-608e-4341-a149-5dd0069c9447"> --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: 6543 <6543@obermui.de>
139 lines
4.3 KiB
Go
139 lines
4.3 KiB
Go
// Copyright 2021 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package repo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.gitea.io/gitea/models/db"
|
|
"code.gitea.io/gitea/modules/git"
|
|
"code.gitea.io/gitea/modules/timeutil"
|
|
"code.gitea.io/gitea/modules/util"
|
|
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
// ArchiverStatus represents repo archive status
|
|
type ArchiverStatus int
|
|
|
|
// enumerate all repo archive statuses
|
|
const (
|
|
ArchiverGenerating = iota // the archiver is generating
|
|
ArchiverReady // it's ready
|
|
)
|
|
|
|
// RepoArchiver represents all archivers
|
|
type RepoArchiver struct { //revive:disable-line:exported
|
|
ID int64 `xorm:"pk autoincr"`
|
|
RepoID int64 `xorm:"index unique(s)"`
|
|
Type git.ArchiveType `xorm:"unique(s)"`
|
|
Status ArchiverStatus
|
|
CommitID string `xorm:"VARCHAR(64) unique(s)"`
|
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
|
|
}
|
|
|
|
func init() {
|
|
db.RegisterModel(new(RepoArchiver))
|
|
}
|
|
|
|
// RelativePath returns the archive path relative to the archive storage root.
|
|
func (archiver *RepoArchiver) RelativePath() string {
|
|
return fmt.Sprintf("%d/%s/%s.%s", archiver.RepoID, archiver.CommitID[:2], archiver.CommitID, archiver.Type.String())
|
|
}
|
|
|
|
// repoArchiverForRelativePath takes a relativePath created from (archiver *RepoArchiver) RelativePath() and creates a shell repoArchiver struct representing it
|
|
func repoArchiverForRelativePath(relativePath string) (*RepoArchiver, error) {
|
|
parts := strings.SplitN(relativePath, "/", 3)
|
|
if len(parts) != 3 {
|
|
return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument}
|
|
}
|
|
repoID, err := strconv.ParseInt(parts[0], 10, 64)
|
|
if err != nil {
|
|
return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument}
|
|
}
|
|
nameExts := strings.SplitN(parts[2], ".", 2)
|
|
if len(nameExts) != 2 {
|
|
return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument}
|
|
}
|
|
|
|
return &RepoArchiver{
|
|
RepoID: repoID,
|
|
CommitID: parts[1] + nameExts[0],
|
|
Type: git.ToArchiveType(nameExts[1]),
|
|
}, nil
|
|
}
|
|
|
|
// GetRepoArchiver get an archiver
|
|
func GetRepoArchiver(ctx context.Context, repoID int64, tp git.ArchiveType, commitID string) (*RepoArchiver, error) {
|
|
var archiver RepoArchiver
|
|
has, err := db.GetEngine(ctx).Where("repo_id=?", repoID).And("`type`=?", tp).And("commit_id=?", commitID).Get(&archiver)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if has {
|
|
return &archiver, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
// ExistsRepoArchiverWithStoragePath checks if there is a RepoArchiver for a given storage path
|
|
func ExistsRepoArchiverWithStoragePath(ctx context.Context, storagePath string) (bool, error) {
|
|
// We need to invert the path provided func (archiver *RepoArchiver) RelativePath() above
|
|
archiver, err := repoArchiverForRelativePath(storagePath)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return db.GetEngine(ctx).Exist(archiver)
|
|
}
|
|
|
|
// UpdateRepoArchiverStatus updates archiver's status
|
|
func UpdateRepoArchiverStatus(ctx context.Context, archiver *RepoArchiver) error {
|
|
_, err := db.GetEngine(ctx).ID(archiver.ID).Cols("status").Update(archiver)
|
|
return err
|
|
}
|
|
|
|
// DeleteAllRepoArchives deletes all repo archives records
|
|
func DeleteAllRepoArchives(ctx context.Context) error {
|
|
// 1=1 to enforce delete all data, otherwise it will delete nothing
|
|
_, err := db.GetEngine(ctx).Where("1=1").Delete(new(RepoArchiver))
|
|
return err
|
|
}
|
|
|
|
// FindRepoArchiversOption represents an archiver options
|
|
type FindRepoArchiversOption struct {
|
|
db.ListOptions
|
|
OlderThan time.Duration
|
|
}
|
|
|
|
func (opts FindRepoArchiversOption) ToConds() builder.Cond {
|
|
cond := builder.NewCond()
|
|
if opts.OlderThan > 0 {
|
|
cond = cond.And(builder.Lt{"created_unix": time.Now().Add(-opts.OlderThan).Unix()})
|
|
}
|
|
return cond
|
|
}
|
|
|
|
func (opts FindRepoArchiversOption) ToOrders() string {
|
|
return "created_unix ASC"
|
|
}
|
|
|
|
// SetArchiveRepoState sets if a repo is archived
|
|
func SetArchiveRepoState(ctx context.Context, repo *Repository, isArchived bool) (err error) {
|
|
repo.IsArchived = isArchived
|
|
|
|
if isArchived {
|
|
repo.ArchivedUnix = timeutil.TimeStampNow()
|
|
} else {
|
|
repo.ArchivedUnix = timeutil.TimeStamp(0)
|
|
}
|
|
|
|
_, err = db.GetEngine(ctx).ID(repo.ID).Cols("is_archived", "archived_unix").NoAutoTime().Update(repo)
|
|
return err
|
|
}
|