code.gitea.io/gitea@v1.22.3/modules/git/repo_base_gogit.go (about)

     1  // Copyright 2015 The Gogs Authors. All rights reserved.
     2  // Copyright 2017 The Gitea Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  //go:build gogit
     6  
     7  package git
     8  
     9  import (
    10  	"context"
    11  	"path/filepath"
    12  
    13  	gitealog "code.gitea.io/gitea/modules/log"
    14  	"code.gitea.io/gitea/modules/setting"
    15  	"code.gitea.io/gitea/modules/util"
    16  
    17  	"github.com/go-git/go-billy/v5"
    18  	"github.com/go-git/go-billy/v5/osfs"
    19  	gogit "github.com/go-git/go-git/v5"
    20  	"github.com/go-git/go-git/v5/plumbing"
    21  	"github.com/go-git/go-git/v5/plumbing/cache"
    22  	"github.com/go-git/go-git/v5/storage/filesystem"
    23  )
    24  
    25  const isGogit = true
    26  
    27  // Repository represents a Git repository.
    28  type Repository struct {
    29  	Path string
    30  
    31  	tagCache *ObjectCache
    32  
    33  	gogitRepo    *gogit.Repository
    34  	gogitStorage *filesystem.Storage
    35  	gpgSettings  *GPGSettings
    36  
    37  	Ctx             context.Context
    38  	LastCommitCache *LastCommitCache
    39  	objectFormat    ObjectFormat
    40  }
    41  
    42  // openRepositoryWithDefaultContext opens the repository at the given path with DefaultContext.
    43  func openRepositoryWithDefaultContext(repoPath string) (*Repository, error) {
    44  	return OpenRepository(DefaultContext, repoPath)
    45  }
    46  
    47  // OpenRepository opens the repository at the given path within the context.Context
    48  func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
    49  	repoPath, err := filepath.Abs(repoPath)
    50  	if err != nil {
    51  		return nil, err
    52  	} else if !isDir(repoPath) {
    53  		return nil, util.NewNotExistErrorf("no such file or directory")
    54  	}
    55  
    56  	fs := osfs.New(repoPath)
    57  	_, err = fs.Stat(".git")
    58  	if err == nil {
    59  		fs, err = fs.Chroot(".git")
    60  		if err != nil {
    61  			return nil, err
    62  		}
    63  	}
    64  	// the "clone --shared" repo doesn't work well with go-git AlternativeFS, https://github.com/go-git/go-git/issues/1006
    65  	// so use "/" for AlternatesFS, I guess it is the same behavior as current nogogit (no limitation or check for the "objects/info/alternates" paths), trust the "clone" command executed by the server.
    66  	var altFs billy.Filesystem
    67  	if setting.IsWindows {
    68  		altFs = osfs.New(filepath.VolumeName(setting.RepoRootPath) + "\\") // TODO: does it really work for Windows? Need some time to check.
    69  	} else {
    70  		altFs = osfs.New("/")
    71  	}
    72  	storage := filesystem.NewStorageWithOptions(fs, cache.NewObjectLRUDefault(), filesystem.Options{KeepDescriptors: true, LargeObjectThreshold: setting.Git.LargeObjectThreshold, AlternatesFS: altFs})
    73  	gogitRepo, err := gogit.Open(storage, fs)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	return &Repository{
    79  		Path:         repoPath,
    80  		gogitRepo:    gogitRepo,
    81  		gogitStorage: storage,
    82  		tagCache:     newObjectCache(),
    83  		Ctx:          ctx,
    84  		objectFormat: ParseGogitHash(plumbing.ZeroHash).Type(),
    85  	}, nil
    86  }
    87  
    88  // Close this repository, in particular close the underlying gogitStorage if this is not nil
    89  func (repo *Repository) Close() error {
    90  	if repo == nil || repo.gogitStorage == nil {
    91  		return nil
    92  	}
    93  	if err := repo.gogitStorage.Close(); err != nil {
    94  		gitealog.Error("Error closing storage: %v", err)
    95  	}
    96  	repo.gogitStorage = nil
    97  	repo.LastCommitCache = nil
    98  	repo.tagCache = nil
    99  	return nil
   100  }
   101  
   102  // GoGitRepo gets the go-git repo representation
   103  func (repo *Repository) GoGitRepo() *gogit.Repository {
   104  	return repo.gogitRepo
   105  }