forked from mirror/gitea
Compare commits
8 Commits
9ecfc54a8f
...
7026a30fdc
Author | SHA1 | Date | |
---|---|---|---|
GiteaBot | 7026a30fdc | ||
zeripath | 7d0629adf8 | ||
wxiaoguang | 042cac5fed | ||
GiteaBot | a3517d8668 | ||
silverwind | 3fd502cca8 | ||
zeripath | 01087e9eef | ||
silverwind | d894c90b70 | ||
singuliere | 64b7d0de8e |
|
@ -66,6 +66,5 @@ CMD ["/bin/s6-svscan", "/etc/s6"]
|
|||
COPY docker/root /
|
||||
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
||||
RUN chmod 755 /usr/bin/entrypoint /app/gitea/gitea /usr/local/bin/environment-to-ini
|
||||
RUN chmod 755 /usr/bin/entrypoint /app/gitea/gitea /usr/local/bin/gitea /usr/local/bin/environment-to-ini
|
||||
RUN chmod 755 /etc/s6/gitea/* /etc/s6/openssh/* /etc/s6/.s6-svscan/*
|
||||
RUN ln -s /app/gitea/gitea /usr/local/bin/gitea
|
||||
|
|
|
@ -53,9 +53,9 @@ RUN mkdir -p /var/lib/gitea /etc/gitea
|
|||
RUN chown git:git /var/lib/gitea /etc/gitea
|
||||
|
||||
COPY docker/rootless /
|
||||
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /usr/local/bin/gitea
|
||||
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
||||
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh /usr/local/bin/docker-setup.sh /usr/local/bin/gitea /usr/local/bin/environment-to-ini
|
||||
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh /usr/local/bin/docker-setup.sh /app/gitea/gitea /usr/local/bin/gitea /usr/local/bin/environment-to-ini
|
||||
|
||||
#git:git
|
||||
USER 1000:1000
|
||||
|
|
17
cmd/cmd.go
17
cmd/cmd.go
|
@ -16,6 +16,7 @@ import (
|
|||
"syscall"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
|
@ -57,15 +58,17 @@ func confirm() (bool, error) {
|
|||
}
|
||||
|
||||
func initDB(ctx context.Context) error {
|
||||
return initDBDisableConsole(ctx, false)
|
||||
}
|
||||
|
||||
func initDBDisableConsole(ctx context.Context, disableConsole bool) error {
|
||||
setting.NewContext()
|
||||
setting.LoadFromExisting()
|
||||
setting.InitDBConfig()
|
||||
setting.NewXORMLogService(disableConsole)
|
||||
setting.NewXORMLogService(false)
|
||||
|
||||
if setting.Database.Type == "" {
|
||||
log.Fatal(`Database settings are missing from the configuration file: %q.
|
||||
Ensure you are running in the correct environment or set the correct configuration file with -c.
|
||||
If this is the intended configuration file complete the [database] section.`, setting.CustomConf)
|
||||
}
|
||||
if err := db.InitEngine(ctx); err != nil {
|
||||
return fmt.Errorf("models.SetEngine: %v", err)
|
||||
return fmt.Errorf("unable to initialise the database using the configuration in %q. Error: %v", setting.CustomConf, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ func runConvert(ctx *cli.Context) error {
|
|||
log.Info("Custom path: %s", setting.CustomPath)
|
||||
log.Info("Log path: %s", setting.LogRootPath)
|
||||
log.Info("Configuration file: %s", setting.CustomConf)
|
||||
setting.InitDBConfig()
|
||||
|
||||
if !setting.Database.UseMySQL {
|
||||
fmt.Println("This command can only be used with a MySQL database")
|
||||
|
|
|
@ -87,7 +87,7 @@ func runRecreateTable(ctx *cli.Context) error {
|
|||
golog.SetPrefix("")
|
||||
golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
|
||||
|
||||
setting.NewContext()
|
||||
setting.LoadFromExisting()
|
||||
setting.InitDBConfig()
|
||||
|
||||
setting.EnableXORMLog = ctx.Bool("debug")
|
||||
|
|
|
@ -159,7 +159,8 @@ func runDump(ctx *cli.Context) error {
|
|||
fatal("Deleting default logger failed. Can not write to stdout: %v", err)
|
||||
}
|
||||
}
|
||||
setting.NewContext()
|
||||
setting.LoadFromExisting()
|
||||
|
||||
// make sure we are logging to the console no matter what the configuration tells us do to
|
||||
if _, err := setting.Cfg.Section("log").NewKey("MODE", "console"); err != nil {
|
||||
fatal("Setting logging mode to console failed: %v", err)
|
||||
|
|
|
@ -88,7 +88,6 @@ func runDumpRepository(ctx *cli.Context) error {
|
|||
log.Info("Custom path: %s", setting.CustomPath)
|
||||
log.Info("Log path: %s", setting.LogRootPath)
|
||||
log.Info("Configuration file: %s", setting.CustomConf)
|
||||
setting.InitDBConfig()
|
||||
|
||||
var (
|
||||
serviceType structs.GitServiceType
|
||||
|
|
|
@ -115,7 +115,7 @@ func initEmbeddedExtractor(c *cli.Context) error {
|
|||
log.DelNamedLogger(log.DEFAULT)
|
||||
|
||||
// Read configuration file
|
||||
setting.NewContext()
|
||||
setting.LoadAllowEmpty()
|
||||
|
||||
pats, err := getPatterns(c.Args())
|
||||
if err != nil {
|
||||
|
|
|
@ -309,7 +309,7 @@ func runHookPostReceive(c *cli.Context) error {
|
|||
defer cancel()
|
||||
|
||||
// First of all run update-server-info no matter what
|
||||
if _, err := git.NewCommand("update-server-info").SetParentContext(ctx).Run(); err != nil {
|
||||
if _, err := git.NewCommandContext(ctx, "update-server-info").Run(); err != nil {
|
||||
return fmt.Errorf("Failed to call 'git update-server-info': %v", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ func runSendMail(c *cli.Context) error {
|
|||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setting.NewContext()
|
||||
setting.LoadFromExisting()
|
||||
|
||||
if err := argsSet(c, "title"); err != nil {
|
||||
return err
|
||||
|
|
|
@ -36,7 +36,6 @@ func runMigrate(ctx *cli.Context) error {
|
|||
log.Info("Custom path: %s", setting.CustomPath)
|
||||
log.Info("Log path: %s", setting.LogRootPath)
|
||||
log.Info("Configuration file: %s", setting.CustomConf)
|
||||
setting.InitDBConfig()
|
||||
|
||||
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
|
||||
log.Fatal("Failed to initialize ORM engine: %v", err)
|
||||
|
|
|
@ -121,7 +121,6 @@ func runMigrateStorage(ctx *cli.Context) error {
|
|||
log.Info("Custom path: %s", setting.CustomPath)
|
||||
log.Info("Log path: %s", setting.LogRootPath)
|
||||
log.Info("Configuration file: %s", setting.CustomConf)
|
||||
setting.InitDBConfig()
|
||||
|
||||
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
|
||||
log.Fatal("Failed to initialize ORM engine: %v", err)
|
||||
|
|
|
@ -50,7 +50,7 @@ func runRestoreRepository(c *cli.Context) error {
|
|||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setting.NewContext()
|
||||
setting.LoadFromExisting()
|
||||
|
||||
statusCode, errStr := private.RestoreRepo(
|
||||
ctx,
|
||||
|
|
|
@ -58,7 +58,7 @@ func setup(logPath string, debug bool) {
|
|||
} else {
|
||||
_ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`)
|
||||
}
|
||||
setting.NewContext()
|
||||
setting.LoadFromExisting()
|
||||
if debug {
|
||||
setting.RunMode = "dev"
|
||||
}
|
||||
|
|
14
cmd/web.go
14
cmd/web.go
|
@ -124,6 +124,10 @@ func runWeb(ctx *cli.Context) error {
|
|||
}
|
||||
c := install.Routes()
|
||||
err := listen(c, false)
|
||||
if err != nil {
|
||||
log.Critical("Unable to open listener for installer. Is Gitea already running?")
|
||||
graceful.GetManager().DoGracefulShutdown()
|
||||
}
|
||||
select {
|
||||
case <-graceful.GetManager().IsShutdown():
|
||||
<-graceful.GetManager().Done()
|
||||
|
@ -145,7 +149,15 @@ func runWeb(ctx *cli.Context) error {
|
|||
|
||||
log.Info("Global init")
|
||||
// Perform global initialization
|
||||
routers.GlobalInit(graceful.GetManager().HammerContext())
|
||||
setting.LoadFromExisting()
|
||||
routers.GlobalInitInstalled(graceful.GetManager().HammerContext())
|
||||
|
||||
// We check that AppDataPath exists here (it should have been created during installation)
|
||||
// We can't check it in `GlobalInitInstalled`, because some integration tests
|
||||
// use cmd -> GlobalInitInstalled, but the AppDataPath doesn't exist during those tests.
|
||||
if _, err := os.Stat(setting.AppDataPath); err != nil {
|
||||
log.Fatal("Can not find APP_DATA_PATH '%s'", setting.AppDataPath)
|
||||
}
|
||||
|
||||
// Override the provided port number within the configuration
|
||||
if ctx.IsSet("port") {
|
||||
|
|
|
@ -156,6 +156,7 @@ func runEnvironmentToIni(c *cli.Context) error {
|
|||
destination = setting.CustomConf
|
||||
}
|
||||
if destination != setting.CustomConf || changed {
|
||||
log.Info("Settings saved to: %q", destination)
|
||||
err = cfg.SaveTo(destination)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
########################################################################
|
||||
# This script some defaults for gitea to run in a FHS compliant manner #
|
||||
########################################################################
|
||||
#############################################################################
|
||||
# This script sets some defaults for gitea to run in a FHS compliant manner #
|
||||
#############################################################################
|
||||
|
||||
# It assumes that you place this script as gitea in /usr/bin
|
||||
#
|
||||
|
@ -36,7 +36,7 @@ if [ -z "$APP_INI_SET" ]; then
|
|||
CONF_ARG="-c \"$APP_INI\""
|
||||
fi
|
||||
|
||||
# Provide FHS compliant defaults to
|
||||
exec -a "$0" GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" "$GITEA" $CONF_ARG "$@"
|
||||
# Provide FHS compliant defaults
|
||||
GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" $CONF_ARG "$@"
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ func runPR() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
setting.SetCustomPathAndConf("", "", "")
|
||||
setting.NewContext()
|
||||
setting.LoadAllowEmpty()
|
||||
|
||||
setting.RepoRootPath, err = os.MkdirTemp(os.TempDir(), "repos")
|
||||
if err != nil {
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
[[ -f ./setup ]] && source ./setup
|
||||
|
||||
pushd /app/gitea >/dev/null
|
||||
exec su-exec $USER /app/gitea/gitea web
|
||||
exec su-exec $USER /usr/local/bin/gitea web
|
||||
popd
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
###############################################################
|
||||
# This script sets defaults for gitea to run in the container #
|
||||
###############################################################
|
||||
|
||||
# It assumes that you place this script as gitea in /usr/local/bin
|
||||
#
|
||||
# And place the original in /usr/lib/gitea with working files in /data/gitea
|
||||
GITEA="/app/gitea/gitea"
|
||||
WORK_DIR="/app/gitea"
|
||||
CUSTOM_PATH="/data/gitea"
|
||||
|
||||
# Provide docker defaults
|
||||
GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" GITEA_CUSTOM="${GITEA_CUSTOM:-$CUSTOM_PATH}" exec -a "$0" "$GITEA" $CONF_ARG "$@"
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#!/bin/bash
|
||||
|
||||
###############################################################
|
||||
# This script sets defaults for gitea to run in the container #
|
||||
###############################################################
|
||||
|
||||
# It assumes that you place this script as gitea in /usr/local/bin
|
||||
#
|
||||
# And place the original in /usr/lib/gitea with working files in /data/gitea
|
||||
GITEA="/app/gitea/gitea"
|
||||
WORK_DIR="/var/lib/gitea"
|
||||
APP_INI="/etc/gitea/app.ini"
|
||||
|
||||
APP_INI_SET=""
|
||||
for i in "$@"; do
|
||||
case "$i" in
|
||||
"-c")
|
||||
APP_INI_SET=1
|
||||
;;
|
||||
"-c="*)
|
||||
APP_INI_SET=1
|
||||
;;
|
||||
"--config")
|
||||
APP_INI_SET=1
|
||||
;;
|
||||
"--config="*)
|
||||
APP_INI_SET=1
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$APP_INI_SET" ]; then
|
||||
CONF_ARG="-c \"$APP_INI\""
|
||||
fi
|
||||
|
||||
|
||||
# Provide docker defaults
|
||||
GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" $CONF_ARG "$@"
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ To maintain understandable code and avoid circular dependencies it is important
|
|||
- `models/db`: Basic database operations. All other `models/xxx` packages should depend on this package. The `GetEngine` function should only be invoked from `models/`.
|
||||
- `models/fixtures`: Sample data used in unit tests and integration tests. One `yml` file means one table which will be loaded into database when beginning the tests.
|
||||
- `models/migrations`: Stores database migrations between versions. PRs that change a database structure **MUST** also have a migration step.
|
||||
- `modules`: Different modules to handle specific functionality in Gitea. Work in Progress: Some of them should be moved to `services`.
|
||||
- `modules`: Different modules to handle specific functionality in Gitea. Work in Progress: Some of them should be moved to `services`, in particular those that depend on models because they rely on the database.
|
||||
- `modules/setting`: Store all system configurations read from ini files and has been referenced by everywhere. But they should be used as function parameters when possible.
|
||||
- `modules/git`: Package to interactive with `Git` command line or Gogit package.
|
||||
- `public`: Compiled frontend files (javascript, images, css, etc.)
|
||||
|
|
|
@ -164,8 +164,8 @@ func initIntegrationTest() {
|
|||
}
|
||||
|
||||
setting.SetCustomPathAndConf("", "", "")
|
||||
setting.NewContext()
|
||||
util.RemoveAll(models.LocalCopyPath())
|
||||
setting.LoadForTest()
|
||||
_ = util.RemoveAll(models.LocalCopyPath())
|
||||
git.CheckLFSVersion()
|
||||
setting.InitDBConfig()
|
||||
if err := storage.Init(); err != nil {
|
||||
|
@ -240,7 +240,8 @@ func initIntegrationTest() {
|
|||
}
|
||||
defer db.Close()
|
||||
}
|
||||
routers.GlobalInit(graceful.GetManager().HammerContext())
|
||||
|
||||
routers.GlobalInitInstalled(graceful.GetManager().HammerContext())
|
||||
}
|
||||
|
||||
func prepareTestEnv(t testing.TB, skip ...int) func() {
|
||||
|
@ -254,6 +255,7 @@ func prepareTestEnv(t testing.TB, skip ...int) func() {
|
|||
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
|
||||
|
||||
assert.NoError(t, util.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
|
||||
|
||||
return deferFn
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ func initMigrationTest(t *testing.T) func() {
|
|||
setting.CustomConf = giteaConf
|
||||
}
|
||||
|
||||
setting.NewContext()
|
||||
setting.LoadForTest()
|
||||
|
||||
assert.True(t, len(setting.RepoRootPath) != 0)
|
||||
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
|
||||
|
|
|
@ -8,7 +8,6 @@ package db
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
@ -92,8 +91,8 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
// NewEngine returns a new xorm engine from the configuration
|
||||
func NewEngine() (*xorm.Engine, error) {
|
||||
// newXORMEngine returns a new XORM engine from the configuration
|
||||
func newXORMEngine() (*xorm.Engine, error) {
|
||||
connStr, err := setting.DBConnStr()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -126,40 +125,49 @@ func SyncAllTables() error {
|
|||
return x.StoreEngine("InnoDB").Sync2(tables...)
|
||||
}
|
||||
|
||||
// InitEngine sets the xorm.Engine
|
||||
func InitEngine(ctx context.Context) (err error) {
|
||||
x, err = NewEngine()
|
||||
// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext
|
||||
func InitEngine(ctx context.Context) error {
|
||||
xormEngine, err := newXORMEngine()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to connect to database: %v", err)
|
||||
return fmt.Errorf("failed to connect to database: %v", err)
|
||||
}
|
||||
|
||||
x.SetMapper(names.GonicMapper{})
|
||||
xormEngine.SetMapper(names.GonicMapper{})
|
||||
// WARNING: for serv command, MUST remove the output to os.stdout,
|
||||
// so use log file to instead print to stdout.
|
||||
x.SetLogger(NewXORMLogger(setting.Database.LogSQL))
|
||||
x.ShowSQL(setting.Database.LogSQL)
|
||||
x.SetMaxOpenConns(setting.Database.MaxOpenConns)
|
||||
x.SetMaxIdleConns(setting.Database.MaxIdleConns)
|
||||
x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime)
|
||||
xormEngine.SetLogger(NewXORMLogger(setting.Database.LogSQL))
|
||||
xormEngine.ShowSQL(setting.Database.LogSQL)
|
||||
xormEngine.SetMaxOpenConns(setting.Database.MaxOpenConns)
|
||||
xormEngine.SetMaxIdleConns(setting.Database.MaxIdleConns)
|
||||
xormEngine.SetConnMaxLifetime(setting.Database.ConnMaxLifetime)
|
||||
xormEngine.SetDefaultContext(ctx)
|
||||
|
||||
SetDefaultEngine(ctx, xormEngine)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetDefaultEngine sets the default engine for db
|
||||
func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) {
|
||||
x = eng
|
||||
DefaultContext = &Context{
|
||||
Context: ctx,
|
||||
e: x,
|
||||
}
|
||||
x.SetDefaultContext(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetEngine is used by unit test code
|
||||
func SetEngine(eng *xorm.Engine) {
|
||||
x = eng
|
||||
DefaultContext = &Context{
|
||||
Context: context.Background(),
|
||||
e: x,
|
||||
// UnsetDefaultEngine closes and unsets the default engine
|
||||
// We hope the SetDefaultEngine and UnsetDefaultEngine can be paired, but it's impossible now,
|
||||
// there are many calls to InitEngine -> SetDefaultEngine directly to overwrite the `x` and DefaultContext without close
|
||||
// Global database engine related functions are all racy and there is no graceful close right now.
|
||||
func UnsetDefaultEngine() {
|
||||
if x != nil {
|
||||
_ = x.Close()
|
||||
x = nil
|
||||
}
|
||||
DefaultContext = nil
|
||||
}
|
||||
|
||||
// InitEngineWithMigration initializes a new xorm.Engine
|
||||
// InitEngineWithMigration initializes a new xorm.Engine and sets it as the db.DefaultContext
|
||||
// This function must never call .Sync2() if the provided migration function fails.
|
||||
// When called from the "doctor" command, the migration function is a version check
|
||||
// that prevents the doctor from fixing anything in the database if the migration level
|
||||
|
@ -226,14 +234,6 @@ func NamesToBean(names ...string) ([]interface{}, error) {
|
|||
return beans, nil
|
||||
}
|
||||
|
||||
// Ping tests if database is alive
|
||||
func Ping() error {
|
||||
if x != nil {
|
||||
return x.Ping()
|
||||
}
|
||||
return errors.New("database not configured")
|
||||
}
|
||||
|
||||
// DumpDatabase dumps all data from database according the special database SQL syntax to file system.
|
||||
func DumpDatabase(filePath, dbType string) error {
|
||||
var tbs []*schemas.Table
|
||||
|
@ -291,11 +291,3 @@ func GetMaxID(beanOrTableName interface{}) (maxID int64, err error) {
|
|||
_, err = x.Select("MAX(id)").Table(beanOrTableName).Get(&maxID)
|
||||
return
|
||||
}
|
||||
|
||||
// FindByMaxID filled results as the condition from database
|
||||
func FindByMaxID(maxID int64, limit int, results interface{}) error {
|
||||
return x.Where("id <= ?", maxID).
|
||||
OrderBy("id DESC").
|
||||
Limit(limit).
|
||||
Find(results)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
// 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 install
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func getXORMEngine() *xorm.Engine {
|
||||
return db.DefaultContext.(*db.Context).Engine().(*xorm.Engine)
|
||||
}
|
||||
|
||||
// CheckDatabaseConnection checks the database connection
|
||||
func CheckDatabaseConnection() error {
|
||||
e := db.GetEngine(db.DefaultContext)
|
||||
_, err := e.Exec("SELECT 1")
|
||||
return err
|
||||
}
|
||||
|
||||
// GetMigrationVersion gets the database migration version
|
||||
func GetMigrationVersion() (int64, error) {
|
||||
var installedDbVersion int64
|
||||
x := getXORMEngine()
|
||||
exist, err := x.IsTableExist("version")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !exist {
|
||||
return 0, nil
|
||||
}
|
||||
_, err = x.Table("version").Cols("version").Get(&installedDbVersion)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return installedDbVersion, nil
|
||||
}
|
||||
|
||||
// HasPostInstallationUsers checks whether there are users after installation
|
||||
func HasPostInstallationUsers() (bool, error) {
|
||||
x := getXORMEngine()
|
||||
exist, err := x.IsTableExist("user")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !exist {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// if there are 2 or more users in database, we consider there are users created after installation
|
||||
threshold := 2
|
||||
if !setting.IsProd {
|
||||
// to debug easily, with non-prod RUN_MODE, we only check the count to 1
|
||||
threshold = 1
|
||||
}
|
||||
res, err := x.Table("user").Cols("id").Limit(threshold).Query()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return len(res) >= threshold, nil
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
|
@ -57,7 +58,7 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
|
||||
setting.SetCustomPathAndConf("", "", "")
|
||||
setting.NewContext()
|
||||
setting.LoadForTest()
|
||||
git.CheckLFSVersion()
|
||||
setting.InitDBConfig()
|
||||
setting.NewLogServices(true)
|
||||
|
@ -85,21 +86,11 @@ func removeAllWithRetry(dir string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// newEngine sets the xorm.Engine
|
||||
func newEngine() (*xorm.Engine, error) {
|
||||
x, err := db.NewEngine()
|
||||
if err != nil {
|
||||
return x, fmt.Errorf("Failed to connect to database: %v", err)
|
||||
func newXORMEngine() (*xorm.Engine, error) {
|
||||
if err := db.InitEngine(context.Background()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
x.SetMapper(names.GonicMapper{})
|
||||
// WARNING: for serv command, MUST remove the output to os.stdout,
|
||||
// so use log file to instead print to stdout.
|
||||
x.SetLogger(db.NewXORMLogger(setting.Database.LogSQL))
|
||||
x.ShowSQL(setting.Database.LogSQL)
|
||||
x.SetMaxOpenConns(setting.Database.MaxOpenConns)
|
||||
x.SetMaxIdleConns(setting.Database.MaxIdleConns)
|
||||
x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime)
|
||||
x := unittest.GetXORMEngine()
|
||||
return x, nil
|
||||
}
|
||||
|
||||
|
@ -213,7 +204,7 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En
|
|||
return nil, deferFn
|
||||
}
|
||||
|
||||
x, err := newEngine()
|
||||
x, err := newXORMEngine()
|
||||
assert.NoError(t, err)
|
||||
if x != nil {
|
||||
oldDefer := deferFn
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
|
||||
func init() {
|
||||
setting.SetCustomPathAndConf("", "", "")
|
||||
setting.NewContext()
|
||||
setting.LoadForTest()
|
||||
}
|
||||
|
||||
func Test_SSHParsePublicKey(t *testing.T) {
|
||||
|
|
|
@ -18,7 +18,8 @@ import (
|
|||
|
||||
var fixtures *testfixtures.Loader
|
||||
|
||||
func getXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
|
||||
// GetXORMEngine gets the XORM engine
|
||||
func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
|
||||
if len(engine) == 1 {
|
||||
return engine[0]
|
||||
}
|
||||
|
@ -27,7 +28,7 @@ func getXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
|
|||
|
||||
// InitFixtures initialize test fixtures for a test database
|
||||
func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
|
||||
e := getXORMEngine(engine...)
|
||||
e := GetXORMEngine(engine...)
|
||||
var testfiles func(*testfixtures.Loader) error
|
||||
if opts.Dir != "" {
|
||||
testfiles = testfixtures.Directory(opts.Dir)
|
||||
|
@ -69,7 +70,7 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
|
|||
|
||||
// LoadFixtures load fixtures for a test database
|
||||
func LoadFixtures(engine ...*xorm.Engine) error {
|
||||
e := getXORMEngine(engine...)
|
||||
e := GetXORMEngine(engine...)
|
||||
var err error
|
||||
// Database transaction conflicts could occur and result in ROLLBACK
|
||||
// As a simple workaround, we just retry 20 times.
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package unittest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
|
@ -124,7 +125,7 @@ func CreateTestEngine(opts FixturesOptions) error {
|
|||
return err
|
||||
}
|
||||
x.SetMapper(names.GonicMapper{})
|
||||
db.SetEngine(x)
|
||||
db.SetDefaultEngine(context.Background(), x)
|
||||
|
||||
if err = db.SyncAllTables(); err != nil {
|
||||
return err
|
||||
|
|
|
@ -534,7 +534,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
|||
return
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
|
||||
gitRepo, err := git.OpenRepositoryCtx(ctx, models.RepoPath(userName, repoName))
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
|
||||
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
|
||||
|
@ -792,7 +792,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
|
|||
|
||||
if ctx.Repo.GitRepo == nil {
|
||||
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||||
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath)
|
||||
ctx.Repo.GitRepo, err = git.OpenRepositoryCtx(ctx, repoPath)
|
||||
if err != nil {
|
||||
ctx.ServerError("RepoRef Invalid repo "+repoPath, err)
|
||||
return
|
||||
|
|
|
@ -44,7 +44,7 @@ func (w *wrappedLevelLogger) Log(skip int, level log.Level, format string, v ...
|
|||
}
|
||||
|
||||
func initDBDisableConsole(ctx context.Context, disableConsole bool) error {
|
||||
setting.NewContext()
|
||||
setting.LoadFromExisting()
|
||||
setting.InitDBConfig()
|
||||
|
||||
setting.NewXORMLogService(disableConsole)
|
||||
|
|
|
@ -67,7 +67,7 @@ func checkConfigurationFiles(logger log.Logger, autofix bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
setting.NewContext()
|
||||
setting.LoadFromExisting()
|
||||
|
||||
configurationFiles := []configurationFile{
|
||||
{"Configuration File Path", setting.CustomConf, false, true, false},
|
||||
|
|
|
@ -28,17 +28,15 @@ type WriteCloserError interface {
|
|||
}
|
||||
|
||||
// CatFileBatchCheck opens git cat-file --batch-check in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
||||
func CatFileBatchCheck(repoPath string) (WriteCloserError, *bufio.Reader, func()) {
|
||||
func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) {
|
||||
batchStdinReader, batchStdinWriter := io.Pipe()
|
||||
batchStdoutReader, batchStdoutWriter := io.Pipe()
|
||||
ctx, ctxCancel := context.WithCancel(DefaultContext)
|
||||
ctx, ctxCancel := context.WithCancel(ctx)
|
||||
closed := make(chan struct{})
|
||||
cancel := func() {
|
||||
_ = batchStdinReader.Close()
|
||||
_ = batchStdinWriter.Close()
|
||||
_ = batchStdoutReader.Close()
|
||||
_ = batchStdoutWriter.Close()
|
||||
ctxCancel()
|
||||
_ = batchStdoutReader.Close()
|
||||
_ = batchStdinWriter.Close()
|
||||
<-closed
|
||||
}
|
||||
|
||||
|
@ -67,19 +65,17 @@ func CatFileBatchCheck(repoPath string) (WriteCloserError, *bufio.Reader, func()
|
|||
}
|
||||
|
||||
// CatFileBatch opens git cat-file --batch in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
||||
func CatFileBatch(repoPath string) (WriteCloserError, *bufio.Reader, func()) {
|
||||
func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) {
|
||||
// We often want to feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
|
||||
// so let's create a batch stdin and stdout
|
||||
batchStdinReader, batchStdinWriter := io.Pipe()
|
||||
batchStdoutReader, batchStdoutWriter := nio.Pipe(buffer.New(32 * 1024))
|
||||
ctx, ctxCancel := context.WithCancel(DefaultContext)
|
||||
ctx, ctxCancel := context.WithCancel(ctx)
|
||||
closed := make(chan struct{})
|
||||
cancel := func() {
|
||||
_ = batchStdinReader.Close()
|
||||
ctxCancel()
|
||||
_ = batchStdinWriter.Close()
|
||||
_ = batchStdoutReader.Close()
|
||||
_ = batchStdoutWriter.Close()
|
||||
ctxCancel()
|
||||
<-closed
|
||||
}
|
||||
|
||||
|
|
|
@ -24,12 +24,12 @@ type BlamePart struct {
|
|||
|
||||
// BlameReader returns part of file blame one by one
|
||||
type BlameReader struct {
|
||||
cmd *exec.Cmd
|
||||
pid int64
|
||||
output io.ReadCloser
|
||||
reader *bufio.Reader
|
||||
lastSha *string
|
||||
cancel context.CancelFunc
|
||||
cmd *exec.Cmd
|
||||
output io.ReadCloser
|
||||
reader *bufio.Reader
|
||||
lastSha *string
|
||||
cancel context.CancelFunc // Cancels the context that this reader runs in
|
||||
finished process.FinishedFunc // Tells the process manager we're finished and it can remove the associated process from the process table
|
||||
}
|
||||
|
||||
var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
|
||||
|
@ -100,8 +100,8 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
|
|||
|
||||
// Close BlameReader - don't run NextPart after invoking that
|
||||
func (r *BlameReader) Close() error {
|
||||
defer process.GetManager().Remove(r.pid)
|
||||
r.cancel()
|
||||
defer r.finished() // Only remove the process from the process table when the underlying command is closed
|
||||
r.cancel() // However, first cancel our own context early
|
||||
|
||||
_ = r.output.Close()
|
||||
|
||||
|
@ -114,7 +114,7 @@ func (r *BlameReader) Close() error {
|
|||
|
||||
// CreateBlameReader creates reader for given repository, commit and file
|
||||
func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) {
|
||||
gitRepo, err := OpenRepository(repoPath)
|
||||
gitRepo, err := OpenRepositoryCtx(ctx, repoPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -125,32 +125,31 @@ func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*B
|
|||
|
||||
func createBlameReader(ctx context.Context, dir string, command ...string) (*BlameReader, error) {
|
||||
// Here we use the provided context - this should be tied to the request performing the blame so that it does not hang around.
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
ctx, cancel, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("GetBlame [repo_path: %s]", dir))
|
||||
|
||||
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
|
||||
cmd.Dir = dir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
defer cancel()
|
||||
defer finished()
|
||||
return nil, fmt.Errorf("StdoutPipe: %v", err)
|
||||
}
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
defer cancel()
|
||||
defer finished()
|
||||
_ = stdout.Close()
|
||||
return nil, fmt.Errorf("Start: %v", err)
|
||||
}
|
||||
|
||||
pid := process.GetManager().Add(fmt.Sprintf("GetBlame [repo_path: %s]", dir), cancel)
|
||||
|
||||
reader := bufio.NewReader(stdout)
|
||||
|
||||
return &BlameReader{
|
||||
cmd,
|
||||
pid,
|
||||
stdout,
|
||||
reader,
|
||||
nil,
|
||||
cancel,
|
||||
cmd: cmd,
|
||||
output: stdout,
|
||||
reader: reader,
|
||||
cancel: cancel,
|
||||
finished: finished,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ type Blob struct {
|
|||
// DataAsync gets a ReadCloser for the contents of a blob without reading it all.
|
||||
// Calling the Close function on the result will discard all unread output.
|
||||
func (b *Blob) DataAsync() (io.ReadCloser, error) {
|
||||
wr, rd, cancel := b.repo.CatFileBatch()
|
||||
wr, rd, cancel := b.repo.CatFileBatch(b.repo.Ctx)
|
||||
|
||||
_, err := wr.Write([]byte(b.ID.String() + "\n"))
|
||||
if err != nil {
|
||||
|
@ -67,7 +67,7 @@ func (b *Blob) Size() int64 {
|
|||
return b.size
|
||||
}
|
||||
|
||||
wr, rd, cancel := b.repo.CatFileBatchCheck()
|
||||
wr, rd, cancel := b.repo.CatFileBatchCheck(b.repo.Ctx)
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(b.ID.String() + "\n"))
|
||||
if err != nil {
|
||||
|
|
|
@ -143,8 +143,13 @@ func (c *Command) RunWithContext(rc *RunContext) error {
|
|||
log.Debug("%s: %v", rc.Dir, c)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(c.parentContext, rc.Timeout)
|
||||
defer cancel()
|
||||
desc := c.desc
|
||||
if desc == "" {
|
||||
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(c.args, " "), rc.Dir)
|
||||
}
|
||||
|
||||
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, rc.Timeout, desc)
|
||||
defer finished()
|
||||
|
||||
cmd := exec.CommandContext(ctx, c.name, c.args...)
|
||||
if rc.Env == nil {
|
||||
|
@ -172,13 +177,6 @@ func (c *Command) RunWithContext(rc *RunContext) error {
|
|||
return err
|
||||
}
|
||||
|
||||
desc := c.desc
|
||||
if desc == "" {
|
||||
desc = fmt.Sprintf("%s %s %s [repo_path: %s]", GitExecutable, c.name, strings.Join(c.args, " "), rc.Dir)
|
||||
}
|
||||
pid := process.GetManager().Add(desc, cancel)
|
||||
defer process.GetManager().Remove(pid)
|
||||
|
||||
if rc.PipelineFunc != nil {
|
||||
err := rc.PipelineFunc(ctx, cancel)
|
||||
if err != nil {
|
||||
|
|
|
@ -100,7 +100,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
|
|||
}
|
||||
|
||||
func getLastCommitForPathsByCache(ctx context.Context, commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
|
||||
wr, rd, cancel := cache.repo.CatFileBatch()
|
||||
wr, rd, cancel := cache.repo.CatFileBatch(ctx)
|
||||
defer cancel()
|
||||
|
||||
var unHitEntryPaths []string
|
||||
|
@ -129,7 +129,7 @@ func GetLastCommitForPaths(ctx context.Context, cache *LastCommitCache, commit *
|
|||
return nil, err
|
||||
}
|
||||
|
||||
batchStdinWriter, batchReader, cancel := commit.repo.CatFileBatch()
|
||||
batchStdinWriter, batchReader, cancel := commit.repo.CatFileBatch(ctx)
|
||||
defer cancel()
|
||||
|
||||
commitsMap := map[string]*Commit{}
|
||||
|
|
|
@ -56,8 +56,8 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
|
|||
fileArgs = append(fileArgs, "--", file)
|
||||
}
|
||||
// FIXME: graceful: These commands should have a timeout
|
||||
ctx, cancel := context.WithCancel(DefaultContext)
|
||||
defer cancel()
|
||||
ctx, _, finished := process.GetManager().AddContext(repo.Ctx, fmt.Sprintf("GetRawDiffForFile: [repo_path: %s]", repo.Path))
|
||||
defer finished()
|
||||
|
||||
var cmd *exec.Cmd
|
||||
switch diffType {
|
||||
|
@ -90,8 +90,6 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
|
|||
cmd.Dir = repo.Path
|
||||
cmd.Stdout = writer
|
||||
cmd.Stderr = stderr
|
||||
pid := process.GetManager().Add(fmt.Sprintf("GetRawDiffForFile: [repo_path: %s]", repo.Path), cancel)
|
||||
defer process.GetManager().Remove(pid)
|
||||
|
||||
if err = cmd.Run(); err != nil {
|
||||
return fmt.Errorf("Run: %v - %s", err, stderr)
|
||||
|
|
|
@ -63,7 +63,7 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
|
|||
|
||||
// Next feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
|
||||
// so let's create a batch stdin and stdout
|
||||
batchStdinWriter, batchReader, cancel := repo.CatFileBatch()
|
||||
batchStdinWriter, batchReader, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
defer cancel()
|
||||
|
||||
// We'll use a scanner for the revList because it's simpler than a bufio.Reader
|
||||
|
|
|
@ -4,19 +4,22 @@
|
|||
|
||||
package git
|
||||
|
||||
import "net/url"
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// GetRemoteAddress returns the url of a specific remote of the repository.
|
||||
func GetRemoteAddress(repoPath, remoteName string) (*url.URL, error) {
|
||||
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.URL, error) {
|
||||
err := LoadGitVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var cmd *Command
|
||||
if CheckGitVersionAtLeast("2.7") == nil {
|
||||
cmd = NewCommand("remote", "get-url", remoteName)
|
||||
cmd = NewCommandContext(ctx, "remote", "get-url", remoteName)
|
||||
} else {
|
||||
cmd = NewCommand("config", "--get", "remote."+remoteName+".url")
|
||||
cmd = NewCommandContext(ctx, "config", "--get", "remote."+remoteName+".url")
|
||||
}
|
||||
|
||||
result, err := cmd.RunInDir(repoPath)
|
||||
|
|
|
@ -211,8 +211,8 @@ type PushOptions struct {
|
|||
}
|
||||
|
||||
// Push pushs local commits to given remote branch.
|
||||
func Push(repoPath string, opts PushOptions) error {
|
||||
cmd := NewCommand("push")
|
||||
func Push(ctx context.Context, repoPath string, opts PushOptions) error {
|
||||
cmd := NewCommandContext(ctx, "push")
|
||||
if opts.Force {
|
||||
cmd.AddArguments("-f")
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[
|
|||
}
|
||||
}
|
||||
|
||||
cmd := NewCommand(cmdArgs...)
|
||||
cmd := NewCommandContext(repo.Ctx, cmdArgs...)
|
||||
|
||||
if err := cmd.RunInDirTimeoutEnvPipeline(env, -1, repo.Path, stdOut, stdErr); err != nil {
|
||||
return nil, fmt.Errorf("failed to run check-attr: %v\n%s\n%s", err, stdOut.String(), stdErr.String())
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
|
||||
|
@ -30,10 +31,17 @@ type Repository struct {
|
|||
gogitRepo *gogit.Repository
|
||||
gogitStorage *filesystem.Storage
|
||||
gpgSettings *GPGSettings
|
||||
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
// OpenRepository opens the repository at the given path.
|
||||
func OpenRepository(repoPath string) (*Repository, error) {
|
||||
return OpenRepositoryCtx(DefaultContext, repoPath)
|
||||
}
|
||||
|
||||
// OpenRepositoryCtx opens the repository at the given path within the context.Context
|
||||
func OpenRepositoryCtx(ctx context.Context, repoPath string) (*Repository, error) {
|
||||
repoPath, err := filepath.Abs(repoPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -60,6 +68,7 @@ func OpenRepository(repoPath string) (*Repository, error) {
|
|||
gogitRepo: gogitRepo,
|
||||
gogitStorage: storage,
|
||||
tagCache: newObjectCache(),
|
||||
Ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,17 @@ type Repository struct {
|
|||
checkCancel context.CancelFunc
|
||||
checkReader *bufio.Reader
|
||||
checkWriter WriteCloserError
|
||||
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
// OpenRepository opens the repository at the given path.
|
||||
func OpenRepository(repoPath string) (*Repository, error) {
|
||||
return OpenRepositoryCtx(DefaultContext, repoPath)
|
||||
}
|
||||
|
||||
// OpenRepositoryCtx opens the repository at the given path with the provided context.
|
||||
func OpenRepositoryCtx(ctx context.Context, repoPath string) (*Repository, error) {
|
||||
repoPath, err := filepath.Abs(repoPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -46,28 +53,29 @@ func OpenRepository(repoPath string) (*Repository, error) {
|
|||
repo := &Repository{
|
||||
Path: repoPath,
|
||||
tagCache: newObjectCache(),
|
||||
Ctx: ctx,
|
||||
}
|
||||
|
||||
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(repoPath)
|
||||
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(repo.Path)
|
||||
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath)
|
||||
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repo.Path)
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
// CatFileBatch obtains a CatFileBatch for this repository
|
||||
func (repo *Repository) CatFileBatch() (WriteCloserError, *bufio.Reader, func()) {
|
||||
func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
|
||||
if repo.batchCancel == nil || repo.batchReader.Buffered() > 0 {
|
||||
log.Debug("Opening temporary cat file batch for: %s", repo.Path)
|
||||
return CatFileBatch(repo.Path)
|
||||
return CatFileBatch(ctx, repo.Path)
|
||||
}
|
||||
return repo.batchWriter, repo.batchReader, func() {}
|
||||
}
|
||||
|
||||
// CatFileBatchCheck obtains a CatFileBatchCheck for this repository
|
||||
func (repo *Repository) CatFileBatchCheck() (WriteCloserError, *bufio.Reader, func()) {
|
||||
func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
|
||||
if repo.checkCancel == nil || repo.checkReader.Buffered() > 0 {
|
||||
log.Debug("Opening temporary cat file batch-check: %s", repo.Path)
|
||||
return CatFileBatchCheck(repo.Path)
|
||||
return CatFileBatchCheck(ctx, repo.Path)
|
||||
}
|
||||
return repo.checkWriter, repo.checkReader, func() {}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@ import "fmt"
|
|||
|
||||
// FileBlame return the Blame object of file
|
||||
func (repo *Repository) FileBlame(revision, path, file string) ([]byte, error) {
|
||||
return NewCommand("blame", "--root", "--", file).RunInDirBytes(path)
|
||||
return NewCommandContext(repo.Ctx, "blame", "--root", "--", file).RunInDirBytes(path)
|
||||
}
|
||||
|
||||
// LineBlame returns the latest commit at the given line
|
||||
func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) {
|
||||
res, err := NewCommand("blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunInDir(path)
|
||||
res, err := NewCommandContext(repo.Ctx, "blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunInDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
@ -22,14 +23,14 @@ const PullRequestPrefix = "refs/for/"
|
|||
// TODO: /refs/for-review for suggest change interface
|
||||
|
||||
// IsReferenceExist returns true if given reference exists in the repository.
|
||||
func IsReferenceExist(repoPath, name string) bool {
|
||||
_, err := NewCommand("show-ref", "--verify", "--", name).RunInDir(repoPath)
|
||||
func IsReferenceExist(ctx context.Context, repoPath, name string) bool {
|
||||
_, err := NewCommandContext(ctx, "show-ref", "--verify", "--", name).RunInDir(repoPath)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsBranchExist returns true if given branch exists in the repository.
|
||||
func IsBranchExist(repoPath, name string) bool {
|
||||
return IsReferenceExist(repoPath, BranchPrefix+name)
|
||||
func IsBranchExist(ctx context.Context, repoPath, name string) bool {
|
||||
return IsReferenceExist(ctx, repoPath, BranchPrefix+name)
|
||||
}
|
||||
|
||||
// Branch represents a Git branch.
|
||||
|
@ -45,7 +46,7 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
|
|||
if repo == nil {
|
||||
return nil, fmt.Errorf("nil repo")
|
||||
}
|
||||
stdout, err := NewCommand("symbolic-ref", "HEAD").RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "symbolic-ref", "HEAD").RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -64,13 +65,13 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
|
|||
|
||||
// SetDefaultBranch sets default branch of repository.
|
||||
func (repo *Repository) SetDefaultBranch(name string) error {
|
||||
_, err := NewCommand("symbolic-ref", "HEAD", BranchPrefix+name).RunInDir(repo.Path)
|
||||
_, err := NewCommandContext(repo.Ctx, "symbolic-ref", "HEAD", BranchPrefix+name).RunInDir(repo.Path)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetDefaultBranch gets default branch of repository.
|
||||
func (repo *Repository) GetDefaultBranch() (string, error) {
|
||||
return NewCommand("symbolic-ref", "HEAD").RunInDir(repo.Path)
|
||||
return NewCommandContext(repo.Ctx, "symbolic-ref", "HEAD").RunInDir(repo.Path)
|
||||
}
|
||||
|
||||
// GetBranch returns a branch by it's name
|
||||
|
@ -118,7 +119,7 @@ type DeleteBranchOptions struct {
|
|||
|
||||
// DeleteBranch delete a branch by name on repository.
|
||||
func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) error {
|
||||
cmd := NewCommand("branch")
|
||||
cmd := NewCommandContext(repo.Ctx, "branch")
|
||||
|
||||
if opts.Force {
|
||||
cmd.AddArguments("-D")
|
||||
|
@ -134,7 +135,7 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
|
|||
|
||||
// CreateBranch create a new branch
|
||||
func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
|
||||
cmd := NewCommand("branch")
|
||||
cmd := NewCommandContext(repo.Ctx, "branch")
|
||||
cmd.AddArguments("--", branch, oldbranchOrCommit)
|
||||
|
||||
_, err := cmd.RunInDir(repo.Path)
|
||||
|
@ -144,7 +145,7 @@ func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
|
|||
|
||||
// AddRemote adds a new remote to repository.
|
||||
func (repo *Repository) AddRemote(name, url string, fetch bool) error {
|
||||
cmd := NewCommand("remote", "add")
|
||||
cmd := NewCommandContext(repo.Ctx, "remote", "add")
|
||||
if fetch {
|
||||
cmd.AddArguments("-f")
|
||||
}
|
||||
|
@ -156,7 +157,7 @@ func (repo *Repository) AddRemote(name, url string, fetch bool) error {
|
|||
|
||||
// RemoveRemote removes a remote from repository.
|
||||
func (repo *Repository) RemoveRemote(name string) error {
|
||||
_, err := NewCommand("remote", "rm", name).RunInDir(repo.Path)
|
||||
_, err := NewCommandContext(repo.Ctx, "remote", "rm", name).RunInDir(repo.Path)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -167,6 +168,6 @@ func (branch *Branch) GetCommit() (*Commit, error) {
|
|||
|
||||
// RenameBranch rename a branch
|
||||
func (repo *Repository) RenameBranch(from, to string) error {
|
||||
_, err := NewCommand("branch", "-m", from, to).RunInDir(repo.Path)
|
||||
_, err := NewCommandContext(repo.Ctx, "branch", "-m", from, to).RunInDir(repo.Path)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ package git
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
|
@ -23,7 +24,7 @@ func (repo *Repository) IsObjectExist(name string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
wr, rd, cancel := repo.CatFileBatchCheck()
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(name + "\n"))
|
||||
if err != nil {
|
||||
|
@ -40,7 +41,7 @@ func (repo *Repository) IsReferenceExist(name string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
wr, rd, cancel := repo.CatFileBatchCheck()
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(name + "\n"))
|
||||
if err != nil {
|
||||
|
@ -63,11 +64,11 @@ func (repo *Repository) IsBranchExist(name string) bool {
|
|||
// GetBranches returns branches from the repository, skipping skip initial branches and
|
||||
// returning at most limit branches, or all branches if limit is 0.
|
||||
func (repo *Repository) GetBranches(skip, limit int) ([]string, int, error) {
|
||||
return callShowRef(repo.Path, BranchPrefix, "--heads", skip, limit)
|
||||
return callShowRef(repo.Ctx, repo.Path, BranchPrefix, "--heads", skip, limit)
|
||||
}
|
||||
|
||||
// callShowRef return refs, if limit = 0 it will not limit
|
||||
func callShowRef(repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) {
|
||||
func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) {
|
||||
stdoutReader, stdoutWriter := io.Pipe()
|
||||
defer func() {
|
||||
_ = stdoutReader.Close()
|
||||
|
@ -76,7 +77,7 @@ func callShowRef(repoPath, prefix, arg string, skip, limit int) (branchNames []s
|
|||
|
||||
go func() {
|
||||
stderrBuilder := &strings.Builder{}
|
||||
err := NewCommand("show-ref", arg).RunInDirPipeline(repoPath, stdoutWriter, stderrBuilder)
|
||||
err := NewCommandContext(ctx, "show-ref", arg).RunInDirPipeline(repoPath, stdoutWriter, stderrBuilder)
|
||||
if err != nil {
|
||||
if stderrBuilder.Len() == 0 {
|
||||
_ = stdoutWriter.Close()
|
||||
|
|
|
@ -58,7 +58,7 @@ func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit,
|
|||
relpath = `\` + relpath
|
||||
}
|
||||
|
||||
stdout, err := NewCommand("log", "-1", prettyLogFormat, id.String(), "--", relpath).RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "log", "-1", prettyLogFormat, id.String(), "--", relpath).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit,
|
|||
|
||||
// GetCommitByPath returns the last commit of relative path.
|
||||
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
|
||||
stdout, err := NewCommand("log", "-1", prettyLogFormat, "--", relpath).RunInDirBytes(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "log", "-1", prettyLogFormat, "--", relpath).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
|
|||
}
|
||||
|
||||
func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) ([]*Commit, error) {
|
||||
stdout, err := NewCommand("log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize),
|
||||
stdout, err := NewCommandContext(repo.Ctx, "log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize),
|
||||
"--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunInDirBytes(repo.Path)
|
||||
|
||||
if err != nil {
|
||||
|
@ -97,7 +97,7 @@ func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) ([]*Commit,
|
|||
|
||||
func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Commit, error) {
|
||||
// create new git log command with limit of 100 commis
|
||||
cmd := NewCommand("log", id.String(), "-100", prettyLogFormat)
|
||||
cmd := NewCommandContext(repo.Ctx, "log", id.String(), "-100", prettyLogFormat)
|
||||
// ignore case
|
||||
args := []string{"-i"}
|
||||
|
||||
|
@ -155,7 +155,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
|
|||
// ignore anything below 4 characters as too unspecific
|
||||
if len(v) >= 4 {
|
||||
// create new git log command with 1 commit limit
|
||||
hashCmd := NewCommand("log", "-1", prettyLogFormat)
|
||||
hashCmd := NewCommandContext(repo.Ctx, "log", "-1", prettyLogFormat)
|
||||
// add previous arguments except for --grep and --all
|
||||
hashCmd.AddArguments(args...)
|
||||
// add keyword as <commit>
|
||||
|
@ -176,7 +176,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
|
|||
}
|
||||
|
||||
func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
|
||||
stdout, err := NewCommand("diff", "--name-only", id1, id2).RunInDirBytes(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "diff", "--name-only", id1, id2).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
|
|||
// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
|
||||
// You must ensure that id1 and id2 are valid commit ids.
|
||||
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
|
||||
stdout, err := NewCommand("diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
|
|||
}()
|
||||
go func() {
|
||||
stderr := strings.Builder{}
|
||||
err := NewCommand("log", revision, "--follow",
|
||||
err := NewCommandContext(repo.Ctx, "log", revision, "--follow",
|
||||
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page),
|
||||
prettyLogFormat, "--", file).
|
||||
RunInDirPipeline(repo.Path, stdoutWriter, &stderr)
|
||||
|
@ -240,7 +240,7 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
|
|||
|
||||
// CommitsByFileAndRangeNoFollow return the commits according revision file and the page
|
||||
func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, page int) ([]*Commit, error) {
|
||||
stdout, err := NewCommand("log", revision, "--skip="+strconv.Itoa((page-1)*50),
|
||||
stdout, err := NewCommandContext(repo.Ctx, "log", revision, "--skip="+strconv.Itoa((page-1)*50),
|
||||
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -250,11 +250,11 @@ func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, pag
|
|||
|
||||
// FilesCountBetween return the number of files changed between two commits
|
||||
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
|
||||
stdout, err := NewCommand("diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
|
||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||
// git >= 2.28 now returns an error if startCommitID and endCommitID have become unrelated.
|
||||
// previously it would return the results of git diff --name-only startCommitID endCommitID so let's try that...
|
||||
stdout, err = NewCommand("diff", "--name-only", startCommitID, endCommitID).RunInDir(repo.Path)
|
||||
stdout, err = NewCommandContext(repo.Ctx, "diff", "--name-only", startCommitID, endCommitID).RunInDir(repo.Path)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -268,13 +268,13 @@ func (repo *Repository) CommitsBetween(last *Commit, before *Commit) ([]*Commit,
|
|||
var stdout []byte
|
||||
var err error
|
||||
if before == nil {
|
||||
stdout, err = NewCommand("rev-list", last.ID.String()).RunInDirBytes(repo.Path)
|
||||
stdout, err = NewCommandContext(repo.Ctx, "rev-list", last.ID.String()).RunInDirBytes(repo.Path)
|
||||
} else {
|
||||
stdout, err = NewCommand("rev-list", before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path)
|
||||
stdout, err = NewCommandContext(repo.Ctx, "rev-list", before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path)
|
||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
||||
// previously it would return the results of git rev-list before last so let's try that...
|
||||
stdout, err = NewCommand("rev-list", before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
|
||||
stdout, err = NewCommandContext(repo.Ctx, "rev-list", before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -288,13 +288,13 @@ func (repo *Repository) CommitsBetweenLimit(last *Commit, before *Commit, limit,
|
|||
var stdout []byte
|
||||
var err error
|
||||
if before == nil {
|
||||
stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunInDirBytes(repo.Path)
|
||||
stdout, err = NewCommandContext(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunInDirBytes(repo.Path)
|
||||
} else {
|
||||
stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path)
|
||||
stdout, err = NewCommandContext(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path)
|
||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
||||
// previously it would return the results of git rev-list --max-count n before last so let's try that...
|
||||
stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
|
||||
stdout, err = NewCommandContext(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -333,7 +333,7 @@ func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
|
|||
|
||||
// commitsBefore the limit is depth, not total number of returned commits.
|
||||
func (repo *Repository) commitsBefore(id SHA1, limit int) ([]*Commit, error) {
|
||||
cmd := NewCommand("log")
|
||||
cmd := NewCommandContext(repo.Ctx, "log")
|
||||
if limit > 0 {
|
||||
cmd.AddArguments("-"+strconv.Itoa(limit), prettyLogFormat, id.String())
|
||||
} else {
|
||||
|
@ -377,7 +377,7 @@ func (repo *Repository) getCommitsBeforeLimit(id SHA1, num int) ([]*Commit, erro
|
|||
|
||||
func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) {
|
||||
if CheckGitVersionAtLeast("2.7.0") == nil {
|
||||
stdout, err := NewCommand("for-each-ref", "--count="+strconv.Itoa(limit), "--format=%(refname:strip=2)", "--contains", commit.ID.String(), BranchPrefix).RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "for-each-ref", "--count="+strconv.Itoa(limit), "--format=%(refname:strip=2)", "--contains", commit.ID.String(), BranchPrefix).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error)
|
|||
return branches, nil
|
||||
}
|
||||
|
||||
stdout, err := NewCommand("branch", "--contains", commit.ID.String()).RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "branch", "--contains", commit.ID.String()).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -425,7 +425,7 @@ func (repo *Repository) GetCommitsFromIDs(commitIDs []string) []*Commit {
|
|||
|
||||
// IsCommitInBranch check if the commit is on the branch
|
||||
func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err error) {
|
||||
stdout, err := NewCommand("branch", "--contains", commitID, branch).RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "branch", "--contains", commitID, branch).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
|
|||
}
|
||||
}
|
||||
|
||||
actualCommitID, err := NewCommand("rev-parse", "--verify", commitID).RunInDir(repo.Path)
|
||||
actualCommitID, err := NewCommandContext(repo.Ctx, "rev-parse", "--verify", commitID).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "unknown revision or path") ||
|
||||
strings.Contains(err.Error(), "fatal: Needed a single revision") {
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
|
||||
// ResolveReference resolves a name to a reference
|
||||
func (repo *Repository) ResolveReference(name string) (string, error) {
|
||||
stdout, err := NewCommand("show-ref", "--hash", name).RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "show-ref", "--hash", name).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not a valid ref") {
|
||||
return "", ErrNotExist{name, ""}
|
||||
|
@ -35,7 +35,7 @@ func (repo *Repository) ResolveReference(name string) (string, error) {
|
|||
|
||||
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
|
||||
func (repo *Repository) GetRefCommitID(name string) (string, error) {
|
||||
wr, rd, cancel := repo.CatFileBatchCheck()
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
defer cancel()
|
||||
_, _ = wr.Write([]byte(name + "\n"))
|
||||
shaBs, _, _, err := ReadBatchLine(rd)
|
||||
|
@ -48,12 +48,12 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) {
|
|||
|
||||
// IsCommitExist returns true if given commit exists in current repository.
|
||||
func (repo *Repository) IsCommitExist(name string) bool {
|
||||
_, err := NewCommand("cat-file", "-e", name).RunInDir(repo.Path)
|
||||
_, err := NewCommandContext(repo.Ctx, "cat-file", "-e", name).RunInDir(repo.Path)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
|
||||
wr, rd, cancel := repo.CatFileBatch()
|
||||
wr, rd, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
defer cancel()
|
||||
|
||||
_, _ = wr.Write([]byte(id.String() + "\n"))
|
||||
|
@ -132,7 +132,7 @@ func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
|
|||
}
|
||||
}
|
||||
|
||||
wr, rd, cancel := repo.CatFileBatchCheck()
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(commitID + "\n"))
|
||||
if err != nil {
|
||||
|
|
|
@ -35,13 +35,13 @@ func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (strin
|
|||
if tmpRemote != "origin" {
|
||||
tmpBaseName := "refs/remotes/" + tmpRemote + "/tmp_" + base
|
||||
// Fetch commit into a temporary branch in order to be able to handle commits and tags
|
||||
_, err := NewCommand("fetch", tmpRemote, base+":"+tmpBaseName).RunInDir(repo.Path)
|
||||
_, err := NewCommandContext(repo.Ctx, "fetch", tmpRemote, base+":"+tmpBaseName).RunInDir(repo.Path)
|
||||
if err == nil {
|
||||
base = tmpBaseName
|
||||
}
|
||||
}
|
||||
|
||||
stdout, err := NewCommand("merge-base", "--", base, head).RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "merge-base", "--", base, head).RunInDir(repo.Path)
|
||||
return strings.TrimSpace(stdout), base, err
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string,
|
|||
|
||||
// We have a common base - therefore we know that ... should work
|
||||
if !fileOnly {
|
||||
logs, err := NewCommand("log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
|
||||
logs, err := NewCommandContext(repo.Ctx, "log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -141,14 +141,14 @@ func (repo *Repository) GetDiffNumChangedFiles(base, head string, directComparis
|
|||
separator = ".."
|
||||
}
|
||||
|
||||
if err := NewCommand("diff", "-z", "--name-only", base+separator+head).
|
||||
if err := NewCommandContext(repo.Ctx, "diff", "-z", "--name-only", base+separator+head).
|
||||
RunInDirPipeline(repo.Path, w, stderr); err != nil {
|
||||
if strings.Contains(stderr.String(), "no merge base") {
|
||||
// git >= 2.28 now returns an error if base and head have become unrelated.
|
||||
// previously it would return the results of git diff -z --name-only base head so let's try that...
|
||||
w = &lineCountWriter{}
|
||||
stderr.Reset()
|
||||
if err = NewCommand("diff", "-z", "--name-only", base, head).RunInDirPipeline(repo.Path, w, stderr); err == nil {
|
||||
if err = NewCommandContext(repo.Ctx, "diff", "-z", "--name-only", base, head).RunInDirPipeline(repo.Path, w, stderr); err == nil {
|
||||
return w.numLines, nil
|
||||
}
|
||||
}
|
||||
|
@ -231,23 +231,23 @@ func (repo *Repository) GetDiffOrPatch(base, head string, w io.Writer, patch, bi
|
|||
|
||||
// GetDiff generates and returns patch data between given revisions, optimized for human readability
|
||||
func (repo *Repository) GetDiff(base, head string, w io.Writer) error {
|
||||
return NewCommand("diff", "-p", base, head).
|
||||
return NewCommandContext(repo.Ctx, "diff", "-p", base, head).
|
||||
RunInDirPipeline(repo.Path, w, nil)
|
||||
}
|
||||
|
||||
// GetDiffBinary generates and returns patch data between given revisions, including binary diffs.
|
||||
func (repo *Repository) GetDiffBinary(base, head string, w io.Writer) error {
|
||||
return NewCommand("diff", "-p", "--binary", base, head).
|
||||
return NewCommandContext(repo.Ctx, "diff", "-p", "--binary", base, head).
|
||||
RunInDirPipeline(repo.Path, w, nil)
|
||||
}
|
||||
|
||||
// GetPatch generates and returns format-patch data between given revisions, able to be used with `git apply`
|
||||
func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
|
||||
stderr := new(bytes.Buffer)
|
||||
err := NewCommand("format-patch", "--binary", "--stdout", base+"..."+head).
|
||||
err := NewCommandContext(repo.Ctx, "format-patch", "--binary", "--stdout", base+"..."+head).
|
||||
RunInDirPipeline(repo.Path, w, stderr)
|
||||
if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) {
|
||||
return NewCommand("format-patch", "--binary", "--stdout", base, head).
|
||||
return NewCommandContext(repo.Ctx, "format-patch", "--binary", "--stdout", base, head).
|
||||
RunInDirPipeline(repo.Path, w, nil)
|
||||
}
|
||||
return err
|
||||
|
@ -256,7 +256,7 @@ func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
|
|||
// GetDiffFromMergeBase generates and return patch data from merge base to head
|
||||
func (repo *Repository) GetDiffFromMergeBase(base, head string, w io.Writer) error {
|
||||
stderr := new(bytes.Buffer)
|
||||
err := NewCommand("diff", "-p", "--binary", base+"..."+head).
|
||||
err := NewCommandContext(repo.Ctx, "diff", "-p", "--binary", base+"..."+head).
|
||||
RunInDirPipeline(repo.Path, w, stderr)
|
||||
if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) {
|
||||
return repo.GetDiffBinary(base, head, w)
|
||||
|
|
|
@ -34,7 +34,7 @@ func (repo *Repository) GetDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings,
|
|||
Sign: true,
|
||||
}
|
||||
|
||||
value, _ := NewCommand("config", "--get", "commit.gpgsign").RunInDir(repo.Path)
|
||||
value, _ := NewCommandContext(repo.Ctx, "config", "--get", "commit.gpgsign").RunInDir(repo.Path)
|
||||
sign, valid := ParseBool(strings.TrimSpace(value))
|
||||
if !sign || !valid {
|
||||
gpgSettings.Sign = false
|
||||
|
@ -42,13 +42,13 @@ func (repo *Repository) GetDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings,
|
|||
return gpgSettings, nil
|
||||
}
|
||||
|
||||
signingKey, _ := NewCommand("config", "--get", "user.signingkey").RunInDir(repo.Path)
|
||||
signingKey, _ := NewCommandContext(repo.Ctx, "config", "--get", "user.signingkey").RunInDir(repo.Path)
|
||||
gpgSettings.KeyID = strings.TrimSpace(signingKey)
|
||||
|
||||
defaultEmail, _ := NewCommand("config", "--get", "user.email").RunInDir(repo.Path)
|
||||
defaultEmail, _ := NewCommandContext(repo.Ctx, "config", "--get", "user.email").RunInDir(repo.Path)
|
||||
gpgSettings.Email = strings.TrimSpace(defaultEmail)
|
||||
|
||||
defaultName, _ := NewCommand("config", "--get", "user.name").RunInDir(repo.Path)
|
||||
defaultName, _ := NewCommandContext(repo.Ctx, "config", "--get", "user.name").RunInDir(repo.Path)
|
||||
gpgSettings.Name = strings.TrimSpace(defaultName)
|
||||
|
||||
if err := gpgSettings.LoadPublicKeyContent(); err != nil {
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
// ReadTreeToIndex reads a treeish to the index
|
||||
func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error {
|
||||
if len(treeish) != 40 {
|
||||
res, err := NewCommand("rev-parse", "--verify", treeish).RunInDir(repo.Path)
|
||||
res, err := NewCommandContext(repo.Ctx, "rev-parse", "--verify", treeish).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func (repo *Repository) readTreeToIndex(id SHA1, indexFilename ...string) error
|
|||
if len(indexFilename) > 0 {
|
||||
env = append(os.Environ(), "GIT_INDEX_FILE="+indexFilename[0])
|
||||
}
|
||||
_, err := NewCommand("read-tree", id.String()).RunInDirWithEnv(repo.Path, env)
|
||||
_, err := NewCommandContext(repo.Ctx, "read-tree", id.String()).RunInDirWithEnv(repo.Path, env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -69,13 +69,13 @@ func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (filename, tmpD
|
|||
|
||||
// EmptyIndex empties the index
|
||||
func (repo *Repository) EmptyIndex() error {
|
||||
_, err := NewCommand("read-tree", "--empty").RunInDir(repo.Path)
|
||||
_, err := NewCommandContext(repo.Ctx, "read-tree", "--empty").RunInDir(repo.Path)
|
||||
return err
|
||||
}
|
||||
|
||||
// LsFiles checks if the given filenames are in the index
|
||||
func (repo *Repository) LsFiles(filenames ...string) ([]string, error) {
|
||||
cmd := NewCommand("ls-files", "-z", "--")
|
||||
cmd := NewCommandContext(repo.Ctx, "ls-files", "-z", "--")
|
||||
for _, arg := range filenames {
|
||||
if arg != "" {
|
||||
cmd.AddArguments(arg)
|
||||
|
@ -95,7 +95,7 @@ func (repo *Repository) LsFiles(filenames ...string) ([]string, error) {
|
|||
|
||||
// RemoveFilesFromIndex removes given filenames from the index - it does not check whether they are present.
|
||||
func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
|
||||
cmd := NewCommand("update-index", "--remove", "-z", "--index-info")
|
||||
cmd := NewCommandContext(repo.Ctx, "update-index", "--remove", "-z", "--index-info")
|
||||
stdout := new(bytes.Buffer)
|
||||
stderr := new(bytes.Buffer)
|
||||
buffer := new(bytes.Buffer)
|
||||
|
@ -111,14 +111,14 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
|
|||
|
||||
// AddObjectToIndex adds the provided object hash to the index at the provided filename
|
||||
func (repo *Repository) AddObjectToIndex(mode string, object SHA1, filename string) error {
|
||||
cmd := NewCommand("update-index", "--add", "--replace", "--cacheinfo", mode, object.String(), filename)
|
||||
cmd := NewCommandContext(repo.Ctx, "update-index", "--add", "--replace", "--cacheinfo", mode, object.String(), filename)
|
||||
_, err := cmd.RunInDir(repo.Path)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteTree writes the current index as a tree to the object db and returns its hash
|
||||
func (repo *Repository) WriteTree() (*Tree, error) {
|
||||
res, err := NewCommand("write-tree").RunInDir(repo.Path)
|
||||
res, err := NewCommandContext(repo.Ctx, "write-tree").RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, error) {
|
||||
// We will feed the commit IDs in order into cat-file --batch, followed by blobs as necessary.
|
||||
// so let's create a batch stdin and stdout
|
||||
batchStdinWriter, batchReader, cancel := repo.CatFileBatch()
|
||||
batchStdinWriter, batchReader, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
defer cancel()
|
||||
|
||||
writeID := func(id string) error {
|
||||
|
@ -76,7 +76,7 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
|
|||
IndexFile: indexFilename,
|
||||
WorkTree: worktree,
|
||||
}
|
||||
ctx, cancel := context.WithCancel(DefaultContext)
|
||||
ctx, cancel := context.WithCancel(repo.Ctx)
|
||||
if err := checker.Init(ctx); err != nil {
|
||||
log.Error("Unable to open checker for %s. Error: %v", commitID, err)
|
||||
} else {
|
||||
|
@ -96,6 +96,12 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
|
|||
var content []byte
|
||||
sizes := make(map[string]int64)
|
||||
for _, f := range entries {
|
||||
select {
|
||||
case <-repo.Ctx.Done():
|
||||
return sizes, repo.Ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
contentBuf.Reset()
|
||||
content = contentBuf.Bytes()
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ func (repo *Repository) HashObject(reader io.Reader) (SHA1, error) {
|
|||
}
|
||||
|
||||
func (repo *Repository) hashObject(reader io.Reader) (string, error) {
|
||||
cmd := NewCommand("hash-object", "-w", "--stdin")
|
||||
cmd := NewCommandContext(repo.Ctx, "hash-object", "-w", "--stdin")
|
||||
stdout := new(bytes.Buffer)
|
||||
stderr := new(bytes.Buffer)
|
||||
err := cmd.RunInDirFullPipeline(repo.Path, stdout, stderr, reader)
|
||||
|
|
|
@ -23,7 +23,7 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
|
|||
|
||||
go func() {
|
||||
stderrBuilder := &strings.Builder{}
|
||||
err := NewCommand("for-each-ref").RunInDirPipeline(repo.Path, stdoutWriter, stderrBuilder)
|
||||
err := NewCommandContext(repo.Ctx, "for-each-ref").RunInDirPipeline(repo.Path, stdoutWriter, stderrBuilder)
|
||||
if err != nil {
|
||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String()))
|
||||
} else {
|
||||
|
|
|
@ -39,7 +39,7 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
|||
|
||||
since := fromTime.Format(time.RFC3339)
|
||||
|
||||
stdout, err := NewCommand("rev-list", "--count", "--no-merges", "--branches=*", "--date=iso", fmt.Sprintf("--since='%s'", since)).RunInDirBytes(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "rev-list", "--count", "--no-merges", "--branches=*", "--date=iso", fmt.Sprintf("--since='%s'", since)).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
|||
}
|
||||
|
||||
stderr := new(strings.Builder)
|
||||
err = NewCommand(args...).RunInDirTimeoutEnvFullPipelineFunc(
|
||||
err = NewCommandContext(repo.Ctx, args...).RunInDirTimeoutEnvFullPipelineFunc(
|
||||
nil, -1, repo.Path,
|
||||
stdoutWriter, stderr, nil,
|
||||
func(ctx context.Context, cancel context.CancelFunc) error {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -17,19 +18,19 @@ import (
|
|||
const TagPrefix = "refs/tags/"
|
||||
|
||||
// IsTagExist returns true if given tag exists in the repository.
|
||||
func IsTagExist(repoPath, name string) bool {
|
||||
return IsReferenceExist(repoPath, TagPrefix+name)
|
||||
func IsTagExist(ctx context.Context, repoPath, name string) bool {
|
||||
return IsReferenceExist(ctx, repoPath, TagPrefix+name)
|
||||
}
|
||||
|
||||
// CreateTag create one tag in the repository
|
||||
func (repo *Repository) CreateTag(name, revision string) error {
|
||||
_, err := NewCommand("tag", "--", name, revision).RunInDir(repo.Path)
|
||||
_, err := NewCommandContext(repo.Ctx, "tag", "--", name, revision).RunInDir(repo.Path)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateAnnotatedTag create one annotated tag in the repository
|
||||
func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error {
|
||||
_, err := NewCommand("tag", "-a", "-m", message, "--", name, revision).RunInDir(repo.Path)
|
||||
_, err := NewCommandContext(repo.Ctx, "tag", "-a", "-m", message, "--", name, revision).RunInDir(repo.Path)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -79,7 +80,7 @@ func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
|
|||
}
|
||||
|
||||
// The tag is an annotated tag with a message.
|
||||
data, err := NewCommand("cat-file", "-p", tagID.String()).RunInDirBytes(repo.Path)
|
||||
data, err := NewCommandContext(repo.Ctx, "cat-file", "-p", tagID.String()).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -104,7 +105,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
|
|||
return "", fmt.Errorf("SHA is too short: %s", sha)
|
||||
}
|
||||
|
||||
stdout, err := NewCommand("show-ref", "--tags", "-d").RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "show-ref", "--tags", "-d").RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -127,7 +128,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
|
|||
|
||||
// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA)
|
||||
func (repo *Repository) GetTagID(name string) (string, error) {
|
||||
stdout, err := NewCommand("show-ref", "--tags", "--", name).RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "show-ref", "--tags", "--", name).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -163,7 +164,7 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
|
|||
// GetTagInfos returns all tag infos of the repository.
|
||||
func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
|
||||
// TODO this a slow implementation, makes one git command per tag
|
||||
stdout, err := NewCommand("tag").RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "tag").RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
@ -196,7 +197,7 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
|
|||
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
|
||||
func (repo *Repository) GetTagType(id SHA1) (string, error) {
|
||||
// Get tag type
|
||||
stdout, err := NewCommand("cat-file", "-t", id.String()).RunInDir(repo.Path)
|
||||
stdout, err := NewCommandContext(repo.Ctx, "cat-file", "-t", id.String()).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -20,6 +20,6 @@ func (repo *Repository) IsTagExist(name string) bool {
|
|||
// GetTags returns all tags of the repository.
|
||||
// returning at most limit tags, or all if limit is 0.
|
||||
func (repo *Repository) GetTags(skip, limit int) (tags []string, err error) {
|
||||
tags, _, err = callShowRef(repo.Path, TagPrefix, "--tags", skip, limit)
|
||||
tags, _, err = callShowRef(repo.Ctx, repo.Path, TagPrefix, "--tags", skip, limit)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ func (repo *Repository) CommitTree(author *Signature, committer *Signature, tree
|
|||
"GIT_COMMITTER_EMAIL="+committer.Email,
|
||||
"GIT_COMMITTER_DATE="+commitTimeStr,
|
||||
)
|
||||
cmd := NewCommand("commit-tree", tree.ID.String())
|
||||
cmd := NewCommandContext(repo.Ctx, "commit-tree", tree.ID.String())
|
||||
|
||||
for _, parent := range opts.Parents {
|
||||
cmd.AddArguments("-p", parent)
|
||||
|
|
|
@ -22,7 +22,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
|
|||
// GetTree find the tree object in the repository.
|
||||
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
|
||||
if len(idStr) != 40 {
|
||||
res, err := NewCommand("rev-parse", "--verify", idStr).RunInDir(repo.Path)
|
||||
res, err := NewCommandContext(repo.Ctx, "rev-parse", "--verify", idStr).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
func (repo *Repository) getTree(id SHA1) (*Tree, error) {
|
||||
wr, rd, cancel := repo.CatFileBatch()
|
||||
wr, rd, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
defer cancel()
|
||||
|
||||
_, _ = wr.Write([]byte(id.String() + "\n"))
|
||||
|
|
|
@ -36,7 +36,7 @@ func (t *Tree) ListEntries() (Entries, error) {
|
|||
}
|
||||
|
||||
if t.repo != nil {
|
||||
wr, rd, cancel := t.repo.CatFileBatch()
|
||||
wr, rd, cancel := t.repo.CatFileBatch(t.repo.Ctx)
|
||||
defer cancel()
|
||||
|
||||
_, _ = wr.Write([]byte(t.ID.String() + "\n"))
|
||||
|
|
|
@ -275,7 +275,7 @@ func (b *BleveIndexer) Index(repo *models.Repository, sha string, changes *repoC
|
|||
batch := gitea_bleve.NewFlushingBatch(b.indexer, maxBatchSize)
|
||||
if len(changes.Updates) > 0 {
|
||||
|
||||
batchWriter, batchReader, cancel := git.CatFileBatch(repo.RepoPath())
|
||||
batchWriter, batchReader, cancel := git.CatFileBatch(git.DefaultContext, repo.RepoPath())
|
||||
defer cancel()
|
||||
|
||||
for _, update := range changes.Updates {
|
||||
|
|
|
@ -248,7 +248,7 @@ func (b *ElasticSearchIndexer) Index(repo *models.Repository, sha string, change
|
|||
reqs := make([]elastic.BulkableRequest, 0)
|
||||
if len(changes.Updates) > 0 {
|
||||
|
||||
batchWriter, batchReader, cancel := git.CatFileBatch(repo.RepoPath())
|
||||
batchWriter, batchReader, cancel := git.CatFileBatch(git.DefaultContext, repo.RepoPath())
|
||||
defer cancel()
|
||||
|
||||
for _, update := range changes.Updates {
|
||||
|
|
|
@ -5,9 +5,13 @@
|
|||
package stats
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
)
|
||||
|
||||
// DBIndexer implements Indexer interface to use database's like search
|
||||
|
@ -16,6 +20,9 @@ type DBIndexer struct {
|
|||
|
||||
// Index repository status function
|
||||
func (db *DBIndexer) Index(id int64) error {
|
||||
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().ShutdownContext(), fmt.Sprintf("Stats.DB Index Repo[%d]", id))
|
||||
defer finished()
|
||||
|
||||
repo, err := models.GetRepositoryByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -29,7 +36,7 @@ func (db *DBIndexer) Index(id int64) error {
|
|||
return err
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
gitRepo, err := git.OpenRepositoryCtx(ctx, repo.RepoPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package external
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -107,11 +106,8 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.
|
|||
ctx.Ctx = graceful.GetManager().ShutdownContext()
|
||||
}
|
||||
|
||||
processCtx, cancel := context.WithCancel(ctx.Ctx)
|
||||
defer cancel()
|
||||
|
||||
pid := process.GetManager().Add(fmt.Sprintf("Render [%s] for %s", commands[0], ctx.URLPrefix), cancel)
|
||||
defer process.GetManager().Remove(pid)
|
||||
processCtx, _, finished := process.GetManager().AddContext(ctx.Ctx, fmt.Sprintf("Render [%s] for %s", commands[0], ctx.URLPrefix))
|
||||
defer finished()
|
||||
|
||||
cmd := exec.CommandContext(processCtx, commands[0], args...)
|
||||
cmd.Env = append(
|
||||
|
|
|
@ -13,14 +13,18 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
func newRequest(ctx context.Context, url, method string) *httplib.Request {
|
||||
if setting.InternalToken == "" {
|
||||
log.Fatal(`The INTERNAL_TOKEN setting is missing from the configuration file: %q.
|
||||
Ensure you are running in the correct environment or set the correct configuration file with -c.`, setting.CustomConf)
|
||||
}
|
||||
return httplib.NewRequest(url, method).
|
||||
SetContext(ctx).
|
||||
Header("Authorization",
|
||||
fmt.Sprintf("Bearer %s", setting.InternalToken))
|
||||
Header("Authorization", fmt.Sprintf("Bearer %s", setting.InternalToken))
|
||||
}
|
||||
|
||||
// Response internal request response
|
||||
|
@ -44,9 +48,6 @@ func newInternalRequest(ctx context.Context, url, method string) *httplib.Reques
|
|||
})
|
||||
if setting.Protocol == setting.UnixSocket {
|
||||
req.SetTransport(&http.Transport{
|
||||
Dial: func(_, _ string) (net.Conn, error) {
|
||||
return net.Dial("unix", setting.HTTPAddr)
|
||||
},
|
||||
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||
var d net.Dialer
|
||||
return d.DialContext(ctx, "unix", setting.HTTPAddr)
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
// 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 process
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Context is a wrapper around context.Context and contains the current pid for this context
|
||||
type Context struct {
|
||||
context.Context
|
||||
pid IDType
|
||||
}
|
||||
|
||||
// GetPID returns the PID for this context
|
||||
func (c *Context) GetPID() IDType {
|
||||
return c.pid
|
||||
}
|
||||
|
||||
// GetParent returns the parent process context (if any)
|
||||
func (c *Context) GetParent() *Context {
|
||||
return GetContext(c.Context)
|
||||
}
|
||||
|
||||
// Value is part of the interface for context.Context. We mostly defer to the internal context - but we return this in response to the ProcessContextKey
|
||||
func (c *Context) Value(key interface{}) interface{} {
|
||||
if key == ProcessContextKey {
|
||||
return c
|
||||
}
|
||||
return c.Context.Value(key)
|
||||
}
|
||||
|
||||
// ProcessContextKey is the key under which process contexts are stored
|
||||
var ProcessContextKey interface{} = "process-context"
|
||||
|
||||
// GetContext will return a process context if one exists
|
||||
func GetContext(ctx context.Context) *Context {
|
||||
if pCtx, ok := ctx.(*Context); ok {
|
||||
return pCtx
|
||||
}
|
||||
pCtxInterface := ctx.Value(ProcessContextKey)
|
||||
if pCtxInterface == nil {
|
||||
return nil
|
||||
}
|
||||
if pCtx, ok := pCtxInterface.(*Context); ok {
|
||||
return pCtx
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPID returns the PID for this context
|
||||
func GetPID(ctx context.Context) IDType {
|
||||
pCtx := GetContext(ctx)
|
||||
if pCtx == nil {
|
||||
return ""
|
||||
}
|
||||
return pCtx.GetPID()
|
||||
}
|
||||
|
||||
// GetParentPID returns the ParentPID for this context
|
||||
func GetParentPID(ctx context.Context) IDType {
|
||||
var parentPID IDType
|
||||
if parentProcess := GetContext(ctx); parentProcess != nil {
|
||||
parentPID = parentProcess.GetPID()
|
||||
}
|
||||
return parentPID
|
||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||
"io"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
@ -28,57 +29,151 @@ var (
|
|||
DefaultContext = context.Background()
|
||||
)
|
||||
|
||||
// Process represents a working process inheriting from Gitea.
|
||||
type Process struct {
|
||||
PID int64 // Process ID, not system one.
|
||||
Description string
|
||||
Start time.Time
|
||||
Cancel context.CancelFunc
|
||||
}
|
||||
// IDType is a pid type
|
||||
type IDType string
|
||||
|
||||
// Manager knows about all processes and counts PIDs.
|
||||
// FinishedFunc is a function that marks that the process is finished and can be removed from the process table
|
||||
// - it is simply an alias for context.CancelFunc and is only for documentary purposes
|
||||
type FinishedFunc = context.CancelFunc
|
||||
|
||||
// Manager manages all processes and counts PIDs.
|
||||
type Manager struct {
|
||||
mutex sync.Mutex
|
||||
|
||||
counter int64
|
||||
processes map[int64]*Process
|
||||
next int64
|
||||
lastTime int64
|
||||
|
||||
processes map[IDType]*Process
|
||||
}
|
||||
|
||||
// GetManager returns a Manager and initializes one as singleton if there's none yet
|
||||
func GetManager() *Manager {
|
||||
managerInit.Do(func() {
|
||||
manager = &Manager{
|
||||
processes: make(map[int64]*Process),
|
||||
processes: make(map[IDType]*Process),
|
||||
next: 1,
|
||||
}
|
||||
})
|
||||
return manager
|
||||
}
|
||||
|
||||
// Add a process to the ProcessManager and returns its PID.
|
||||
func (pm *Manager) Add(description string, cancel context.CancelFunc) int64 {
|
||||
// AddContext creates a new context and adds it as a process. Once the process is finished, finished must be called
|
||||
// to remove the process from the process table. It should not be called until the process is finished but must always be called.
|
||||
//
|
||||
// cancel should be used to cancel the returned context, however it will not remove the process from the process table.
|
||||
// finished will cancel the returned context and remove it from the process table.
|
||||
//
|
||||
// Most processes will not need to use the cancel function but there will be cases whereby you want to cancel the process but not immediately remove it from the
|
||||
// process table.
|
||||
func (pm *Manager) AddContext(parent context.Context, description string) (ctx context.Context, cancel context.CancelFunc, finished FinishedFunc) {
|
||||
parentPID := GetParentPID(parent)
|
||||
|
||||
ctx, cancel = context.WithCancel(parent)
|
||||
|
||||
pid, finished := pm.Add(parentPID, description, cancel)
|
||||
|
||||
return &Context{
|
||||
Context: ctx,
|
||||
pid: pid,
|
||||
}, cancel, finished
|
||||
}
|
||||
|
||||
// AddContextTimeout creates a new context and add it as a process. Once the process is finished, finished must be called
|
||||
// to remove the process from the process table. It should not be called until the process is finsihed but must always be called.
|
||||
//
|
||||
// cancel should be used to cancel the returned context, however it will not remove the process from the process table.
|
||||
// finished will cancel the returned context and remove it from the process table.
|
||||
//
|
||||
// Most processes will not need to use the cancel function but there will be cases whereby you want to cancel the process but not immediately remove it from the
|
||||
// process table.
|
||||
func (pm *Manager) AddContextTimeout(parent context.Context, timeout time.Duration, description string) (ctx context.Context, cancel context.CancelFunc, finshed FinishedFunc) {
|
||||
parentPID := GetParentPID(parent)
|
||||
|
||||
ctx, cancel = context.WithTimeout(parent, timeout)
|
||||
|
||||
pid, finshed := pm.Add(parentPID, description, cancel)
|
||||
|
||||
return &Context{
|
||||
Context: ctx,
|
||||
pid: pid,
|
||||
}, cancel, finshed
|
||||
}
|
||||
|
||||
// Add create a new process
|
||||
func (pm *Manager) Add(parentPID IDType, description string, cancel context.CancelFunc) (IDType, FinishedFunc) {
|
||||
pm.mutex.Lock()
|
||||
pid := pm.counter + 1
|
||||
pm.processes[pid] = &Process{
|
||||
start, pid := pm.nextPID()
|
||||
|
||||
parent := pm.processes[parentPID]
|
||||
if parent == nil {
|
||||
parentPID = ""
|
||||
}
|
||||
|
||||
process := &Process{
|
||||
PID: pid,
|
||||
ParentPID: parentPID,
|
||||
Description: description,
|
||||
Start: time.Now(),
|
||||
Start: start,
|
||||
Cancel: cancel,
|
||||
}
|
||||
pm.counter = pid
|
||||
|
||||
finished := func() {
|
||||
cancel()
|
||||
pm.remove(process)
|
||||
}
|
||||
|
||||
if parent != nil {
|
||||
parent.AddChild(process)
|
||||
}
|
||||
pm.processes[pid] = process
|
||||
pm.mutex.Unlock()
|
||||
|
||||
return pid
|
||||
return pid, finished
|
||||
}
|
||||
|
||||
// nextPID will return the next available PID. pm.mutex should already be locked.
|
||||
func (pm *Manager) nextPID() (start time.Time, pid IDType) {
|
||||
start = time.Now()
|
||||
startUnix := start.Unix()
|
||||
if pm.lastTime == startUnix {
|
||||
pm.next++
|
||||
} else {
|
||||
pm.next = 1
|
||||
}
|
||||
pm.lastTime = startUnix
|
||||
pid = IDType(strconv.FormatInt(start.Unix(), 16))
|
||||
|
||||
if pm.next == 1 {
|
||||
return
|
||||
}
|
||||
pid = IDType(string(pid) + "-" + strconv.FormatInt(pm.next, 10))
|
||||
return
|
||||
}
|
||||
|
||||
// Remove a process from the ProcessManager.
|
||||
func (pm *Manager) Remove(pid int64) {
|
||||
func (pm *Manager) Remove(pid IDType) {
|
||||
pm.mutex.Lock()
|
||||
delete(pm.processes, pid)
|
||||
pm.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (pm *Manager) remove(process *Process) {
|
||||
pm.mutex.Lock()
|
||||
if p := pm.processes[process.PID]; p == process {
|
||||
delete(pm.processes, process.PID)
|
||||
}
|
||||
parent := pm.processes[process.ParentPID]
|
||||
pm.mutex.Unlock()
|
||||
|
||||
if parent == nil {
|
||||
return
|
||||
}
|
||||
|
||||
parent.RemoveChild(process)
|
||||
}
|
||||
|
||||
// Cancel a process in the ProcessManager.
|
||||
func (pm *Manager) Cancel(pid int64) {
|
||||
func (pm *Manager) Cancel(pid IDType) {
|
||||
pm.mutex.Lock()
|
||||
process, ok := pm.processes[pid]
|
||||
pm.mutex.Unlock()
|
||||
|
@ -88,14 +183,28 @@ func (pm *Manager) Cancel(pid int64) {
|
|||
}
|
||||
|
||||
// Processes gets the processes in a thread safe manner
|
||||
func (pm *Manager) Processes() []*Process {
|
||||
func (pm *Manager) Processes(onlyRoots bool) []*Process {
|
||||
pm.mutex.Lock()
|
||||
processes := make([]*Process, 0, len(pm.processes))
|
||||
for _, process := range pm.processes {
|
||||
processes = append(processes, process)
|
||||
if onlyRoots {
|
||||
for _, process := range pm.processes {
|
||||
if _, has := pm.processes[process.ParentPID]; !has {
|
||||
processes = append(processes, process)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, process := range pm.processes {
|
||||
processes = append(processes, process)
|
||||
}
|
||||
}
|
||||
pm.mutex.Unlock()
|
||||
sort.Sort(processList(processes))
|
||||
|
||||
sort.Slice(processes, func(i, j int) bool {
|
||||
left, right := processes[i], processes[j]
|
||||
|
||||
return left.Start.Before(right.Start)
|
||||
})
|
||||
|
||||
return processes
|
||||
}
|
||||
|
||||
|
@ -134,8 +243,8 @@ func (pm *Manager) ExecDirEnvStdIn(timeout time.Duration, dir, desc string, env
|
|||
stdOut := new(bytes.Buffer)
|
||||
stdErr := new(bytes.Buffer)
|
||||
|
||||
ctx, cancel := context.WithTimeout(DefaultContext, timeout)
|
||||
defer cancel()
|
||||
ctx, _, finished := pm.AddContextTimeout(DefaultContext, timeout, desc)
|
||||
defer finished()
|
||||
|
||||
cmd := exec.CommandContext(ctx, cmdName, args...)
|
||||
cmd.Dir = dir
|
||||
|
@ -150,13 +259,11 @@ func (pm *Manager) ExecDirEnvStdIn(timeout time.Duration, dir, desc string, env
|
|||
return "", "", err
|
||||
}
|
||||
|
||||
pid := pm.Add(desc, cancel)
|
||||
err := cmd.Wait()
|
||||
pm.Remove(pid)
|
||||
|
||||
if err != nil {
|
||||
err = &Error{
|
||||
PID: pid,
|
||||
PID: GetPID(ctx),
|
||||
Description: desc,
|
||||
Err: err,
|
||||
CtxErr: ctx.Err(),
|
||||
|
@ -168,23 +275,9 @@ func (pm *Manager) ExecDirEnvStdIn(timeout time.Duration, dir, desc string, env
|
|||
return stdOut.String(), stdErr.String(), err
|
||||
}
|
||||
|
||||
type processList []*Process
|
||||
|
||||
func (l processList) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
func (l processList) Less(i, j int) bool {
|
||||
return l[i].PID < l[j].PID
|
||||
}
|
||||
|
||||
func (l processList) Swap(i, j int) {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
|
||||
// Error is a wrapped error describing the error results of Process Execution
|
||||
type Error struct {
|
||||
PID int64
|
||||
PID IDType
|
||||
Description string
|
||||
Err error
|
||||
CtxErr error
|
||||
|
@ -193,7 +286,7 @@ type Error struct {
|
|||
}
|
||||
|
||||
func (err *Error) Error() string {
|
||||
return fmt.Sprintf("exec(%d:%s) failed: %v(%v) stdout: %s stderr: %s", err.PID, err.Description, err.Err, err.CtxErr, err.Stdout, err.Stderr)
|
||||
return fmt.Sprintf("exec(%s:%s) failed: %v(%v) stdout: %s stderr: %s", err.PID, err.Description, err.Err, err.CtxErr, err.Stdout, err.Stderr)
|
||||
}
|
||||
|
||||
// Unwrap implements the unwrappable implicit interface for go1.13 Unwrap()
|
||||
|
|
|
@ -21,44 +21,72 @@ func TestGetManager(t *testing.T) {
|
|||
assert.NotNil(t, pm)
|
||||
}
|
||||
|
||||
func TestManager_Add(t *testing.T) {
|
||||
pm := Manager{processes: make(map[int64]*Process)}
|
||||
func TestManager_AddContext(t *testing.T) {
|
||||
pm := Manager{processes: make(map[IDType]*Process), next: 1}
|
||||
|
||||
pid := pm.Add("foo", nil)
|
||||
assert.Equal(t, int64(1), pid, "expected to get pid 1 got %d", pid)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
pid = pm.Add("bar", nil)
|
||||
assert.Equal(t, int64(2), pid, "expected to get pid 2 got %d", pid)
|
||||
p1Ctx, _, finished := pm.AddContext(ctx, "foo")
|
||||
defer finished()
|
||||
assert.NotEmpty(t, GetContext(p1Ctx).GetPID(), "expected to get non-empty pid")
|
||||
|
||||
p2Ctx, _, finished := pm.AddContext(p1Ctx, "bar")
|
||||
defer finished()
|
||||
|
||||
assert.NotEmpty(t, GetContext(p2Ctx).GetPID(), "expected to get non-empty pid")
|
||||
|
||||
assert.NotEqual(t, GetContext(p1Ctx).GetPID(), GetContext(p2Ctx).GetPID(), "expected to get different pids %s == %s", GetContext(p2Ctx).GetPID(), GetContext(p1Ctx).GetPID())
|
||||
assert.Equal(t, GetContext(p1Ctx).GetPID(), GetContext(p2Ctx).GetParent().GetPID(), "expected to get pid %s got %s", GetContext(p1Ctx).GetPID(), GetContext(p2Ctx).GetParent().GetPID())
|
||||
}
|
||||
|
||||
func TestManager_Cancel(t *testing.T) {
|
||||
pm := Manager{processes: make(map[int64]*Process)}
|
||||
pm := Manager{processes: make(map[IDType]*Process), next: 1}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
pid := pm.Add("foo", cancel)
|
||||
ctx, _, finished := pm.AddContext(context.Background(), "foo")
|
||||
defer finished()
|
||||
|
||||
pm.Cancel(pid)
|
||||
pm.Cancel(GetPID(ctx))
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
default:
|
||||
assert.Fail(t, "Cancel should cancel the provided context")
|
||||
}
|
||||
finished()
|
||||
|
||||
ctx, cancel, finished := pm.AddContext(context.Background(), "foo")
|
||||
defer finished()
|
||||
|
||||
cancel()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
default:
|
||||
assert.Fail(t, "Cancel should cancel the provided context")
|
||||
}
|
||||
finished()
|
||||
}
|
||||
|
||||
func TestManager_Remove(t *testing.T) {
|
||||
pm := Manager{processes: make(map[int64]*Process)}
|
||||
pm := Manager{processes: make(map[IDType]*Process), next: 1}
|
||||
|
||||
pid1 := pm.Add("foo", nil)
|
||||
assert.Equal(t, int64(1), pid1, "expected to get pid 1 got %d", pid1)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
pid2 := pm.Add("bar", nil)
|
||||
assert.Equal(t, int64(2), pid2, "expected to get pid 2 got %d", pid2)
|
||||
p1Ctx, _, finished := pm.AddContext(ctx, "foo")
|
||||
defer finished()
|
||||
assert.NotEmpty(t, GetContext(p1Ctx).GetPID(), "expected to have non-empty PID")
|
||||
|
||||
pm.Remove(pid2)
|
||||
p2Ctx, _, finished := pm.AddContext(p1Ctx, "bar")
|
||||
defer finished()
|
||||
|
||||
_, exists := pm.processes[pid2]
|
||||
assert.False(t, exists, "PID %d is in the list but shouldn't", pid2)
|
||||
assert.NotEqual(t, GetContext(p1Ctx).GetPID(), GetContext(p2Ctx).GetPID(), "expected to get different pids got %s == %s", GetContext(p2Ctx).GetPID(), GetContext(p1Ctx).GetPID())
|
||||
|
||||
pm.Remove(GetPID(p2Ctx))
|
||||
|
||||
_, exists := pm.processes[GetPID(p2Ctx)]
|
||||
assert.False(t, exists, "PID %d is in the list but shouldn't", GetPID(p2Ctx))
|
||||
}
|
||||
|
||||
func TestExecTimeoutNever(t *testing.T) {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
// 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 process
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Process represents a working process inheriting from Gitea.
|
||||
type Process struct {
|
||||
PID IDType // Process ID, not system one.
|
||||
ParentPID IDType
|
||||
Description string
|
||||
Start time.Time
|
||||
Cancel context.CancelFunc
|
||||
|
||||
lock sync.Mutex
|
||||
children []*Process
|
||||
}
|
||||
|
||||
// Children gets the children of the process
|
||||
// Note: this function will behave nicely even if p is nil
|
||||
func (p *Process) Children() (children []*Process) {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
children = make([]*Process, len(p.children))
|
||||
copy(children, p.children)
|
||||
return children
|
||||
}
|
||||
|
||||
// AddChild adds a child process
|
||||
// Note: this function will behave nicely even if p is nil
|
||||
func (p *Process) AddChild(child *Process) {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
p.children = append(p.children, child)
|
||||
}
|
||||
|
||||
// RemoveChild removes a child process
|
||||
// Note: this function will behave nicely even if p is nil
|
||||
func (p *Process) RemoveChild(process *Process) {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
for i, child := range p.children {
|
||||
if child == process {
|
||||
p.children = append(p.children[:i], p.children[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// 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 setting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// PrepareAppDataPath creates app data directory if necessary
|
||||
func PrepareAppDataPath() error {
|
||||
// FIXME: There are too many calls to MkdirAll in old code. It is incorrect.
|
||||
// For example, if someDir=/mnt/vol1/gitea-home/data, if the mount point /mnt/vol1 is not mounted when Gitea runs,
|
||||
// then gitea will make new empty directories in /mnt/vol1, all are stored in the root filesystem.
|
||||
// The correct behavior should be: creating parent directories is end users' duty. We only create sub-directories in existing parent directories.
|
||||
// For quickstart, the parent directories should be created automatically for first startup (eg: a flag or a check of INSTALL_LOCK).
|
||||
// Now we can take the first step to do correctly (using Mkdir) in other packages, and prepare the AppDataPath here, then make a refactor in future.
|
||||
|
||||
st, err := os.Stat(AppDataPath)
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
err = os.MkdirAll(AppDataPath, os.ModePerm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create the APP_DATA_PATH directory: %q, Error: %v", AppDataPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to use APP_DATA_PATH %q. Error: %v", AppDataPath, err)
|
||||
}
|
||||
|
||||
if !st.IsDir() /* also works for symlink */ {
|
||||
return fmt.Errorf("the APP_DATA_PATH %q is not a directory (or symlink to a directory) and can't be used", AppDataPath)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
// 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 setting
|
||||
|
||||
// defaultI18nLangNames must be a slice, we need the order
|
||||
var defaultI18nLangNames = []string{
|
||||
"en-US", "English",
|
||||
"zh-CN", "简体中文",
|
||||
"zh-HK", "繁體中文(香港)",
|
||||
"zh-TW", "繁體中文(台灣)",
|
||||
"de-DE", "Deutsch",
|
||||
"fr-FR", "français",
|
||||
"nl-NL", "Nederlands",
|
||||
"lv-LV", "latviešu",
|
||||
"ru-RU", "русский",
|
||||
"uk-UA", "Українська",
|
||||
"ja-JP", "日本語",
|
||||
"es-ES", "español",
|
||||
"pt-BR", "português do Brasil",
|
||||
"pt-PT", "Português de Portugal",
|
||||
"pl-PL", "polski",
|
||||
"bg-BG", "български",
|
||||
"it-IT", "italiano",
|
||||
"fi-FI", "suomi",
|
||||
"tr-TR", "Türkçe",
|
||||
"cs-CZ", "čeština",
|
||||
"sr-SP", "српски",
|
||||
"sv-SE", "svenska",
|
||||
"ko-KR", "한국어",
|
||||
"el-GR", "ελληνικά",
|
||||
"fa-IR", "فارسی",
|
||||
"hu-HU", "magyar nyelv",
|
||||
"id-ID", "bahasa Indonesia",
|
||||
"ml-IN", "മലയാളം",
|
||||
}
|
||||
|
||||
func defaultI18nLangs() (res []string) {
|
||||
for i := 0; i < len(defaultI18nLangNames); i += 2 {
|
||||
res = append(res, defaultI18nLangNames[i])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func defaultI18nNames() (res []string) {
|
||||
for i := 0; i < len(defaultI18nLangNames); i += 2 {
|
||||
res = append(res, defaultI18nLangNames[i+1])
|
||||
}
|
||||
return
|
||||
}
|
|
@ -546,9 +546,27 @@ func SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath string)
|
|||
}
|
||||
}
|
||||
|
||||
// NewContext initializes configuration context.
|
||||
// LoadFromExisting initializes setting options from an existing config file (app.ini)
|
||||
func LoadFromExisting() {
|
||||
loadFromConf(false)
|
||||
}
|
||||
|
||||
// LoadAllowEmpty initializes setting options, it's also fine that if the config file (app.ini) doesn't exist
|
||||
func LoadAllowEmpty() {
|
||||
loadFromConf(true)
|
||||
}
|
||||
|
||||
// LoadForTest initializes setting options for tests
|
||||
func LoadForTest() {
|
||||
loadFromConf(true)
|
||||
if err := PrepareAppDataPath(); err != nil {
|
||||
log.Fatal("Can not prepare APP_DATA_PATH: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// loadFromConf initializes configuration context.
|
||||
// NOTE: do not print any log except error.
|
||||
func NewContext() {
|
||||
func loadFromConf(allowEmpty bool) {
|
||||
Cfg = ini.Empty()
|
||||
|
||||
if WritePIDFile && len(PIDFile) > 0 {
|
||||
|
@ -563,9 +581,10 @@ func NewContext() {
|
|||
if err := Cfg.Append(CustomConf); err != nil {
|
||||
log.Fatal("Failed to load custom conf '%s': %v", CustomConf, err)
|
||||
}
|
||||
} else {
|
||||
log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf)
|
||||
}
|
||||
} else if !allowEmpty {
|
||||
log.Fatal("Unable to find configuration file: %q.\nEnsure you are running in the correct environment or set the correct configuration file with -c.", CustomConf)
|
||||
} // else: no config file, a config file might be created at CustomConf later (might not)
|
||||
|
||||
Cfg.NameMapper = ini.SnackCase
|
||||
|
||||
homeDir, err := com.HomeDir()
|
||||
|
@ -698,18 +717,7 @@ func NewContext() {
|
|||
StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(StaticRootPath)
|
||||
StaticCacheTime = sec.Key("STATIC_CACHE_TIME").MustDuration(6 * time.Hour)
|
||||
AppDataPath = sec.Key("APP_DATA_PATH").MustString(path.Join(AppWorkPath, "data"))
|
||||
if _, err = os.Stat(AppDataPath); err != nil {
|
||||
// FIXME: There are too many calls to MkdirAll in old code. It is incorrect.
|
||||
// For example, if someDir=/mnt/vol1/gitea-home/data, if the mount point /mnt/vol1 is not mounted when Gitea runs,
|
||||
// then gitea will make new empty directories in /mnt/vol1, all are stored in the root filesystem.
|
||||
// The correct behavior should be: creating parent directories is end users' duty. We only create sub-directories in existing parent directories.
|
||||
// For quickstart, the parent directories should be created automatically for first startup (eg: a flag or a check of INSTALL_LOCK).
|
||||
// Now we can take the first step to do correctly (using Mkdir) in other packages, and prepare the AppDataPath here, then make a refactor in future.
|
||||
err = os.MkdirAll(AppDataPath, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create the directory for app data path '%s'", AppDataPath)
|
||||
}
|
||||
}
|
||||
|
||||
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
|
||||
EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false)
|
||||
PprofDataPath = sec.Key("PPROF_DATA_PATH").MustString(path.Join(AppWorkPath, "data/tmp/pprof"))
|
||||
|
@ -864,6 +872,10 @@ func NewContext() {
|
|||
SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20)
|
||||
|
||||
InternalToken = loadInternalToken(sec)
|
||||
if InstallLock && InternalToken == "" {
|
||||
// if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate
|
||||
generateSaveInternalToken()
|
||||
}
|
||||
|
||||
cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",")
|
||||
if len(cfgdata) == 0 {
|
||||
|
@ -975,19 +987,11 @@ func NewContext() {
|
|||
|
||||
Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
|
||||
if len(Langs) == 0 {
|
||||
Langs = []string{
|
||||
"en-US", "zh-CN", "zh-HK", "zh-TW", "de-DE", "fr-FR", "nl-NL", "lv-LV",
|
||||
"ru-RU", "uk-UA", "ja-JP", "es-ES", "pt-BR", "pt-PT", "pl-PL", "bg-BG",
|
||||
"it-IT", "fi-FI", "tr-TR", "cs-CZ", "sr-SP", "sv-SE", "ko-KR", "el-GR",
|
||||
"fa-IR", "hu-HU", "id-ID", "ml-IN"}
|
||||
Langs = defaultI18nLangs()
|
||||
}
|
||||
Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
|
||||
if len(Names) == 0 {
|
||||
Names = []string{"English", "简体中文", "繁體中文(香港)", "繁體中文(台灣)", "Deutsch",
|
||||
"français", "Nederlands", "latviešu", "русский", "Українська", "日本語",
|
||||
"español", "português do Brasil", "Português de Portugal", "polski", "български",
|
||||
"italiano", "suomi", "Türkçe", "čeština", "српски", "svenska", "한국어", "ελληνικά",
|
||||
"فارسی", "magyar nyelv", "bahasa Indonesia", "മലയാളം"}
|
||||
Names = defaultI18nNames()
|
||||
}
|
||||
|
||||
ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool(false)
|
||||
|
@ -1054,8 +1058,8 @@ func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) {
|
|||
|
||||
func loadInternalToken(sec *ini.Section) string {
|
||||
uri := sec.Key("INTERNAL_TOKEN_URI").String()
|
||||
if len(uri) == 0 {
|
||||
return loadOrGenerateInternalToken(sec)
|
||||
if uri == "" {
|
||||
return sec.Key("INTERNAL_TOKEN").String()
|
||||
}
|
||||
tempURI, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
|
@ -1092,21 +1096,17 @@ func loadInternalToken(sec *ini.Section) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func loadOrGenerateInternalToken(sec *ini.Section) string {
|
||||
var err error
|
||||
token := sec.Key("INTERNAL_TOKEN").String()
|
||||
if len(token) == 0 {
|
||||
token, err = generate.NewInternalToken()
|
||||
if err != nil {
|
||||
log.Fatal("Error generate internal token: %v", err)
|
||||
}
|
||||
|
||||
// Save secret
|
||||
CreateOrAppendToCustomConf(func(cfg *ini.File) {
|
||||
cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
|
||||
})
|
||||
// generateSaveInternalToken generates and saves the internal token to app.ini
|
||||
func generateSaveInternalToken() {
|
||||
token, err := generate.NewInternalToken()
|
||||
if err != nil {
|
||||
log.Fatal("Error generate internal token: %v", err)
|
||||
}
|
||||
return token
|
||||
|
||||
InternalToken = token
|
||||
CreateOrAppendToCustomConf(func(cfg *ini.File) {
|
||||
cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
|
||||
})
|
||||
}
|
||||
|
||||
// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash
|
||||
|
@ -1186,6 +1186,8 @@ func CreateOrAppendToCustomConf(callback func(cfg *ini.File)) {
|
|||
|
||||
callback(cfg)
|
||||
|
||||
log.Info("Settings saved to: %q", CustomConf)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
|
||||
log.Fatal("failed to create '%s': %v", CustomConf, err)
|
||||
return
|
||||
|
|
|
@ -957,7 +957,7 @@ type remoteAddress struct {
|
|||
func mirrorRemoteAddress(m models.RemoteMirrorer) remoteAddress {
|
||||
a := remoteAddress{}
|
||||
|
||||
u, err := git.GetRemoteAddress(m.GetRepository().RepoPath(), m.GetRemoteName())
|
||||
u, err := git.GetRemoteAddress(git.DefaultContext, m.GetRepository().RepoPath(), m.GetRemoteName())
|
||||
if err != nil {
|
||||
log.Error("GetRemoteAddress %v", err)
|
||||
return a
|
||||
|
|
|
@ -138,6 +138,11 @@ ssl_mode = SSL
|
|||
charset = Charset
|
||||
path = Path
|
||||
sqlite_helper = File path for the SQLite3 database.<br>Enter an absolute path if you run Gitea as a service.
|
||||
reinstall_error = You are trying to install into an existing Gitea database
|
||||
reinstall_confirm_message = Re-installing with an existing Gitea database can cause multiple problems. In most cases, you should use your existing "app.ini" to run Gitea. If you know what you are doing, confirm the following:
|
||||
reinstall_confirm_check_1 = The data encrypted by the SECRET_KEY in app.ini may be lost: users may not be able to log in with 2FA/OTP & mirrors may not function correctly. By checking this box you confirm that the current app.ini file contains the correct the SECRET_KEY.
|
||||
reinstall_confirm_check_2 = The repositories and settings may need to be re-synchronized. By checking this box you confirm that you will resynchronize the hooks for the repositories and authorized_keys file manually. You confirm that you will ensure that repository and mirror settings are correct.
|
||||
reinstall_confirm_check_3 = You confirm that you are absolutely sure that this Gitea is running with the correct app.ini location and that you are sure that you have have to re-install. You confirm that you acknowledge the above risks.
|
||||
err_empty_db_path = The SQLite3 database path cannot be empty.
|
||||
no_admin_and_disable_registration = You cannot disable user self-registration without creating an administrator account.
|
||||
err_empty_admin_password = The administrator password cannot be empty.
|
||||
|
@ -203,8 +208,12 @@ install_btn_confirm = Install Gitea
|
|||
test_git_failed = Could not test 'git' command: %v
|
||||
sqlite3_not_available = This Gitea version does not support SQLite3. Please download the official binary version from %s (not the 'gobuild' version).
|
||||
invalid_db_setting = The database settings are invalid: %v
|
||||
invalid_db_table = The database table '%s' is invalid: %v
|
||||
invalid_repo_path = The repository root path is invalid: %v
|
||||
invalid_app_data_path = The app data path is invalid: %v
|
||||
run_user_not_match = The 'run as' username is not the current username: %s -> %s
|
||||
internal_token_failed = Failed to generate internal token: %v
|
||||
secret_key_failed = Failed to generate secret key: %v
|
||||
save_config_failed = Failed to save configuration: %v
|
||||
invalid_admin_setting = Administrator account setting is invalid: %v
|
||||
install_success = Welcome! Thank you for choosing Gitea. Have fun and take care!
|
||||
|
@ -2696,6 +2705,7 @@ monitor.execute_time = Execution Time
|
|||
monitor.process.cancel = Cancel process
|
||||
monitor.process.cancel_desc = Cancelling a process may cause data loss
|
||||
monitor.process.cancel_notices = Cancel: <strong>%s</strong>?
|
||||
monitor.process.children = Children
|
||||
monitor.queues = Queues
|
||||
monitor.queue = Queue: %s
|
||||
monitor.queue.name = Name
|
||||
|
|
|
@ -85,6 +85,11 @@ remove=Remover
|
|||
remove_all=Excluir todos
|
||||
edit=Editar
|
||||
|
||||
copy=Copiar
|
||||
copy_url=Copiar URL
|
||||
copy_branch=Copiar nome do branch
|
||||
copy_success=Copiado!
|
||||
copy_error=A cópia falhou
|
||||
|
||||
write=Escrever
|
||||
preview=Pré-visualização
|
||||
|
@ -332,6 +337,7 @@ register_success=Cadastro bem-sucedido
|
|||
|
||||
|
||||
release.new.subject=%s em %s lançado
|
||||
release.new.text=<b>@%[1]s</b> lançou a versão %[2]s em %[3]s
|
||||
|
||||
repo.transfer.subject_to=%s gostaria de transferir "%s" para %s
|
||||
repo.transfer.subject_to_you=%s gostaria de transferir "%s" para você
|
||||
|
@ -497,6 +503,7 @@ delete_current_avatar=Excluir o avatar atual
|
|||
uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem.
|
||||
uploaded_avatar_is_too_big=O arquivo enviado excedeu o tamanho máximo.
|
||||
update_avatar_success=Seu avatar foi atualizado.
|
||||
update_user_avatar_success=O avatar do usuário foi atualizado.
|
||||
|
||||
change_password=Atualizar senha
|
||||
old_password=Senha atual
|
||||
|
@ -732,6 +739,7 @@ repo_desc=Descrição
|
|||
repo_desc_helper=Digite uma breve descrição (opcional)
|
||||
repo_lang=Linguagem
|
||||
repo_gitignore_helper=Selecione modelos do .gitignore.
|
||||
repo_gitignore_helper_desc=Escolha os arquivos que não serão rastreados da lista de modelos para linguagens comuns. Artefatos típicos gerados pelos compiladores de cada linguagem estão incluídos no .gitignore por padrão.
|
||||
issue_labels=Etiquetas de issue
|
||||
issue_labels_helper=Selecione um conjunto de etiquetas de issue.
|
||||
license=Licença
|
||||
|
@ -743,6 +751,7 @@ readme_helper_desc=Aqui você pode escrever uma descrição completa para o seu
|
|||
auto_init=Inicializar o repositório (adicionando .gitignore, licença e LEIA-ME)
|
||||
trust_model_helper=Selecione o modelo de confiança para verificação de assinatura. As opções possíveis são:
|
||||
trust_model_helper_collaborator=Colaborador: Confiar em assinaturas de colaboradores
|
||||
trust_model_helper_committer=Committer: Confiar em assinaturas que correspondem aos committers
|
||||
trust_model_helper_default=Padrão: Usar o modelo de confiança padrão para esta instalação
|
||||
create_repo=Criar repositório
|
||||
default_branch=Branch padrão
|
||||
|
@ -840,6 +849,7 @@ migrate.clone_address_desc=URL HTTP (S) ou Git 'clone' de um repositório existe
|
|||
migrate.github_token_desc=Você pode colocar aqui um ou mais tokens separados com vírgula para tornar a migração mais rápida devido ao limite de taxa de API do Github. AVISO: abusar desse recurso pode violar a política do provedor de serviço e levar ao bloqueio da conta.
|
||||
migrate.clone_local_path=ou um caminho de servidor local
|
||||
migrate.permission_denied=Você não pode importar repositórios locais.
|
||||
migrate.permission_denied_blocked=Você não pode importar dos hosts não permitidos, por favor peça ao administrador para verificar as configurações ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS.
|
||||
migrate.invalid_local_path=O caminho local é inválido. Ele não existe ou não é um diretório.
|
||||
migrate.invalid_lfs_endpoint=O destino LFS não é válido.
|
||||
migrate.failed=Migração falhou: %v
|
||||
|
@ -886,6 +896,7 @@ clone_this_repo=Clonar este repositório
|
|||
create_new_repo_command=Criando um novo repositório por linha de comando
|
||||
push_exist_repo=Realizando push para um repositório existente por linha de comando
|
||||
empty_message=Este repositório está vazio.
|
||||
broken_message=Os dados do git subjacente a este repositório não podem ser lidos. Entre em contato com o administrador desta instância ou exclua este repositório.
|
||||
|
||||
code=Código
|
||||
code.desc=Acesso a código-fonte, arquivos, commits e branches.
|
||||
|
@ -908,6 +919,7 @@ commit=Commit
|
|||
release=Versão
|
||||
releases=Versões
|
||||
released_this=lançou isto
|
||||
file.title=%s em %s
|
||||
file_raw=Original
|
||||
file_history=Histórico
|
||||
file_view_source=Exibir código-fonte
|
||||
|
@ -1101,6 +1113,9 @@ issues.add_assignee_at=`foi atribuído por <b>%s</b> %s`
|
|||
issues.remove_assignee_at=`teve sua atribuição removida por <b>%s</b> %s`
|
||||
issues.remove_self_assignment=`removeu sua atribuição %s`
|
||||
issues.change_title_at=`alterou o título de <b><strike>%s</strike></b> para <b>%s</b> %s`
|
||||
issues.change_ref_at=`mudou a referência de <b><strike>%s</strike></b> para <b>%s</b> %s`
|
||||
issues.remove_ref_at=`removeu a referência <b>%s</b> %s`
|
||||
issues.add_ref_at=`adicionou a referência <b>%s</b> %s`
|
||||
issues.delete_branch_at=`excluiu branch <b>%s</b> %s`
|
||||
issues.open_tab=%d aberto
|
||||
issues.close_tab=%d fechado
|
||||
|
@ -1297,6 +1312,7 @@ pulls.switch_head_and_base=Trocar cabeça e base
|
|||
pulls.filter_branch=Filtrar branch
|
||||
pulls.no_results=Nada encontrado.
|
||||
pulls.nothing_to_compare=Estes branches são iguais. Não há nenhuma necessidade para criar um pull request.
|
||||
pulls.has_pull_request=`Um pull request entre esses branches já existe: <a href="%[1]s">%[2]s#%[3]d</a>`
|
||||
pulls.create=Criar pull request
|
||||
pulls.title_desc=quer aplicar o merge de %[1]d commits de <code>%[2]s</code> em <code id="branch_target">%[3]s</code>
|
||||
pulls.merged_title_desc=aplicou merge dos %[1]d commits de <code>%[2]s</code> em <code>%[3]s</code> %[4]s
|
||||
|
@ -1813,6 +1829,7 @@ diff.file_byte_size=Tamanho
|
|||
diff.file_suppressed=Diferenças do arquivo suprimidas por serem muito extensas
|
||||
diff.too_many_files=Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff
|
||||
diff.show_more=Mostrar mais
|
||||
diff.load=Carregar Diff
|
||||
diff.generated=gerado
|
||||
diff.vendored=externo
|
||||
diff.comment.placeholder=Deixe um comentário
|
||||
|
@ -2373,6 +2390,7 @@ monitor.execute_time=Tempo de execução
|
|||
monitor.process.cancel=Cancelar processo
|
||||
monitor.process.cancel_desc=Cancelar um processo pode causar perda de dados
|
||||
monitor.process.cancel_notices=Cancelar: <strong>%s</strong>?
|
||||
monitor.process.children=Descendentes
|
||||
monitor.queues=Filas
|
||||
monitor.queue=Fila: %s
|
||||
monitor.queue.name=Nome
|
||||
|
@ -2444,13 +2462,31 @@ notices.delete_success=Os avisos do sistema foram excluídos.
|
|||
[action]
|
||||
create_repo=criou o repositório <a href="%s">%s</a>
|
||||
rename_repo=renomeou o repositório <code>%[1]s</code> para <a href="%[2]s">%[3]s</a>
|
||||
commit_repo=push feito para <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
|
||||
create_issue=`abriu a issue <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
close_issue=`fechou a issue <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
reopen_issue=`reabriu a issue <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
create_pull_request=`criou o pull request <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
close_pull_request=`fechou o pull request <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
reopen_pull_request=`reabriu o pull request <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
comment_issue=`comentou na issue <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
comment_pull=`comentou no pull request <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
merge_pull_request=`fez merge do pull request <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
transfer_repo=transferiu repositório de <code>%s</code> para <a href="%s">%s</a>
|
||||
push_tag=fez push da tag <a href="%[2]s">%[3]s</a> to <a href="%[1]s">%[4]s</a>
|
||||
delete_tag=excluiu tag %[2]s de <a href="%[1]s"> %[3]s</a>
|
||||
delete_branch=excluiu branch %[2]s de <a href="%[1]s">%[3]s</a>
|
||||
compare_branch=Comparar
|
||||
compare_commits=Compare %d commits
|
||||
compare_commits_general=Comparar commits
|
||||
mirror_sync_push=sincronizou os commits para <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a> do espelho
|
||||
mirror_sync_create=sincronizou a nova referência <a href="%[2]s">%[3]s</a> para <a href="%[1]s">%[4]s</a> do espelho
|
||||
mirror_sync_delete=referência excluída e sincronizada <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> do espelhamento
|
||||
approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
publish_release=`lançou a versão <a href="%[2]s"> "%[4]s" </a> em <a href="%[1]s">%[3]s</a>`
|
||||
review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
create_branch=criou o branch <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
|
||||
watched_repo=começou a observar <a href="%[1]s">%[2]s</a>
|
||||
|
||||
[tool]
|
||||
|
|
|
@ -1598,7 +1598,6 @@ activity.closed_issues_count_1=questão encerrada
|
|||
activity.closed_issues_count_n=questões encerradas
|
||||
activity.title.issues_1=%d questão
|
||||
activity.title.issues_n=%d questões
|
||||
activity.title.issues_closed_from=%s resolvidas de %s
|
||||
activity.title.issues_created_by=%s criada por %s
|
||||
activity.closed_issue_label=Encerrada
|
||||
activity.new_issues_count_1=questão nova
|
||||
|
@ -2037,6 +2036,7 @@ diff.file_suppressed_line_too_long=A apresentação das diferenças entre fichei
|
|||
diff.too_many_files=Alguns ficheiros não foram mostrados porque foram modificados demasiados ficheiros neste diff
|
||||
diff.show_more=Mostrar mais
|
||||
diff.load=Carregar diff
|
||||
diff.generated=gerado
|
||||
diff.comment.placeholder=Deixar um comentário
|
||||
diff.comment.markdown_info=A formatação com markdown é suportada.
|
||||
diff.comment.add_single_comment=Adicionar um único comentário
|
||||
|
@ -2389,6 +2389,8 @@ users.list_status_filter.is_restricted=Restrito
|
|||
users.list_status_filter.not_restricted=Não restrito
|
||||
users.list_status_filter.is_prohibit_login=Proibir início de sessão
|
||||
users.list_status_filter.not_prohibit_login=Permitir início de sessão
|
||||
users.list_status_filter.is_2fa_enabled=Autenticação em dois passos habilitada
|
||||
users.list_status_filter.not_2fa_enabled=Autenticação em dois passos desabilitada
|
||||
|
||||
emails.email_manage_panel=Gestão de endereços de email do utilizador
|
||||
emails.primary=Principal
|
||||
|
@ -2454,6 +2456,7 @@ auths.attribute_name=Atributo do Primeiro Nome
|
|||
auths.attribute_surname=Atributo do Sobrenome
|
||||
auths.attribute_mail=Atributo do email
|
||||
auths.attribute_ssh_public_key=Atributo da chave pública SSH
|
||||
auths.attribute_avatar=Atributo do avatar
|
||||
auths.attributes_in_bind=Buscar os atributos no contexto de Bind DN
|
||||
auths.allow_deactivate_all=Permitir que um resultado de pesquisa vazio desabilite todos os utilizadores
|
||||
auths.use_paged_search=Usar pesquisa paginada
|
||||
|
@ -2683,6 +2686,7 @@ monitor.execute_time=Tempo de execução
|
|||
monitor.process.cancel=Cancelar processo
|
||||
monitor.process.cancel_desc=Cancelar um processo pode resultar na perda de dados
|
||||
monitor.process.cancel_notices=Cancelar: <strong>%s</strong>?
|
||||
monitor.process.children=Descendentes
|
||||
monitor.queues=Filas
|
||||
monitor.queue=Fila: %s
|
||||
monitor.queue.name=Nome
|
||||
|
@ -2780,6 +2784,7 @@ publish_release=`lançou <a href="%[2]s"> "%[4]s" </a> em <a href="%[1]s">%[3]s<
|
|||
review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||
review_dismissed_reason=Motivo:
|
||||
create_branch=criou o ramo <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
|
||||
starred_repo=juntou <a href="%[1]s">%[2]s</a> aos favoritos
|
||||
watched_repo=começou a vigiar <a href="%[1]s">%[2]s</a>
|
||||
|
||||
[tool]
|
||||
|
|
|
@ -0,0 +1,854 @@
|
|||
home=මුල් පිටුව
|
||||
dashboard=උපකරණ පුවරුව
|
||||
explore=ගවේෂණය
|
||||
help=උපකාර
|
||||
sign_up=ලියාපදිංචිය
|
||||
register=ලියාපදිංචිය
|
||||
website=වියමන අඩවිය
|
||||
version=අනුවාදය
|
||||
page=පිටුව
|
||||
language=භාෂාව
|
||||
notifications=දැනුම්දීම්
|
||||
create_new=සාදන්න…
|
||||
user_profile_and_more=පැතිකඩ සහ සැකසුම්…
|
||||
enable_javascript=මෙම වියමන අඩවිය ජාවාස්ක්රිප්ට් සමඟ හොදින් ක්රියා කරයි.
|
||||
toc=පටුන
|
||||
licenses=බලපත්ර
|
||||
return_to_gitea=ගිටියා වෙත ආපසු
|
||||
|
||||
username=පරිශීලක නාමය
|
||||
email=වි-තැපැල් ලිපිනය
|
||||
password=මුරපදය
|
||||
passcode=මුරකේතය
|
||||
|
||||
u2f_insert_key=ආරක්ෂණ යතුර ඇතුල් කරන්න
|
||||
u2f_unsupported_browser=අතිරික්සුව යූ2එෆ් ආරක්ෂණ යතුරු සඳහා සහාය නොදක්වයි.
|
||||
u2f_reload=නැවත පූරණය
|
||||
|
||||
repository=කෝෂ්ඨය
|
||||
organization=සංවිධානය
|
||||
new_repo=නව කෝෂ්ඨය
|
||||
new_org=නව සංවිධානය
|
||||
new_project=නව ව්යාපෘතිය
|
||||
manage_org=සංවිධාන කළමනාකරණය
|
||||
admin_panel=අඩවිය පරිපාලනය
|
||||
account_settings=ගිණුමේ සැකසුම්
|
||||
settings=සැකසුම්
|
||||
your_profile=පැතිකඩ
|
||||
your_settings=සැකසුම්
|
||||
|
||||
all=සියල්ල
|
||||
sources=මූලාශ්ර
|
||||
|
||||
activities=ක්රියාකාරකම්
|
||||
|
||||
ok=හරි
|
||||
cancel=අවලංගු කරන්න
|
||||
save=සුරකින්න
|
||||
add=එකතු
|
||||
remove=ඉවත් කරන්න
|
||||
remove_all=සියල්ල ඉවත් කරන්න
|
||||
edit=සංස්කරණය
|
||||
|
||||
copy=පිටපත් කරන්න
|
||||
copy_branch=ශාඛාවේ නම පිටපත් කරන්න
|
||||
copy_success=පිටපත් විය!
|
||||
copy_error=පිටපත් වීමට අසමත් විය
|
||||
|
||||
write=ලියන්න
|
||||
preview=පෙරදසුන
|
||||
loading=පූරණය වෙමින්...
|
||||
|
||||
step1=පියවර 1:
|
||||
step2=පියවර 2:
|
||||
|
||||
error=දෝෂයකි
|
||||
|
||||
|
||||
[error]
|
||||
|
||||
[startpage]
|
||||
install=ස්ථාපනයට පහසුය
|
||||
license=විවෘත මූලාශ්ර
|
||||
|
||||
[install]
|
||||
db_title=දත්ත සමුදායේ සැකසුම්
|
||||
db_type=දත්ත සමුදායේ වර්ගය
|
||||
user=පරිශීලක නාමය
|
||||
password=මුරපදය
|
||||
db_name=දත්ත සමුදායේ නම
|
||||
err_admin_name_is_invalid=පරිපාලක පරිශීලක නාමය වලංගු නොවේ
|
||||
|
||||
app_name=අඩවියේ සිරැසිය
|
||||
domain=සේවාදායකයේ වසම
|
||||
|
||||
email_title=වි-තැපෑලේ සැකසුම්
|
||||
smtp_from=ලෙස වි-තැපෑල යවන්න
|
||||
mail_notify=වි-තැපැල් දැනුම්දීම් සබල කරන්න
|
||||
server_service_title=සේවාදායකය සහ තෙවන පාර්ශවීය සේවා සැකසුම්
|
||||
disable_gravatar=ග්රැවටාර් අබල කරන්න
|
||||
admin_title=පරිපාලක ගිණුමේ සැකසුම්
|
||||
admin_name=පරිපාලක පරිශීලක නාමය
|
||||
admin_password=මුරපදය
|
||||
admin_email=වි-තැපැල් ලිපිනය
|
||||
install_btn_confirm=ගිටියා ස්ථාපනය කරන්න
|
||||
install_success=සාදරයෙන් පිළිගනිමු! ගිටියා තෝරා ගැනීම ගැන ස්තූතියි. විනෝද වන්න!
|
||||
no_reply_address=සැඟවුණු වි-තැපැල් වසම
|
||||
|
||||
[home]
|
||||
uname_holder=පරිශීලක නාමය හෝ වි-තැපෑල
|
||||
password_holder=මුරපදය
|
||||
my_repos=කෝෂ්ඨ
|
||||
show_more_repos=තව කෝෂ්ඨ පෙන්වන්න…
|
||||
my_orgs=මාගේ සංවිධාන
|
||||
view_home=%s දකින්න
|
||||
filter=වෙනත් පෙරහන්
|
||||
filter_by_team_repositories=කණ්ඩායම් කෝෂ්ඨ අනුව පෙරන්න
|
||||
|
||||
show_archived=සංරක්ෂිත
|
||||
show_only_archived=සංරක්ෂිත පමණක් පෙන්වයි
|
||||
|
||||
show_private=පෞද්ගලික
|
||||
show_both_private_public=ප්රසිද්ධ හා පෞද්ගලික පෙන්වයි
|
||||
show_only_private=පෞද්ගලික පමණක් පෙන්වයි
|
||||
show_only_public=ප්රසිද්ධ පමණක් පෙන්වයි
|
||||
|
||||
issues.in_your_repos=ඔබගේ කෝෂ්ඨවල
|
||||
|
||||
[explore]
|
||||
repos=කෝෂ්ඨ
|
||||
users=පරිශීලකයින්
|
||||
organizations=සංවිධාන
|
||||
search=සොයන්න
|
||||
code=කේතය
|
||||
code_search_results='%s' සඳහා සෙවුම් ප්රතිඵල
|
||||
|
||||
[auth]
|
||||
create_new_account=ගිණුමක් ලියාපදිංචි කරන්න
|
||||
remember_me=උපාංගය මතක තබාගන්න
|
||||
forgot_password_title=මුරපදය අමතක වුණා
|
||||
forgot_password=මුරපදය අමතක වුණා ද?
|
||||
sign_up_now=ගිණුමක් ඇවැසිද? දැන් ලියාපදිංචි වන්න.
|
||||
sign_up_successful=ගිණුම සාර්ථකව සෑදිණි.
|
||||
must_change_password=මුරපදය යාවත්කාල කරන්න
|
||||
active_your_account=ඔබගේ ගිණුම ක්රියාත්මක කරන්න
|
||||
account_activated=ඔබගේ ගිණුම ක්රියාත්මක කර ඇත
|
||||
reset_password=ගිණුම ප්රතිසාධනය
|
||||
reset_password_helper=ගිණුම ප්රතිසාධනය
|
||||
oauth_signup_tab=නව ගිණුමක් ලියාපදිංචි කරන්න
|
||||
oauth_signup_title=නව ගිණුම සම්පූර්ණ කරන්න
|
||||
oauth_signup_submit=ගිණුම සම්පූර්ණ කරන්න
|
||||
openid_connect_submit=සම්බන්ධ වන්න
|
||||
openid_register_title=නව ගිණුමක් සාදන්න
|
||||
|
||||
[mail]
|
||||
hi_user_x=ආයුබෝ <b>%s</b>,
|
||||
|
||||
activate_account=ඔබගේ ගිණුම ක්රියාත්මක කරන්න
|
||||
activate_account.title=%s, ඔබගේ ගිණුම ක්රියාත්මක කරන්න
|
||||
activate_account.text_1=ආයුබෝ <b>%[1]s</b>, %[2]s හි ලියාපදිංචි වීමට තුති!
|
||||
|
||||
|
||||
register_notify=ගිටියා වෙත සාදරයෙන් පිළිගනිමු
|
||||
register_notify.title=%[1]s, %[2]s වෙත සාදරයෙන් පිළිගනිමු
|
||||
|
||||
reset_password=ඔබගේ ගිණුම ප්රතිසාධනය
|
||||
|
||||
register_success=ලියාපදිංචි වීම සාර්ථකයි
|
||||
|
||||
|
||||
|
||||
release.title=සිරැසිය: %s
|
||||
release.note=සටහන:
|
||||
release.downloads=බාගැනීම්:
|
||||
release.download.zip=ප්රභව කේතය (ZIP)
|
||||
release.download.targz=ප්රභව කේතය (TAR.GZ)
|
||||
|
||||
repo.transfer.to_you=ඔබ
|
||||
|
||||
repo.collaborator.added.subject=%s ඔබව %s ට එකතු කළා
|
||||
|
||||
[modal]
|
||||
yes=ඔව්
|
||||
no=නැහැ
|
||||
modify=යාවත්කාල
|
||||
|
||||
[form]
|
||||
UserName=පරිශීලක නාමය
|
||||
RepoName=කෝෂ්ඨයේ නම
|
||||
Email=වි-තැපැල් ලිපිනය
|
||||
Password=මුරපදය
|
||||
TeamName=කණ්ඩායමේ නම
|
||||
AdminEmail=පරිපාලකගේ වි-තැපෑල
|
||||
|
||||
NewBranchName=නව ශාඛාවේ නම
|
||||
Content=අන්තර්ගතය
|
||||
|
||||
SSPIDefaultLanguage=පෙරනිමි භාෂාව
|
||||
|
||||
unknown_error=නොදන්නා දෝෂය:
|
||||
password_not_match=මුරපද නොගැලපේ.
|
||||
|
||||
username_been_taken=පරිශීලක නාමය දැනටමත් ගෙන ඇත.
|
||||
repo_name_been_taken=කෝෂ්ඨයේ නම භාවිතා කර ඇත.
|
||||
org_name_been_taken=සංවිධානයේ නම දැනටමත් ගෙන ඇත.
|
||||
team_name_been_taken=කණ්ඩායමේ නම දැනටමත් ගෙන ඇත.
|
||||
email_been_used=වි-තැපෑල දැනටමත් භාවිතා කර ඇත.
|
||||
email_invalid=වි-තැපැල් ලිපිනය වලංගු නොවේ.
|
||||
username_password_incorrect=පරිශීලක නාමය හෝ මුරපදය සාවද්යයි.
|
||||
enterred_invalid_owner_name=නව හිමිකරුගේ නම වලංගු නොවේ.
|
||||
enterred_invalid_password=ඔබ ඇතුල් කළ මුරපදය සාවද්යයි.
|
||||
user_not_exist=පරිශීලක නොපවතී.
|
||||
team_not_exist=කණ්ඩායම නොපවතී.
|
||||
|
||||
|
||||
|
||||
|
||||
[user]
|
||||
repositories=කෝෂ්ඨ
|
||||
activity=ප්රසිද්ධ ක්රියාකාරකම
|
||||
projects=ව්යාපෘති
|
||||
|
||||
|
||||
[settings]
|
||||
profile=පැතිකඩ
|
||||
account=ගිණුම
|
||||
password=මුරපදය
|
||||
security=ආරක්ෂාව
|
||||
social=සමාජ ගිණුම්
|
||||
applications=යෙදුම්
|
||||
orgs=සංවිධාන කළමනාකරණය
|
||||
repos=කෝෂ්ඨ
|
||||
organization=සංවිධාන
|
||||
u2f=ආරක්ෂණ යතුරු
|
||||
|
||||
public_profile=ප්රසිද්ධ පැතිකඩ
|
||||
full_name=සම්පූර්ණ නම
|
||||
website=වියමන අඩවිය
|
||||
location=ස්ථානය
|
||||
update_language_not_found='%s' භාෂාව නැත.
|
||||
update_language_success=භාෂාව යාවත්කාල වී ඇත.
|
||||
continue=ඉදිරියට
|
||||
cancel=අවලංගු කරන්න
|
||||
language=භාෂාව
|
||||
ui=තේමාව
|
||||
privacy=පෞද්ගලිකත්වය
|
||||
|
||||
|
||||
change_password=මුරපදය යාවත්කාල කරන්න
|
||||
old_password=වත්මන් මුරපදය
|
||||
new_password=නව මුරපදය
|
||||
|
||||
emails=වි-තැපැල් ලිපින
|
||||
manage_emails=වි-තැපැල් ලිපින කළමනාකරණය
|
||||
delete_email=ඉවත් කරන්න
|
||||
email_deletion=වි-තැපෑල ඉවත් කරන්න
|
||||
theme_update_success=ඔබගේ තේමාව යාවත්කාල කෙරිණි.
|
||||
add_email=වි-තැපෑල එකතු කරන්න
|
||||
keep_email_private=වි-තැපෑල සඟවන්න
|
||||
|
||||
manage_gpg_keys=ජීපීජී යතුරු කළමනාකරණය
|
||||
add_key=යතුර එක්කරන්න
|
||||
key_id=යතුරෙහි හැඳු.
|
||||
key_name=යතුරෙහි නම
|
||||
key_content=අන්තර්ගතය
|
||||
principal_content=අන්තර්ගතය
|
||||
delete_key=ඉවත් කරන්න
|
||||
gpg_key_deletion=ජීපීජී යතුර ඉවත් කරන්න
|
||||
valid_until=තෙක් වලංගු වේ
|
||||
valid_forever=සදහටම වලංගු වේ
|
||||
no_activity=මෑත ක්රියාකාරකම් නැත
|
||||
show_openid=පැතිකඩ මත පෙන්වන්න
|
||||
hide_openid=පැතිකඩෙන් සඟවන්න
|
||||
|
||||
|
||||
create_oauth2_application_button=යෙදුම සාදන්න
|
||||
oauth2_application_name=යෙදුමේ නම
|
||||
save_application=සුරකින්න
|
||||
oauth2_client_id=අනුග්රාහකයේ හැඳු.
|
||||
oauth2_client_secret=අනුග්රාහකයේ රහස
|
||||
oauth2_regenerate_secret_hint=ඔබගේ රහස නැති වුනාද?
|
||||
oauth2_application_edit=සංස්කරණය
|
||||
|
||||
|
||||
|
||||
u2f_nickname=අපනාමය
|
||||
u2f_delete_key=ආරක්ෂක යතුර ඉවත් කරන්න
|
||||
|
||||
|
||||
|
||||
|
||||
email_notifications.enable=වි-තැපැල් දැනුම්දීම් සබල කරන්න
|
||||
email_notifications.onmention=සැඳහුම් සඳහා තැපැල් කරන්න
|
||||
email_notifications.disable=වි-තැපැල් දැනුම්දීම් අබල කරන්න
|
||||
|
||||
visibility.public=ප්රසිද්ධ
|
||||
visibility.private=පෞද්ගලික
|
||||
|
||||
[repo]
|
||||
owner=හිමිකරු
|
||||
repo_name=කෝෂ්ඨයේ නම
|
||||
repo_size=කෝෂ්ඨයේ ප්රමාණය
|
||||
download_zip=ZIP බාගන්න
|
||||
download_tar=TAR.GZ බාගන්න
|
||||
repo_desc=සවිස්තරය
|
||||
repo_lang=භාෂාව
|
||||
license=බලපත්රය
|
||||
readme=මෙයකියවන්න
|
||||
create_repo=කෝෂ්ඨය සාදන්න
|
||||
default_branch=පෙරනිමි ශාඛාව
|
||||
reactions_more=සහ තවත් %d
|
||||
language_other=වෙනත්
|
||||
adopt_preexisting_content=%s වෙතින් කෝෂ්ඨය සාදන්න
|
||||
|
||||
|
||||
desc.private=පෞද්ගලික
|
||||
desc.public=ප්රසිද්ධ
|
||||
desc.internal=අභ්යන්තර
|
||||
desc.archived=සංරක්ෂිත
|
||||
|
||||
template.topics=මාතෘකා
|
||||
|
||||
|
||||
|
||||
migrate_items_merge_requests=සංයුක්ත කිරීමේ ඉල්ලීම්
|
||||
migrate_items_releases=නිකුතු
|
||||
migrate.migrating_failed.error=දෝෂය: %s
|
||||
|
||||
download_archive=කෝෂ්ඨය බාගන්න
|
||||
|
||||
no_desc=සවිස්තරයක් නැත
|
||||
|
||||
code=කේතය
|
||||
branch=ශාඛාව
|
||||
branches=ශාඛා
|
||||
project_board=ව්යාපෘති
|
||||
org_labels_desc_manage=කළමනාකරණය
|
||||
|
||||
release=නිකුතුව
|
||||
releases=නිකුතු
|
||||
file_history=ඉතිහාසය
|
||||
file_view_source=මූලාශ්රය දකින්න
|
||||
commit_graph.color=වර්ණය
|
||||
download_file=ගොනුව බාගන්න
|
||||
|
||||
editor.new_file=නව ගොනුව
|
||||
editor.upload_file=ගොනුව උඩුගත කරන්න
|
||||
editor.edit_file=ගොනුව සංස්කරණය
|
||||
editor.preview_changes=වෙනස්කම් පෙරදසුන
|
||||
editor.edit_this_file=ගොනුව සංස්කරණය
|
||||
editor.this_file_locked=ගොනුවට අගුළු ලා ඇත
|
||||
editor.name_your_file=ගොනුව නම් කරන්න…
|
||||
editor.or=හෝ
|
||||
editor.cancel_lower=අවලංගු කරන්න
|
||||
editor.add_tmpl='<filename>' එකතු කරන්න
|
||||
editor.add='%s' එකතු කරන්න
|
||||
editor.update='%s' යාවත්කාල කරන්න
|
||||
editor.new_branch_name_desc=නව ශාඛාවේ නම…
|
||||
editor.cancel=අවලංගු කරන්න
|
||||
editor.filename_is_invalid=ගොනුවේ නම වලංගු නොවේ: '%s'.
|
||||
editor.branch_does_not_exist=මෙම කෝෂ්ඨයෙහි '%s' ශාඛාව නොපවතී.
|
||||
editor.branch_already_exists=මෙම කෝෂ්ඨයෙහි '%s' ශාඛාව දැනටමත් පවතී.
|
||||
editor.no_changes_to_show=පෙන්වීමට කිසිදු වෙනසක් නැත.
|
||||
editor.fail_to_update_file='%s' ගොනුව යාවත්කාල/සෑදීමට අසමත් විය.
|
||||
editor.fail_to_update_file_summary=දෝෂ පණිවිඩය:
|
||||
editor.upload_files_to_dir='%s' වෙත ගොනු උඩුගත කරන්න
|
||||
|
||||
commits.find=සොයන්න
|
||||
commits.search_all=සියළුම ශාඛා
|
||||
commits.author=කතෘ
|
||||
commits.message=පණිවිඩය
|
||||
commits.date=දිනය
|
||||
commits.gpg_key_id=ජීපීජී යතුරෙහි හැඳු.
|
||||
|
||||
|
||||
projects=ව්යාපෘති
|
||||
projects.description_placeholder=සවිස්තරය
|
||||
projects.create=ව්යාපෘතිය සාදන්න
|
||||
projects.title=සිරැසිය
|
||||
projects.new=නව ව්යාපෘතිය
|
||||
projects.edit=ව්යාපෘති සංස්කරණය
|
||||
projects.modify=ව්යාපෘතිය යාවත්කාල කරන්න
|
||||
projects.edit_success='%s' ව්යාපෘතිය යාවත්කාල කර ඇත.
|
||||
projects.type.uncategorized=ප්රවර්ග ගත නැති
|
||||
projects.board.edit=පුවරුව සංස්කරණය
|
||||
projects.board.edit_title=නව පුවරුවේ නම
|
||||
projects.board.new_title=නව පුවරුවේ නම
|
||||
projects.board.new_submit=යොමන්න
|
||||
projects.board.new=නව පුවරුව
|
||||
projects.board.color=වර්ණය
|
||||
projects.open=විවෘත
|
||||
projects.close=වසන්න
|
||||
|
||||
issues.filter_projects=ව්යාපෘතිය පෙරන්න
|
||||
issues.new.projects=ව්යාපෘති
|
||||
issues.new.add_project_title=ව්යාපෘතිය සකසන්න
|
||||
issues.new.no_projects=ව්යාපෘති නැත
|
||||
issues.new.open_projects=විවෘත ව්යාපෘති
|
||||
issues.new.closed_projects=සංවෘත ව්යාපෘති
|
||||
issues.choose.blank=පෙරනිමි
|
||||
issues.new_label_desc_placeholder=සවිස්තරය
|
||||
issues.filter_type=වර්ගය
|
||||
issues.filter_sort.recentupdate=මෑතදී යාවත්කාල
|
||||
issues.action_open=විවෘත
|
||||
issues.action_close=වසන්න
|
||||
issues.next=ඊළඟ
|
||||
issues.open_title=විවෘත
|
||||
issues.closed_title=වසා ඇත
|
||||
issues.num_comments=අදහස් %d
|
||||
issues.context.copy_link=සබැඳිය පිටපත්
|
||||
issues.context.edit=සංස්කරණය
|
||||
issues.no_content=තවම අන්තර්ගතයක් නැත.
|
||||
issues.close_issue=වසන්න
|
||||
issues.close_comment_issue=අදහස් දක්වා වසන්න
|
||||
issues.reopen_comment_issue=අදහස් දක්වා විවෘත කරන්න
|
||||
issues.create_comment=අදහස
|
||||
issues.owner=හිමිකරු
|
||||
issues.edit=සංස්කරණය
|
||||
issues.cancel=අවලංගු කරන්න
|
||||
issues.save=සුරකින්න
|
||||
issues.label_edit=සංස්කරණය
|
||||
issues.label.filter_sort.by_size=කුඩාම ප්රමාණය
|
||||
issues.label.filter_sort.reverse_by_size=විශාලම ප්රමාණය
|
||||
issues.num_participants=සහභාගිවන්නන් %d
|
||||
issues.attachment.download=`"%s“ බාගැනීමට ඔබන්න`
|
||||
issues.lock_confirm=අගුළු ලන්න
|
||||
issues.unlock_confirm=අගුළු හරින්න
|
||||
issues.lock.reason=අගුළු දැමීමට හේතුව
|
||||
issues.add_time_cancel=අවලංගු කරන්න
|
||||
issues.add_time_hours=පැය
|
||||
issues.add_time_minutes=විනාඩි
|
||||
issues.due_date_form_edit=සංස්කරණය
|
||||
issues.due_date_form_remove=ඉවත් කරන්න
|
||||
issues.dependency.title=පරායත්ත
|
||||
issues.dependency.add=පරායත්ත එක් කරන්න…
|
||||
issues.dependency.cancel=අවලංගු කරන්න
|
||||
issues.dependency.remove=ඉවත් කරන්න
|
||||
issues.dependency.remove_info=මෙම පරායත්තය ඉවත් කරන්න
|
||||
issues.dependency.added_dependency=`%s නව පරායත්තයක් එකතු කළා`
|
||||
issues.dependency.removed_dependency=`%s පරායත්තයක් ඉවත් කළා`
|
||||
issues.dependency.remove_header=පරායත්තය ඉවත් කරන්න
|
||||
issues.dependency.add_error_dep_not_exist=පරායත්තය නොපවතී.
|
||||
issues.dependency.add_error_dep_exists=පරායත්තය දැනටමත් පවතී.
|
||||
issues.review.left_comment=අදහසක් හැරගියා
|
||||
issues.review.reject=%s ඉල්ලූ වෙනස්කම්
|
||||
issues.content_history.options=විකල්ප
|
||||
|
||||
compare.compare_head=සසඳන්න
|
||||
|
||||
pulls.filter_branch=ශාඛාව පෙරන්න
|
||||
pulls.tab_files=වෙනස් වූ ගොනු
|
||||
pulls.merged=සංයුක්ත කෙරිණි
|
||||
pulls.manually_merged=අතින් සංයුක්ත කර ඇත
|
||||
pulls.reject_count_1=වෙනස් කිරීමේ ඉල්ලීම් %d
|
||||
pulls.reject_count_n=වෙනස් කිරීමේ ඉල්ලීම් %d
|
||||
|
||||
pulls.merge_manually=අතින් සංයුක්ත කර ඇත
|
||||
pulls.merge_conflict_summary=දෝෂ පණිවිඩය
|
||||
pulls.rebase_conflict_summary=දෝෂ පණිවිඩය
|
||||
; </summary><code>%[2]s<br>%[3]s</code></details>
|
||||
pulls.status_checks_requested=ඇවැසිය
|
||||
pulls.status_checks_details=වැණුම
|
||||
pulls.update_branch=සංයුක්ත කිරීමෙන් ශාඛාව යාවත්කාල කරන්න
|
||||
|
||||
|
||||
milestones.closed=%s වසා ඇත
|
||||
milestones.close=වසන්න
|
||||
milestones.title=සිරැසිය
|
||||
milestones.desc=සවිස්තරය
|
||||
milestones.cancel=අවලංගු කරන්න
|
||||
|
||||
|
||||
|
||||
wiki.create_first_page=පළමු පිටුව සාදන්න
|
||||
wiki.page=පිටුව
|
||||
wiki.filter_page=පිටුව පෙරන්න
|
||||
wiki.new_page=පිටුව
|
||||
wiki.save_page=පිටුව සුරකින්න
|
||||
wiki.edit_page_button=සංස්කරණය
|
||||
wiki.new_page_button=නව පිටුව
|
||||
wiki.pages=පිටු
|
||||
|
||||
activity=ක්රියාකාරකම
|
||||
activity.period.daily=දවස් 1
|
||||
activity.period.halfweekly=දවස් 3
|
||||
activity.period.weekly=සති 1
|
||||
activity.period.monthly=මාස 1
|
||||
activity.period.quarterly=මාස 3
|
||||
activity.period.semiyearly=මාස 6
|
||||
activity.period.yearly=වසර 1
|
||||
activity.overview=දළ විශ්ලේෂණය
|
||||
activity.title.user_1=පරිශීලකයින් %d
|
||||
activity.title.user_n=පරිශීලකයින් %d
|
||||
activity.merged_prs_label=සංයුක්ත කෙරිණි
|
||||
activity.closed_issue_label=වසා ඇත
|
||||
activity.title.releases_1=නිකුතු %d
|
||||
activity.title.releases_n=නිකුතු %d
|
||||
activity.git_stats_file_1=ගොනු %d
|
||||
activity.git_stats_file_n=ගොනු %d
|
||||
activity.git_stats_and_deletions=සහ
|
||||
|
||||
search=සොයන්න
|
||||
search.search_repo=කෝෂ්ඨය සොයන්න
|
||||
search.results=<a href="%s">%s</a> හි "%s" සඳහා සෙවුම් ප්රතිඵල
|
||||
|
||||
settings=සැකසුම්
|
||||
settings.options=කෝෂ්ඨය
|
||||
settings.collaboration.admin=පරිපාලක
|
||||
settings.collaboration.owner=හිමිකරු
|
||||
settings.basic_settings=මූලික සැකසුම්
|
||||
settings.sync_mirror=සමමුහූර්ත කරන්න
|
||||
settings.email_notifications.enable=වි-තැපැල් දැනුම්දීම් සබල කරන්න
|
||||
settings.email_notifications.onmention=සැඳහුම් සඳහා තැපැල් කරන්න
|
||||
settings.email_notifications.disable=වි-තැපැල් දැනුම්දීම් අබල කරන්න
|
||||
settings.site=වියමන අඩවිය
|
||||
settings.update_settings=යාවත්කාල සැකසුම්
|
||||
settings.branches.update_default_branch=පෙරනිමි ශාඛාව යාවත්කාල කරන්න
|
||||
settings.advanced_settings=වැඩිදුර සැකසුම්
|
||||
settings.admin_settings=පරිපාලක සැකසුම්
|
||||
settings.danger_zone=අන්තරාය කලාපය
|
||||
settings.transfer_owner=නව හිමිකරු
|
||||
settings.delete_collaborator=ඉවත් කරන්න
|
||||
settings.search_user_placeholder=පරිශීලක සොයන්න…
|
||||
settings.teams=කණ්ඩායම්
|
||||
settings.add_team_success=කණ්ඩායමට දැන් කෝෂ්ඨයට ප්රවේශය ඇත.
|
||||
settings.search_team=කණ්ඩායම සොයන්න…
|
||||
settings.change_team_permission_tip=කණ්ඩායමේ අවසරය කණ්ඩායම් සැකසුම් පිටුවේ සකසන අතර කෝෂ්ඨය අනුව වෙනස් කළ නොහැකිය
|
||||
settings.delete_team_tip=මෙම කණ්ඩායම සියළුම කෝෂ්ඨවලට ප්රවේශය ඇති අතර ඉවත් කළ නොහැකිය
|
||||
settings.remove_team_success=කෝෂ්ඨය වෙත කණ්ඩායමේ ප්රවේශය ඉවත් කර ඇත.
|
||||
settings.webhook.request=ඉල්ලීම
|
||||
settings.webhook.response=ප්රතිචාරය
|
||||
settings.webhook.headers=ශීර්ෂ
|
||||
settings.webhook.payload=අන්තර්ගතය
|
||||
settings.http_method=HTTP ක්රමය
|
||||
settings.secret=රහස
|
||||
settings.slack_username=පරිශීලක නාමය
|
||||
settings.slack_icon_url=නිරූපකයේ ඒ.ස.නි.
|
||||
settings.slack_color=වර්ණය
|
||||
settings.discord_username=පරිශීලක නාමය
|
||||
settings.discord_icon_url=නිරූපකයේ ඒ.ස.නි.
|
||||
settings.event_send_everything=සියළුම සිදුවීම්
|
||||
settings.event_choose=අභිරුචි සිදුවීම්…
|
||||
settings.event_header_repository=කෝෂ්ඨයේ සිදුවීම්
|
||||
settings.event_create=සාදන්න
|
||||
settings.event_release=නිකුතුව
|
||||
settings.event_repository=කෝෂ්ඨය
|
||||
settings.branch_filter=ශාඛා පෙරහන
|
||||
settings.slack_domain=වසම
|
||||
settings.slack_channel=නාලිකාව
|
||||
settings.is_writable=ලිවීමේ ප්රවේශය සබල කරන්න
|
||||
settings.title=සිරැසිය
|
||||
settings.deploy_key_content=අන්තර්ගතය
|
||||
settings.branches=ශාඛා
|
||||
settings.protect_whitelist_search_users=පරිශීලකයින් සොයන්න…
|
||||
settings.protect_whitelist_search_teams=කණ්ඩායම් සොයන්න…
|
||||
settings.protect_check_status_contexts=තත්වය පරීක්ෂාව සබල කරන්න
|
||||
settings.edit_protected_branch=සංස්කරණය
|
||||
settings.tags.protection.allowed=ඉඩ දී ඇත
|
||||
settings.tags.protection.allowed.users=ඉඩ දී ඇති පරිශීලකයින්
|
||||
settings.tags.protection.allowed.teams=ඉඩ දී ඇති කණ්ඩායම්
|
||||
settings.matrix.room_id=කාමරයේ හැඳු.
|
||||
settings.matrix.message_type=පණිවිඩ වර්ගය
|
||||
settings.archive.button=කෝෂ්ඨය සංරක්ෂණය
|
||||
settings.archive.header=මෙම කෝෂ්ඨය සංරක්ෂණය
|
||||
settings.archive.success=කෝෂ්ඨය සාර්ථකව සංරක්ෂණය කෙරිණි.
|
||||
settings.lfs_locks=අගුළු
|
||||
settings.lfs_lock=අගුල
|
||||
settings.lfs_locks_no_locks=අගුළු නැත
|
||||
settings.lfs_force_unlock=බලාත්මක අගුළු හැරීම
|
||||
settings.rename_branch_from=පරණ ශාඛාවේ නම
|
||||
settings.rename_branch_to=නව ශාඛාවේ නම
|
||||
settings.rename_branch=ශාඛාව යළි නම් කරන්න
|
||||
|
||||
diff.browse_source=මූලාශ්රය පිරික්සන්න
|
||||
diff.git-notes=සටහන්
|
||||
diff.whitespace_show_everything=සියළුම වෙනස්කම් පෙන්වන්න
|
||||
diff.bin_not_shown=ද්විමය ගොනුව පෙන්වා නැත.
|
||||
diff.view_file=ගොනුව දකින්න
|
||||
diff.file_image_width=පළල
|
||||
diff.file_image_height=උස
|
||||
diff.file_byte_size=ප්රමාණය
|
||||
diff.show_more=තව පෙන්වන්න
|
||||
diff.comment.placeholder=අදහසක් හැරයන්න
|
||||
diff.comment.add_review_comment=අදහස එකතු කරන්න
|
||||
diff.comment.reply=පිළිතුර
|
||||
diff.review.comment=අදහස
|
||||
diff.review.reject=වෙනස්කම් ඉල්ලන්න
|
||||
|
||||
release.releases=නිකුතු
|
||||
release.detail=නිකුතුවේ විස්තර
|
||||
release.new_release=නව නිකුතුව
|
||||
release.draft=කටුපිටපත
|
||||
release.prerelease=පූර්ව-නිකුතුව
|
||||
release.stable=ස්ථාවර
|
||||
release.compare=සසඳන්න
|
||||
release.edit=සංස්කරණය
|
||||
release.source_code=ප්රභව කේතය
|
||||
release.title=සිරැසිය
|
||||
release.content=අන්තර්ගතය
|
||||
release.cancel=අවලංගු කරන්න
|
||||
release.save_draft=කටුපිටපත සුරකින්න
|
||||
release.edit_release=නිකුතුව යාවත්කාල කරන්න
|
||||
release.downloads=බාගැනීම්
|
||||
release.download_count=බාගැනීම්: %s
|
||||
|
||||
branch.name=ශාඛාවේ නම
|
||||
branch.search=ශාඛා සොයන්න
|
||||
branch.create_from='%s' වෙතින්
|
||||
branch.restore_success='%s' ශාඛාව ප්රත්යර්පණය කෙරිණි.
|
||||
branch.restore_failed='%s' ශාඛාව ප්රත්යර්පණයට අසමත් විය.
|
||||
branch.restore=ශාඛාව '%s' ප්රත්යර්පණය
|
||||
branch.download='%s' ශාඛාව බාගන්න
|
||||
branch.included_desc=මෙම ශාඛාව පෙරනිමි ශාඛාවේ කොටසකි
|
||||
branch.included=ඇතුළත්
|
||||
branch.create_new_branch=ශාඛාවෙන් ශාඛාව සාදන්න:
|
||||
branch.confirm_create_branch=ශාඛාව සාදන්න
|
||||
branch.new_branch=නව ශාඛාවක් සාදන්න
|
||||
branch.new_branch_from='%s' වෙතින් නව ශාඛාවක් සාදන්න
|
||||
|
||||
|
||||
topic.manage_topics=මාතෘකා කළමනාකරණය
|
||||
|
||||
|
||||
[org]
|
||||
org_name_holder=සංවිධානයේ නම
|
||||
org_full_name_holder=සංවිධානයේ සම්පූර්ණ නම
|
||||
create_org=සංවිධානය සාදන්න
|
||||
repo_updated=යාවත්කාල කෙරිණි
|
||||
people=මිනිසුන්
|
||||
teams=කණ්ඩායම්
|
||||
lower_members=සාමාජිකයින්
|
||||
lower_repositories=කෝෂ්ඨ
|
||||
create_new_team=නව කණ්ඩායම
|
||||
create_team=කණ්ඩායම සාදන්න
|
||||
org_desc=සවිස්තරය
|
||||
team_name=කණ්ඩායමේ නම
|
||||
team_desc=සවිස්තරය
|
||||
team_access_desc=කෝෂ්ඨයට ප්රවේශය
|
||||
team_permission_desc=අවසරය
|
||||
team_unit_disabled=(අබල කර ඇත)
|
||||
|
||||
|
||||
settings=සැකසුම්
|
||||
settings.options=සංවිධානය
|
||||
settings.full_name=සම්පූර්ණ නම
|
||||
settings.website=වියමන අඩවිය
|
||||
settings.location=ස්ථානය
|
||||
settings.permission=අවසර
|
||||
settings.visibility.public=ප්රසිද්ධ
|
||||
settings.visibility.private_shortname=පෞද්ගලික
|
||||
|
||||
settings.update_settings=සැකසුම් යාවත්කාල කරන්න
|
||||
settings.update_setting_success=සංවිධානයේ සැකසුම් යාවත්කාල කර ඇත.
|
||||
settings.change_orgname_prompt=සටහන: සංවිධානයේ නම වෙනස් කිරීම සංවිධානයේ ඒ.ස.නි. ද වෙනස් කරයි.
|
||||
|
||||
|
||||
members.private=සැඟවුනු
|
||||
members.owner=හිමිකරු
|
||||
members.member=සාමාජික
|
||||
members.remove=ඉවත් කරන්න
|
||||
members.leave=හැරයන්න
|
||||
members.leave.detail=%s හැරයනවාද?
|
||||
members.invite_now=දැන් ආරාධනා කරන්න
|
||||
|
||||
teams.join=එක්වන්න
|
||||
teams.leave=හැරයන්න
|
||||
teams.leave.detail=%s හැරයනවාද?
|
||||
teams.can_create_org_repo=කෝෂ්ඨය සාදන්න
|
||||
teams.can_create_org_repo_helper=සාමාජිකයින්ට සංවිධානයෙහි නව කෝෂ්ඨ සෑදීමට හැකිය. නිර්මාතෘ ට නව කෝෂ්ඨයෙහි පරිපාලක ප්රවේශය ලැබෙනු ඇත.
|
||||
teams.read_access=කියවීමේ ප්රවේශය
|
||||
teams.write_access=ලිවීමේ ප්රවේශය
|
||||
teams.admin_access=පරිපාලක ප්රවේශය
|
||||
teams.no_desc=මෙම කණ්ඩායමට සවිස්තරයක් නැත
|
||||
teams.settings=සැකසුම්
|
||||
teams.members=කණ්ඩායමේ සාමාජිකයින්
|
||||
teams.update_settings=සැකසුම් යාවත්කාල කරන්න
|
||||
teams.repositories=කණ්ඩායම් කෝෂ්ඨ
|
||||
teams.search_repo_placeholder=කෝෂ්ඨය සොයන්න…
|
||||
teams.remove_all_repos_title=සියළුම කණ්ඩායම් කෝෂ්ඨ ඉවත් කරන්න
|
||||
teams.remove_all_repos_desc=මෙය කණ්ඩායමෙන් සියළුම කෝෂ්ඨ ඉවත් කෙරෙනු ඇත.
|
||||
teams.add_all_repos_title=සියළුම කෝෂ්ඨ එක්කරන්න
|
||||
teams.add_all_repos_desc=මෙය සංවිධානයේ සියළුම කෝෂ්ඨ කණ්ඩායමට එකතු කෙරෙනු ඇත.
|
||||
teams.add_nonexistent_repo=ඔබ එකතු කිරීමට උත්සාහ කරන කෝෂ්ඨය නොපවතී; පළමුව එය සාදන්න.
|
||||
teams.add_duplicate_users=පරිශීලක දැනටමත් කණ්ඩායමේ සාමාජිකයෙකි.
|
||||
teams.members.none=මෙම කණ්ඩායමෙහි සාමාජිකයින් නැත.
|
||||
teams.specific_repositories=විශේෂිත කෝෂ්ඨ
|
||||
teams.all_repositories=සියළුම කෝෂ්ඨ
|
||||
|
||||
[admin]
|
||||
dashboard=උපකරණ පුවරුව
|
||||
users=පරිශීලක ගිණුම්
|
||||
organizations=සංවිධාන
|
||||
repositories=කෝෂ්ඨ
|
||||
emails=පරිශීලක වි-තැපැල්
|
||||
config=වින්යාසය
|
||||
notices=පද්ධතියේ දැන්වීම්
|
||||
total=මුළු: %d
|
||||
|
||||
dashboard.statistic=සාරාංශය
|
||||
dashboard.operations=නඩත්තු මෙහෙයුම්
|
||||
dashboard.system_status=පද්ධතියේ තත්වය
|
||||
dashboard.operation_name=මෙහෙයුමේ නම
|
||||
dashboard.operation_switch=මාරුවන්න
|
||||
dashboard.operation_run=ධාවනය
|
||||
dashboard.check_repo_stats=සියළුම කෝෂ්ඨවල සංඛ්යාලේඛන පරීක්ෂා කරන්න
|
||||
dashboard.sync_external_users=බාහිර පරිශීලක දත්ත සමමුහූර්තනය
|
||||
dashboard.current_memory_usage=වත්මන් මතක භාවිතය
|
||||
|
||||
users.user_manage_panel=පරිශීලක ගිණුම් කළමනාකරණය
|
||||
users.new_account=පරිශීලක ගිණුමක් සාදන්න
|
||||
users.name=පරිශීලක නාමය
|
||||
users.full_name=සම්පූර්ණ නම
|
||||
users.admin=පරිපාලක
|
||||
users.send_register_notify=පරිශීලක ලියාපදිංචි දැනුම්දීම යවන්න
|
||||
users.edit=සංස්කරණය
|
||||
users.local=ස්ථානීය
|
||||
users.edit_account=පරිශීලක ගිණුම සංස්කරණය
|
||||
users.max_repo_creation=උපරිම කෝෂ්ඨ ගණන
|
||||
users.is_activated=පරිශීලක ගිණුම ක්රියාත්මකයි
|
||||
users.is_admin=පරිපාලකයෙකි
|
||||
users.allow_import_local=ස්ථානීය කෝෂ්ඨ ආයාත කළ හැකිය
|
||||
users.allow_create_organization=සංවිධාන සෑදිය හැකිය
|
||||
users.update_profile=පරිශීලක ගිණුම යාවත්කාල කරන්න
|
||||
users.list_status_filter.menu_text=පෙරහන
|
||||
users.list_status_filter.is_admin=පරිපාලක
|
||||
users.list_status_filter.not_admin=පරිපාලක නොවන
|
||||
|
||||
emails.filter_sort.email=වි-තැපෑල
|
||||
emails.filter_sort.name=පරිශීලක නාමය
|
||||
emails.updated=වි-තැපෑල යාවත්කාල කෙරිණි
|
||||
|
||||
orgs.org_manage_panel=සංවිධාන කළමනාකරණය
|
||||
orgs.name=නම
|
||||
orgs.teams=කණ්ඩායම්
|
||||
orgs.members=සාමාජිකයින්
|
||||
orgs.new_orga=නව සංවිධානය
|
||||
|
||||
repos.repo_manage_panel=කෝෂ්ඨ කළමනාකරණය
|
||||
repos.owner=හිමිකරු
|
||||
repos.name=නම
|
||||
repos.private=පෞද්ගලික
|
||||
repos.size=ප්රමාණය
|
||||
|
||||
|
||||
|
||||
auths.name=නම
|
||||
auths.type=වර්ගය
|
||||
auths.enabled=සබල කර ඇත
|
||||
auths.syncenabled=පරිශීලක සමමුහූර්තය සබල කරන්න
|
||||
auths.updated=යාවත්කාල කෙරිණි
|
||||
auths.security_protocol=ආරක්ෂණ කෙටුම්පත
|
||||
auths.domain=වසම
|
||||
auths.search_page_size=පිටුවේ ප්රමාණය
|
||||
auths.filter=පරිශීලක පෙරහන
|
||||
auths.admin_filter=පරිපාලක පෙරහන
|
||||
auths.allowed_domains=ඉඩ දී ඇති වසම්
|
||||
auths.oauth2_icon_url=නිරූපකයේ ඒ.ස.නි.
|
||||
auths.oauth2_clientID=අනුග්රාහකයේ හැඳු. (යතුර)
|
||||
auths.oauth2_clientSecret=අනුග්රාහකයේ රහස
|
||||
auths.oauth2_profileURL=පැතිකඩ ඒ.ස.නි.
|
||||
auths.oauth2_emailURL=වි-තැපෑල ඒ.ස.නි.
|
||||
auths.enable_auto_register=ස්වයං ලියාපදිංචිය සබල කරන්න
|
||||
auths.sspi_auto_create_users=ස්වයංක්රීයව පරිශීලකයින් සාදන්න
|
||||
auths.sspi_strip_domain_names=පරිශීලක නාම වලින් වසම් නාම ඉවත් කරන්න
|
||||
auths.sspi_default_language=පෙරනිමි පරිශීලක භාෂාව
|
||||
|
||||
config.server_config=සේවාදායකයේ වින්යාසය
|
||||
config.app_name=අඩවියේ සිරැසිය
|
||||
config.app_ver=ගිටියා අනුවාදය
|
||||
config.domain=සේවාදායකයේ වසම
|
||||
|
||||
config.ssh_enabled=සබල කර ඇත
|
||||
config.ssh_minimum_key_sizes=අවම යතුරෙහි ප්රමාණ
|
||||
|
||||
config.lfs_enabled=සබල කර ඇත
|
||||
|
||||
config.db_config=දත්ත සමුදායෙහි වින්යාසය
|
||||
config.db_type=වර්ගය
|
||||
config.db_name=නම
|
||||
config.db_user=පරිශීලක නාමය
|
||||
|
||||
config.service_config=සේවාවේ වින්යාසය
|
||||
config.show_registration_button=ලියාපදිංචි බොත්තම පෙන්වන්න
|
||||
config.mail_notify=වි-තැපැල් දැනුම්දීම් සබල කරන්න
|
||||
|
||||
|
||||
config.mailer_enabled=සබල කර ඇත
|
||||
config.mailer_name=නම
|
||||
config.mailer_user=පරිශීලක
|
||||
config.mailer_use_sendmail=සෙන්ඩ්මේල් භාවිතා කරන්න
|
||||
config.test_email_placeholder=වි-තැපෑල (උදා. පරීක්ෂාව@උදාහරණය.ලංකා)
|
||||
config.send_test_mail=අත්හදා බැලීමේ වි-තැපෑල යවන්න
|
||||
|
||||
config.oauth_enabled=සබල කර ඇත
|
||||
|
||||
config.cache_config=නිහිතයේ වින්යාසය
|
||||
config.cache_conn=නිහිතයේ සම්බන්ධතාවය
|
||||
|
||||
config.https_only=HTTPS පමණි
|
||||
|
||||
config.disable_gravatar=ග්රැවටාර් අබල කරන්න
|
||||
|
||||
|
||||
config.disabled_logger=අබල කර ඇත
|
||||
|
||||
monitor.name=නම
|
||||
monitor.next=ඊළඟ වේලාව
|
||||
monitor.desc=සවිස්තරය
|
||||
monitor.start=ආරම්භක වේලාව
|
||||
monitor.process.cancel_notices=<strong>%s</strong>: අවලංගු කරන්නද?
|
||||
monitor.queues=පෝලිම්
|
||||
monitor.queue=පෝලිම: %s
|
||||
monitor.queue.name=නම
|
||||
monitor.queue.type=වර්ගය
|
||||
|
||||
monitor.queue.settings.submit=සැකසුම් යාවත්කාල කරන්න
|
||||
monitor.queue.settings.changed=සැකසුම් යාවත්කාල කෙරිණි
|
||||
|
||||
|
||||
notices.system_notice_list=පද්ධතියේ දැන්වීම්
|
||||
notices.view_detail_header=දැන්වීමේ විස්තර දකින්න
|
||||
notices.actions=ක්රියාමාර්ග
|
||||
notices.type=වර්ගය
|
||||
notices.type_1=කෝෂ්ඨය
|
||||
notices.type_2=කාර්යය
|
||||
notices.desc=සවිස්තරය
|
||||
|
||||
[action]
|
||||
compare_branch=සසඳන්න
|
||||
review_dismissed_reason=හේතුව:
|
||||
|
||||
[tool]
|
||||
now=දැන්
|
||||
1s=තත්පර 1
|
||||
1m=විනාඩි 1
|
||||
1h=පැය 1
|
||||
1d=දවස් 1
|
||||
1w=සති 1
|
||||
1mon=මාස 1
|
||||
1y=වසර 1
|
||||
seconds=තත්පර %d
|
||||
minutes=විනාඩි %d
|
||||
hours=පැය %d
|
||||
days=දවස් %d
|
||||
weeks=සති %d
|
||||
months=මාස %d
|
||||
years=අවුරුදු %d
|
||||
raw_seconds=තත්පර
|
||||
raw_minutes=විනාඩි
|
||||
|
||||
[dropzone]
|
||||
default_message=ගොනු දමන්න හෝ උඩුගත කිරීමට මෙතැන ඔබන්න.
|
||||
remove_file=ගොනුව ඉවත් කරන්න
|
||||
|
||||
[notification]
|
||||
notifications=දැනුම්දීම්
|
||||
unread=නොකියවූ
|
||||
read=කියවූ
|
||||
no_unread=නොකියවූ දැනුම්දීම් නැත.
|
||||
no_read=කියවූ දැනුම්දීම් නැත.
|
||||
|
||||
[gpg]
|
||||
|
||||
[units]
|
||||
|
|
@ -2214,7 +2214,7 @@ members.member_role=成员角色:
|
|||
members.owner=管理员
|
||||
members.member=普通成员
|
||||
members.remove=移除成员
|
||||
members.remove.detail=从 %[2] 中移除 %[1] 吗?
|
||||
members.remove.detail=从 %[2]s 中移除 %[1]s 吗?
|
||||
members.leave=离开组织
|
||||
members.leave.detail=离开 %s?
|
||||
members.invite_desc=邀请新的用户加入 %s:
|
||||
|
|
|
@ -2696,6 +2696,7 @@ monitor.execute_time=已執行時間
|
|||
monitor.process.cancel=結束處理程序
|
||||
monitor.process.cancel_desc=結束處理程序可能造成資料遺失
|
||||
monitor.process.cancel_notices=結束: <strong>%s</strong>?
|
||||
monitor.process.children=子程序
|
||||
monitor.queues=佇列
|
||||
monitor.queue=佇列: %s
|
||||
monitor.queue.name=名稱
|
||||
|
|
|
@ -405,7 +405,7 @@ func CreateBranchProtection(ctx *context.APIContext) {
|
|||
repo := ctx.Repo.Repository
|
||||
|
||||
// Currently protection must match an actual branch
|
||||
if !git.IsBranchExist(ctx.Repo.Repository.RepoPath(), form.BranchName) {
|
||||
if !git.IsBranchExist(ctx.Req.Context(), ctx.Repo.Repository.RepoPath(), form.BranchName) {
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/chi-middleware/proxy"
|
||||
|
@ -22,7 +23,9 @@ func Middlewares() []func(http.Handler) http.Handler {
|
|||
var handlers = []func(http.Handler) http.Handler{
|
||||
func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
next.ServeHTTP(context.NewResponse(resp), req)
|
||||
ctx, _, finished := process.GetManager().AddContext(req.Context(), fmt.Sprintf("%s: %s", req.Method, req.RequestURI))
|
||||
defer finished()
|
||||
next.ServeHTTP(context.NewResponse(resp), req.WithContext(ctx))
|
||||
})
|
||||
},
|
||||
}
|
||||
|
|
|
@ -95,9 +95,8 @@ func syncAppPathForGit(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GlobalInit is for global configuration reload-able.
|
||||
func GlobalInit(ctx context.Context) {
|
||||
setting.NewContext()
|
||||
// GlobalInitInstalled is for global installed configuration.
|
||||
func GlobalInitInstalled(ctx context.Context) {
|
||||
if !setting.InstallLock {
|
||||
log.Fatal("Gitea is not installed")
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
db_install "code.gitea.io/gitea/models/db/install"
|
||||
"code.gitea.io/gitea/models/migrations"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
|
@ -161,10 +162,81 @@ func Install(ctx *context.Context) {
|
|||
ctx.HTML(http.StatusOK, tplInstall)
|
||||
}
|
||||
|
||||
func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
|
||||
var err error
|
||||
|
||||
if (setting.Database.Type == "sqlite3") &&
|
||||
len(setting.Database.Path) == 0 {
|
||||
ctx.Data["Err_DbPath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_db_path"), tplInstall, form)
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the user is trying to re-install in an installed database
|
||||
db.UnsetDefaultEngine()
|
||||
defer db.UnsetDefaultEngine()
|
||||
|
||||
if err = db.InitEngine(ctx); err != nil {
|
||||
if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
|
||||
ctx.Data["Err_DbType"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "https://docs.gitea.io/en-us/install-from-binary/"), tplInstall, form)
|
||||
} else {
|
||||
ctx.Data["Err_DbSetting"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), tplInstall, form)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
err = db_install.CheckDatabaseConnection()
|
||||
if err != nil {
|
||||
ctx.Data["Err_DbSetting"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), tplInstall, form)
|
||||
return false
|
||||
}
|
||||
|
||||
hasPostInstallationUser, err := db_install.HasPostInstallationUsers()
|
||||
if err != nil {
|
||||
ctx.Data["Err_DbSetting"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_db_table", "user", err), tplInstall, form)
|
||||
return false
|
||||
}
|
||||
dbMigrationVersion, err := db_install.GetMigrationVersion()
|
||||
if err != nil {
|
||||
ctx.Data["Err_DbSetting"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_db_table", "version", err), tplInstall, form)
|
||||
return false
|
||||
}
|
||||
|
||||
if hasPostInstallationUser && dbMigrationVersion > 0 {
|
||||
log.Error("The database is likely to have been used by Gitea before, database migration version=%d", dbMigrationVersion)
|
||||
confirmed := form.ReinstallConfirmFirst && form.ReinstallConfirmSecond && form.ReinstallConfirmThird
|
||||
if !confirmed {
|
||||
ctx.Data["Err_DbInstalledBefore"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.reinstall_error"), tplInstall, form)
|
||||
return false
|
||||
}
|
||||
|
||||
log.Info("User confirmed reinstallation of Gitea into a pre-existing database")
|
||||
}
|
||||
|
||||
if hasPostInstallationUser || dbMigrationVersion > 0 {
|
||||
log.Info("Gitea will be installed in a database with: hasPostInstallationUser=%v, dbMigrationVersion=%v", hasPostInstallationUser, dbMigrationVersion)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// SubmitInstall response for submit install items
|
||||
func SubmitInstall(ctx *context.Context) {
|
||||
form := *web.GetForm(ctx).(*forms.InstallForm)
|
||||
var err error
|
||||
|
||||
form := *web.GetForm(ctx).(*forms.InstallForm)
|
||||
|
||||
// fix form values
|
||||
if form.AppURL != "" && form.AppURL[len(form.AppURL)-1] != '/' {
|
||||
form.AppURL += "/"
|
||||
}
|
||||
|
||||
ctx.Data["CurDbOption"] = form.DbType
|
||||
|
||||
if ctx.HasError() {
|
||||
|
@ -186,9 +258,9 @@ func SubmitInstall(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// Pass basic check, now test configuration.
|
||||
// Test database setting.
|
||||
// ---- Basic checks are passed, now test configuration.
|
||||
|
||||
// Test database setting.
|
||||
setting.Database.Type = setting.GetDBTypeByName(form.DbType)
|
||||
setting.Database.Host = form.DbHost
|
||||
setting.Database.User = form.DbUser
|
||||
|
@ -201,22 +273,13 @@ func SubmitInstall(ctx *context.Context) {
|
|||
setting.Database.LogSQL = !setting.IsProd
|
||||
setting.PasswordHashAlgo = form.PasswordAlgorithm
|
||||
|
||||
if (setting.Database.Type == "sqlite3") &&
|
||||
len(setting.Database.Path) == 0 {
|
||||
ctx.Data["Err_DbPath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_db_path"), tplInstall, &form)
|
||||
if !checkDatabase(ctx, &form) {
|
||||
return
|
||||
}
|
||||
|
||||
// Set test engine.
|
||||
if err = db.InitEngineWithMigration(ctx, migrations.Migrate); err != nil {
|
||||
if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
|
||||
ctx.Data["Err_DbType"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "https://docs.gitea.io/en-us/install-from-binary/"), tplInstall, &form)
|
||||
} else {
|
||||
ctx.Data["Err_DbSetting"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), tplInstall, &form)
|
||||
}
|
||||
// Prepare AppDataPath, it is very important for Gitea
|
||||
if err = setting.PrepareAppDataPath(); err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_app_data_path", err), tplInstall, &form)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -299,9 +362,14 @@ func SubmitInstall(ctx *context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
if form.AppURL[len(form.AppURL)-1] != '/' {
|
||||
form.AppURL += "/"
|
||||
// Init the engine with migration
|
||||
if err = db.InitEngineWithMigration(ctx, migrations.Migrate); err != nil {
|
||||
db.UnsetDefaultEngine()
|
||||
ctx.Data["Err_DbSetting"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), tplInstall, &form)
|
||||
return
|
||||
}
|
||||
db.UnsetDefaultEngine()
|
||||
|
||||
// Save settings.
|
||||
cfg := ini.Empty()
|
||||
|
@ -344,12 +412,12 @@ func SubmitInstall(ctx *context.Context) {
|
|||
if form.LFSRootPath != "" {
|
||||
cfg.Section("server").Key("LFS_START_SERVER").SetValue("true")
|
||||
cfg.Section("server").Key("LFS_CONTENT_PATH").SetValue(form.LFSRootPath)
|
||||
var secretKey string
|
||||
if secretKey, err = generate.NewJwtSecretBase64(); err != nil {
|
||||
var lfsJwtSecret string
|
||||
if lfsJwtSecret, err = generate.NewJwtSecretBase64(); err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.lfs_jwt_secret_failed", err), tplInstall, &form)
|
||||
return
|
||||
}
|
||||
cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(secretKey)
|
||||
cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(lfsJwtSecret)
|
||||
} else {
|
||||
cfg.Section("server").Key("LFS_START_SERVER").SetValue("false")
|
||||
}
|
||||
|
@ -390,16 +458,30 @@ func SubmitInstall(ctx *context.Context) {
|
|||
cfg.Section("log").Key("ROUTER").SetValue("console")
|
||||
|
||||
cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
|
||||
var secretKey string
|
||||
if secretKey, err = generate.NewSecretKey(); err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), tplInstall, &form)
|
||||
|
||||
var internalToken string
|
||||
if internalToken, err = generate.NewInternalToken(); err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.internal_token_failed", err), tplInstall, &form)
|
||||
return
|
||||
}
|
||||
cfg.Section("security").Key("SECRET_KEY").SetValue(secretKey)
|
||||
cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(internalToken)
|
||||
|
||||
// if there is already a SECRET_KEY, we should not overwrite it, otherwise the encrypted data will not be able to be decrypted
|
||||
if setting.SecretKey == "" {
|
||||
var secretKey string
|
||||
if secretKey, err = generate.NewSecretKey(); err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), tplInstall, &form)
|
||||
return
|
||||
}
|
||||
cfg.Section("security").Key("SECRET_KEY").SetValue(secretKey)
|
||||
}
|
||||
|
||||
if len(form.PasswordAlgorithm) > 0 {
|
||||
cfg.Section("security").Key("PASSWORD_HASH_ALGO").SetValue(form.PasswordAlgorithm)
|
||||
}
|
||||
|
||||
log.Info("Save settings to custom config file %s", setting.CustomConf)
|
||||
|
||||
err = os.MkdirAll(filepath.Dir(setting.CustomConf), os.ModePerm)
|
||||
if err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
|
||||
|
@ -411,8 +493,10 @@ func SubmitInstall(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// Re-read settings
|
||||
ReloadSettings(ctx)
|
||||
// ---- All checks are passed
|
||||
|
||||
// Reload settings (and re-initialize database connection)
|
||||
reloadSettings(ctx)
|
||||
|
||||
// Create admin account
|
||||
if len(form.AdminName) > 0 {
|
||||
|
|
|
@ -16,17 +16,17 @@ import (
|
|||
|
||||
// PreloadSettings preloads the configuration to check if we need to run install
|
||||
func PreloadSettings(ctx context.Context) bool {
|
||||
setting.NewContext()
|
||||
setting.LoadAllowEmpty()
|
||||
if !setting.InstallLock {
|
||||
log.Info("AppPath: %s", setting.AppPath)
|
||||
log.Info("AppWorkPath: %s", setting.AppWorkPath)
|
||||
log.Info("Custom path: %s", setting.CustomPath)
|
||||
log.Info("Log path: %s", setting.LogRootPath)
|
||||
log.Info("Configuration file: %s", setting.CustomConf)
|
||||
log.Info("Preparing to run install page")
|
||||
log.Info("Prepare to run install page")
|
||||
translation.InitLocales()
|
||||
if setting.EnableSQLite3 {
|
||||
log.Info("SQLite3 Supported")
|
||||
log.Info("SQLite3 is supported")
|
||||
}
|
||||
setting.InitDBConfig()
|
||||
setting.NewServicesForInstall()
|
||||
|
@ -36,9 +36,9 @@ func PreloadSettings(ctx context.Context) bool {
|
|||
return !setting.InstallLock
|
||||
}
|
||||
|
||||
// ReloadSettings rereads the settings and starts up the database
|
||||
func ReloadSettings(ctx context.Context) {
|
||||
setting.NewContext()
|
||||
// reloadSettings reloads the existing settings and starts up the database
|
||||
func reloadSettings(ctx context.Context) {
|
||||
setting.LoadFromExisting()
|
||||
setting.InitDBConfig()
|
||||
if setting.InstallLock {
|
||||
if err := common.InitDBEngine(ctx); err == nil {
|
||||
|
|
|
@ -326,7 +326,7 @@ func Monitor(ctx *context.Context) {
|
|||
ctx.Data["Title"] = ctx.Tr("admin.monitor")
|
||||
ctx.Data["PageIsAdmin"] = true
|
||||
ctx.Data["PageIsAdminMonitor"] = true
|
||||
ctx.Data["Processes"] = process.GetManager().Processes()
|
||||
ctx.Data["Processes"] = process.GetManager().Processes(true)
|
||||
ctx.Data["Entries"] = cron.ListTasks()
|
||||
ctx.Data["Queues"] = queue.GetManager().ManagedQueues()
|
||||
ctx.HTML(http.StatusOK, tplMonitor)
|
||||
|
@ -334,8 +334,8 @@ func Monitor(ctx *context.Context) {
|
|||
|
||||
// MonitorCancel cancels a process
|
||||
func MonitorCancel(ctx *context.Context) {
|
||||
pid := ctx.ParamsInt64("pid")
|
||||
process.GetManager().Cancel(pid)
|
||||
pid := ctx.Params("pid")
|
||||
process.GetManager().Cancel(process.IDType(pid))
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"redirect": setting.AppSubURL + "/admin/monitor",
|
||||
})
|
||||
|
|
|
@ -124,7 +124,7 @@ func RestoreBranchPost(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := git.Push(ctx.Repo.Repository.RepoPath(), git.PushOptions{
|
||||
if err := git.Push(ctx, ctx.Repo.Repository.RepoPath(), git.PushOptions{
|
||||
Remote: ctx.Repo.Repository.RepoPath(),
|
||||
Branch: fmt.Sprintf("%s:%s%s", deletedBranch.Commit, git.BranchPrefix, deletedBranch.Name),
|
||||
Env: models.PushingEnvironment(ctx.User, ctx.Repo.Repository),
|
||||
|
|
|
@ -8,7 +8,6 @@ package repo
|
|||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
gocontext "context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -485,8 +484,10 @@ func serviceRPC(h serviceHandler, service string) {
|
|||
h.environ = append(h.environ, "GIT_PROTOCOL="+protocol)
|
||||
}
|
||||
|
||||
ctx, cancel := gocontext.WithCancel(git.DefaultContext)
|
||||
defer cancel()
|
||||
// ctx, cancel := gocontext.WithCancel(git.DefaultContext)
|
||||
ctx, _, finished := process.GetManager().AddContext(h.r.Context(), fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir))
|
||||
defer finished()
|
||||
|
||||
var stderr bytes.Buffer
|
||||
cmd := exec.CommandContext(ctx, git.GitExecutable, service, "--stateless-rpc", h.dir)
|
||||
cmd.Dir = h.dir
|
||||
|
@ -495,9 +496,6 @@ func serviceRPC(h serviceHandler, service string) {
|
|||
cmd.Stdin = reqBody
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
pid := process.GetManager().Add(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir), cancel)
|
||||
defer process.GetManager().Remove(pid)
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String())
|
||||
return
|
||||
|
|
|
@ -1594,7 +1594,7 @@ func ViewIssue(ctx *context.Context) {
|
|||
}
|
||||
ctx.Data["IsPullBranchDeletable"] = canDelete &&
|
||||
pull.HeadRepo != nil &&
|
||||
git.IsBranchExist(pull.HeadRepo.RepoPath(), pull.HeadBranch) &&
|
||||
git.IsBranchExist(ctx, pull.HeadRepo.RepoPath(), pull.HeadBranch) &&
|
||||
(!pull.HasMerged || ctx.Data["HeadBranchCommitID"] == ctx.Data["PullHeadCommitID"])
|
||||
|
||||
stillCanManualMerge := func() bool {
|
||||
|
|
|
@ -436,7 +436,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
|
|||
if pull.Flow == models.PullRequestFlowGithub {
|
||||
headBranchExist = headGitRepo.IsBranchExist(pull.HeadBranch)
|
||||
} else {
|
||||
headBranchExist = git.IsReferenceExist(baseGitRepo.Path, pull.GetGitRefName())
|
||||
headBranchExist = git.IsReferenceExist(ctx, baseGitRepo.Path, pull.GetGitRefName())
|
||||
}
|
||||
|
||||
if headBranchExist {
|
||||
|
|
|
@ -178,7 +178,7 @@ func SettingsPost(ctx *context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
u, _ := git.GetRemoteAddress(ctx.Repo.Repository.RepoPath(), ctx.Repo.Mirror.GetRemoteName())
|
||||
u, _ := git.GetRemoteAddress(ctx, ctx.Repo.Repository.RepoPath(), ctx.Repo.Mirror.GetRemoteName())
|
||||
if u.User != nil && form.MirrorPassword == "" && form.MirrorUsername == u.User.Username() {
|
||||
form.MirrorPassword, _ = u.User.Password()
|
||||
}
|
||||
|
|
|
@ -82,11 +82,10 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) {
|
|||
}
|
||||
}()
|
||||
graceful.GetManager().RunWithShutdownContext(func(baseCtx context.Context) {
|
||||
ctx, cancel := context.WithCancel(baseCtx)
|
||||
defer cancel()
|
||||
pm := process.GetManager()
|
||||
pid := pm.Add(config.FormatMessage(t.Name, "process", doer), cancel)
|
||||
defer pm.Remove(pid)
|
||||
ctx, _, finished := pm.AddContext(baseCtx, config.FormatMessage(t.Name, "process", doer))
|
||||
defer finished()
|
||||
|
||||
if err := t.fun(ctx, doer, config); err != nil {
|
||||
if db.IsErrCancelled(err) {
|
||||
message := err.(db.ErrCancelled).Message
|
||||
|
|
|
@ -67,6 +67,11 @@ type InstallForm struct {
|
|||
AdminPasswd string `binding:"OmitEmpty;MaxSize(255)" locale:"install.admin_password"`
|
||||
AdminConfirmPasswd string
|
||||
AdminEmail string `binding:"OmitEmpty;MinSize(3);MaxSize(254);Include(@)" locale:"install.admin_email"`
|
||||
|
||||
// ReinstallConfirmFirst we can not use 1/2/3 or A/B/C here, there is a framework bug, can not parse "reinstall_confirm_1" or "reinstall_confirm_a"
|
||||
ReinstallConfirmFirst bool
|
||||
ReinstallConfirmSecond bool
|
||||
ReinstallConfirmThird bool
|
||||
}
|
||||
|
||||
// Validate validates the fields
|
||||
|
|
|
@ -1303,8 +1303,9 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
|
|||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(git.DefaultContext, time.Duration(setting.Git.Timeout.Default)*time.Second)
|
||||
defer cancel()
|
||||
timeout := time.Duration(setting.Git.Timeout.Default) * time.Second
|
||||
ctx, _, finished := process.GetManager().AddContextTimeout(gitRepo.Ctx, timeout, fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath))
|
||||
defer finished()
|
||||
|
||||
argsLength := 6
|
||||
if len(opts.WhitespaceBehavior) > 0 {
|
||||
|
@ -1369,9 +1370,6 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
|
|||
return nil, fmt.Errorf("error during Start: %w", err)
|
||||
}
|
||||
|
||||
pid := process.GetManager().Add(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath), cancel)
|
||||
defer process.GetManager().Remove(pid)
|
||||
|
||||
diff, err := ParsePatch(opts.MaxLines, opts.MaxLineCharacters, opts.MaxFiles, stdout, parsePatchSkipToFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to ParsePatch: %w", err)
|
||||
|
|
|
@ -7,7 +7,6 @@ package mailer
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -258,11 +257,10 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error {
|
|||
args = append(args, to...)
|
||||
log.Trace("Sending with: %s %v", setting.MailService.SendmailPath, args)
|
||||
|
||||
pm := process.GetManager()
|
||||
desc := fmt.Sprintf("SendMail: %s %v", setting.MailService.SendmailPath, args)
|
||||
|
||||
ctx, cancel := context.WithTimeout(graceful.GetManager().HammerContext(), setting.MailService.SendmailTimeout)
|
||||
defer cancel()
|
||||
ctx, _, finished := process.GetManager().AddContextTimeout(graceful.GetManager().HammerContext(), setting.MailService.SendmailTimeout, desc)
|
||||
defer finished()
|
||||
|
||||
cmd := exec.CommandContext(ctx, setting.MailService.SendmailPath, args...)
|
||||
pipe, err := cmd.StdinPipe()
|
||||
|
@ -272,18 +270,17 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error {
|
|||
}
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
_ = pipe.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
pid := pm.Add(desc, cancel)
|
||||
|
||||
_, err = msg.WriteTo(pipe)
|
||||
|
||||
// we MUST close the pipe or sendmail will hang waiting for more of the message
|
||||
// Also we should wait on our sendmail command even if something fails
|
||||
closeError = pipe.Close()
|
||||
waitError = cmd.Wait()
|
||||
pm.Remove(pid)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if closeError != nil {
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/lfs"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
@ -192,7 +193,7 @@ func runSync(ctx context.Context, m *models.Mirror) ([]*mirrorSyncResult, bool)
|
|||
}
|
||||
gitArgs = append(gitArgs, m.GetRemoteName())
|
||||
|
||||
remoteAddr, remoteErr := git.GetRemoteAddress(repoPath, m.GetRemoteName())
|
||||
remoteAddr, remoteErr := git.GetRemoteAddress(ctx, repoPath, m.GetRemoteName())
|
||||
if remoteErr != nil {
|
||||
log.Error("GetRemoteAddress Error %v", remoteErr)
|
||||
}
|
||||
|
@ -287,7 +288,7 @@ func runSync(ctx context.Context, m *models.Mirror) ([]*mirrorSyncResult, bool)
|
|||
// sanitize the output, since it may contain the remote address, which may
|
||||
// contain a password
|
||||
|
||||
remoteAddr, remoteErr := git.GetRemoteAddress(wikiPath, m.GetRemoteName())
|
||||
remoteAddr, remoteErr := git.GetRemoteAddress(ctx, wikiPath, m.GetRemoteName())
|
||||
if remoteErr != nil {
|
||||
log.Error("GetRemoteAddress Error %v", remoteErr)
|
||||
}
|
||||
|
@ -367,6 +368,9 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
ctx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Syncing Mirror %s/%s", m.Repo.OwnerName, m.Repo.Name))
|
||||
defer finished()
|
||||
|
||||
log.Trace("SyncMirrors [repo: %-v]: Running Sync", m.Repo)
|
||||
results, ok := runSync(ctx, m)
|
||||
if !ok {
|
||||
|
@ -385,7 +389,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
|||
log.Trace("SyncMirrors [repo: %-v]: no branches updated", m.Repo)
|
||||
} else {
|
||||
log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results))
|
||||
gitRepo, err = git.OpenRepository(m.Repo.RepoPath())
|
||||
gitRepo, err = git.OpenRepositoryCtx(ctx, m.Repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error("OpenRepository [%d]: %v", m.RepoID, err)
|
||||
return false
|
||||
|
|
|
@ -7,6 +7,7 @@ package mirror
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"time"
|
||||
|
@ -15,6 +16,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/lfs"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
@ -92,6 +94,9 @@ func SyncPushMirror(ctx context.Context, mirrorID int64) bool {
|
|||
|
||||
m.LastError = ""
|
||||
|
||||
ctx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Syncing PushMirror %s/%s to %s", m.Repo.OwnerName, m.Repo.Name, m.RemoteName))
|
||||
defer finished()
|
||||
|
||||
log.Trace("SyncPushMirror [mirror: %d][repo: %-v]: Running Sync", m.ID, m.Repo)
|
||||
err = runPushSync(ctx, m)
|
||||
if err != nil {
|
||||
|
@ -116,7 +121,7 @@ func runPushSync(ctx context.Context, m *models.PushMirror) error {
|
|||
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second
|
||||
|
||||
performPush := func(path string) error {
|
||||
remoteAddr, err := git.GetRemoteAddress(path, m.RemoteName)
|
||||
remoteAddr, err := git.GetRemoteAddress(ctx, path, m.RemoteName)
|
||||
if err != nil {
|
||||
log.Error("GetRemoteAddress(%s) Error %v", path, err)
|
||||
return errors.New("Unexpected error")
|
||||
|
@ -125,7 +130,7 @@ func runPushSync(ctx context.Context, m *models.PushMirror) error {
|
|||
if setting.LFS.StartServer {
|
||||
log.Trace("SyncMirrors [repo: %-v]: syncing LFS objects...", m.Repo)
|
||||
|
||||
gitRepo, err := git.OpenRepository(path)
|
||||
gitRepo, err := git.OpenRepositoryCtx(ctx, path)
|
||||
if err != nil {
|
||||
log.Error("OpenRepository: %v", err)
|
||||
return errors.New("Unexpected error")
|
||||
|
@ -141,7 +146,7 @@ func runPushSync(ctx context.Context, m *models.PushMirror) error {
|
|||
|
||||
log.Trace("Pushing %s mirror[%d] remote %s", path, m.ID, m.RemoteName)
|
||||
|
||||
if err := git.Push(path, git.PushOptions{
|
||||
if err := git.Push(ctx, path, git.PushOptions{
|
||||
Remote: m.RemoteName,
|
||||
Force: true,
|
||||
Mirror: true,
|
||||
|
@ -162,7 +167,7 @@ func runPushSync(ctx context.Context, m *models.PushMirror) error {
|
|||
|
||||
if m.Repo.HasWiki() {
|
||||
wikiPath := m.Repo.WikiPath()
|
||||
_, err := git.GetRemoteAddress(wikiPath, m.RemoteName)
|
||||
_, err := git.GetRemoteAddress(ctx, wikiPath, m.RemoteName)
|
||||
if err == nil {
|
||||
err := performPush(wikiPath)
|
||||
if err != nil {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue