mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-18 23:34:52 +02:00
Merge branch 'go-gitea:main' into main
This commit is contained in:
@@ -29,8 +29,10 @@ func TestShortSha(t *testing.T) {
|
||||
func TestVerifyTimeLimitCode(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.InstallLock, true)()
|
||||
initGeneralSecret := func(secret string) {
|
||||
setting.InstallLock = true
|
||||
setting.CfgProvider, _ = setting.NewConfigProviderFromData(fmt.Sprintf(`
|
||||
[security]
|
||||
INTERNAL_TOKEN = dummy
|
||||
INSTALL_LOCK = true
|
||||
[oauth2]
|
||||
JWT_SECRET = %s
|
||||
`, secret))
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -49,9 +50,11 @@ func TestRunWithContextStd(t *testing.T) {
|
||||
stdout, stderr, err := cmd.RunStdString(t.Context())
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, stderr, err.Stderr())
|
||||
assert.Equal(t, "fatal: Not a valid object name no-such\n", err.Stderr())
|
||||
stderrLower := strings.ToLower(stderr) // see: IsStdErrorNotValidObjectName
|
||||
assert.Equal(t, "fatal: not a valid object name no-such\n", stderrLower)
|
||||
// FIXME: GIT-CMD-STDERR: it is a bad design, the stderr should not be put in the error message
|
||||
assert.Equal(t, "exit status 128 - fatal: Not a valid object name no-such", err.Error())
|
||||
errLower := strings.ToLower(err.Error())
|
||||
assert.Equal(t, "exit status 128 - fatal: not a valid object name no-such", errLower)
|
||||
assert.Empty(t, stdout)
|
||||
}
|
||||
}
|
||||
@@ -61,9 +64,11 @@ func TestRunWithContextStd(t *testing.T) {
|
||||
stdout, stderr, err := cmd.RunStdBytes(t.Context())
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, string(stderr), err.Stderr())
|
||||
assert.Equal(t, "fatal: Not a valid object name no-such\n", err.Stderr())
|
||||
stderrLower := strings.ToLower(err.Stderr()) // see: IsStdErrorNotValidObjectName
|
||||
assert.Equal(t, "fatal: not a valid object name no-such\n", stderrLower)
|
||||
// FIXME: GIT-CMD-STDERR: it is a bad design, the stderr should not be put in the error message
|
||||
assert.Equal(t, "exit status 128 - fatal: Not a valid object name no-such", err.Error())
|
||||
errLower := strings.ToLower(err.Error())
|
||||
assert.Equal(t, "exit status 128 - fatal: not a valid object name no-such", errLower)
|
||||
assert.Empty(t, stdout)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,13 @@ func IsErrorCanceledOrKilled(err error) bool {
|
||||
return errors.Is(err, context.Canceled) || IsErrorSignalKilled(err)
|
||||
}
|
||||
|
||||
func IsStdErrorNotValidObjectName(err error) bool {
|
||||
stderr, ok := ErrorAsStderr(err)
|
||||
// Git is lowercasing the "fatal: Not a valid object name" error message
|
||||
// ref: https://lore.kernel.org/git/pull.2052.git.1771836302101.gitgitgadget@gmail.com
|
||||
return ok && strings.Contains(strings.ToLower(stderr), "fatal: not a valid object name")
|
||||
}
|
||||
|
||||
type pipelineError struct {
|
||||
error
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func (t *Tree) ListEntries() (Entries, error) {
|
||||
|
||||
stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-l").AddDynamicArguments(t.ID.String()).WithDir(t.repo.Path).RunStdBytes(t.repo.Ctx)
|
||||
if runErr != nil {
|
||||
if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") {
|
||||
if gitcmd.IsStdErrorNotValidObjectName(runErr) || strings.Contains(runErr.Error(), "fatal: not a tree object") {
|
||||
return nil, ErrNotExist{
|
||||
ID: t.ID.String(),
|
||||
}
|
||||
|
||||
@@ -109,7 +109,6 @@ func generateSaveInternalToken(rootCfg ConfigProvider) {
|
||||
|
||||
func loadSecurityFrom(rootCfg ConfigProvider) {
|
||||
sec := rootCfg.Section("security")
|
||||
InstallLock = HasInstallLock(rootCfg)
|
||||
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(31)
|
||||
SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY")
|
||||
if SecretKey == "" {
|
||||
|
||||
@@ -108,6 +108,9 @@ func LoadCommonSettings() {
|
||||
|
||||
// loadCommonSettingsFrom loads common configurations from a configuration provider.
|
||||
func loadCommonSettingsFrom(cfg ConfigProvider) error {
|
||||
// a lot of logic depends on InstallLock value, so it must be loaded before any other settings
|
||||
InstallLock = HasInstallLock(cfg)
|
||||
|
||||
// WARNING: don't change the sequence except you know what you are doing.
|
||||
loadRunModeFrom(cfg)
|
||||
loadLogGlobalFrom(cfg)
|
||||
|
||||
+69
-9
@@ -64,7 +64,7 @@ func PathJoinRelX(elem ...string) string {
|
||||
return PathJoinRel(elems...)
|
||||
}
|
||||
|
||||
const pathSeparator = string(os.PathSeparator)
|
||||
const filepathSeparator = string(os.PathSeparator)
|
||||
|
||||
// FilePathJoinAbs joins the path elements into a single file path, each element is cleaned by filepath.Clean separately.
|
||||
// All slashes/backslashes are converted to path separators before cleaning, the result only contains path separators.
|
||||
@@ -82,7 +82,7 @@ func FilePathJoinAbs(base string, sub ...string) string {
|
||||
if isOSWindows() {
|
||||
elems[0] = filepath.Clean(base)
|
||||
} else {
|
||||
elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", pathSeparator))
|
||||
elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", filepathSeparator))
|
||||
}
|
||||
if !filepath.IsAbs(elems[0]) {
|
||||
// This shouldn't happen. If there is really necessary to pass in relative path, return the full path with filepath.Abs() instead
|
||||
@@ -93,9 +93,9 @@ func FilePathJoinAbs(base string, sub ...string) string {
|
||||
continue
|
||||
}
|
||||
if isOSWindows() {
|
||||
elems = append(elems, filepath.Clean(pathSeparator+s))
|
||||
elems = append(elems, filepath.Clean(filepathSeparator+s))
|
||||
} else {
|
||||
elems = append(elems, filepath.Clean(pathSeparator+strings.ReplaceAll(s, "\\", pathSeparator)))
|
||||
elems = append(elems, filepath.Clean(filepathSeparator+strings.ReplaceAll(s, "\\", filepathSeparator)))
|
||||
}
|
||||
}
|
||||
// the elems[0] must be an absolute path, just join them together
|
||||
@@ -115,12 +115,72 @@ func IsDir(dir string) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
func IsRegularFile(filePath string) (bool, error) {
|
||||
f, err := os.Lstat(filePath)
|
||||
if err == nil {
|
||||
return f.Mode().IsRegular(), nil
|
||||
var ErrNotRegularPathFile = errors.New("not a regular file")
|
||||
|
||||
// ReadRegularPathFile reads a file with given sub path in root dir.
|
||||
// It returns error when the path is not a regular file, or any parent path is not a regular directory.
|
||||
func ReadRegularPathFile(root, filePathIn string, limit int) ([]byte, error) {
|
||||
pathFields := strings.Split(PathJoinRelX(filePathIn), "/")
|
||||
|
||||
targetPathBuilder := strings.Builder{}
|
||||
targetPathBuilder.Grow(len(root) + len(filePathIn) + 2)
|
||||
targetPathBuilder.WriteString(root)
|
||||
targetPathString := root
|
||||
for i, subPath := range pathFields {
|
||||
targetPathBuilder.WriteByte(filepath.Separator)
|
||||
targetPathBuilder.WriteString(subPath)
|
||||
targetPathString = targetPathBuilder.String()
|
||||
|
||||
expectFile := i == len(pathFields)-1
|
||||
st, err := os.Lstat(targetPathString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if expectFile && !st.Mode().IsRegular() || !expectFile && !st.Mode().IsDir() {
|
||||
return nil, fmt.Errorf("%w: %s", ErrNotRegularPathFile, filePathIn)
|
||||
}
|
||||
}
|
||||
return false, err
|
||||
f, err := os.Open(targetPathString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return ReadWithLimit(f, limit)
|
||||
}
|
||||
|
||||
// WriteRegularPathFile writes data to a file with given sub path in root dir, it creates parent directories if necessary.
|
||||
// The file is created with fileMode, and the directories are created with dirMode.
|
||||
// It returns error when the path already exists but is not a regular file, or any parent path is not a regular directory.
|
||||
func WriteRegularPathFile(root, filePathIn string, data []byte, dirMode, fileMode os.FileMode) error {
|
||||
pathFields := strings.Split(PathJoinRelX(filePathIn), "/")
|
||||
|
||||
targetPathBuilder := strings.Builder{}
|
||||
targetPathBuilder.Grow(len(root) + len(filePathIn) + 2)
|
||||
targetPathBuilder.WriteString(root)
|
||||
targetPathString := root
|
||||
for i, subPath := range pathFields {
|
||||
targetPathBuilder.WriteByte(filepath.Separator)
|
||||
targetPathBuilder.WriteString(subPath)
|
||||
targetPathString = targetPathBuilder.String()
|
||||
|
||||
expectFile := i == len(pathFields)-1
|
||||
st, err := os.Lstat(targetPathString)
|
||||
if err == nil {
|
||||
if expectFile && !st.Mode().IsRegular() || !expectFile && !st.Mode().IsDir() {
|
||||
return fmt.Errorf("%w: %s", ErrNotRegularPathFile, filePathIn)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
if !expectFile {
|
||||
if err = os.Mkdir(targetPathString, dirMode); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return os.WriteFile(targetPathString, data, fileMode)
|
||||
}
|
||||
|
||||
// IsExist checks whether a file or directory exists.
|
||||
|
||||
@@ -6,6 +6,7 @@ package util
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
@@ -230,3 +231,70 @@ func TestListDirRecursively(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.ElementsMatch(t, []string{"d1/f-d1", "d1/s1/f-d1s1"}, res)
|
||||
}
|
||||
|
||||
func TestReadWriteRegularPathFile(t *testing.T) {
|
||||
const readLimit = 10000
|
||||
tmpDir := t.TempDir()
|
||||
rootDir := tmpDir + "/root"
|
||||
_ = os.Mkdir(rootDir, 0o755)
|
||||
_ = os.WriteFile(tmpDir+"/other-file", []byte("other-content"), 0o755)
|
||||
_ = os.Mkdir(rootDir+"/real-dir", 0o755)
|
||||
_ = os.WriteFile(rootDir+"/real-dir/real-file", []byte("dummy-content"), 0o644)
|
||||
_ = os.Symlink(rootDir+"/real-dir", rootDir+"/link-dir")
|
||||
_ = os.Symlink(rootDir+"/real-dir/real-file", rootDir+"/real-dir/link-file")
|
||||
|
||||
t.Run("Read", func(t *testing.T) {
|
||||
content, err := os.ReadFile(filepath.Join(rootDir, "../other-file"))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "other-content", string(content))
|
||||
|
||||
content, err = ReadRegularPathFile(rootDir, "../other-file", readLimit)
|
||||
require.ErrorIs(t, err, os.ErrNotExist)
|
||||
assert.Empty(t, string(content))
|
||||
|
||||
content, err = ReadRegularPathFile(rootDir, "real-dir/real-file", readLimit)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "dummy-content", string(content))
|
||||
|
||||
_, err = ReadRegularPathFile(rootDir, "link-dir/real-file", readLimit)
|
||||
require.ErrorIs(t, err, ErrNotRegularPathFile)
|
||||
_, err = ReadRegularPathFile(rootDir, "real-dir/link-file", readLimit)
|
||||
require.ErrorIs(t, err, ErrNotRegularPathFile)
|
||||
_, err = ReadRegularPathFile(rootDir, "link-dir/link-file", readLimit)
|
||||
require.ErrorIs(t, err, ErrNotRegularPathFile)
|
||||
})
|
||||
|
||||
t.Run("Write", func(t *testing.T) {
|
||||
assertFileContent := func(path, expected string) {
|
||||
data, err := os.ReadFile(path)
|
||||
if expected == "" {
|
||||
assert.ErrorIs(t, err, os.ErrNotExist)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expected, string(data), "file content mismatch for %s", path)
|
||||
}
|
||||
|
||||
err := WriteRegularPathFile(rootDir, "new-dir/new-file", []byte("new-content"), 0o755, 0o644)
|
||||
require.NoError(t, err)
|
||||
assertFileContent(rootDir+"/new-dir/new-file", "new-content")
|
||||
|
||||
err = WriteRegularPathFile(rootDir, "link-dir/real-file", []byte("new-content"), 0o755, 0o644)
|
||||
require.ErrorIs(t, err, ErrNotRegularPathFile)
|
||||
err = WriteRegularPathFile(rootDir, "link-dir/link-file", []byte("new-content"), 0o755, 0o644)
|
||||
require.ErrorIs(t, err, ErrNotRegularPathFile)
|
||||
err = WriteRegularPathFile(rootDir, "link-dir/new-file", []byte("new-content"), 0o755, 0o644)
|
||||
require.ErrorIs(t, err, ErrNotRegularPathFile)
|
||||
err = WriteRegularPathFile(rootDir, "real-dir/link-file", []byte("new-content"), 0o755, 0o644)
|
||||
require.ErrorIs(t, err, ErrNotRegularPathFile)
|
||||
|
||||
err = WriteRegularPathFile(rootDir, "../other-file", []byte("new-content"), 0o755, 0o644)
|
||||
require.NoError(t, err)
|
||||
assertFileContent(rootDir+"/../other-file", "other-content")
|
||||
assertFileContent(rootDir+"/other-file", "new-content")
|
||||
|
||||
err = WriteRegularPathFile(rootDir, "real-dir/real-file", []byte("changed-content"), 0o755, 0o644)
|
||||
require.NoError(t, err)
|
||||
assertFileContent(rootDir+"/real-dir/real-file", "changed-content")
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user