2020-12-17 17:00:47 +03:00
// Copyright 2015 The Gogs Authors. All rights reserved.
// Copyright 2017 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2020-12-17 17:00:47 +03:00
2021-08-24 19:47:09 +03:00
//go:build gogit
2020-12-17 17:00:47 +03:00
package git
import (
2021-11-30 23:06:32 +03:00
"context"
2020-12-17 17:00:47 +03:00
"errors"
"path/filepath"
gitealog "code.gitea.io/gitea/modules/log"
2021-06-30 23:58:45 +03:00
"code.gitea.io/gitea/modules/setting"
2024-01-23 08:40:00 +03:00
"github.com/go-git/go-billy/v5"
2020-12-17 17:00:47 +03:00
"github.com/go-git/go-billy/v5/osfs"
gogit "github.com/go-git/go-git/v5"
2023-12-14 00:02:00 +03:00
"github.com/go-git/go-git/v5/plumbing"
2020-12-17 17:00:47 +03:00
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/storage/filesystem"
)
2024-01-19 19:05:02 +03:00
func init ( ) {
isGogit = true
}
2020-12-17 17:00:47 +03:00
// Repository represents a Git repository.
type Repository struct {
Path string
tagCache * ObjectCache
gogitRepo * gogit . Repository
gogitStorage * filesystem . Storage
gpgSettings * GPGSettings
2021-11-30 23:06:32 +03:00
2022-07-25 18:39:42 +03:00
Ctx context . Context
LastCommitCache * LastCommitCache
2023-12-14 00:02:00 +03:00
objectFormat ObjectFormat
2020-12-17 17:00:47 +03:00
}
2022-03-29 22:13:41 +03:00
// openRepositoryWithDefaultContext opens the repository at the given path with DefaultContext.
func openRepositoryWithDefaultContext ( repoPath string ) ( * Repository , error ) {
return OpenRepository ( DefaultContext , repoPath )
2021-11-30 23:06:32 +03:00
}
2022-03-29 22:13:41 +03:00
// OpenRepository opens the repository at the given path within the context.Context
func OpenRepository ( ctx context . Context , repoPath string ) ( * Repository , error ) {
2020-12-17 17:00:47 +03:00
repoPath , err := filepath . Abs ( repoPath )
if err != nil {
return nil , err
} else if ! isDir ( repoPath ) {
return nil , errors . New ( "no such file or directory" )
}
fs := osfs . New ( repoPath )
_ , err = fs . Stat ( ".git" )
if err == nil {
fs , err = fs . Chroot ( ".git" )
if err != nil {
return nil , err
}
}
2024-01-23 08:40:00 +03:00
// the "clone --shared" repo doesn't work well with go-git AlternativeFS, https://github.com/go-git/go-git/issues/1006
// 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.
var altFs billy . Filesystem
if setting . IsWindows {
altFs = osfs . New ( filepath . VolumeName ( setting . RepoRootPath ) + "\\" ) // TODO: does it really work for Windows? Need some time to check.
} else {
altFs = osfs . New ( "/" )
}
storage := filesystem . NewStorageWithOptions ( fs , cache . NewObjectLRUDefault ( ) , filesystem . Options { KeepDescriptors : true , LargeObjectThreshold : setting . Git . LargeObjectThreshold , AlternatesFS : altFs } )
2020-12-17 17:00:47 +03:00
gogitRepo , err := gogit . Open ( storage , fs )
if err != nil {
return nil , err
}
return & Repository {
Path : repoPath ,
gogitRepo : gogitRepo ,
gogitStorage : storage ,
tagCache : newObjectCache ( ) ,
2021-11-30 23:06:32 +03:00
Ctx : ctx ,
2023-12-14 00:02:00 +03:00
objectFormat : ParseGogitHash ( plumbing . ZeroHash ) . Type ( ) ,
2020-12-17 17:00:47 +03:00
} , nil
}
// Close this repository, in particular close the underlying gogitStorage if this is not nil
2024-02-25 16:05:23 +03:00
func ( repo * Repository ) Close ( ) error {
2020-12-17 17:00:47 +03:00
if repo == nil || repo . gogitStorage == nil {
2024-02-25 16:05:23 +03:00
return nil
2020-12-17 17:00:47 +03:00
}
if err := repo . gogitStorage . Close ( ) ; err != nil {
gitealog . Error ( "Error closing storage: %v" , err )
}
2024-02-25 16:05:23 +03:00
repo . gogitStorage = nil
2022-07-25 18:39:42 +03:00
repo . LastCommitCache = nil
repo . tagCache = nil
2024-02-25 16:05:23 +03:00
return nil
2020-12-17 17:00:47 +03:00
}
// GoGitRepo gets the go-git repo representation
func ( repo * Repository ) GoGitRepo ( ) * gogit . Repository {
return repo . gogitRepo
}