Skip to content

Commit ad2ff67

Browse files
authored
Move archive function to repo_model and gitrepo (#35514)
1 parent cdc0733 commit ad2ff67

File tree

9 files changed

+172
-182
lines changed

9 files changed

+172
-182
lines changed

modules/git/repo_archive_test.go renamed to models/repo/archive_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2025 The Gitea Authors. All rights reserved.
22
// SPDX-License-Identifier: MIT
33

4-
package git
4+
package repo
55

66
import (
77
"testing"

models/repo/archiver.go

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"time"
1212

1313
"code.gitea.io/gitea/models/db"
14-
"code.gitea.io/gitea/modules/git"
1514
"code.gitea.io/gitea/modules/timeutil"
1615
"code.gitea.io/gitea/modules/util"
1716

@@ -27,11 +26,46 @@ const (
2726
ArchiverReady // it's ready
2827
)
2928

29+
// ArchiveType archive types
30+
type ArchiveType int
31+
32+
const (
33+
ArchiveUnknown ArchiveType = iota
34+
ArchiveZip // 1
35+
ArchiveTarGz // 2
36+
ArchiveBundle // 3
37+
)
38+
39+
// String converts an ArchiveType to string: the extension of the archive file without prefix dot
40+
func (a ArchiveType) String() string {
41+
switch a {
42+
case ArchiveZip:
43+
return "zip"
44+
case ArchiveTarGz:
45+
return "tar.gz"
46+
case ArchiveBundle:
47+
return "bundle"
48+
}
49+
return "unknown"
50+
}
51+
52+
func SplitArchiveNameType(s string) (string, ArchiveType) {
53+
switch {
54+
case strings.HasSuffix(s, ".zip"):
55+
return strings.TrimSuffix(s, ".zip"), ArchiveZip
56+
case strings.HasSuffix(s, ".tar.gz"):
57+
return strings.TrimSuffix(s, ".tar.gz"), ArchiveTarGz
58+
case strings.HasSuffix(s, ".bundle"):
59+
return strings.TrimSuffix(s, ".bundle"), ArchiveBundle
60+
}
61+
return s, ArchiveUnknown
62+
}
63+
3064
// RepoArchiver represents all archivers
3165
type RepoArchiver struct { //revive:disable-line:exported
32-
ID int64 `xorm:"pk autoincr"`
33-
RepoID int64 `xorm:"index unique(s)"`
34-
Type git.ArchiveType `xorm:"unique(s)"`
66+
ID int64 `xorm:"pk autoincr"`
67+
RepoID int64 `xorm:"index unique(s)"`
68+
Type ArchiveType `xorm:"unique(s)"`
3569
Status ArchiverStatus
3670
CommitID string `xorm:"VARCHAR(64) unique(s)"`
3771
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
@@ -56,15 +90,15 @@ func repoArchiverForRelativePath(relativePath string) (*RepoArchiver, error) {
5690
if err != nil {
5791
return nil, util.NewInvalidArgumentErrorf("invalid storage path: invalid repo id")
5892
}
59-
commitID, archiveType := git.SplitArchiveNameType(parts[2])
60-
if archiveType == git.ArchiveUnknown {
93+
commitID, archiveType := SplitArchiveNameType(parts[2])
94+
if archiveType == ArchiveUnknown {
6195
return nil, util.NewInvalidArgumentErrorf("invalid storage path: invalid archive type")
6296
}
6397
return &RepoArchiver{RepoID: repoID, CommitID: commitID, Type: archiveType}, nil
6498
}
6599

66100
// GetRepoArchiver get an archiver
67-
func GetRepoArchiver(ctx context.Context, repoID int64, tp git.ArchiveType, commitID string) (*RepoArchiver, error) {
101+
func GetRepoArchiver(ctx context.Context, repoID int64, tp ArchiveType, commitID string) (*RepoArchiver, error) {
68102
var archiver RepoArchiver
69103
has, err := db.GetEngine(ctx).Where("repo_id=?", repoID).And("`type`=?", tp).And("commit_id=?", commitID).Get(&archiver)
70104
if err != nil {

modules/git/repo.go

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@ import (
1212
"net/url"
1313
"os"
1414
"path"
15-
"path/filepath"
1615
"strconv"
1716
"strings"
1817
"time"
1918

2019
"code.gitea.io/gitea/modules/git/gitcmd"
2120
"code.gitea.io/gitea/modules/proxy"
22-
"code.gitea.io/gitea/modules/setting"
2321
)
2422

2523
// GPGSettings represents the default GPG settings for this repository
@@ -242,43 +240,3 @@ func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error
242240
commitTime := strings.TrimSpace(stdout)
243241
return time.Parse("Mon Jan _2 15:04:05 2006 -0700", commitTime)
244242
}
245-
246-
// CreateBundle create bundle content to the target path
247-
func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.Writer) error {
248-
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
249-
if err != nil {
250-
return err
251-
}
252-
defer cleanup()
253-
254-
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
255-
_, _, err = gitcmd.NewCommand("init", "--bare").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
256-
if err != nil {
257-
return err
258-
}
259-
260-
_, _, err = gitcmd.NewCommand("reset", "--soft").AddDynamicArguments(commit).RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
261-
if err != nil {
262-
return err
263-
}
264-
265-
_, _, err = gitcmd.NewCommand("branch", "-m", "bundle").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
266-
if err != nil {
267-
return err
268-
}
269-
270-
tmpFile := filepath.Join(tmp, "bundle")
271-
_, _, err = gitcmd.NewCommand("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
272-
if err != nil {
273-
return err
274-
}
275-
276-
fi, err := os.Open(tmpFile)
277-
if err != nil {
278-
return err
279-
}
280-
defer fi.Close()
281-
282-
_, err = io.Copy(out, fi)
283-
return err
284-
}

modules/git/repo_archive.go

Lines changed: 0 additions & 75 deletions
This file was deleted.

modules/gitrepo/archive.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package gitrepo
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"io"
10+
"os"
11+
"path/filepath"
12+
"strings"
13+
14+
"code.gitea.io/gitea/modules/git/gitcmd"
15+
"code.gitea.io/gitea/modules/setting"
16+
)
17+
18+
// CreateArchive create archive content to the target path
19+
func CreateArchive(ctx context.Context, repo Repository, format string, target io.Writer, usePrefix bool, commitID string) error {
20+
if format == "unknown" {
21+
return fmt.Errorf("unknown format: %v", format)
22+
}
23+
24+
cmd := gitcmd.NewCommand("archive")
25+
if usePrefix {
26+
cmd.AddOptionFormat("--prefix=%s", filepath.Base(strings.TrimSuffix(repo.RelativePath(), ".git"))+"/")
27+
}
28+
cmd.AddOptionFormat("--format=%s", format)
29+
cmd.AddDynamicArguments(commitID)
30+
31+
var stderr strings.Builder
32+
err := cmd.Run(ctx, &gitcmd.RunOpts{
33+
Dir: repoPath(repo),
34+
Stdout: target,
35+
Stderr: &stderr,
36+
})
37+
if err != nil {
38+
return gitcmd.ConcatenateError(err, stderr.String())
39+
}
40+
return nil
41+
}
42+
43+
// CreateBundle create bundle content to the target path
44+
func CreateBundle(ctx context.Context, repo Repository, commit string, out io.Writer) error {
45+
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
46+
if err != nil {
47+
return err
48+
}
49+
defer cleanup()
50+
51+
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repoPath(repo), "objects"))
52+
_, _, err = gitcmd.NewCommand("init", "--bare").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
53+
if err != nil {
54+
return err
55+
}
56+
57+
_, _, err = gitcmd.NewCommand("reset", "--soft").AddDynamicArguments(commit).RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
58+
if err != nil {
59+
return err
60+
}
61+
62+
_, _, err = gitcmd.NewCommand("branch", "-m", "bundle").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
63+
if err != nil {
64+
return err
65+
}
66+
67+
tmpFile := filepath.Join(tmp, "bundle")
68+
_, _, err = gitcmd.NewCommand("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
69+
if err != nil {
70+
return err
71+
}
72+
73+
fi, err := os.Open(tmpFile)
74+
if err != nil {
75+
return err
76+
}
77+
defer fi.Close()
78+
79+
_, err = io.Copy(out, fi)
80+
return err
81+
}

routers/api/v1/repo/download.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import (
77
"errors"
88
"net/http"
99

10-
"code.gitea.io/gitea/modules/git"
10+
repo_model "code.gitea.io/gitea/models/repo"
1111
"code.gitea.io/gitea/services/context"
1212
archiver_service "code.gitea.io/gitea/services/repository/archiver"
1313
)
1414

1515
func serveRepoArchive(ctx *context.APIContext, reqFileName string) {
16-
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, reqFileName)
16+
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, reqFileName)
1717
if err != nil {
1818
if errors.Is(err, archiver_service.ErrUnknownArchiveFormat{}) {
1919
ctx.APIError(http.StatusBadRequest, err)
@@ -24,18 +24,18 @@ func serveRepoArchive(ctx *context.APIContext, reqFileName string) {
2424
}
2525
return
2626
}
27-
archiver_service.ServeRepoArchive(ctx.Base, ctx.Repo.Repository, ctx.Repo.GitRepo, aReq)
27+
archiver_service.ServeRepoArchive(ctx.Base, aReq)
2828
}
2929

3030
func DownloadArchive(ctx *context.APIContext) {
31-
var tp git.ArchiveType
31+
var tp repo_model.ArchiveType
3232
switch ballType := ctx.PathParam("ball_type"); ballType {
3333
case "tarball":
34-
tp = git.ArchiveTarGz
34+
tp = repo_model.ArchiveTarGz
3535
case "zipball":
36-
tp = git.ArchiveZip
36+
tp = repo_model.ArchiveZip
3737
case "bundle":
38-
tp = git.ArchiveBundle
38+
tp = repo_model.ArchiveBundle
3939
default:
4040
ctx.APIError(http.StatusBadRequest, "Unknown archive type: "+ballType)
4141
return

routers/web/repo/repo.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ func RedirectDownload(ctx *context.Context) {
364364

365365
// Download an archive of a repository
366366
func Download(ctx *context.Context) {
367-
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, ctx.PathParam("*"))
367+
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*"))
368368
if err != nil {
369369
if errors.Is(err, archiver_service.ErrUnknownArchiveFormat{}) {
370370
ctx.HTTPError(http.StatusBadRequest, err.Error())
@@ -375,7 +375,7 @@ func Download(ctx *context.Context) {
375375
}
376376
return
377377
}
378-
archiver_service.ServeRepoArchive(ctx.Base, ctx.Repo.Repository, ctx.Repo.GitRepo, aReq)
378+
archiver_service.ServeRepoArchive(ctx.Base, aReq)
379379
}
380380

381381
// InitiateDownload will enqueue an archival request, as needed. It may submit
@@ -388,7 +388,7 @@ func InitiateDownload(ctx *context.Context) {
388388
})
389389
return
390390
}
391-
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, ctx.PathParam("*"))
391+
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*"))
392392
if err != nil {
393393
ctx.HTTPError(http.StatusBadRequest, "invalid archive request")
394394
return
@@ -398,7 +398,7 @@ func InitiateDownload(ctx *context.Context) {
398398
return
399399
}
400400

401-
archiver, err := repo_model.GetRepoArchiver(ctx, aReq.RepoID, aReq.Type, aReq.CommitID)
401+
archiver, err := repo_model.GetRepoArchiver(ctx, aReq.Repo.ID, aReq.Type, aReq.CommitID)
402402
if err != nil {
403403
ctx.ServerError("archiver_service.StartArchive", err)
404404
return

0 commit comments

Comments
 (0)