Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package git
package repo

import (
"testing"
Expand Down
48 changes: 41 additions & 7 deletions models/repo/archiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"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"

Expand All @@ -27,11 +26,46 @@ const (
ArchiverReady // it's ready
)

// ArchiveType archive types
type ArchiveType int

const (
ArchiveUnknown ArchiveType = iota
ArchiveZip // 1
ArchiveTarGz // 2
ArchiveBundle // 3
)

// String converts an ArchiveType to string: the extension of the archive file without prefix dot
func (a ArchiveType) String() string {
switch a {
case ArchiveZip:
return "zip"
case ArchiveTarGz:
return "tar.gz"
case ArchiveBundle:
return "bundle"
}
return "unknown"
}

func SplitArchiveNameType(s string) (string, ArchiveType) {
switch {
case strings.HasSuffix(s, ".zip"):
return strings.TrimSuffix(s, ".zip"), ArchiveZip
case strings.HasSuffix(s, ".tar.gz"):
return strings.TrimSuffix(s, ".tar.gz"), ArchiveTarGz
case strings.HasSuffix(s, ".bundle"):
return strings.TrimSuffix(s, ".bundle"), ArchiveBundle
}
return s, ArchiveUnknown
}

// 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)"`
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"index unique(s)"`
Type ArchiveType `xorm:"unique(s)"`
Status ArchiverStatus
CommitID string `xorm:"VARCHAR(64) unique(s)"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
Expand All @@ -56,15 +90,15 @@ func repoArchiverForRelativePath(relativePath string) (*RepoArchiver, error) {
if err != nil {
return nil, util.NewInvalidArgumentErrorf("invalid storage path: invalid repo id")
}
commitID, archiveType := git.SplitArchiveNameType(parts[2])
if archiveType == git.ArchiveUnknown {
commitID, archiveType := SplitArchiveNameType(parts[2])
if archiveType == ArchiveUnknown {
return nil, util.NewInvalidArgumentErrorf("invalid storage path: invalid archive type")
}
return &RepoArchiver{RepoID: repoID, CommitID: commitID, Type: archiveType}, nil
}

// GetRepoArchiver get an archiver
func GetRepoArchiver(ctx context.Context, repoID int64, tp git.ArchiveType, commitID string) (*RepoArchiver, error) {
func GetRepoArchiver(ctx context.Context, repoID int64, tp 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 {
Expand Down
42 changes: 0 additions & 42 deletions modules/git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ import (
"net/url"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/setting"
)

// GPGSettings represents the default GPG settings for this repository
Expand Down Expand Up @@ -242,43 +240,3 @@ func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error
commitTime := strings.TrimSpace(stdout)
return time.Parse("Mon Jan _2 15:04:05 2006 -0700", commitTime)
}

// CreateBundle create bundle content to the target path
func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.Writer) error {
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
if err != nil {
return err
}
defer cleanup()

env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
_, _, err = gitcmd.NewCommand("init", "--bare").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

_, _, err = gitcmd.NewCommand("reset", "--soft").AddDynamicArguments(commit).RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

_, _, err = gitcmd.NewCommand("branch", "-m", "bundle").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

tmpFile := filepath.Join(tmp, "bundle")
_, _, err = gitcmd.NewCommand("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

fi, err := os.Open(tmpFile)
if err != nil {
return err
}
defer fi.Close()

_, err = io.Copy(out, fi)
return err
}
75 changes: 0 additions & 75 deletions modules/git/repo_archive.go

This file was deleted.

81 changes: 81 additions & 0 deletions modules/gitrepo/archive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package gitrepo

import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"strings"

"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/setting"
)

// CreateArchive create archive content to the target path
func CreateArchive(ctx context.Context, repo Repository, format string, target io.Writer, usePrefix bool, commitID string) error {
if format == "unknown" {
return fmt.Errorf("unknown format: %v", format)
}

cmd := gitcmd.NewCommand("archive")
if usePrefix {
cmd.AddOptionFormat("--prefix=%s", filepath.Base(strings.TrimSuffix(repo.RelativePath(), ".git"))+"/")
}
cmd.AddOptionFormat("--format=%s", format)
cmd.AddDynamicArguments(commitID)

var stderr strings.Builder
err := cmd.Run(ctx, &gitcmd.RunOpts{
Dir: repoPath(repo),
Stdout: target,
Stderr: &stderr,
})
if err != nil {
return gitcmd.ConcatenateError(err, stderr.String())
}
return nil
}

// CreateBundle create bundle content to the target path
func CreateBundle(ctx context.Context, repo Repository, commit string, out io.Writer) error {
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
if err != nil {
return err
}
defer cleanup()

env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repoPath(repo), "objects"))
_, _, err = gitcmd.NewCommand("init", "--bare").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

_, _, err = gitcmd.NewCommand("reset", "--soft").AddDynamicArguments(commit).RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

_, _, err = gitcmd.NewCommand("branch", "-m", "bundle").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

tmpFile := filepath.Join(tmp, "bundle")
_, _, err = gitcmd.NewCommand("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

fi, err := os.Open(tmpFile)
if err != nil {
return err
}
defer fi.Close()

_, err = io.Copy(out, fi)
return err
}
14 changes: 7 additions & 7 deletions routers/api/v1/repo/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import (
"errors"
"net/http"

"code.gitea.io/gitea/modules/git"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/services/context"
archiver_service "code.gitea.io/gitea/services/repository/archiver"
)

func serveRepoArchive(ctx *context.APIContext, reqFileName string) {
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, reqFileName)
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, reqFileName)
if err != nil {
if errors.Is(err, archiver_service.ErrUnknownArchiveFormat{}) {
ctx.APIError(http.StatusBadRequest, err)
Expand All @@ -24,18 +24,18 @@ func serveRepoArchive(ctx *context.APIContext, reqFileName string) {
}
return
}
archiver_service.ServeRepoArchive(ctx.Base, ctx.Repo.Repository, ctx.Repo.GitRepo, aReq)
archiver_service.ServeRepoArchive(ctx.Base, aReq)
}

func DownloadArchive(ctx *context.APIContext) {
var tp git.ArchiveType
var tp repo_model.ArchiveType
switch ballType := ctx.PathParam("ball_type"); ballType {
case "tarball":
tp = git.ArchiveTarGz
tp = repo_model.ArchiveTarGz
case "zipball":
tp = git.ArchiveZip
tp = repo_model.ArchiveZip
case "bundle":
tp = git.ArchiveBundle
tp = repo_model.ArchiveBundle
default:
ctx.APIError(http.StatusBadRequest, "Unknown archive type: "+ballType)
return
Expand Down
8 changes: 4 additions & 4 deletions routers/web/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ func RedirectDownload(ctx *context.Context) {

// Download an archive of a repository
func Download(ctx *context.Context) {
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, ctx.PathParam("*"))
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*"))
if err != nil {
if errors.Is(err, archiver_service.ErrUnknownArchiveFormat{}) {
ctx.HTTPError(http.StatusBadRequest, err.Error())
Expand All @@ -375,7 +375,7 @@ func Download(ctx *context.Context) {
}
return
}
archiver_service.ServeRepoArchive(ctx.Base, ctx.Repo.Repository, ctx.Repo.GitRepo, aReq)
archiver_service.ServeRepoArchive(ctx.Base, aReq)
}

// InitiateDownload will enqueue an archival request, as needed. It may submit
Expand All @@ -388,7 +388,7 @@ func InitiateDownload(ctx *context.Context) {
})
return
}
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, ctx.PathParam("*"))
aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*"))
if err != nil {
ctx.HTTPError(http.StatusBadRequest, "invalid archive request")
return
Expand All @@ -398,7 +398,7 @@ func InitiateDownload(ctx *context.Context) {
return
}

archiver, err := repo_model.GetRepoArchiver(ctx, aReq.RepoID, aReq.Type, aReq.CommitID)
archiver, err := repo_model.GetRepoArchiver(ctx, aReq.Repo.ID, aReq.Type, aReq.CommitID)
if err != nil {
ctx.ServerError("archiver_service.StartArchive", err)
return
Expand Down
Loading