Refactor legacy git init (#20376)

* merge `CheckLFSVersion` into `InitFull` (renamed from `InitWithSyncOnce`)
* remove the `Once` during git init, no data-race now
* for doctor sub-commands, `InitFull` should only be called in initialization stage

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
wxiaoguang 2022-08-09 11:22:24 +08:00 committed by GitHub
parent 820031e556
commit 75d96f4a02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 63 additions and 149 deletions

View File

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/migrations" "code.gitea.io/gitea/models/migrations"
"code.gitea.io/gitea/modules/doctor" "code.gitea.io/gitea/modules/doctor"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -124,13 +125,18 @@ func runRecreateTable(ctx *cli.Context) error {
} }
func runDoctor(ctx *cli.Context) error { func runDoctor(ctx *cli.Context) error {
stdCtx, cancel := installSignals()
defer cancel()
// some doctor sub-commands need to use git command
if err := git.InitFull(stdCtx); err != nil {
return err
}
// Silence the default loggers // Silence the default loggers
log.DelNamedLogger("console") log.DelNamedLogger("console")
log.DelNamedLogger(log.DEFAULT) log.DelNamedLogger(log.DEFAULT)
stdCtx, cancel := installSignals()
defer cancel()
// Now setup our own // Now setup our own
logFile := ctx.String("log-file") logFile := ctx.String("log-file")
if !ctx.IsSet("log-file") { if !ctx.IsSet("log-file") {

View File

@ -80,7 +80,6 @@ func runPR() {
setting.RunUser = curUser.Username setting.RunUser = curUser.Username
log.Printf("[PR] Loading fixtures data ...\n") log.Printf("[PR] Loading fixtures data ...\n")
gitea_git.CheckLFSVersion()
//models.LoadConfigs() //models.LoadConfigs()
/* /*
setting.Database.Type = "sqlite3" setting.Database.Type = "sqlite3"

View File

@ -156,11 +156,6 @@ func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string
func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) { func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) {
t.Run("LFS", func(t *testing.T) { t.Run("LFS", func(t *testing.T) {
defer PrintCurrentTest(t)() defer PrintCurrentTest(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
prefix := "lfs-data-file-" prefix := "lfs-data-file-"
err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath}) err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
@ -226,7 +221,6 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length) assert.Equal(t, littleSize, resp.Length)
git.CheckLFSVersion()
if setting.LFS.StartServer { if setting.LFS.StartServer {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS)) req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS))
resp := session.MakeRequest(t, req, http.StatusOK) resp := session.MakeRequest(t, req, http.StatusOK)
@ -268,12 +262,9 @@ func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length) assert.Equal(t, littleSize, resp.Length)
git.CheckLFSVersion()
if setting.LFS.StartServer {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS)) req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS))
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length) assert.Equal(t, littleSize, resp.Length)
}
if !testing.Short() { if !testing.Short() {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", big)) req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", big))

View File

@ -175,10 +175,9 @@ func initIntegrationTest() {
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master" setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
_ = util.RemoveAll(repo_module.LocalCopyPath()) _ = util.RemoveAll(repo_module.LocalCopyPath())
if err := git.InitOnceWithSync(context.Background()); err != nil { if err := git.InitFull(context.Background()); err != nil {
log.Fatal("git.InitOnceWithSync: %v", err) log.Fatal("git.InitOnceWithSync: %v", err)
} }
git.CheckLFSVersion()
setting.InitDBConfig() setting.InitDBConfig()
if err := storage.Init(); err != nil { if err := storage.Init(); err != nil {
@ -285,7 +284,6 @@ func prepareTestEnv(t testing.TB, skip ...int) func() {
assert.NoError(t, unittest.LoadFixtures()) assert.NoError(t, unittest.LoadFixtures())
assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath) ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil { if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err) assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
@ -586,7 +584,6 @@ func resetFixtures(t *testing.T) {
assert.NoError(t, unittest.LoadFixtures()) assert.NoError(t, unittest.LoadFixtures())
assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath) ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil { if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err) assert.NoError(t, err, "unable to read the new repo root: %v\n", err)

View File

@ -14,7 +14,6 @@ import (
git_model "code.gitea.io/gitea/models/git" git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -83,11 +82,6 @@ func checkResponseTestContentEncoding(t *testing.T, content *[]byte, resp *httpt
func TestGetLFSSmall(t *testing.T) { func TestGetLFSSmall(t *testing.T) {
defer prepareTestEnv(t)() defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
content := []byte("A very small file\n") content := []byte("A very small file\n")
resp := storeAndGetLfs(t, &content, nil, http.StatusOK) resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
@ -96,11 +90,6 @@ func TestGetLFSSmall(t *testing.T) {
func TestGetLFSLarge(t *testing.T) { func TestGetLFSLarge(t *testing.T) {
defer prepareTestEnv(t)() defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
content := make([]byte, web.GzipMinSize*10) content := make([]byte, web.GzipMinSize*10)
for i := range content { for i := range content {
content[i] = byte(i % 256) content[i] = byte(i % 256)
@ -112,11 +101,6 @@ func TestGetLFSLarge(t *testing.T) {
func TestGetLFSGzip(t *testing.T) { func TestGetLFSGzip(t *testing.T) {
defer prepareTestEnv(t)() defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
b := make([]byte, web.GzipMinSize*10) b := make([]byte, web.GzipMinSize*10)
for i := range b { for i := range b {
b[i] = byte(i % 256) b[i] = byte(i % 256)
@ -133,11 +117,6 @@ func TestGetLFSGzip(t *testing.T) {
func TestGetLFSZip(t *testing.T) { func TestGetLFSZip(t *testing.T) {
defer prepareTestEnv(t)() defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
b := make([]byte, web.GzipMinSize*10) b := make([]byte, web.GzipMinSize*10)
for i := range b { for i := range b {
b[i] = byte(i % 256) b[i] = byte(i % 256)
@ -156,11 +135,6 @@ func TestGetLFSZip(t *testing.T) {
func TestGetLFSRangeNo(t *testing.T) { func TestGetLFSRangeNo(t *testing.T) {
defer prepareTestEnv(t)() defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
content := []byte("123456789\n") content := []byte("123456789\n")
resp := storeAndGetLfs(t, &content, nil, http.StatusOK) resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
@ -169,11 +143,6 @@ func TestGetLFSRangeNo(t *testing.T) {
func TestGetLFSRange(t *testing.T) { func TestGetLFSRange(t *testing.T) {
defer prepareTestEnv(t)() defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
content := []byte("123456789\n") content := []byte("123456789\n")
tests := []struct { tests := []struct {

View File

@ -82,8 +82,7 @@ func initMigrationTest(t *testing.T) func() {
} }
} }
assert.NoError(t, git.InitOnceWithSync(context.Background())) assert.NoError(t, git.InitFull(context.Background()))
git.CheckLFSVersion()
setting.InitDBConfig() setting.InitDBConfig()
setting.NewLogServices(true) setting.NewLogServices(true)
return deferFn return deferFn

View File

@ -66,11 +66,10 @@ func TestMain(m *testing.M) {
setting.SetCustomPathAndConf("", "", "") setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest() setting.LoadForTest()
if err = git.InitOnceWithSync(context.Background()); err != nil { if err = git.InitFull(context.Background()); err != nil {
fmt.Printf("Unable to InitOnceWithSync: %v\n", err) fmt.Printf("Unable to InitFull: %v\n", err)
os.Exit(1) os.Exit(1)
} }
git.CheckLFSVersion()
setting.InitDBConfig() setting.InitDBConfig()
setting.NewLogServices(true) setting.NewLogServices(true)
@ -207,7 +206,6 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En
deferFn := PrintCurrentTest(t, ourSkip) deferFn := PrintCurrentTest(t, ourSkip)
assert.NoError(t, os.RemoveAll(setting.RepoRootPath)) assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath) ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil { if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err) assert.NoError(t, err, "unable to read the new repo root: %v\n", err)

View File

@ -120,11 +120,9 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
fatalTestError("util.CopyDir: %v\n", err) fatalTestError("util.CopyDir: %v\n", err)
} }
if err = git.InitOnceWithSync(context.Background()); err != nil { if err = git.InitFull(context.Background()); err != nil {
fatalTestError("git.Init: %v\n", err) fatalTestError("git.Init: %v\n", err)
} }
git.CheckLFSVersion()
ownerDirs, err := os.ReadDir(setting.RepoRootPath) ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil { if err != nil {
fatalTestError("unable to read the new repo root: %v\n", err) fatalTestError("unable to read the new repo root: %v\n", err)
@ -206,8 +204,6 @@ func PrepareTestEnv(t testing.TB) {
assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta") metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta")
assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath)) assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath))
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath) ownerDirs, err := os.ReadDir(setting.RepoRootPath)
assert.NoError(t, err) assert.NoError(t, err)
for _, ownerDir := range ownerDirs { for _, ownerDir := range ownerDirs {

View File

@ -30,9 +30,6 @@ func iteratePRs(ctx context.Context, repo *repo_model.Repository, each func(*rep
} }
func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) error { func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) error {
if err := git.InitOnceWithSync(ctx); err != nil {
return err
}
numRepos := 0 numRepos := 0
numPRs := 0 numPRs := 0
numPRsUpdated := 0 numPRsUpdated := 0

View File

@ -190,10 +190,6 @@ func checkDaemonExport(ctx context.Context, logger log.Logger, autofix bool) err
} }
func checkCommitGraph(ctx context.Context, logger log.Logger, autofix bool) error { func checkCommitGraph(ctx context.Context, logger log.Logger, autofix bool) error {
if err := git.InitOnceWithSync(ctx); err != nil {
return err
}
numRepos := 0 numRepos := 0
numNeedUpdate := 0 numNeedUpdate := 0
numWritten := 0 numWritten := 0

View File

@ -15,7 +15,6 @@ import (
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
"sync"
"time" "time"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -24,8 +23,8 @@ import (
"github.com/hashicorp/go-version" "github.com/hashicorp/go-version"
) )
// GitVersionRequired is the minimum Git version required // RequiredVersion is the minimum Git version required
const GitVersionRequired = "2.0.0" const RequiredVersion = "2.0.0"
var ( var (
// GitExecutable is the command name of git // GitExecutable is the command name of git
@ -43,7 +42,7 @@ var (
// loadGitVersion returns current Git version from shell. Internal usage only. // loadGitVersion returns current Git version from shell. Internal usage only.
func loadGitVersion() (*version.Version, error) { func loadGitVersion() (*version.Version, error) {
// doesn't need RWMutex because its exec by Init() // doesn't need RWMutex because it's executed by Init()
if gitVersion != nil { if gitVersion != nil {
return gitVersion, nil return gitVersion, nil
} }
@ -90,7 +89,7 @@ func SetExecutablePath(path string) error {
return fmt.Errorf("unable to load git version: %w", err) return fmt.Errorf("unable to load git version: %w", err)
} }
versionRequired, err := version.NewVersion(GitVersionRequired) versionRequired, err := version.NewVersion(RequiredVersion)
if err != nil { if err != nil {
return err return err
} }
@ -104,7 +103,7 @@ func SetExecutablePath(path string) error {
moreHint = "get git: https://git-scm.com/download/linux and https://ius.io" moreHint = "get git: https://git-scm.com/download/linux and https://ius.io"
} }
} }
return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", gitVersion.Original(), GitVersionRequired, moreHint) return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", gitVersion.Original(), RequiredVersion, moreHint)
} }
return nil return nil
@ -131,7 +130,7 @@ func checkInit() error {
return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules") return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
} }
if DefaultContext != nil { if DefaultContext != nil {
log.Warn("git module has been initialized already, duplicate init should be fixed") log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it")
} }
return nil return nil
} }
@ -140,7 +139,7 @@ func checkInit() error {
func HomeDir() string { func HomeDir() string {
if setting.Git.HomePath == "" { if setting.Git.HomePath == "" {
// strict check, make sure the git module is initialized correctly. // strict check, make sure the git module is initialized correctly.
// attention: when the git module is called in gitea sub-command (serv/hook), the log module is not able to show messages to users. // attention: when the git module is called in gitea sub-command (serv/hook), the log module might not obviously show messages to users/developers.
// for example: if there is gitea git hook code calling git.NewCommand before git.InitXxx, the integration test won't show the real failure reasons. // for example: if there is gitea git hook code calling git.NewCommand before git.InitXxx, the integration test won't show the real failure reasons.
log.Fatal("Unable to init Git's HomeDir, incorrect initialization of the setting and git modules") log.Fatal("Unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
return "" return ""
@ -149,14 +148,14 @@ func HomeDir() string {
} }
// InitSimple initializes git module with a very simple step, no config changes, no global command arguments. // InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
// This method doesn't change anything to filesystem. At the moment, it is only used by "git serv" sub-command, no data-race // This method doesn't change anything to filesystem. At the moment, it is only used by some Gitea sub-commands.
// However, in integration test, the sub-command function may be called in the current process, so the InitSimple would be called multiple times, too
func InitSimple(ctx context.Context) error { func InitSimple(ctx context.Context) error {
if err := checkInit(); err != nil { if err := checkInit(); err != nil {
return err return err
} }
DefaultContext = ctx DefaultContext = ctx
globalCommandArgs = nil
if setting.Git.Timeout.Default > 0 { if setting.Git.Timeout.Default > 0 {
defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second
@ -165,17 +164,13 @@ func InitSimple(ctx context.Context) error {
return SetExecutablePath(setting.Git.Path) return SetExecutablePath(setting.Git.Path)
} }
var initOnce sync.Once // InitFull initializes git module with version check and change global variables, sync gitconfig.
// It should only be called once at the beginning of the program initialization (TestMain/GlobalInitInstalled) as this code makes unsynchronized changes to variables.
// InitOnceWithSync initializes git module with version check and change global variables, sync gitconfig. func InitFull(ctx context.Context) (err error) {
// This method will update the global variables ONLY ONCE (just like git.CheckLFSVersion -- which is not ideal too),
// otherwise there will be data-race problem at the moment.
func InitOnceWithSync(ctx context.Context) (err error) {
if err = checkInit(); err != nil { if err = checkInit(); err != nil {
return err return err
} }
initOnce.Do(func() {
if err = InitSimple(ctx); err != nil { if err = InitSimple(ctx); err != nil {
return return
} }
@ -201,10 +196,14 @@ func InitOnceWithSync(ctx context.Context) (err error) {
} }
SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
})
if err != nil { if setting.LFS.StartServer {
return err if CheckGitVersionAtLeast("2.1.2") != nil {
return errors.New("LFS server support requires Git >= 2.1.2")
} }
globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
}
return syncGitConfig() return syncGitConfig()
} }

View File

@ -28,7 +28,7 @@ func testRun(m *testing.M) error {
defer util.RemoveAll(gitHomePath) defer util.RemoveAll(gitHomePath)
setting.Git.HomePath = gitHomePath setting.Git.HomePath = gitHomePath
if err = InitOnceWithSync(context.Background()); err != nil { if err = InitFull(context.Background()); err != nil {
return fmt.Errorf("failed to call Init: %w", err) return fmt.Errorf("failed to call Init: %w", err)
} }

View File

@ -1,31 +0,0 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package git
import (
"sync"
logger "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
var once sync.Once
// CheckLFSVersion will check lfs version, if not satisfied, then disable it.
func CheckLFSVersion() {
if setting.LFS.StartServer {
// Disable LFS client hooks if installed for the current OS user
// Needs at least git v2.1.2
if CheckGitVersionAtLeast("2.1.2") != nil {
setting.LFS.StartServer = false
logger.Error("LFS server support needs at least Git v2.1.2")
} else {
once.Do(func() {
globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=",
"-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
})
}
}
}

View File

@ -100,10 +100,8 @@ func GlobalInitInstalled(ctx context.Context) {
log.Fatal("Gitea is not installed") log.Fatal("Gitea is not installed")
} }
mustInitCtx(ctx, git.InitOnceWithSync) mustInitCtx(ctx, git.InitFull)
log.Info("Git Version: %s (home: %s)", git.VersionInfo(), git.HomeDir()) log.Info("Git Version: %s (home: %s)", git.VersionInfo(), git.HomeDir())
git.CheckLFSVersion()
log.Info("AppPath: %s", setting.AppPath) log.Info("AppPath: %s", setting.AppPath)
log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("AppWorkPath: %s", setting.AppWorkPath)
log.Info("Custom path: %s", setting.CustomPath) log.Info("Custom path: %s", setting.CustomPath)