mirror of
https://github.com/go-gitea/gitea.git
synced 2025-04-12 10:48:46 +03:00
Uniform all temporary directories and allow customizing temp path (#32352)
This PR uniform all temporary directory usage so that it will be easier to manage. Relate to #31792 - [x] Added a new setting to allow users to configure the global temporary directory. - [x] Move all temporary files and directories to be placed under os.Temp()/gitea. - [x] `setting.Repository.Local.LocalCopyPath` now will be `setting.TempPath/local-repo` and the customized path is removed. ```diff -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;[repository.local] -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; Path for local repository copy. Defaults to TEMP_PATH + `local-repo`, this is deprecated and cannot be changed -;LOCAL_COPY_PATH = local-repo ``` - [x] `setting.Repository.Upload.TempPath` now will be `settting.TempPath/uploads` and the customized path is removed. ```diff ;[repository.upload] -;; -;; Path for uploads. Defaults to TEMP_PATH + `uploads` -;TEMP_PATH = uploads ``` - [x] `setting.Packages.ChunkedUploadPath` now will be `settting.TempPath/package-upload` and the customized path is removed. ```diff ;[packages] -;; -;; Path for chunked uploads. Defaults it's `package-upload` under `TEMP_PATH` unless it's an absolute path. -;CHUNKED_UPLOAD_PATH = package-upload ``` - [x] `setting.SSH.KeyTestPath` now will be `settting.TempPath/ssh_key_test` and the customized path is removed. ```diff [server] -;; -;; Directory to create temporary files in when testing public keys using ssh-keygen, -;; default is the system temporary directory. -;SSH_KEY_TEST_PATH = ``` TODO: - [ ] setting.PprofDataPath haven't been changed because it may need to be kept until somebody read it but temp path may be clean up any time. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@ -213,6 +213,10 @@ func serveInstalled(ctx *cli.Context) error {
|
|||||||
log.Fatal("Can not find APP_DATA_PATH %q", setting.AppDataPath)
|
log.Fatal("Can not find APP_DATA_PATH %q", setting.AppDataPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the AppDataTempDir is fully managed by us with a safe sub-path
|
||||||
|
// so it's safe to automatically remove the outdated files
|
||||||
|
setting.AppDataTempDir("").RemoveOutdated(3 * 24 * time.Hour)
|
||||||
|
|
||||||
// Override the provided port number within the configuration
|
// Override the provided port number within the configuration
|
||||||
if ctx.IsSet("port") {
|
if ctx.IsSet("port") {
|
||||||
if err := setPort(ctx.String("port")); err != nil {
|
if err := setPort(ctx.String("port")); err != nil {
|
||||||
|
@ -197,13 +197,6 @@ RUN_USER = ; git
|
|||||||
;; relative paths are made absolute relative to the APP_DATA_PATH
|
;; relative paths are made absolute relative to the APP_DATA_PATH
|
||||||
;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
|
;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
|
||||||
;;
|
;;
|
||||||
;; Directory to create temporary files in when testing public keys using ssh-keygen,
|
|
||||||
;; default is the system temporary directory.
|
|
||||||
;SSH_KEY_TEST_PATH =
|
|
||||||
;;
|
|
||||||
;; Use `ssh-keygen` to parse public SSH keys. The value is passed to the shell. By default, Gitea does the parsing itself.
|
|
||||||
;SSH_KEYGEN_PATH =
|
|
||||||
;;
|
|
||||||
;; Enable SSH Authorized Key Backup when rewriting all keys, default is false
|
;; Enable SSH Authorized Key Backup when rewriting all keys, default is false
|
||||||
;SSH_AUTHORIZED_KEYS_BACKUP = false
|
;SSH_AUTHORIZED_KEYS_BACKUP = false
|
||||||
;;
|
;;
|
||||||
@ -294,6 +287,9 @@ RUN_USER = ; git
|
|||||||
;; Default path for App data
|
;; Default path for App data
|
||||||
;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_
|
;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_
|
||||||
;;
|
;;
|
||||||
|
;; Base path for App's temp files, leave empty to use the managed tmp directory in APP_DATA_PATH
|
||||||
|
;APP_TEMP_PATH =
|
||||||
|
;;
|
||||||
;; Enable gzip compression for runtime-generated content, static resources excluded
|
;; Enable gzip compression for runtime-generated content, static resources excluded
|
||||||
;ENABLE_GZIP = false
|
;ENABLE_GZIP = false
|
||||||
;;
|
;;
|
||||||
@ -1069,15 +1065,6 @@ LEVEL = Info
|
|||||||
;; Separate extensions with a comma. To line wrap files without an extension, just put a comma
|
;; Separate extensions with a comma. To line wrap files without an extension, just put a comma
|
||||||
;LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,.livemd,
|
;LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,.livemd,
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;[repository.local]
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;;
|
|
||||||
;; Path for local repository copy. Defaults to `tmp/local-repo` (content gets deleted on gitea restart)
|
|
||||||
;LOCAL_COPY_PATH = tmp/local-repo
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;[repository.upload]
|
;[repository.upload]
|
||||||
@ -1087,9 +1074,6 @@ LEVEL = Info
|
|||||||
;; Whether repository file uploads are enabled. Defaults to `true`
|
;; Whether repository file uploads are enabled. Defaults to `true`
|
||||||
;ENABLED = true
|
;ENABLED = true
|
||||||
;;
|
;;
|
||||||
;; Path for uploads. Defaults to `data/tmp/uploads` (content gets deleted on gitea restart)
|
|
||||||
;TEMP_PATH = data/tmp/uploads
|
|
||||||
;;
|
|
||||||
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
|
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
|
||||||
;ALLOWED_TYPES =
|
;ALLOWED_TYPES =
|
||||||
;;
|
;;
|
||||||
@ -2594,9 +2578,6 @@ LEVEL = Info
|
|||||||
;; Currently, only `minio` and `azureblob` is supported.
|
;; Currently, only `minio` and `azureblob` is supported.
|
||||||
;SERVE_DIRECT = false
|
;SERVE_DIRECT = false
|
||||||
;;
|
;;
|
||||||
;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload`
|
|
||||||
;CHUNKED_UPLOAD_PATH = tmp/package-upload
|
|
||||||
;;
|
|
||||||
;; Maximum count of package versions a single owner can have (`-1` means no limits)
|
;; Maximum count of package versions a single owner can have (`-1` means no limits)
|
||||||
;LIMIT_TOTAL_OWNER_COUNT = -1
|
;LIMIT_TOTAL_OWNER_COUNT = -1
|
||||||
;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
|
||||||
|
@ -6,27 +6,13 @@ package asymkey
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/process"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ___________.__ .__ __
|
|
||||||
// \_ _____/|__| ____ ____ ________________________|__| _____/ |_
|
|
||||||
// | __) | |/ \ / ___\_/ __ \_ __ \____ \_ __ \ |/ \ __\
|
|
||||||
// | \ | | | \/ /_/ > ___/| | \/ |_> > | \/ | | \ |
|
|
||||||
// \___ / |__|___| /\___ / \___ >__| | __/|__| |__|___| /__|
|
|
||||||
// \/ \//_____/ \/ |__| \/
|
|
||||||
//
|
|
||||||
// This file contains functions for fingerprinting SSH keys
|
|
||||||
//
|
|
||||||
// The database is used in checkKeyFingerprint however most of these functions probably belong in a module
|
// The database is used in checkKeyFingerprint however most of these functions probably belong in a module
|
||||||
|
|
||||||
// checkKeyFingerprint only checks if key fingerprint has been used as public key,
|
// checkKeyFingerprint only checks if key fingerprint has been used as public key,
|
||||||
@ -41,29 +27,6 @@ func checkKeyFingerprint(ctx context.Context, fingerprint string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) {
|
|
||||||
// Calculate fingerprint.
|
|
||||||
tmpPath, err := writeTmpKeyFile(publicKeyContent)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err := util.Remove(tmpPath); err != nil {
|
|
||||||
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpPath, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
|
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(stderr, "is not a public key file") {
|
|
||||||
return "", ErrKeyUnableVerify{stderr}
|
|
||||||
}
|
|
||||||
return "", util.NewInvalidArgumentErrorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
|
|
||||||
} else if len(stdout) < 2 {
|
|
||||||
return "", util.NewInvalidArgumentErrorf("not enough output for calculating fingerprint: %s", stdout)
|
|
||||||
}
|
|
||||||
return strings.Split(stdout, " ")[1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func calcFingerprintNative(publicKeyContent string) (string, error) {
|
func calcFingerprintNative(publicKeyContent string) (string, error) {
|
||||||
// Calculate fingerprint.
|
// Calculate fingerprint.
|
||||||
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent))
|
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent))
|
||||||
@ -75,15 +38,12 @@ func calcFingerprintNative(publicKeyContent string) (string, error) {
|
|||||||
|
|
||||||
// CalcFingerprint calculate public key's fingerprint
|
// CalcFingerprint calculate public key's fingerprint
|
||||||
func CalcFingerprint(publicKeyContent string) (string, error) {
|
func CalcFingerprint(publicKeyContent string) (string, error) {
|
||||||
// Call the method based on configuration
|
fp, err := calcFingerprintNative(publicKeyContent)
|
||||||
useNative := setting.SSH.KeygenPath == ""
|
|
||||||
calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen)
|
|
||||||
fp, err := calcFn(publicKeyContent)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsErrKeyUnableVerify(err) {
|
if IsErrKeyUnableVerify(err) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err)
|
return "", fmt.Errorf("CalcFingerprint: %w", err)
|
||||||
}
|
}
|
||||||
return fp, nil
|
return fp, nil
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/process"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
@ -175,20 +172,9 @@ func CheckPublicKeyString(content string) (_ string, err error) {
|
|||||||
return content, nil
|
return content, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
keyType, length, err := SSHNativeParsePublicKey(content)
|
||||||
fnName string
|
|
||||||
keyType string
|
|
||||||
length int
|
|
||||||
)
|
|
||||||
if len(setting.SSH.KeygenPath) == 0 {
|
|
||||||
fnName = "SSHNativeParsePublicKey"
|
|
||||||
keyType, length, err = SSHNativeParsePublicKey(content)
|
|
||||||
} else {
|
|
||||||
fnName = "SSHKeyGenParsePublicKey"
|
|
||||||
keyType, length, err = SSHKeyGenParsePublicKey(content)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("%s: %w", fnName, err)
|
return "", fmt.Errorf("SSHNativeParsePublicKey: %w", err)
|
||||||
}
|
}
|
||||||
log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length)
|
log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length)
|
||||||
|
|
||||||
@ -258,56 +244,3 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
|
|||||||
}
|
}
|
||||||
return "", 0, fmt.Errorf("unsupported key length detection for type: %s", pkey.Type())
|
return "", 0, fmt.Errorf("unsupported key length detection for type: %s", pkey.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeTmpKeyFile writes key content to a temporary file
|
|
||||||
// and returns the name of that file, along with any possible errors.
|
|
||||||
func writeTmpKeyFile(content string) (string, error) {
|
|
||||||
tmpFile, err := os.CreateTemp(setting.SSH.KeyTestPath, "gitea_keytest")
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("TempFile: %w", err)
|
|
||||||
}
|
|
||||||
defer tmpFile.Close()
|
|
||||||
|
|
||||||
if _, err = tmpFile.WriteString(content); err != nil {
|
|
||||||
return "", fmt.Errorf("WriteString: %w", err)
|
|
||||||
}
|
|
||||||
return tmpFile.Name(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SSHKeyGenParsePublicKey extracts key type and length using ssh-keygen.
|
|
||||||
func SSHKeyGenParsePublicKey(key string) (string, int, error) {
|
|
||||||
tmpName, err := writeTmpKeyFile(key)
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, fmt.Errorf("writeTmpKeyFile: %w", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err := util.Remove(tmpName); err != nil {
|
|
||||||
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpName, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
keygenPath := setting.SSH.KeygenPath
|
|
||||||
if len(keygenPath) == 0 {
|
|
||||||
keygenPath = "ssh-keygen"
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout, stderr, err := process.GetManager().Exec("SSHKeyGenParsePublicKey", keygenPath, "-lf", tmpName)
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, fmt.Errorf("fail to parse public key: %s - %s", err, stderr)
|
|
||||||
}
|
|
||||||
if strings.Contains(stdout, "is not a public key file") {
|
|
||||||
return "", 0, ErrKeyUnableVerify{stdout}
|
|
||||||
}
|
|
||||||
|
|
||||||
fields := strings.Split(stdout, " ")
|
|
||||||
if len(fields) < 4 {
|
|
||||||
return "", 0, fmt.Errorf("invalid public key line: %s", stdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyType := strings.Trim(fields[len(fields)-1], "()\r\n")
|
|
||||||
length, err := strconv.ParseInt(fields[0], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, err
|
|
||||||
}
|
|
||||||
return strings.ToLower(keyType), int(length), nil
|
|
||||||
}
|
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
|
|
||||||
"github.com/42wim/sshsig"
|
"github.com/42wim/sshsig"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_SSHParsePublicKey(t *testing.T) {
|
func Test_SSHParsePublicKey(t *testing.T) {
|
||||||
@ -45,27 +44,6 @@ func Test_SSHParsePublicKey(t *testing.T) {
|
|||||||
assert.Equal(t, tc.keyType, keyTypeN)
|
assert.Equal(t, tc.keyType, keyTypeN)
|
||||||
assert.Equal(t, tc.length, lengthN)
|
assert.Equal(t, tc.length, lengthN)
|
||||||
})
|
})
|
||||||
if tc.skipSSHKeygen {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.Run("SSHKeygen", func(t *testing.T) {
|
|
||||||
keyTypeK, lengthK, err := SSHKeyGenParsePublicKey(tc.content)
|
|
||||||
if err != nil {
|
|
||||||
// Some servers do not support ecdsa format.
|
|
||||||
if !strings.Contains(err.Error(), "line 1 too long:") {
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert.Equal(t, tc.keyType, keyTypeK)
|
|
||||||
assert.Equal(t, tc.length, lengthK)
|
|
||||||
})
|
|
||||||
t.Run("SSHParseKeyNative", func(t *testing.T) {
|
|
||||||
keyTypeK, lengthK, err := SSHNativeParsePublicKey(tc.content)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, tc.keyType, keyTypeK)
|
|
||||||
assert.Equal(t, tc.length, lengthK)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,14 +164,6 @@ func Test_calcFingerprint(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tc.fp, fpN)
|
assert.Equal(t, tc.fp, fpN)
|
||||||
})
|
})
|
||||||
if tc.skipSSHKeygen {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.Run("SSHKeygen", func(t *testing.T) {
|
|
||||||
fpK, err := calcFingerprintSSHKeygen(tc.content)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tc.fp, fpK)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -845,6 +845,7 @@ func DeleteOrphanedIssues(ctx context.Context) error {
|
|||||||
|
|
||||||
// Remove issue attachment files.
|
// Remove issue attachment files.
|
||||||
for i := range attachmentPaths {
|
for i := range attachmentPaths {
|
||||||
|
// FIXME: it's not right, because the attachment might not be on local filesystem
|
||||||
system_model.RemoveAllWithNotice(ctx, "Delete issue attachment", attachmentPaths[i])
|
system_model.RemoveAllWithNotice(ctx, "Delete issue attachment", attachmentPaths[i])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/tempdir"
|
||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/modules/testlogger"
|
"code.gitea.io/gitea/modules/testlogger"
|
||||||
|
|
||||||
@ -114,15 +115,16 @@ func MainTest(m *testing.M) {
|
|||||||
setting.CustomConf = giteaConf
|
setting.CustomConf = giteaConf
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpDataPath, err := os.MkdirTemp("", "data")
|
tmpDataPath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("data")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
testlogger.Fatalf("Unable to create temporary data path %v\n", err)
|
testlogger.Fatalf("Unable to create temporary data path %v\n", err)
|
||||||
}
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom")
|
setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom")
|
||||||
setting.AppDataPath = tmpDataPath
|
setting.AppDataPath = tmpDataPath
|
||||||
|
|
||||||
unittest.InitSettings()
|
unittest.InitSettingsForTesting()
|
||||||
if err = git.InitFull(context.Background()); err != nil {
|
if err = git.InitFull(context.Background()); err != nil {
|
||||||
testlogger.Fatalf("Unable to InitFull: %v\n", err)
|
testlogger.Fatalf("Unable to InitFull: %v\n", err)
|
||||||
}
|
}
|
||||||
@ -134,8 +136,5 @@ func MainTest(m *testing.M) {
|
|||||||
if err := removeAllWithRetry(setting.RepoRootPath); err != nil {
|
if err := removeAllWithRetry(setting.RepoRootPath); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
|
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
|
||||||
}
|
}
|
||||||
if err := removeAllWithRetry(tmpDataPath); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
|
|
||||||
}
|
|
||||||
os.Exit(exitStatus)
|
os.Exit(exitStatus)
|
||||||
}
|
}
|
||||||
|
@ -51,14 +51,10 @@ func init() {
|
|||||||
db.RegisterModel(new(Upload))
|
db.RegisterModel(new(Upload))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
|
// LocalPath returns where uploads are temporarily stored in local file system based on given UUID.
|
||||||
func UploadLocalPath(uuid string) string {
|
|
||||||
return filepath.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocalPath returns where uploads are temporarily stored in local file system.
|
|
||||||
func (upload *Upload) LocalPath() string {
|
func (upload *Upload) LocalPath() string {
|
||||||
return UploadLocalPath(upload.UUID)
|
uuid := upload.UUID
|
||||||
|
return setting.AppDataTempDir("repo-uploads").JoinPath(uuid[0:1], uuid[1:2], uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUpload creates a new upload object.
|
// NewUpload creates a new upload object.
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/setting/config"
|
"code.gitea.io/gitea/modules/setting/config"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
|
"code.gitea.io/gitea/modules/tempdir"
|
||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
@ -35,8 +36,8 @@ func fatalTestError(fmtStr string, args ...any) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitSettings initializes config provider and load common settings for tests
|
// InitSettingsForTesting initializes config provider and load common settings for tests
|
||||||
func InitSettings() {
|
func InitSettingsForTesting() {
|
||||||
setting.IsInTesting = true
|
setting.IsInTesting = true
|
||||||
log.OsExiter = func(code int) {
|
log.OsExiter = func(code int) {
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
@ -75,7 +76,7 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
|
|||||||
testOpts := util.OptionalArg(testOptsArg, &TestOptions{})
|
testOpts := util.OptionalArg(testOptsArg, &TestOptions{})
|
||||||
giteaRoot = test.SetupGiteaRoot()
|
giteaRoot = test.SetupGiteaRoot()
|
||||||
setting.CustomPath = filepath.Join(giteaRoot, "custom")
|
setting.CustomPath = filepath.Join(giteaRoot, "custom")
|
||||||
InitSettings()
|
InitSettingsForTesting()
|
||||||
|
|
||||||
fixturesOpts := FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: testOpts.FixtureFiles}
|
fixturesOpts := FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: testOpts.FixtureFiles}
|
||||||
if err := CreateTestEngine(fixturesOpts); err != nil {
|
if err := CreateTestEngine(fixturesOpts); err != nil {
|
||||||
@ -92,15 +93,19 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
|
|||||||
setting.SSH.Domain = "try.gitea.io"
|
setting.SSH.Domain = "try.gitea.io"
|
||||||
setting.Database.Type = "sqlite3"
|
setting.Database.Type = "sqlite3"
|
||||||
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
|
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
|
||||||
repoRootPath, err := os.MkdirTemp(os.TempDir(), "repos")
|
repoRootPath, cleanup1, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("repos")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalTestError("TempDir: %v\n", err)
|
fatalTestError("TempDir: %v\n", err)
|
||||||
}
|
}
|
||||||
|
defer cleanup1()
|
||||||
|
|
||||||
setting.RepoRootPath = repoRootPath
|
setting.RepoRootPath = repoRootPath
|
||||||
appDataPath, err := os.MkdirTemp(os.TempDir(), "appdata")
|
appDataPath, cleanup2, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("appdata")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalTestError("TempDir: %v\n", err)
|
fatalTestError("TempDir: %v\n", err)
|
||||||
}
|
}
|
||||||
|
defer cleanup2()
|
||||||
|
|
||||||
setting.AppDataPath = appDataPath
|
setting.AppDataPath = appDataPath
|
||||||
setting.AppWorkPath = giteaRoot
|
setting.AppWorkPath = giteaRoot
|
||||||
setting.StaticRootPath = giteaRoot
|
setting.StaticRootPath = giteaRoot
|
||||||
@ -153,13 +158,6 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
|
|||||||
fatalTestError("tear down failed: %v\n", err)
|
fatalTestError("tear down failed: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = util.RemoveAll(repoRootPath); err != nil {
|
|
||||||
fatalTestError("util.RemoveAll: %v\n", err)
|
|
||||||
}
|
|
||||||
if err = util.RemoveAll(appDataPath); err != nil {
|
|
||||||
fatalTestError("util.RemoveAll: %v\n", err)
|
|
||||||
}
|
|
||||||
os.Exit(exitStatus)
|
os.Exit(exitStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BlamePart represents block of blame - continuous lines with one sha
|
// BlamePart represents block of blame - continuous lines with one sha
|
||||||
@ -29,12 +29,13 @@ type BlameReader struct {
|
|||||||
bufferedReader *bufio.Reader
|
bufferedReader *bufio.Reader
|
||||||
done chan error
|
done chan error
|
||||||
lastSha *string
|
lastSha *string
|
||||||
ignoreRevsFile *string
|
ignoreRevsFile string
|
||||||
objectFormat ObjectFormat
|
objectFormat ObjectFormat
|
||||||
|
cleanupFuncs []func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *BlameReader) UsesIgnoreRevs() bool {
|
func (r *BlameReader) UsesIgnoreRevs() bool {
|
||||||
return r.ignoreRevsFile != nil
|
return r.ignoreRevsFile != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextPart returns next part of blame (sequential code lines with the same commit)
|
// NextPart returns next part of blame (sequential code lines with the same commit)
|
||||||
@ -122,36 +123,37 @@ func (r *BlameReader) Close() error {
|
|||||||
r.bufferedReader = nil
|
r.bufferedReader = nil
|
||||||
_ = r.reader.Close()
|
_ = r.reader.Close()
|
||||||
_ = r.output.Close()
|
_ = r.output.Close()
|
||||||
if r.ignoreRevsFile != nil {
|
for _, cleanup := range r.cleanupFuncs {
|
||||||
_ = util.Remove(*r.ignoreRevsFile)
|
if cleanup != nil {
|
||||||
|
cleanup()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBlameReader creates reader for given repository, commit and file
|
// CreateBlameReader creates reader for given repository, commit and file
|
||||||
func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) {
|
func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) {
|
||||||
var ignoreRevsFile *string
|
|
||||||
if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
|
|
||||||
ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := NewCommandNoGlobals("blame", "--porcelain")
|
|
||||||
if ignoreRevsFile != nil {
|
|
||||||
// Possible improvement: use --ignore-revs-file /dev/stdin on unix
|
|
||||||
// There is no equivalent on Windows. May be implemented if Gitea uses an external git backend.
|
|
||||||
cmd.AddOptionValues("--ignore-revs-file", *ignoreRevsFile)
|
|
||||||
}
|
|
||||||
cmd.AddDynamicArguments(commit.ID.String()).AddDashesAndList(file)
|
|
||||||
reader, stdout, err := os.Pipe()
|
reader, stdout, err := os.Pipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ignoreRevsFile != nil {
|
|
||||||
_ = util.Remove(*ignoreRevsFile)
|
|
||||||
}
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
done := make(chan error, 1)
|
cmd := NewCommandNoGlobals("blame", "--porcelain")
|
||||||
|
|
||||||
|
var ignoreRevsFileName string
|
||||||
|
var ignoreRevsFileCleanup func() // TODO: maybe it should check the returned err in a defer func to make sure the cleanup could always be executed correctly
|
||||||
|
if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
|
||||||
|
ignoreRevsFileName, ignoreRevsFileCleanup = tryCreateBlameIgnoreRevsFile(commit)
|
||||||
|
if ignoreRevsFileName != "" {
|
||||||
|
// Possible improvement: use --ignore-revs-file /dev/stdin on unix
|
||||||
|
// There is no equivalent on Windows. May be implemented if Gitea uses an external git backend.
|
||||||
|
cmd.AddOptionValues("--ignore-revs-file", ignoreRevsFileName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.AddDynamicArguments(commit.ID.String()).AddDashesAndList(file)
|
||||||
|
|
||||||
|
done := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
stderr := bytes.Buffer{}
|
stderr := bytes.Buffer{}
|
||||||
// TODO: it doesn't work for directories (the directories shouldn't be "blamed"), and the "err" should be returned by "Read" but not by "Close"
|
// TODO: it doesn't work for directories (the directories shouldn't be "blamed"), and the "err" should be returned by "Read" but not by "Close"
|
||||||
@ -169,40 +171,44 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
bufferedReader := bufio.NewReader(reader)
|
bufferedReader := bufio.NewReader(reader)
|
||||||
|
|
||||||
return &BlameReader{
|
return &BlameReader{
|
||||||
output: stdout,
|
output: stdout,
|
||||||
reader: reader,
|
reader: reader,
|
||||||
bufferedReader: bufferedReader,
|
bufferedReader: bufferedReader,
|
||||||
done: done,
|
done: done,
|
||||||
ignoreRevsFile: ignoreRevsFile,
|
ignoreRevsFile: ignoreRevsFileName,
|
||||||
objectFormat: objectFormat,
|
objectFormat: objectFormat,
|
||||||
|
cleanupFuncs: []func(){ignoreRevsFileCleanup},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryCreateBlameIgnoreRevsFile(commit *Commit) *string {
|
func tryCreateBlameIgnoreRevsFile(commit *Commit) (string, func()) {
|
||||||
entry, err := commit.GetTreeEntryByPath(".git-blame-ignore-revs")
|
entry, err := commit.GetTreeEntryByPath(".git-blame-ignore-revs")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
log.Error("Unable to get .git-blame-ignore-revs file: GetTreeEntryByPath: %v", err)
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := entry.Blob().DataAsync()
|
r, err := entry.Blob().DataAsync()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
log.Error("Unable to get .git-blame-ignore-revs file data: DataAsync: %v", err)
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
f, err := os.CreateTemp("", "gitea_git-blame-ignore-revs")
|
f, cleanup, err := setting.AppDataTempDir("git-repo-content").CreateTempFileRandom("git-blame-ignore-revs")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
log.Error("Unable to get .git-blame-ignore-revs file data: CreateTempFileRandom: %v", err)
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
filename := f.Name()
|
||||||
_, err = io.Copy(f, r)
|
_, err = io.Copy(f, r)
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = util.Remove(f.Name())
|
cleanup()
|
||||||
return nil
|
log.Error("Unable to get .git-blame-ignore-revs file data: Copy: %v", err)
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.ToPointer(f.Name())
|
return filename, cleanup
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReadingBlameOutputSha256(t *testing.T) {
|
func TestReadingBlameOutputSha256(t *testing.T) {
|
||||||
|
setting.AppDataPath = t.TempDir()
|
||||||
ctx, cancel := context.WithCancel(t.Context())
|
ctx, cancel := context.WithCancel(t.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -7,10 +7,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReadingBlameOutput(t *testing.T) {
|
func TestReadingBlameOutput(t *testing.T) {
|
||||||
|
setting.AppDataPath = t.TempDir()
|
||||||
ctx, cancel := context.WithCancel(t.Context())
|
ctx, cancel := context.WithCancel(t.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -10,18 +10,19 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/tempdir"
|
||||||
|
|
||||||
"github.com/hashicorp/go-version"
|
"github.com/hashicorp/go-version"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testRun(m *testing.M) error {
|
func testRun(m *testing.M) error {
|
||||||
gitHomePath, err := os.MkdirTemp(os.TempDir(), "git-home")
|
gitHomePath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("git-home")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create temp dir: %w", err)
|
return fmt.Errorf("unable to create temp dir: %w", err)
|
||||||
}
|
}
|
||||||
defer util.RemoveAll(gitHomePath)
|
defer cleanup()
|
||||||
|
|
||||||
setting.Git.HomePath = gitHomePath
|
setting.Git.HomePath = gitHomePath
|
||||||
|
|
||||||
if err = InitFull(context.Background()); err != nil {
|
if err = InitFull(context.Background()); err != nil {
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/proxy"
|
"code.gitea.io/gitea/modules/proxy"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GPGSettings represents the default GPG settings for this repository
|
// GPGSettings represents the default GPG settings for this repository
|
||||||
@ -266,11 +267,11 @@ func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch
|
|||||||
|
|
||||||
// CreateBundle create bundle content to the target path
|
// CreateBundle create bundle content to the target path
|
||||||
func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.Writer) error {
|
func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.Writer) error {
|
||||||
tmp, err := os.MkdirTemp(os.TempDir(), "gitea-bundle")
|
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmp)
|
defer cleanup()
|
||||||
|
|
||||||
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
|
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
|
||||||
_, _, err = NewCommand("init", "--bare").RunStdString(ctx, &RunOpts{Dir: tmp, Env: env})
|
_, _, err = NewCommand("init", "--bare").RunStdString(ctx, &RunOpts{Dir: tmp, Env: env})
|
||||||
|
@ -10,8 +10,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadTreeToIndex reads a treeish to the index
|
// ReadTreeToIndex reads a treeish to the index
|
||||||
@ -59,26 +58,18 @@ func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (tmpIndexFilena
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
removeDirFn := func(dir string) func() { // it can't use the return value "tmpDir" directly because it is empty when error occurs
|
tmpDir, cancel, err = setting.AppDataTempDir("git-repo-content").MkdirTempRandom("index")
|
||||||
return func() {
|
|
||||||
if err := util.RemoveAll(dir); err != nil {
|
|
||||||
log.Error("failed to remove tmp index dir: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpDir, err = os.MkdirTemp("", "index")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", nil, err
|
return "", "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpIndexFilename = filepath.Join(tmpDir, ".tmp-index")
|
tmpIndexFilename = filepath.Join(tmpDir, ".tmp-index")
|
||||||
cancel = removeDirFn(tmpDir)
|
|
||||||
err = repo.ReadTreeToIndex(treeish, tmpIndexFilename)
|
err = repo.ReadTreeToIndex(treeish, tmpIndexFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", cancel, err
|
return "", "", cancel, err
|
||||||
}
|
}
|
||||||
return tmpIndexFilename, tmpDir, cancel, err
|
return tmpIndexFilename, tmpDir, cancel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmptyIndex empties the index
|
// EmptyIndex empties the index
|
||||||
|
@ -9,11 +9,14 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRepository_GetLanguageStats(t *testing.T) {
|
func TestRepository_GetLanguageStats(t *testing.T) {
|
||||||
|
setting.AppDataPath = t.TempDir()
|
||||||
repoPath := filepath.Join(testReposDir, "language_stats_repo")
|
repoPath := filepath.Join(testReposDir, "language_stats_repo")
|
||||||
gitRepo, err := openRepositoryWithDefaultContext(repoPath)
|
gitRepo, err := openRepositoryWithDefaultContext(repoPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
11
modules/markup/external/external.go
vendored
11
modules/markup/external/external.go
vendored
@ -12,11 +12,9 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegisterRenderers registers all supported third part renderers according settings
|
// RegisterRenderers registers all supported third part renderers according settings
|
||||||
@ -88,16 +86,11 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.
|
|||||||
|
|
||||||
if p.IsInputFile {
|
if p.IsInputFile {
|
||||||
// write to temp file
|
// write to temp file
|
||||||
f, err := os.CreateTemp("", "gitea_input")
|
f, cleanup, err := setting.AppDataTempDir("git-repo-content").CreateTempFileRandom("gitea_input")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s create temp file when rendering %s failed: %w", p.Name(), p.Command, err)
|
return fmt.Errorf("%s create temp file when rendering %s failed: %w", p.Name(), p.Command, err)
|
||||||
}
|
}
|
||||||
tmpPath := f.Name()
|
defer cleanup()
|
||||||
defer func() {
|
|
||||||
if err := util.Remove(tmpPath); err != nil {
|
|
||||||
log.Warn("Unable to remove temporary file: %s: Error: %v", tmpPath, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = io.Copy(f, input)
|
_, err = io.Copy(f, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -6,6 +6,7 @@ package packages
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util/filebuffer"
|
"code.gitea.io/gitea/modules/util/filebuffer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,11 +35,11 @@ func NewHashedBuffer() (*HashedBuffer, error) {
|
|||||||
|
|
||||||
// NewHashedBufferWithSize creates a hashed buffer with a specific memory size
|
// NewHashedBufferWithSize creates a hashed buffer with a specific memory size
|
||||||
func NewHashedBufferWithSize(maxMemorySize int) (*HashedBuffer, error) {
|
func NewHashedBufferWithSize(maxMemorySize int) (*HashedBuffer, error) {
|
||||||
b, err := filebuffer.New(maxMemorySize)
|
tempDir, err := setting.AppDataTempDir("package-hashed-buffer").MkdirAllSub("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
b := filebuffer.New(maxMemorySize, tempDir)
|
||||||
hash := NewMultiHasher()
|
hash := NewMultiHasher()
|
||||||
|
|
||||||
combinedWriter := io.MultiWriter(b, hash)
|
combinedWriter := io.MultiWriter(b, hash)
|
||||||
|
@ -9,10 +9,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHashedBuffer(t *testing.T) {
|
func TestHashedBuffer(t *testing.T) {
|
||||||
|
setting.AppDataPath = t.TempDir()
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
MaxMemorySize int
|
MaxMemorySize int
|
||||||
Data string
|
Data string
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,6 +19,7 @@ fgAA3AEAAAQAAAAjU3RyaW5ncwAAAADgAQAABAAAACNVUwDkAQAAMAAAACNHVUlEAAAAFAIAACgB
|
|||||||
AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`
|
AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`
|
||||||
|
|
||||||
func TestExtractPortablePdb(t *testing.T) {
|
func TestExtractPortablePdb(t *testing.T) {
|
||||||
|
setting.AppDataPath = t.TempDir()
|
||||||
createArchive := func(name string, content []byte) []byte {
|
createArchive := func(name string, content []byte) []byte {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
archive := zip.NewWriter(&buf)
|
archive := zip.NewWriter(&buf)
|
||||||
|
@ -4,41 +4,19 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalCopyPath returns the local repository temporary copy path.
|
|
||||||
func LocalCopyPath() string {
|
|
||||||
if filepath.IsAbs(setting.Repository.Local.LocalCopyPath) {
|
|
||||||
return setting.Repository.Local.LocalCopyPath
|
|
||||||
}
|
|
||||||
return filepath.Join(setting.AppDataPath, setting.Repository.Local.LocalCopyPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateTemporaryPath creates a temporary path
|
// CreateTemporaryPath creates a temporary path
|
||||||
func CreateTemporaryPath(prefix string) (string, error) {
|
func CreateTemporaryPath(prefix string) (string, context.CancelFunc, error) {
|
||||||
if err := os.MkdirAll(LocalCopyPath(), os.ModePerm); err != nil {
|
basePath, cleanup, err := setting.AppDataTempDir("local-repo").MkdirTempRandom(prefix + ".git")
|
||||||
log.Error("Unable to create localcopypath directory: %s (%v)", LocalCopyPath(), err)
|
|
||||||
return "", fmt.Errorf("Failed to create localcopypath directory %s: %w", LocalCopyPath(), err)
|
|
||||||
}
|
|
||||||
basePath, err := os.MkdirTemp(LocalCopyPath(), prefix+".git")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to create temporary directory: %s-*.git (%v)", prefix, err)
|
log.Error("Unable to create temporary directory: %s-*.git (%v)", prefix, err)
|
||||||
return "", fmt.Errorf("Failed to create dir %s-*.git: %w", prefix, err)
|
return "", nil, fmt.Errorf("failed to create dir %s-*.git: %w", prefix, err)
|
||||||
}
|
}
|
||||||
return basePath, nil
|
return basePath, cleanup, nil
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveTemporaryPath removes the temporary path
|
|
||||||
func RemoveTemporaryPath(basePath string) error {
|
|
||||||
if _, err := os.Stat(basePath); !os.IsNotExist(err) {
|
|
||||||
return util.RemoveAll(basePath)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,6 @@ package setting
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
)
|
)
|
||||||
@ -67,14 +65,10 @@ func loadPackagesFrom(rootCfg ConfigProvider) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
Packages.ChunkedUploadPath = filepath.ToSlash(sec.Key("CHUNKED_UPLOAD_PATH").MustString("tmp/package-upload"))
|
|
||||||
if !filepath.IsAbs(Packages.ChunkedUploadPath) {
|
|
||||||
Packages.ChunkedUploadPath = filepath.ToSlash(filepath.Join(AppDataPath, Packages.ChunkedUploadPath))
|
|
||||||
}
|
|
||||||
|
|
||||||
if HasInstallLock(rootCfg) {
|
if HasInstallLock(rootCfg) {
|
||||||
if err := os.MkdirAll(Packages.ChunkedUploadPath, os.ModePerm); err != nil {
|
Packages.ChunkedUploadPath, err = AppDataTempDir("package-upload").MkdirAllSub("")
|
||||||
return fmt.Errorf("unable to create chunked upload directory: %s (%v)", Packages.ChunkedUploadPath, err)
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to create chunked upload directory: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/tempdir"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -196,3 +197,18 @@ func InitWorkPathAndCfgProvider(getEnvFn func(name string) string, args ArgWorkP
|
|||||||
CustomPath = tmpCustomPath.Value
|
CustomPath = tmpCustomPath.Value
|
||||||
CustomConf = tmpCustomConf.Value
|
CustomConf = tmpCustomConf.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AppDataTempDir returns a managed temporary directory for the application data.
|
||||||
|
// Using empty sub will get the managed base temp directory, and it's safe to delete it.
|
||||||
|
// Gitea only creates subdirectories under it, but not the APP_TEMP_PATH directory itself.
|
||||||
|
// * When APP_TEMP_PATH="/tmp": the managed temp directory is "/tmp/gitea-tmp"
|
||||||
|
// * When APP_TEMP_PATH is not set: the managed temp directory is "/{APP_DATA_PATH}/tmp"
|
||||||
|
func AppDataTempDir(sub string) *tempdir.TempDir {
|
||||||
|
if appTempPathInternal != "" {
|
||||||
|
return tempdir.New(appTempPathInternal, "gitea-tmp/"+sub)
|
||||||
|
}
|
||||||
|
if AppDataPath == "" {
|
||||||
|
panic("setting.AppDataPath is not set")
|
||||||
|
}
|
||||||
|
return tempdir.New(AppDataPath, "tmp/"+sub)
|
||||||
|
}
|
||||||
|
@ -62,17 +62,11 @@ var (
|
|||||||
// Repository upload settings
|
// Repository upload settings
|
||||||
Upload struct {
|
Upload struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
TempPath string
|
|
||||||
AllowedTypes string
|
AllowedTypes string
|
||||||
FileMaxSize int64
|
FileMaxSize int64
|
||||||
MaxFiles int
|
MaxFiles int
|
||||||
} `ini:"-"`
|
} `ini:"-"`
|
||||||
|
|
||||||
// Repository local settings
|
|
||||||
Local struct {
|
|
||||||
LocalCopyPath string
|
|
||||||
} `ini:"-"`
|
|
||||||
|
|
||||||
// Pull request settings
|
// Pull request settings
|
||||||
PullRequest struct {
|
PullRequest struct {
|
||||||
WorkInProgressPrefixes []string
|
WorkInProgressPrefixes []string
|
||||||
@ -181,25 +175,16 @@ var (
|
|||||||
// Repository upload settings
|
// Repository upload settings
|
||||||
Upload: struct {
|
Upload: struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
TempPath string
|
|
||||||
AllowedTypes string
|
AllowedTypes string
|
||||||
FileMaxSize int64
|
FileMaxSize int64
|
||||||
MaxFiles int
|
MaxFiles int
|
||||||
}{
|
}{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
TempPath: "data/tmp/uploads",
|
|
||||||
AllowedTypes: "",
|
AllowedTypes: "",
|
||||||
FileMaxSize: 50,
|
FileMaxSize: 50,
|
||||||
MaxFiles: 5,
|
MaxFiles: 5,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Repository local settings
|
|
||||||
Local: struct {
|
|
||||||
LocalCopyPath string
|
|
||||||
}{
|
|
||||||
LocalCopyPath: "tmp/local-repo",
|
|
||||||
},
|
|
||||||
|
|
||||||
// Pull request settings
|
// Pull request settings
|
||||||
PullRequest: struct {
|
PullRequest: struct {
|
||||||
WorkInProgressPrefixes []string
|
WorkInProgressPrefixes []string
|
||||||
@ -308,8 +293,6 @@ func loadRepositoryFrom(rootCfg ConfigProvider) {
|
|||||||
log.Fatal("Failed to map Repository.Editor settings: %v", err)
|
log.Fatal("Failed to map Repository.Editor settings: %v", err)
|
||||||
} else if err = rootCfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
|
} else if err = rootCfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
|
||||||
log.Fatal("Failed to map Repository.Upload settings: %v", err)
|
log.Fatal("Failed to map Repository.Upload settings: %v", err)
|
||||||
} else if err = rootCfg.Section("repository.local").MapTo(&Repository.Local); err != nil {
|
|
||||||
log.Fatal("Failed to map Repository.Local settings: %v", err)
|
|
||||||
} else if err = rootCfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil {
|
} else if err = rootCfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil {
|
||||||
log.Fatal("Failed to map Repository.PullRequest settings: %v", err)
|
log.Fatal("Failed to map Repository.PullRequest settings: %v", err)
|
||||||
}
|
}
|
||||||
@ -361,10 +344,6 @@ func loadRepositoryFrom(rootCfg ConfigProvider) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !filepath.IsAbs(Repository.Upload.TempPath) {
|
|
||||||
Repository.Upload.TempPath = filepath.Join(AppWorkPath, Repository.Upload.TempPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := loadRepoArchiveFrom(rootCfg); err != nil {
|
if err := loadRepoArchiveFrom(rootCfg); err != nil {
|
||||||
log.Fatal("loadRepoArchiveFrom: %v", err)
|
log.Fatal("loadRepoArchiveFrom: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -59,6 +60,8 @@ var (
|
|||||||
// AssetVersion holds a opaque value that is used for cache-busting assets
|
// AssetVersion holds a opaque value that is used for cache-busting assets
|
||||||
AssetVersion string
|
AssetVersion string
|
||||||
|
|
||||||
|
appTempPathInternal string // the temporary path for the app, it is only an internal variable, do not use it, always use AppDataTempDir
|
||||||
|
|
||||||
Protocol Scheme
|
Protocol Scheme
|
||||||
UseProxyProtocol bool // `ini:"USE_PROXY_PROTOCOL"`
|
UseProxyProtocol bool // `ini:"USE_PROXY_PROTOCOL"`
|
||||||
ProxyProtocolTLSBridging bool //`ini:"PROXY_PROTOCOL_TLS_BRIDGING"`
|
ProxyProtocolTLSBridging bool //`ini:"PROXY_PROTOCOL_TLS_BRIDGING"`
|
||||||
@ -330,6 +333,19 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
|||||||
if !filepath.IsAbs(AppDataPath) {
|
if !filepath.IsAbs(AppDataPath) {
|
||||||
AppDataPath = filepath.ToSlash(filepath.Join(AppWorkPath, AppDataPath))
|
AppDataPath = filepath.ToSlash(filepath.Join(AppWorkPath, AppDataPath))
|
||||||
}
|
}
|
||||||
|
if IsInTesting && HasInstallLock(rootCfg) {
|
||||||
|
// FIXME: in testing, the "app data" directory is not correctly initialized before loading settings
|
||||||
|
if _, err := os.Stat(AppDataPath); err != nil {
|
||||||
|
_ = os.MkdirAll(AppDataPath, os.ModePerm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appTempPathInternal = sec.Key("APP_TEMP_PATH").String()
|
||||||
|
if appTempPathInternal != "" {
|
||||||
|
if _, err := os.Stat(appTempPathInternal); err != nil {
|
||||||
|
log.Fatal("APP_TEMP_PATH %q is not accessible: %v", appTempPathInternal, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
|
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
|
||||||
EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false)
|
EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false)
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package setting
|
package setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
@ -31,8 +30,6 @@ var SSH = struct {
|
|||||||
ServerKeyExchanges []string `ini:"SSH_SERVER_KEY_EXCHANGES"`
|
ServerKeyExchanges []string `ini:"SSH_SERVER_KEY_EXCHANGES"`
|
||||||
ServerMACs []string `ini:"SSH_SERVER_MACS"`
|
ServerMACs []string `ini:"SSH_SERVER_MACS"`
|
||||||
ServerHostKeys []string `ini:"SSH_SERVER_HOST_KEYS"`
|
ServerHostKeys []string `ini:"SSH_SERVER_HOST_KEYS"`
|
||||||
KeyTestPath string `ini:"SSH_KEY_TEST_PATH"`
|
|
||||||
KeygenPath string `ini:"SSH_KEYGEN_PATH"`
|
|
||||||
AuthorizedKeysBackup bool `ini:"SSH_AUTHORIZED_KEYS_BACKUP"`
|
AuthorizedKeysBackup bool `ini:"SSH_AUTHORIZED_KEYS_BACKUP"`
|
||||||
AuthorizedPrincipalsBackup bool `ini:"SSH_AUTHORIZED_PRINCIPALS_BACKUP"`
|
AuthorizedPrincipalsBackup bool `ini:"SSH_AUTHORIZED_PRINCIPALS_BACKUP"`
|
||||||
AuthorizedKeysCommandTemplate string `ini:"SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE"`
|
AuthorizedKeysCommandTemplate string `ini:"SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE"`
|
||||||
@ -57,7 +54,6 @@ var SSH = struct {
|
|||||||
ServerCiphers: []string{"chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"},
|
ServerCiphers: []string{"chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"},
|
||||||
ServerKeyExchanges: []string{"curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"},
|
ServerKeyExchanges: []string{"curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"},
|
||||||
ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1"},
|
ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1"},
|
||||||
KeygenPath: "",
|
|
||||||
MinimumKeySizeCheck: true,
|
MinimumKeySizeCheck: true,
|
||||||
MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 3071},
|
MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 3071},
|
||||||
ServerHostKeys: []string{"ssh/gitea.rsa", "ssh/gogs.rsa"},
|
ServerHostKeys: []string{"ssh/gitea.rsa", "ssh/gogs.rsa"},
|
||||||
@ -123,7 +119,6 @@ func loadSSHFrom(rootCfg ConfigProvider) {
|
|||||||
if len(serverMACs) > 0 {
|
if len(serverMACs) > 0 {
|
||||||
SSH.ServerMACs = serverMACs
|
SSH.ServerMACs = serverMACs
|
||||||
}
|
}
|
||||||
SSH.KeyTestPath = os.TempDir()
|
|
||||||
if err = sec.MapTo(&SSH); err != nil {
|
if err = sec.MapTo(&SSH); err != nil {
|
||||||
log.Fatal("Failed to map SSH settings: %v", err)
|
log.Fatal("Failed to map SSH settings: %v", err)
|
||||||
}
|
}
|
||||||
@ -133,7 +128,6 @@ func loadSSHFrom(rootCfg ConfigProvider) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH.KeygenPath = sec.Key("SSH_KEYGEN_PATH").String()
|
|
||||||
SSH.Port = sec.Key("SSH_PORT").MustInt(22)
|
SSH.Port = sec.Key("SSH_PORT").MustInt(22)
|
||||||
SSH.ListenPort = sec.Key("SSH_LISTEN_PORT").MustInt(SSH.Port)
|
SSH.ListenPort = sec.Key("SSH_LISTEN_PORT").MustInt(SSH.Port)
|
||||||
SSH.UseProxyProtocol = sec.Key("SSH_SERVER_USE_PROXY_PROTOCOL").MustBool(false)
|
SSH.UseProxyProtocol = sec.Key("SSH_SERVER_USE_PROXY_PROTOCOL").MustBool(false)
|
||||||
|
@ -32,11 +32,6 @@ func Init() error {
|
|||||||
|
|
||||||
builtinUnused()
|
builtinUnused()
|
||||||
|
|
||||||
// FIXME: why 0o644 for a directory .....
|
|
||||||
if err := os.MkdirAll(setting.SSH.KeyTestPath, 0o644); err != nil {
|
|
||||||
return fmt.Errorf("failed to create directory %q for ssh key test: %w", setting.SSH.KeyTestPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(setting.SSH.TrustedUserCAKeys) > 0 && setting.SSH.AuthorizedPrincipalsEnabled {
|
if len(setting.SSH.TrustedUserCAKeys) > 0 && setting.SSH.AuthorizedPrincipalsEnabled {
|
||||||
caKeysFileName := setting.SSH.TrustedUserCAKeysFile
|
caKeysFileName := setting.SSH.TrustedUserCAKeysFile
|
||||||
caKeysFileDir := filepath.Dir(caKeysFileName)
|
caKeysFileDir := filepath.Dir(caKeysFileName)
|
||||||
|
112
modules/tempdir/tempdir.go
Normal file
112
modules/tempdir/tempdir.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package tempdir
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TempDir struct {
|
||||||
|
// base is the base directory for temporary files, it must exist before accessing and won't be created automatically.
|
||||||
|
// for example: base="/system-tmpdir", sub="gitea-tmp"
|
||||||
|
base, sub string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (td *TempDir) JoinPath(elems ...string) string {
|
||||||
|
return filepath.Join(append([]string{td.base, td.sub}, elems...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkdirAllSub works like os.MkdirAll, but the base directory must exist
|
||||||
|
func (td *TempDir) MkdirAllSub(dir string) (string, error) {
|
||||||
|
if _, err := os.Stat(td.base); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
full := filepath.Join(td.base, td.sub, dir)
|
||||||
|
if err := os.MkdirAll(full, os.ModePerm); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return full, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (td *TempDir) prepareDirWithPattern(elems ...string) (dir, pattern string, err error) {
|
||||||
|
if _, err = os.Stat(td.base); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
dir, pattern = filepath.Split(filepath.Join(append([]string{td.base, td.sub}, elems...)...))
|
||||||
|
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return dir, pattern, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkdirTempRandom works like os.MkdirTemp, the last path field is the "pattern"
|
||||||
|
func (td *TempDir) MkdirTempRandom(elems ...string) (string, func(), error) {
|
||||||
|
dir, pattern, err := td.prepareDirWithPattern(elems...)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
dir, err = os.MkdirTemp(dir, pattern)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
return dir, func() {
|
||||||
|
if err := util.RemoveAll(dir); err != nil {
|
||||||
|
log.Error("Failed to remove temp directory %s: %v", dir, err)
|
||||||
|
}
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTempFileRandom works like os.CreateTemp, the last path field is the "pattern"
|
||||||
|
func (td *TempDir) CreateTempFileRandom(elems ...string) (*os.File, func(), error) {
|
||||||
|
dir, pattern, err := td.prepareDirWithPattern(elems...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
f, err := os.CreateTemp(dir, pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
filename := f.Name()
|
||||||
|
return f, func() {
|
||||||
|
_ = f.Close()
|
||||||
|
if err := util.Remove(filename); err != nil {
|
||||||
|
log.Error("Unable to remove temporary file: %s: Error: %v", filename, err)
|
||||||
|
}
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (td *TempDir) RemoveOutdated(d time.Duration) {
|
||||||
|
var remove func(path string)
|
||||||
|
remove = func(path string) {
|
||||||
|
entries, _ := os.ReadDir(path)
|
||||||
|
for _, entry := range entries {
|
||||||
|
full := filepath.Join(path, entry.Name())
|
||||||
|
if entry.IsDir() {
|
||||||
|
remove(full)
|
||||||
|
_ = os.Remove(full)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
info, err := entry.Info()
|
||||||
|
if err == nil && time.Since(info.ModTime()) > d {
|
||||||
|
_ = os.Remove(full)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remove(td.JoinPath(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// New create a new TempDir instance, "base" must be an existing directory,
|
||||||
|
// "sub" could be a multi-level directory and will be created if not exist
|
||||||
|
func New(base, sub string) *TempDir {
|
||||||
|
return &TempDir{base: base, sub: sub}
|
||||||
|
}
|
||||||
|
|
||||||
|
func OsTempDir(sub string) *TempDir {
|
||||||
|
return New(os.TempDir(), sub)
|
||||||
|
}
|
75
modules/tempdir/tempdir_test.go
Normal file
75
modules/tempdir/tempdir_test.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package tempdir
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTempDir(t *testing.T) {
|
||||||
|
base := t.TempDir()
|
||||||
|
|
||||||
|
t.Run("Create", func(t *testing.T) {
|
||||||
|
td := New(base, "sub1/sub2") // make sure the sub dir supports "/" in the path
|
||||||
|
assert.Equal(t, filepath.Join(base, "sub1", "sub2"), td.JoinPath())
|
||||||
|
assert.Equal(t, filepath.Join(base, "sub1", "sub2/test"), td.JoinPath("test"))
|
||||||
|
|
||||||
|
t.Run("MkdirTempRandom", func(t *testing.T) {
|
||||||
|
s, cleanup, err := td.MkdirTempRandom("foo")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, strings.HasPrefix(s, filepath.Join(base, "sub1/sub2", "foo")))
|
||||||
|
|
||||||
|
_, err = os.Stat(s)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
cleanup()
|
||||||
|
_, err = os.Stat(s)
|
||||||
|
assert.ErrorIs(t, err, os.ErrNotExist)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("CreateTempFileRandom", func(t *testing.T) {
|
||||||
|
f, cleanup, err := td.CreateTempFileRandom("foo", "bar")
|
||||||
|
filename := f.Name()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, strings.HasPrefix(filename, filepath.Join(base, "sub1/sub2", "foo", "bar")))
|
||||||
|
_, err = os.Stat(filename)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
cleanup()
|
||||||
|
_, err = os.Stat(filename)
|
||||||
|
assert.ErrorIs(t, err, os.ErrNotExist)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("RemoveOutDated", func(t *testing.T) {
|
||||||
|
fa1, _, err := td.CreateTempFileRandom("dir-a", "f1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
fa2, _, err := td.CreateTempFileRandom("dir-a", "f2")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_ = os.Chtimes(fa2.Name(), time.Now().Add(-time.Hour), time.Now().Add(-time.Hour))
|
||||||
|
fb1, _, err := td.CreateTempFileRandom("dir-b", "f1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_ = os.Chtimes(fb1.Name(), time.Now().Add(-time.Hour), time.Now().Add(-time.Hour))
|
||||||
|
_, _, _ = fa1.Close(), fa2.Close(), fb1.Close()
|
||||||
|
|
||||||
|
td.RemoveOutdated(time.Minute)
|
||||||
|
|
||||||
|
_, err = os.Stat(fa1.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = os.Stat(fa2.Name())
|
||||||
|
assert.ErrorIs(t, err, os.ErrNotExist)
|
||||||
|
_, err = os.Stat(fb1.Name())
|
||||||
|
assert.ErrorIs(t, err, os.ErrNotExist)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("BaseNotExist", func(t *testing.T) {
|
||||||
|
td := New(filepath.Join(base, "not-exist"), "sub")
|
||||||
|
_, _, err := td.MkdirTempRandom("foo")
|
||||||
|
assert.ErrorIs(t, err, os.ErrNotExist)
|
||||||
|
})
|
||||||
|
}
|
@ -56,7 +56,7 @@ var testMetas = map[string]string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
unittest.InitSettings()
|
unittest.InitSettingsForTesting()
|
||||||
if err := git.InitSimple(context.Background()); err != nil {
|
if err := git.InitSimple(context.Background()); err != nil {
|
||||||
log.Fatal("git init failed, err: %v", err)
|
log.Fatal("git init failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,10 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ErrWriteAfterRead = errors.New("write is unsupported after a read operation") // occurs if Write is called after a read operation
|
||||||
// ErrInvalidMemorySize occurs if the memory size is not in a valid range
|
|
||||||
ErrInvalidMemorySize = errors.New("Memory size must be greater 0 and lower math.MaxInt32")
|
|
||||||
// ErrWriteAfterRead occurs if Write is called after a read operation
|
|
||||||
ErrWriteAfterRead = errors.New("Write is unsupported after a read operation")
|
|
||||||
)
|
|
||||||
|
|
||||||
type readAtSeeker interface {
|
type readAtSeeker interface {
|
||||||
io.ReadSeeker
|
io.ReadSeeker
|
||||||
@ -30,34 +24,17 @@ type FileBackedBuffer struct {
|
|||||||
maxMemorySize int64
|
maxMemorySize int64
|
||||||
size int64
|
size int64
|
||||||
buffer bytes.Buffer
|
buffer bytes.Buffer
|
||||||
|
tempDir string
|
||||||
file *os.File
|
file *os.File
|
||||||
reader readAtSeeker
|
reader readAtSeeker
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a file backed buffer with a specific maximum memory size
|
// New creates a file backed buffer with a specific maximum memory size
|
||||||
func New(maxMemorySize int) (*FileBackedBuffer, error) {
|
func New(maxMemorySize int, tempDir string) *FileBackedBuffer {
|
||||||
if maxMemorySize < 0 || maxMemorySize > math.MaxInt32 {
|
|
||||||
return nil, ErrInvalidMemorySize
|
|
||||||
}
|
|
||||||
|
|
||||||
return &FileBackedBuffer{
|
return &FileBackedBuffer{
|
||||||
maxMemorySize: int64(maxMemorySize),
|
maxMemorySize: int64(maxMemorySize),
|
||||||
}, nil
|
tempDir: tempDir,
|
||||||
}
|
|
||||||
|
|
||||||
// CreateFromReader creates a file backed buffer and copies the provided reader data into it.
|
|
||||||
func CreateFromReader(r io.Reader, maxMemorySize int) (*FileBackedBuffer, error) {
|
|
||||||
b, err := New(maxMemorySize)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = io.Copy(b, r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return b, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write implements io.Writer
|
// Write implements io.Writer
|
||||||
@ -73,7 +50,7 @@ func (b *FileBackedBuffer) Write(p []byte) (int, error) {
|
|||||||
n, err = b.file.Write(p)
|
n, err = b.file.Write(p)
|
||||||
} else {
|
} else {
|
||||||
if b.size+int64(len(p)) > b.maxMemorySize {
|
if b.size+int64(len(p)) > b.maxMemorySize {
|
||||||
b.file, err = os.CreateTemp("", "gitea-buffer-")
|
b.file, err = os.CreateTemp(b.tempDir, "gitea-buffer-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -148,7 +125,7 @@ func (b *FileBackedBuffer) Seek(offset int64, whence int) (int64, error) {
|
|||||||
func (b *FileBackedBuffer) Close() error {
|
func (b *FileBackedBuffer) Close() error {
|
||||||
if b.file != nil {
|
if b.file != nil {
|
||||||
err := b.file.Close()
|
err := b.file.Close()
|
||||||
os.Remove(b.file.Name())
|
_ = os.Remove(b.file.Name())
|
||||||
b.file = nil
|
b.file = nil
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@ func TestFileBackedBuffer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
buf, err := CreateFromReader(strings.NewReader(c.Data), c.MaxMemorySize)
|
buf := New(c.MaxMemorySize, t.TempDir())
|
||||||
|
_, err := io.Copy(buf, strings.NewReader(c.Data))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.EqualValues(t, len(c.Data), buf.Size())
|
assert.EqualValues(t, len(c.Data), buf.Size())
|
||||||
|
@ -3287,8 +3287,6 @@ config.ssh_domain = SSH Server Domain
|
|||||||
config.ssh_port = Port
|
config.ssh_port = Port
|
||||||
config.ssh_listen_port = Listen Port
|
config.ssh_listen_port = Listen Port
|
||||||
config.ssh_root_path = Root Path
|
config.ssh_root_path = Root Path
|
||||||
config.ssh_key_test_path = Key Test Path
|
|
||||||
config.ssh_keygen_path = Keygen ('ssh-keygen') Path
|
|
||||||
config.ssh_minimum_key_size_check = Minimum Key Size Check
|
config.ssh_minimum_key_size_check = Minimum Key Size Check
|
||||||
config.ssh_minimum_key_sizes = Minimum Key Sizes
|
config.ssh_minimum_key_sizes = Minimum Key Sizes
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
repo_service "code.gitea.io/gitea/services/repository"
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
|
|
||||||
@ -303,17 +302,12 @@ var (
|
|||||||
|
|
||||||
func dummyInfoRefs(ctx *context.Context) {
|
func dummyInfoRefs(ctx *context.Context) {
|
||||||
infoRefsOnce.Do(func() {
|
infoRefsOnce.Do(func() {
|
||||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "gitea-info-refs-cache")
|
tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-info-refs-cache")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to create temp dir for git-receive-pack cache: %v", err)
|
log.Error("Failed to create temp dir for git-receive-pack cache: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer cleanup()
|
||||||
defer func() {
|
|
||||||
if err := util.RemoveAll(tmpDir); err != nil {
|
|
||||||
log.Error("RemoveAll: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := git.InitRepository(ctx, tmpDir, true, git.Sha1ObjectFormat.Name()); err != nil {
|
if err := git.InitRepository(ctx, tmpDir, true, git.Sha1ObjectFormat.Name()); err != nil {
|
||||||
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)
|
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)
|
||||||
|
@ -109,17 +109,13 @@ func LFSLocks(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clone base repo.
|
// Clone base repo.
|
||||||
tmpBasePath, err := repo_module.CreateTemporaryPath("locks")
|
tmpBasePath, cleanup, err := repo_module.CreateTemporaryPath("locks")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to create temporary path: %v", err)
|
log.Error("Failed to create temporary path: %v", err)
|
||||||
ctx.ServerError("LFSLocks", err)
|
ctx.ServerError("LFSLocks", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer func() {
|
defer cleanup()
|
||||||
if err := repo_module.RemoveTemporaryPath(tmpBasePath); err != nil {
|
|
||||||
log.Error("LFSLocks: RemoveTemporaryPath: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := git.Clone(ctx, ctx.Repo.Repository.RepoPath(), tmpBasePath, git.CloneRepoOptions{
|
if err := git.Clone(ctx, ctx.Repo.Repository.RepoPath(), tmpBasePath, git.CloneRepoOptions{
|
||||||
Bare: true,
|
Bare: true,
|
||||||
|
@ -355,23 +355,19 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3b. Create a plain patch from head to base
|
// 3b. Create a plain patch from head to base
|
||||||
tmpPatchFile, err := os.CreateTemp("", "patch")
|
tmpPatchFile, cleanup, err := setting.AppDataTempDir("git-repo-content").CreateTempFileRandom("patch")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to create temporary patch file! Error: %v", err)
|
log.Error("Unable to create temporary patch file! Error: %v", err)
|
||||||
return false, fmt.Errorf("unable to create temporary patch file! Error: %w", err)
|
return false, fmt.Errorf("unable to create temporary patch file! Error: %w", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer cleanup()
|
||||||
_ = util.Remove(tmpPatchFile.Name())
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := gitRepo.GetDiffBinary(pr.MergeBase+"...tracking", tmpPatchFile); err != nil {
|
if err := gitRepo.GetDiffBinary(pr.MergeBase+"...tracking", tmpPatchFile); err != nil {
|
||||||
tmpPatchFile.Close()
|
|
||||||
log.Error("Unable to get patch file from %s to %s in %s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err)
|
log.Error("Unable to get patch file from %s to %s in %s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err)
|
||||||
return false, fmt.Errorf("unable to get patch file from %s to %s in %s Error: %w", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err)
|
return false, fmt.Errorf("unable to get patch file from %s to %s in %s Error: %w", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err)
|
||||||
}
|
}
|
||||||
stat, err := tmpPatchFile.Stat()
|
stat, err := tmpPatchFile.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tmpPatchFile.Close()
|
|
||||||
return false, fmt.Errorf("unable to stat patch file: %w", err)
|
return false, fmt.Errorf("unable to stat patch file: %w", err)
|
||||||
}
|
}
|
||||||
patchPath := tmpPatchFile.Name()
|
patchPath := tmpPatchFile.Name()
|
||||||
|
@ -74,11 +74,13 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clone base repo.
|
// Clone base repo.
|
||||||
tmpBasePath, err := repo_module.CreateTemporaryPath("pull")
|
tmpBasePath, cleanup, err := repo_module.CreateTemporaryPath("pull")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("CreateTemporaryPath[%-v]: %v", pr, err)
|
log.Error("CreateTemporaryPath[%-v]: %v", pr, err)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
cancel = cleanup
|
||||||
|
|
||||||
prCtx = &prContext{
|
prCtx = &prContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
tmpBasePath: tmpBasePath,
|
tmpBasePath: tmpBasePath,
|
||||||
@ -86,11 +88,6 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
|
|||||||
outbuf: &strings.Builder{},
|
outbuf: &strings.Builder{},
|
||||||
errbuf: &strings.Builder{},
|
errbuf: &strings.Builder{},
|
||||||
}
|
}
|
||||||
cancel = func() {
|
|
||||||
if err := repo_module.RemoveTemporaryPath(tmpBasePath); err != nil {
|
|
||||||
log.Error("Error whilst removing removing temporary repo for %-v: %v", pr, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
baseRepoPath := pr.BaseRepo.RepoPath()
|
baseRepoPath := pr.BaseRepo.RepoPath()
|
||||||
headRepoPath := pr.HeadRepo.RepoPath()
|
headRepoPath := pr.HeadRepo.RepoPath()
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/templates/vars"
|
"code.gitea.io/gitea/modules/templates/vars"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateRepoOptions contains the create repository options
|
// CreateRepoOptions contains the create repository options
|
||||||
@ -150,15 +149,11 @@ func initRepository(ctx context.Context, u *user_model.User, repo *repo_model.Re
|
|||||||
|
|
||||||
// Initialize repository according to user's choice.
|
// Initialize repository according to user's choice.
|
||||||
if opts.AutoInit {
|
if opts.AutoInit {
|
||||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "gitea-"+repo.Name)
|
tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("repos-" + repo.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to create temp dir for repository %s: %w", repo.FullName(), err)
|
return fmt.Errorf("failed to create temp dir for repository %s: %w", repo.FullName(), err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer cleanup()
|
||||||
if err := util.RemoveAll(tmpDir); err != nil {
|
|
||||||
log.Warn("Unable to remove temporary directory: %s: Error: %v", tmpDir, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = prepareRepoCommit(ctx, repo, tmpDir, opts); err != nil {
|
if err = prepareRepoCommit(ctx, repo, tmpDir, opts); err != nil {
|
||||||
return fmt.Errorf("prepareRepoCommit: %w", err)
|
return fmt.Errorf("prepareRepoCommit: %w", err)
|
||||||
|
@ -30,23 +30,24 @@ type TemporaryUploadRepository struct {
|
|||||||
repo *repo_model.Repository
|
repo *repo_model.Repository
|
||||||
gitRepo *git.Repository
|
gitRepo *git.Repository
|
||||||
basePath string
|
basePath string
|
||||||
|
cleanup func()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTemporaryUploadRepository creates a new temporary upload repository
|
// NewTemporaryUploadRepository creates a new temporary upload repository
|
||||||
func NewTemporaryUploadRepository(repo *repo_model.Repository) (*TemporaryUploadRepository, error) {
|
func NewTemporaryUploadRepository(repo *repo_model.Repository) (*TemporaryUploadRepository, error) {
|
||||||
basePath, err := repo_module.CreateTemporaryPath("upload")
|
basePath, cleanup, err := repo_module.CreateTemporaryPath("upload")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t := &TemporaryUploadRepository{repo: repo, basePath: basePath}
|
t := &TemporaryUploadRepository{repo: repo, basePath: basePath, cleanup: cleanup}
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the repository cleaning up all files
|
// Close the repository cleaning up all files
|
||||||
func (t *TemporaryUploadRepository) Close() {
|
func (t *TemporaryUploadRepository) Close() {
|
||||||
defer t.gitRepo.Close()
|
defer t.gitRepo.Close()
|
||||||
if err := repo_module.RemoveTemporaryPath(t.basePath); err != nil {
|
if t.cleanup != nil {
|
||||||
log.Error("Failed to remove temporary path %s: %v", t.basePath, err)
|
t.cleanup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
@ -255,16 +256,11 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository) (err error) {
|
func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository) (err error) {
|
||||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "gitea-"+repo.Name)
|
tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-" + repo.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to create temp dir for repository %s: %w", repo.FullName(), err)
|
return fmt.Errorf("failed to create temp dir for repository %s: %w", repo.FullName(), err)
|
||||||
}
|
}
|
||||||
|
defer cleanup()
|
||||||
defer func() {
|
|
||||||
if err := util.RemoveAll(tmpDir); err != nil {
|
|
||||||
log.Error("RemoveAll: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = generateRepoCommit(ctx, repo, templateRepo, generateRepo, tmpDir); err != nil {
|
if err = generateRepoCommit(ctx, repo, templateRepo, generateRepo, tmpDir); err != nil {
|
||||||
return fmt.Errorf("generateRepoCommit: %w", err)
|
return fmt.Errorf("generateRepoCommit: %w", err)
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
system_model "code.gitea.io/gitea/models/system"
|
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
@ -102,8 +101,6 @@ func Init(ctx context.Context) error {
|
|||||||
if err := repo_module.LoadRepoConfig(); err != nil {
|
if err := repo_module.LoadRepoConfig(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
system_model.RemoveAllWithNotice(ctx, "Clean up temporary repository uploads", setting.Repository.Upload.TempPath)
|
|
||||||
system_model.RemoveAllWithNotice(ctx, "Clean up temporary repositories", repo_module.LocalCopyPath())
|
|
||||||
if err := initPushQueue(); err != nil {
|
if err := initPushQueue(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -102,15 +102,11 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
|
|||||||
|
|
||||||
hasDefaultBranch := gitrepo.IsBranchExist(ctx, repo.WikiStorageRepo(), repo.DefaultWikiBranch)
|
hasDefaultBranch := gitrepo.IsBranchExist(ctx, repo.WikiStorageRepo(), repo.DefaultWikiBranch)
|
||||||
|
|
||||||
basePath, err := repo_module.CreateTemporaryPath("update-wiki")
|
basePath, cleanup, err := repo_module.CreateTemporaryPath("update-wiki")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer cleanup()
|
||||||
if err := repo_module.RemoveTemporaryPath(basePath); err != nil {
|
|
||||||
log.Error("Merge: RemoveTemporaryPath: %s", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
cloneOpts := git.CloneRepoOptions{
|
cloneOpts := git.CloneRepoOptions{
|
||||||
Bare: true,
|
Bare: true,
|
||||||
@ -264,15 +260,11 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
|
|||||||
return fmt.Errorf("InitWiki: %w", err)
|
return fmt.Errorf("InitWiki: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
basePath, err := repo_module.CreateTemporaryPath("update-wiki")
|
basePath, cleanup, err := repo_module.CreateTemporaryPath("update-wiki")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer cleanup()
|
||||||
if err := repo_module.RemoveTemporaryPath(basePath); err != nil {
|
|
||||||
log.Error("Merge: RemoveTemporaryPath: %s", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := git.Clone(ctx, repo.WikiPath(), basePath, git.CloneRepoOptions{
|
if err := git.Clone(ctx, repo.WikiPath(), basePath, git.CloneRepoOptions{
|
||||||
Bare: true,
|
Bare: true,
|
||||||
|
@ -69,10 +69,6 @@
|
|||||||
{{if not .SSH.StartBuiltinServer}}
|
{{if not .SSH.StartBuiltinServer}}
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.ssh_root_path"}}</dt>
|
<dt>{{ctx.Locale.Tr "admin.config.ssh_root_path"}}</dt>
|
||||||
<dd>{{.SSH.RootPath}}</dd>
|
<dd>{{.SSH.RootPath}}</dd>
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.ssh_key_test_path"}}</dt>
|
|
||||||
<dd>{{.SSH.KeyTestPath}}</dd>
|
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.ssh_keygen_path"}}</dt>
|
|
||||||
<dd>{{.SSH.KeygenPath}}</dd>
|
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.ssh_minimum_key_size_check"}}</dt>
|
<dt>{{ctx.Locale.Tr "admin.config.ssh_minimum_key_size_check"}}</dt>
|
||||||
<dd>{{svg (Iif .SSH.MinimumKeySizeCheck "octicon-check" "octicon-x")}}</dd>
|
<dd>{{svg (Iif .SSH.MinimumKeySizeCheck "octicon-check" "octicon-x")}}</dd>
|
||||||
{{if .SSH.MinimumKeySizeCheck}}
|
{{if .SSH.MinimumKeySizeCheck}}
|
||||||
|
@ -52,7 +52,7 @@ func initMigrationTest(t *testing.T) func() {
|
|||||||
setting.CustomConf = giteaConf
|
setting.CustomConf = giteaConf
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest.InitSettings()
|
unittest.InitSettingsForTesting()
|
||||||
|
|
||||||
assert.NotEmpty(t, setting.RepoRootPath)
|
assert.NotEmpty(t, setting.RepoRootPath)
|
||||||
assert.NoError(t, unittest.SyncDirs(filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
|
assert.NoError(t, unittest.SyncDirs(filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
@ -67,9 +66,8 @@ func InitTest(requireGitea bool) {
|
|||||||
setting.CustomConf = giteaConf
|
setting.CustomConf = giteaConf
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest.InitSettings()
|
unittest.InitSettingsForTesting()
|
||||||
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
|
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
|
||||||
_ = util.RemoveAll(repo_module.LocalCopyPath())
|
|
||||||
|
|
||||||
if err := git.InitFull(context.Background()); err != nil {
|
if err := git.InitFull(context.Background()); err != nil {
|
||||||
log.Fatal("git.InitOnceWithSync: %v", err)
|
log.Fatal("git.InitOnceWithSync: %v", err)
|
||||||
|
Reference in New Issue
Block a user