mirror of
https://github.com/go-gitea/gitea
synced 2025-12-07 13:28:25 +00:00
Merge branch 'main' into allow-force-push-protected-branches
This commit is contained in:
Vendored
+3
-3
@@ -24,11 +24,11 @@ func newCache(cacheConfig setting.Cache) (mc.Cache, error) {
|
||||
})
|
||||
}
|
||||
|
||||
// NewContext start cache service
|
||||
func NewContext() error {
|
||||
// Init start cache service
|
||||
func Init() error {
|
||||
var err error
|
||||
|
||||
if conn == nil && setting.CacheService.Enabled {
|
||||
if conn == nil {
|
||||
if conn, err = newCache(setting.CacheService.Cache); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -22,9 +22,9 @@ func createTestCache() {
|
||||
}
|
||||
|
||||
func TestNewContext(t *testing.T) {
|
||||
assert.NoError(t, NewContext())
|
||||
assert.NoError(t, Init())
|
||||
|
||||
setting.CacheService.Cache = setting.Cache{Enabled: true, Adapter: "redis", Conn: "some random string"}
|
||||
setting.CacheService.Cache = setting.Cache{Adapter: "redis", Conn: "some random string"}
|
||||
con, err := newCache(setting.Cache{
|
||||
Adapter: "rand",
|
||||
Conn: "false conf",
|
||||
|
||||
+10
-49
@@ -8,11 +8,12 @@
|
||||
package charset
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"html/template"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
)
|
||||
|
||||
@@ -20,20 +21,18 @@ import (
|
||||
const RuneNBSP = 0xa0
|
||||
|
||||
// EscapeControlHTML escapes the unicode control sequences in a provided html document
|
||||
func EscapeControlHTML(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) {
|
||||
func EscapeControlHTML(html template.HTML, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output template.HTML) {
|
||||
sb := &strings.Builder{}
|
||||
outputStream := &HTMLStreamerWriter{Writer: sb}
|
||||
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
|
||||
|
||||
if err := StreamHTML(strings.NewReader(text), streamer); err != nil {
|
||||
streamer.escaped.HasError = true
|
||||
log.Error("Error whilst escaping: %v", err)
|
||||
}
|
||||
return streamer.escaped, sb.String()
|
||||
escaped, _ = EscapeControlReader(strings.NewReader(string(html)), sb, locale, allowed...) // err has been handled in EscapeControlReader
|
||||
return escaped, template.HTML(sb.String())
|
||||
}
|
||||
|
||||
// EscapeControlReaders escapes the unicode control sequences in a provided reader of HTML content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
|
||||
// EscapeControlReader escapes the unicode control sequences in a provided reader of HTML content and writer in a locale and returns the findings as an EscapeStatus
|
||||
func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
|
||||
if !setting.UI.AmbiguousUnicodeDetection {
|
||||
_, err = io.Copy(writer, reader)
|
||||
return &EscapeStatus{}, err
|
||||
}
|
||||
outputStream := &HTMLStreamerWriter{Writer: writer}
|
||||
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
|
||||
|
||||
@@ -43,41 +42,3 @@ func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.
|
||||
}
|
||||
return streamer.escaped, err
|
||||
}
|
||||
|
||||
// EscapeControlStringReader escapes the unicode control sequences in a provided reader of string content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte. HTML line breaks are not inserted after every newline by this method.
|
||||
func EscapeControlStringReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
|
||||
bufRd := bufio.NewReader(reader)
|
||||
outputStream := &HTMLStreamerWriter{Writer: writer}
|
||||
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
|
||||
|
||||
for {
|
||||
line, rdErr := bufRd.ReadString('\n')
|
||||
if len(line) > 0 {
|
||||
if err := streamer.Text(line); err != nil {
|
||||
streamer.escaped.HasError = true
|
||||
log.Error("Error whilst escaping: %v", err)
|
||||
return streamer.escaped, err
|
||||
}
|
||||
}
|
||||
if rdErr != nil {
|
||||
if rdErr != io.EOF {
|
||||
err = rdErr
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return streamer.escaped, err
|
||||
}
|
||||
|
||||
// EscapeControlString escapes the unicode control sequences in a provided string and returns the findings as an EscapeStatus and the escaped string
|
||||
func EscapeControlString(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) {
|
||||
sb := &strings.Builder{}
|
||||
outputStream := &HTMLStreamerWriter{Writer: sb}
|
||||
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
|
||||
|
||||
if err := streamer.Text(text); err != nil {
|
||||
streamer.escaped.HasError = true
|
||||
log.Error("Error whilst escaping: %v", err)
|
||||
}
|
||||
return streamer.escaped, sb.String()
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func (e *escapeStreamer) Text(data string) error {
|
||||
until, next = nextIdxs[0]+pos, nextIdxs[1]+pos
|
||||
}
|
||||
|
||||
// from pos until until we know that the runes are not \r\t\n or even ' '
|
||||
// from pos until we know that the runes are not \r\t\n or even ' '
|
||||
runes := make([]rune, 0, next-until)
|
||||
positions := make([]int, 0, next-until+1)
|
||||
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
package charset
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type escapeControlTest struct {
|
||||
@@ -132,22 +135,8 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`,
|
||||
},
|
||||
}
|
||||
|
||||
func TestEscapeControlString(t *testing.T) {
|
||||
for _, tt := range escapeControlTests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, result := EscapeControlString(tt.text, &translation.MockLocale{})
|
||||
if !reflect.DeepEqual(*status, tt.status) {
|
||||
t.Errorf("EscapeControlString() status = %v, wanted= %v", status, tt.status)
|
||||
}
|
||||
if result != tt.result {
|
||||
t.Errorf("EscapeControlString()\nresult= %v,\nwanted= %v", result, tt.result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEscapeControlReader(t *testing.T) {
|
||||
// lets add some control characters to the tests
|
||||
// add some control characters to the tests
|
||||
tests := make([]escapeControlTest, 0, len(escapeControlTests)*3)
|
||||
copy(tests, escapeControlTests)
|
||||
|
||||
@@ -169,29 +158,20 @@ func TestEscapeControlReader(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
input := strings.NewReader(tt.text)
|
||||
output := &strings.Builder{}
|
||||
status, err := EscapeControlReader(input, output, &translation.MockLocale{})
|
||||
result := output.String()
|
||||
if err != nil {
|
||||
t.Errorf("EscapeControlReader(): err = %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(*status, tt.status) {
|
||||
t.Errorf("EscapeControlReader() status = %v, wanted= %v", status, tt.status)
|
||||
}
|
||||
if result != tt.result {
|
||||
t.Errorf("EscapeControlReader()\nresult= %v,\nwanted= %v", result, tt.result)
|
||||
}
|
||||
status, err := EscapeControlReader(strings.NewReader(tt.text), output, &translation.MockLocale{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.status, *status)
|
||||
assert.Equal(t, tt.result, output.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEscapeControlReader_panic(t *testing.T) {
|
||||
bs := make([]byte, 0, 20479)
|
||||
bs = append(bs, 'A')
|
||||
for i := 0; i < 6826; i++ {
|
||||
bs = append(bs, []byte("—")...)
|
||||
}
|
||||
_, _ = EscapeControlString(string(bs), &translation.MockLocale{})
|
||||
func TestSettingAmbiguousUnicodeDetection(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.UI.AmbiguousUnicodeDetection, true)()
|
||||
_, out := EscapeControlHTML("a test", &translation.MockLocale{})
|
||||
assert.EqualValues(t, `a<span class="escaped-code-point" data-escaped="[U+00A0]"><span class="char"> </span></span>test`, out)
|
||||
setting.UI.AmbiguousUnicodeDetection = false
|
||||
_, out = EscapeControlHTML("a test", &translation.MockLocale{})
|
||||
assert.EqualValues(t, `a test`, out)
|
||||
}
|
||||
|
||||
@@ -158,6 +158,12 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
|
||||
Fixer: actions_model.FixRunnersWithoutBelongingOwner,
|
||||
FixedMessage: "Removed",
|
||||
},
|
||||
{
|
||||
Name: "Topics with empty repository count",
|
||||
Counter: repo_model.CountOrphanedTopics,
|
||||
Fixer: repo_model.DeleteOrphanedTopics,
|
||||
FixedMessage: "Removed",
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: function to recalc all counters
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
||||
"xorm.io/builder"
|
||||
@@ -31,6 +32,10 @@ func countOrphanedRepos(ctx context.Context) (int64, error) {
|
||||
|
||||
// deleteOrphanedRepos delete repository where user of owner_id do not exist
|
||||
func deleteOrphanedRepos(ctx context.Context) (int64, error) {
|
||||
if err := storage.Init(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
batchSize := db.MaxBatchInsertSize("repository")
|
||||
e := db.GetEngine(ctx)
|
||||
var deleted int64
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestReadingBlameOutput(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, bypass := range []bool{false, true} {
|
||||
blameReader, err := CreateBlameReader(ctx, &Sha1ObjectFormat{}, "./tests/repos/repo5_pulls", commit, "README.md", bypass)
|
||||
blameReader, err := CreateBlameReader(ctx, Sha1ObjectFormat, "./tests/repos/repo5_pulls", commit, "README.md", bypass)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, blameReader)
|
||||
defer blameReader.Close()
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"code.gitea.io/gitea/modules/git/internal" //nolint:depguard // only this file can use the internal type CmdArg, other files and packages should use AddXxx functions
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
@@ -389,15 +388,11 @@ func (r *runStdError) IsExitCode(code int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func bytesToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b)) // that's what Golang's strings.Builder.String() does (go/src/strings/builder.go)
|
||||
}
|
||||
|
||||
// RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
|
||||
func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
|
||||
stdoutBytes, stderrBytes, err := c.RunStdBytes(opts)
|
||||
stdout = bytesToString(stdoutBytes)
|
||||
stderr = bytesToString(stderrBytes)
|
||||
stdout = util.UnsafeBytesToString(stdoutBytes)
|
||||
stderr = util.UnsafeBytesToString(stderrBytes)
|
||||
if err != nil {
|
||||
return stdout, stderr, &runStdError{err: err, stderr: stderr}
|
||||
}
|
||||
@@ -432,7 +427,7 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS
|
||||
err := c.Run(newOpts)
|
||||
stderr = stderrBuf.Bytes()
|
||||
if err != nil {
|
||||
return nil, stderr, &runStdError{err: err, stderr: bytesToString(stderr)}
|
||||
return nil, stderr, &runStdError{err: err, stderr: util.UnsafeBytesToString(stderr)}
|
||||
}
|
||||
// even if there is no err, there could still be some stderr output
|
||||
return stdoutBuf.Bytes(), stderr, nil
|
||||
|
||||
@@ -236,7 +236,7 @@ func (c *Commit) IsForcePush(oldCommitID string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if oldCommitID == objectFormat.Empty().String() {
|
||||
if oldCommitID == objectFormat.EmptyObjectID().String() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string,
|
||||
if typ != "commit" {
|
||||
return nil, fmt.Errorf("unexpected type: %s for commit id: %s", typ, commitID)
|
||||
}
|
||||
c, err = CommitFromReader(commit.repo, commit.ID.Type().MustIDFromString(commitID), io.LimitReader(batchReader, size))
|
||||
c, err = CommitFromReader(commit.repo, MustIDFromString(commitID), io.LimitReader(batchReader, size))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -71,10 +71,10 @@ readLoop:
|
||||
|
||||
switch string(split[0]) {
|
||||
case "tree":
|
||||
commit.Tree = *NewTree(gitRepo, objectID.Type().MustIDFromString(string(data)))
|
||||
commit.Tree = *NewTree(gitRepo, MustIDFromString(string(data)))
|
||||
_, _ = payloadSB.Write(line)
|
||||
case "parent":
|
||||
commit.Parents = append(commit.Parents, objectID.Type().MustIDFromString(string(data)))
|
||||
commit.Parents = append(commit.Parents, MustIDFromString(string(data)))
|
||||
_, _ = payloadSB.Write(line)
|
||||
case "author":
|
||||
commit.Author = &Signature{}
|
||||
|
||||
@@ -135,8 +135,8 @@ func TestHasPreviousCommit(t *testing.T) {
|
||||
commit, err := repo.GetCommit("8006ff9adbf0cb94da7dad9e537e53817f9fa5c0")
|
||||
assert.NoError(t, err)
|
||||
|
||||
parentSHA := repo.objectFormat.MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2")
|
||||
notParentSHA := repo.objectFormat.MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3")
|
||||
parentSHA := MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2")
|
||||
notParentSHA := MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3")
|
||||
|
||||
haz, err := commit.HasPreviousCommit(parentSHA)
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -39,7 +39,7 @@ func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache
|
||||
if cache == nil {
|
||||
return nil
|
||||
}
|
||||
if !setting.CacheService.LastCommit.Enabled || count < setting.CacheService.LastCommit.CommitsCount {
|
||||
if count < setting.CacheService.LastCommit.CommitsCount {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -92,11 +92,7 @@ func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) {
|
||||
|
||||
// GetCommitByPath gets the last commit for the entry in the provided commit
|
||||
func (c *LastCommitCache) GetCommitByPath(commitID, entryPath string) (*Commit, error) {
|
||||
objectFormat, err := c.repo.GetObjectFormat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sha, err := objectFormat.NewIDFromString(commitID)
|
||||
sha, err := NewIDFromString(commitID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -5,97 +5,89 @@ package git
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ObjectFormatID int
|
||||
|
||||
const (
|
||||
Sha1 ObjectFormatID = iota
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// sha1Pattern can be used to determine if a string is an valid sha
|
||||
var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
|
||||
|
||||
type ObjectFormat interface {
|
||||
ID() ObjectFormatID
|
||||
String() string
|
||||
|
||||
// Empty is the hash of empty git
|
||||
Empty() ObjectID
|
||||
// Name returns the name of the object format
|
||||
Name() string
|
||||
// EmptyObjectID creates a new empty ObjectID from an object format hash name
|
||||
EmptyObjectID() ObjectID
|
||||
// EmptyTree is the hash of an empty tree
|
||||
EmptyTree() ObjectID
|
||||
// FullLength is the length of the hash's hex string
|
||||
FullLength() int
|
||||
|
||||
// IsValid returns true if the input is a valid hash
|
||||
IsValid(input string) bool
|
||||
// MustID creates a new ObjectID from a byte slice
|
||||
MustID(b []byte) ObjectID
|
||||
MustIDFromString(s string) ObjectID
|
||||
NewID(b []byte) (ObjectID, error)
|
||||
NewIDFromString(s string) (ObjectID, error)
|
||||
NewEmptyID() ObjectID
|
||||
|
||||
NewHasher() HasherInterface
|
||||
// ComputeHash compute the hash for a given ObjectType and content
|
||||
ComputeHash(t ObjectType, content []byte) ObjectID
|
||||
}
|
||||
|
||||
type Sha1ObjectFormat struct{}
|
||||
type Sha1ObjectFormatImpl struct{}
|
||||
|
||||
func (*Sha1ObjectFormat) ID() ObjectFormatID { return Sha1 }
|
||||
func (*Sha1ObjectFormat) String() string { return "sha1" }
|
||||
func (*Sha1ObjectFormat) Empty() ObjectID { return &Sha1Hash{} }
|
||||
func (*Sha1ObjectFormat) EmptyTree() ObjectID {
|
||||
return &Sha1Hash{
|
||||
var (
|
||||
emptyObjectID = &Sha1Hash{}
|
||||
emptyTree = &Sha1Hash{
|
||||
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
|
||||
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
|
||||
}
|
||||
)
|
||||
|
||||
func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
|
||||
func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
|
||||
return emptyObjectID
|
||||
}
|
||||
func (*Sha1ObjectFormat) FullLength() int { return 40 }
|
||||
func (*Sha1ObjectFormat) IsValid(input string) bool {
|
||||
|
||||
func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
|
||||
return emptyTree
|
||||
}
|
||||
func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
|
||||
func (Sha1ObjectFormatImpl) IsValid(input string) bool {
|
||||
return sha1Pattern.MatchString(input)
|
||||
}
|
||||
|
||||
func (*Sha1ObjectFormat) MustID(b []byte) ObjectID {
|
||||
func (Sha1ObjectFormatImpl) MustID(b []byte) ObjectID {
|
||||
var id Sha1Hash
|
||||
copy(id[0:20], b)
|
||||
return &id
|
||||
}
|
||||
|
||||
func (h *Sha1ObjectFormat) MustIDFromString(s string) ObjectID {
|
||||
return MustIDFromString(h, s)
|
||||
// ComputeHash compute the hash for a given ObjectType and content
|
||||
func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID {
|
||||
hasher := sha1.New()
|
||||
_, _ = hasher.Write(t.Bytes())
|
||||
_, _ = hasher.Write([]byte(" "))
|
||||
_, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
|
||||
_, _ = hasher.Write([]byte{0})
|
||||
|
||||
// HashSum generates a SHA1 for the provided hash
|
||||
var sha1 Sha1Hash
|
||||
copy(sha1[:], hasher.Sum(nil))
|
||||
return &sha1
|
||||
}
|
||||
|
||||
func (h *Sha1ObjectFormat) NewID(b []byte) (ObjectID, error) {
|
||||
return IDFromRaw(h, b)
|
||||
var Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
|
||||
|
||||
var SupportedObjectFormats = []ObjectFormat{
|
||||
Sha1ObjectFormat,
|
||||
// TODO: add sha256
|
||||
}
|
||||
|
||||
func (h *Sha1ObjectFormat) NewIDFromString(s string) (ObjectID, error) {
|
||||
return genericIDFromString(h, s)
|
||||
}
|
||||
|
||||
func (*Sha1ObjectFormat) NewEmptyID() ObjectID {
|
||||
return NewSha1()
|
||||
}
|
||||
|
||||
func (h *Sha1ObjectFormat) NewHasher() HasherInterface {
|
||||
return &Sha1Hasher{sha1.New()}
|
||||
}
|
||||
|
||||
func ObjectFormatFromID(id ObjectFormatID) ObjectFormat {
|
||||
switch id {
|
||||
case Sha1:
|
||||
return &Sha1ObjectFormat{}
|
||||
func ObjectFormatFromName(name string) ObjectFormat {
|
||||
for _, objectFormat := range SupportedObjectFormats {
|
||||
if name == objectFormat.Name() {
|
||||
return objectFormat
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ObjectFormatFromString(hash string) (ObjectFormat, error) {
|
||||
switch strings.ToLower(hash) {
|
||||
case "sha1":
|
||||
return &Sha1ObjectFormat{}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown hash type: %s", hash)
|
||||
func IsValidObjectFormat(name string) bool {
|
||||
return ObjectFormatFromName(name) != nil
|
||||
}
|
||||
|
||||
+27
-78
@@ -6,11 +6,7 @@ package git
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ObjectID interface {
|
||||
@@ -31,59 +27,40 @@ func (h *Sha1Hash) IsZero() bool {
|
||||
return bytes.Equal(empty[:], h[:])
|
||||
}
|
||||
func (h *Sha1Hash) RawValue() []byte { return h[:] }
|
||||
func (*Sha1Hash) Type() ObjectFormat { return &Sha1ObjectFormat{} }
|
||||
func (*Sha1Hash) Type() ObjectFormat { return Sha1ObjectFormat }
|
||||
|
||||
func NewSha1() *Sha1Hash {
|
||||
return &Sha1Hash{}
|
||||
}
|
||||
var _ ObjectID = &Sha1Hash{}
|
||||
|
||||
// NewHash is for generic implementations
|
||||
func NewHash(hash string) (ObjectID, error) {
|
||||
hash = strings.ToLower(hash)
|
||||
switch hash {
|
||||
case "sha1":
|
||||
return &Sha1Hash{}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unsupported hash type")
|
||||
}
|
||||
|
||||
func IDFromRaw(h ObjectFormat, b []byte) (ObjectID, error) {
|
||||
if len(b) != h.FullLength()/2 {
|
||||
return h.Empty(), fmt.Errorf("length must be %d: %v", h.FullLength(), b)
|
||||
}
|
||||
return h.MustID(b), nil
|
||||
}
|
||||
|
||||
func MustIDFromString(h ObjectFormat, s string) ObjectID {
|
||||
b, _ := hex.DecodeString(s)
|
||||
return h.MustID(b)
|
||||
}
|
||||
|
||||
func genericIDFromString(h ObjectFormat, s string) (ObjectID, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) != h.FullLength() {
|
||||
return h.Empty(), fmt.Errorf("length must be %d: %s", h.FullLength(), s)
|
||||
}
|
||||
b, err := hex.DecodeString(s)
|
||||
func MustIDFromString(hexHash string) ObjectID {
|
||||
id, err := NewIDFromString(hexHash)
|
||||
if err != nil {
|
||||
return h.Empty(), err
|
||||
panic(err)
|
||||
}
|
||||
return h.NewID(b)
|
||||
return id
|
||||
}
|
||||
|
||||
func IDFromString(hexHash string) (ObjectID, error) {
|
||||
switch len(hexHash) {
|
||||
case 40:
|
||||
hashType := Sha1ObjectFormat{}
|
||||
h, err := hashType.NewIDFromString(hexHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func NewIDFromString(hexHash string) (ObjectID, error) {
|
||||
var theObjectFormat ObjectFormat
|
||||
for _, objectFormat := range SupportedObjectFormats {
|
||||
if len(hexHash) == objectFormat.FullLength() {
|
||||
theObjectFormat = objectFormat
|
||||
break
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid hash hex string: '%s' len: %d", hexHash, len(hexHash))
|
||||
if theObjectFormat == nil {
|
||||
return nil, fmt.Errorf("length %d has no matched object format: %s", len(hexHash), hexHash)
|
||||
}
|
||||
|
||||
b, err := hex.DecodeString(hexHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(b) != theObjectFormat.FullLength()/2 {
|
||||
return theObjectFormat.EmptyObjectID(), fmt.Errorf("length must be %d: %v", theObjectFormat.FullLength(), b)
|
||||
}
|
||||
return theObjectFormat.MustID(b), nil
|
||||
}
|
||||
|
||||
func IsEmptyCommitID(commitID string) bool {
|
||||
@@ -91,7 +68,7 @@ func IsEmptyCommitID(commitID string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
id, err := IDFromString(commitID)
|
||||
id, err := NewIDFromString(commitID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -99,37 +76,9 @@ func IsEmptyCommitID(commitID string) bool {
|
||||
return id.IsZero()
|
||||
}
|
||||
|
||||
// HasherInterface is a struct that will generate a Hash
|
||||
type HasherInterface interface {
|
||||
hash.Hash
|
||||
|
||||
HashSum() ObjectID
|
||||
}
|
||||
|
||||
type Sha1Hasher struct {
|
||||
hash.Hash
|
||||
}
|
||||
|
||||
// ComputeBlobHash compute the hash for a given blob content
|
||||
func ComputeBlobHash(hashType ObjectFormat, content []byte) ObjectID {
|
||||
return ComputeHash(hashType, ObjectBlob, content)
|
||||
}
|
||||
|
||||
// ComputeHash compute the hash for a given ObjectType and content
|
||||
func ComputeHash(hashType ObjectFormat, t ObjectType, content []byte) ObjectID {
|
||||
h := hashType.NewHasher()
|
||||
_, _ = h.Write(t.Bytes())
|
||||
_, _ = h.Write([]byte(" "))
|
||||
_, _ = h.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
|
||||
_, _ = h.Write([]byte{0})
|
||||
return h.HashSum()
|
||||
}
|
||||
|
||||
// HashSum generates a SHA1 for the provided hash
|
||||
func (h *Sha1Hasher) HashSum() ObjectID {
|
||||
var sha1 Sha1Hash
|
||||
copy(sha1[:], h.Hash.Sum(nil))
|
||||
return &sha1
|
||||
return hashType.ComputeHash(ObjectBlob, content)
|
||||
}
|
||||
|
||||
type ErrInvalidSHA struct {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
func ParseGogitHash(h plumbing.Hash) ObjectID {
|
||||
switch hash.Size {
|
||||
case 20:
|
||||
return ObjectFormatFromID(Sha1).MustID(h[:])
|
||||
return Sha1ObjectFormat.MustID(h[:])
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestIsValidSHAPattern(t *testing.T) {
|
||||
h := NewSha1().Type()
|
||||
h := Sha1ObjectFormat
|
||||
assert.True(t, h.IsValid("fee1"))
|
||||
assert.True(t, h.IsValid("abc000"))
|
||||
assert.True(t, h.IsValid("9023902390239023902390239023902390239023"))
|
||||
|
||||
@@ -57,7 +57,7 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
|
||||
return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data))
|
||||
}
|
||||
var err error
|
||||
entry.ID, err = IDFromString(string(data[pos : pos+hash.Size*2]))
|
||||
entry.ID, err = NewIDFromString(string(data[pos : pos+hash.Size*2]))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ls-tree output: %w", err)
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@ func TestParseTreeEntries(t *testing.T) {
|
||||
Input: "100644 blob 61ab7345a1a3bbc590068ccae37b8515cfc5843c 1022\texample/file2.txt\n",
|
||||
Expected: []*TreeEntry{
|
||||
{
|
||||
ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
|
||||
ID: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
|
||||
gogitTreeEntry: &object.TreeEntry{
|
||||
Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
|
||||
Hash: plumbing.Hash(MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
|
||||
Name: "example/file2.txt",
|
||||
Mode: filemode.Regular,
|
||||
},
|
||||
@@ -44,9 +44,9 @@ func TestParseTreeEntries(t *testing.T) {
|
||||
"040000 tree 1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8 -\texample\n",
|
||||
Expected: []*TreeEntry{
|
||||
{
|
||||
ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
|
||||
ID: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
|
||||
gogitTreeEntry: &object.TreeEntry{
|
||||
Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
|
||||
Hash: plumbing.Hash(MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
|
||||
Name: "example/\n.txt",
|
||||
Mode: filemode.Symlink,
|
||||
},
|
||||
@@ -54,10 +54,10 @@ func TestParseTreeEntries(t *testing.T) {
|
||||
sized: true,
|
||||
},
|
||||
{
|
||||
ID: ObjectFormatFromID(Sha1).MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"),
|
||||
ID: MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"),
|
||||
sized: true,
|
||||
gogitTreeEntry: &object.TreeEntry{
|
||||
Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8").RawValue()),
|
||||
Hash: plumbing.Hash(MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8").RawValue()),
|
||||
Name: "example",
|
||||
Mode: filemode.Dir,
|
||||
},
|
||||
@@ -67,7 +67,7 @@ func TestParseTreeEntries(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
entries, err := ParseTreeEntries(ObjectFormatFromID(Sha1), []byte(testCase.Input))
|
||||
entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte(testCase.Input))
|
||||
assert.NoError(t, err)
|
||||
if len(entries) > 1 {
|
||||
fmt.Println(testCase.Expected[0].ID)
|
||||
|
||||
@@ -72,7 +72,7 @@ func parseTreeEntries(objectFormat ObjectFormat, data []byte, ptree *Tree) ([]*T
|
||||
return nil, fmt.Errorf("unknown type: %v", string(entryMode))
|
||||
}
|
||||
|
||||
entry.ID, err = objectFormat.NewIDFromString(string(entryObjectID))
|
||||
entry.ID, err = NewIDFromString(string(entryObjectID))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func TestParseTreeEntriesLong(t *testing.T) {
|
||||
objectFormat := ObjectFormatFromID(Sha1)
|
||||
objectFormat := Sha1ObjectFormat
|
||||
|
||||
testCases := []struct {
|
||||
Input string
|
||||
@@ -26,28 +26,28 @@ func TestParseTreeEntriesLong(t *testing.T) {
|
||||
`,
|
||||
Expected: []*TreeEntry{
|
||||
{
|
||||
ID: objectFormat.MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
|
||||
ID: MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
|
||||
name: "README.md",
|
||||
entryMode: EntryModeBlob,
|
||||
size: 8218,
|
||||
sized: true,
|
||||
},
|
||||
{
|
||||
ID: objectFormat.MustIDFromString("037f27dc9d353ae4fd50f0474b2194c593914e35"),
|
||||
ID: MustIDFromString("037f27dc9d353ae4fd50f0474b2194c593914e35"),
|
||||
name: "README_ZH.md",
|
||||
entryMode: EntryModeBlob,
|
||||
size: 4681,
|
||||
sized: true,
|
||||
},
|
||||
{
|
||||
ID: objectFormat.MustIDFromString("9846a94f7e8350a916632929d0fda38c90dd2ca8"),
|
||||
ID: MustIDFromString("9846a94f7e8350a916632929d0fda38c90dd2ca8"),
|
||||
name: "SECURITY.md",
|
||||
entryMode: EntryModeBlob,
|
||||
size: 429,
|
||||
sized: true,
|
||||
},
|
||||
{
|
||||
ID: objectFormat.MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
|
||||
ID: MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
|
||||
name: "assets",
|
||||
entryMode: EntryModeTree,
|
||||
sized: true,
|
||||
@@ -66,7 +66,7 @@ func TestParseTreeEntriesLong(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseTreeEntriesShort(t *testing.T) {
|
||||
objectFormat := ObjectFormatFromID(Sha1)
|
||||
objectFormat := Sha1ObjectFormat
|
||||
|
||||
testCases := []struct {
|
||||
Input string
|
||||
@@ -78,12 +78,12 @@ func TestParseTreeEntriesShort(t *testing.T) {
|
||||
`,
|
||||
Expected: []*TreeEntry{
|
||||
{
|
||||
ID: objectFormat.MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
|
||||
ID: MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
|
||||
name: "README.md",
|
||||
entryMode: EntryModeBlob,
|
||||
},
|
||||
{
|
||||
ID: objectFormat.MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
|
||||
ID: MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
|
||||
name: "assets",
|
||||
entryMode: EntryModeTree,
|
||||
},
|
||||
@@ -102,7 +102,7 @@ func TestParseTreeEntriesShort(t *testing.T) {
|
||||
|
||||
func TestParseTreeEntriesInvalid(t *testing.T) {
|
||||
// there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315
|
||||
entries, err := ParseTreeEntries(ObjectFormatFromID(Sha1), []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af"))
|
||||
entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af"))
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, entries, 0)
|
||||
}
|
||||
|
||||
@@ -115,11 +115,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
||||
continue
|
||||
case "commit":
|
||||
// Read in the commit to get its tree and in case this is one of the last used commits
|
||||
objectFormat, err := repo.GetObjectFormat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
curCommit, err = git.CommitFromReader(repo, objectFormat.MustIDFromString(string(commitID)), io.LimitReader(batchReader, size))
|
||||
curCommit, err = git.CommitFromReader(repo, git.MustIDFromString(string(commitID)), io.LimitReader(batchReader, size))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ func RefURL(repoURL, ref string) string {
|
||||
return repoURL + "/src/branch/" + refName
|
||||
case refFullName.IsTag():
|
||||
return repoURL + "/src/tag/" + refName
|
||||
case !ObjectFormatFromID(Sha1).IsValid(ref):
|
||||
case !Sha1ObjectFormat.IsValid(ref):
|
||||
// assume they mean a branch
|
||||
return repoURL + "/src/branch/" + refName
|
||||
default:
|
||||
|
||||
+9
-3
@@ -81,7 +81,7 @@ func GetObjectFormatOfRepo(ctx context.Context, repoPath string) (ObjectFormat,
|
||||
return nil, errors.New(stderr.String())
|
||||
}
|
||||
|
||||
h, err := IDFromString(strings.TrimRight(stdout.String(), "\n"))
|
||||
h, err := NewIDFromString(strings.TrimRight(stdout.String(), "\n"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -90,7 +90,7 @@ func GetObjectFormatOfRepo(ctx context.Context, repoPath string) (ObjectFormat,
|
||||
}
|
||||
|
||||
// InitRepository initializes a new Git repository.
|
||||
func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormat ObjectFormat) error {
|
||||
func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormatName string) error {
|
||||
err := os.MkdirAll(repoPath, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -98,7 +98,13 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
|
||||
|
||||
cmd := NewCommand(ctx, "init")
|
||||
if SupportHashSha256 {
|
||||
cmd.AddOptionValues("--object-format", objectFormat.String())
|
||||
if objectFormatName == "" {
|
||||
objectFormatName = Sha1ObjectFormat.Name()
|
||||
}
|
||||
if !IsValidObjectFormat(objectFormatName) {
|
||||
return fmt.Errorf("invalid object format: %s", objectFormatName)
|
||||
}
|
||||
cmd.AddOptionValues("--object-format", objectFormatName)
|
||||
}
|
||||
if bare {
|
||||
cmd.AddArguments("--bare")
|
||||
|
||||
@@ -5,7 +5,7 @@ package git
|
||||
|
||||
// GetBlob finds the blob object in the repository.
|
||||
func (repo *Repository) GetBlob(idStr string) (*Blob, error) {
|
||||
id, err := repo.objectFormat.NewIDFromString(idStr)
|
||||
id, err := NewIDFromString(idStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestRepository_GetBlob_NoId(t *testing.T) {
|
||||
defer r.Close()
|
||||
|
||||
testCase := ""
|
||||
testError := fmt.Errorf("length must be 40: %s", testCase)
|
||||
testError := fmt.Errorf("length %d has no matched object format: %s", len(testCase), testCase)
|
||||
|
||||
blob, err := r.GetBlob(testCase)
|
||||
assert.Nil(t, blob)
|
||||
|
||||
@@ -63,7 +63,7 @@ func (repo *Repository) getCommitByPathWithID(id ObjectID, relpath string) (*Com
|
||||
return nil, runErr
|
||||
}
|
||||
|
||||
id, err := repo.objectFormat.NewIDFromString(stdout)
|
||||
id, err := NewIDFromString(stdout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -254,7 +254,7 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
|
||||
}
|
||||
return commits, err
|
||||
}
|
||||
objectID, err := repo.objectFormat.NewIDFromString(string(shaline[0:len]))
|
||||
objectID, err := NewIDFromString(string(shaline[0:len]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func (repo *Repository) RemoveReference(name string) error {
|
||||
func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
|
||||
objectFormat := repo.objectFormat
|
||||
if len(commitID) == hash.HexSize && objectFormat.IsValid(commitID) {
|
||||
ID, err := objectFormat.NewIDFromString(commitID)
|
||||
ID, err := NewIDFromString(commitID)
|
||||
if err == nil {
|
||||
return ID, nil
|
||||
}
|
||||
@@ -54,12 +54,12 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "unknown revision or path") ||
|
||||
strings.Contains(err.Error(), "fatal: Needed a single revision") {
|
||||
return objectFormat.Empty(), ErrNotExist{commitID, ""}
|
||||
return objectFormat.EmptyObjectID(), ErrNotExist{commitID, ""}
|
||||
}
|
||||
return objectFormat.Empty(), err
|
||||
return objectFormat.EmptyObjectID(), err
|
||||
}
|
||||
|
||||
return objectFormat.NewIDFromString(actualCommitID)
|
||||
return NewIDFromString(actualCommitID)
|
||||
}
|
||||
|
||||
// IsCommitExist returns true if given commit exists in current repository.
|
||||
|
||||
@@ -135,7 +135,7 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id ObjectID)
|
||||
func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
|
||||
IDType := repo.objectFormat
|
||||
if len(commitID) == IDType.FullLength() && IDType.IsValid(commitID) {
|
||||
ID, err := repo.objectFormat.NewIDFromString(commitID)
|
||||
ID, err := NewIDFromString(commitID)
|
||||
if err == nil {
|
||||
return ID, nil
|
||||
}
|
||||
@@ -155,5 +155,5 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return repo.objectFormat.MustIDFromString(string(sha)), nil
|
||||
return MustIDFromString(string(sha)), nil
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func (r *Repository) CommitNodeIndex() (cgobject.CommitNodeIndex, *os.File) {
|
||||
|
||||
file, err := os.Open(indexPath)
|
||||
if err == nil {
|
||||
var index commitgraph.Index
|
||||
var index commitgraph.Index // TODO: in newer go-git, it might need to use "github.com/go-git/go-git/v5/plumbing/format/commitgraph/v2" package to compile
|
||||
index, err = commitgraph.OpenFileIndex(file)
|
||||
if err == nil {
|
||||
return cgobject.NewGraphCommitNodeIndex(index, r.gogitRepo.Storer), file
|
||||
|
||||
@@ -284,7 +284,7 @@ func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
|
||||
// If base is the SHA of an empty tree (EmptyTreeSHA), it returns the files changes from the initial commit to the head commit
|
||||
func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, error) {
|
||||
cmd := NewCommand(repo.Ctx, "diff-tree", "--name-only", "--root", "--no-commit-id", "-r", "-z")
|
||||
if base == repo.objectFormat.Empty().String() {
|
||||
if base == repo.objectFormat.EmptyObjectID().String() {
|
||||
cmd.AddDynamicArguments(head)
|
||||
} else {
|
||||
cmd.AddDynamicArguments(base, head)
|
||||
|
||||
@@ -131,12 +131,12 @@ func TestGetCommitFilesChanged(t *testing.T) {
|
||||
files []string
|
||||
}{
|
||||
{
|
||||
repo.objectFormat.Empty().String(),
|
||||
repo.objectFormat.EmptyObjectID().String(),
|
||||
"95bb4d39648ee7e325106df01a621c530863a653",
|
||||
[]string{"file1.txt"},
|
||||
},
|
||||
{
|
||||
repo.objectFormat.Empty().String(),
|
||||
repo.objectFormat.EmptyObjectID().String(),
|
||||
"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
|
||||
[]string{"file2.txt"},
|
||||
},
|
||||
|
||||
@@ -30,7 +30,7 @@ func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string)
|
||||
treeish = res[:len(res)-1]
|
||||
}
|
||||
}
|
||||
id, err := objectFormat.NewIDFromString(treeish)
|
||||
id, err := NewIDFromString(treeish)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -101,7 +101,7 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
|
||||
for _, file := range filenames {
|
||||
if file != "" {
|
||||
buffer.WriteString("0 ")
|
||||
buffer.WriteString(repo.objectFormat.Empty().String())
|
||||
buffer.WriteString(repo.objectFormat.EmptyObjectID().String())
|
||||
buffer.WriteByte('\t')
|
||||
buffer.WriteString(file)
|
||||
buffer.WriteByte('\000')
|
||||
@@ -128,7 +128,7 @@ func (repo *Repository) WriteTree() (*Tree, error) {
|
||||
if runErr != nil {
|
||||
return nil, runErr
|
||||
}
|
||||
id, err := repo.objectFormat.NewIDFromString(strings.TrimSpace(stdout))
|
||||
id, err := NewIDFromString(strings.TrimSpace(stdout))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
|
||||
return nil, ErrNotExist{commitID, ""}
|
||||
}
|
||||
|
||||
sha, err := repo.objectFormat.NewIDFromString(string(shaBytes))
|
||||
sha, err := NewIDFromString(string(shaBytes))
|
||||
if err != nil {
|
||||
log.Debug("Unable to get commit for: %s. Err: %v", commitID, err)
|
||||
return nil, ErrNotExist{commitID, ""}
|
||||
|
||||
@@ -46,7 +46,7 @@ func (repo *Repository) GetObjectFormat() (ObjectFormat, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hash, err := IDFromString(str)
|
||||
hash, err := NewIDFromString(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func (repo *Repository) HashObject(reader io.Reader) (ObjectID, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.objectFormat.NewIDFromString(idStr)
|
||||
return NewIDFromString(idStr)
|
||||
}
|
||||
|
||||
func (repo *Repository) hashObject(reader io.Reader, save bool) (string, error) {
|
||||
|
||||
@@ -75,7 +75,7 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
|
||||
if pattern == "" || strings.HasPrefix(refName, pattern) {
|
||||
r := &Reference{
|
||||
Name: refName,
|
||||
Object: repo.objectFormat.MustIDFromString(sha),
|
||||
Object: MustIDFromString(sha),
|
||||
Type: typ,
|
||||
repo: repo,
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, err := repo.objectFormat.NewIDFromString(idStr)
|
||||
id, err := NewIDFromString(idStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -98,7 +98,7 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
|
||||
|
||||
// GetTagWithID returns a Git tag by given name and ID
|
||||
func (repo *Repository) GetTagWithID(idStr, name string) (*Tag, error) {
|
||||
id, err := repo.objectFormat.NewIDFromString(idStr)
|
||||
id, err := NewIDFromString(idStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -165,7 +165,7 @@ func parseTagRef(objectFormat ObjectFormat, ref map[string]string) (tag *Tag, er
|
||||
Name: ref["refname:short"],
|
||||
}
|
||||
|
||||
tag.ID, err = objectFormat.NewIDFromString(ref["objectname"])
|
||||
tag.ID, err = NewIDFromString(ref["objectname"])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse objectname '%s': %w", ref["objectname"], err)
|
||||
}
|
||||
@@ -175,7 +175,7 @@ func parseTagRef(objectFormat ObjectFormat, ref map[string]string) (tag *Tag, er
|
||||
tag.Object = tag.ID
|
||||
} else {
|
||||
// annotated tag
|
||||
tag.Object, err = objectFormat.NewIDFromString(ref["object"])
|
||||
tag.Object, err = NewIDFromString(ref["object"])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse object '%s': %w", ref["object"], err)
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func parseTagRef(objectFormat ObjectFormat, ref map[string]string) (tag *Tag, er
|
||||
|
||||
// GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag
|
||||
func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) {
|
||||
id, err := repo.objectFormat.NewIDFromString(sha)
|
||||
id, err := NewIDFromString(sha)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) {
|
||||
// every tag should have a commit ID so return all errors
|
||||
return nil, err
|
||||
}
|
||||
commitID, err := IDFromString(commitIDStr)
|
||||
commitID, err := NewIDFromString(commitIDStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) {
|
||||
// every tag should have a commit ID so return all errors
|
||||
return nil, err
|
||||
}
|
||||
commitID, err := repo.objectFormat.NewIDFromString(commitIDStr)
|
||||
commitID, err := NewIDFromString(commitIDStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ func TestRepository_GetAnnotatedTag(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRepository_parseTagRef(t *testing.T) {
|
||||
sha1 := ObjectFormatFromID(Sha1)
|
||||
sha1 := Sha1ObjectFormat
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -224,8 +224,8 @@ func TestRepository_parseTagRef(t *testing.T) {
|
||||
|
||||
want: &Tag{
|
||||
Name: "v1.9.1",
|
||||
ID: sha1.MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
|
||||
Object: sha1.MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
|
||||
ID: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
|
||||
Object: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
|
||||
Type: "commit",
|
||||
Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"),
|
||||
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n",
|
||||
@@ -253,8 +253,8 @@ func TestRepository_parseTagRef(t *testing.T) {
|
||||
|
||||
want: &Tag{
|
||||
Name: "v0.0.1",
|
||||
ID: sha1.MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
|
||||
Object: sha1.MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
|
||||
ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
|
||||
Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
|
||||
Type: "tag",
|
||||
Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"),
|
||||
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n",
|
||||
@@ -311,8 +311,8 @@ qbHDASXl
|
||||
|
||||
want: &Tag{
|
||||
Name: "v0.0.1",
|
||||
ID: sha1.MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
|
||||
Object: sha1.MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
|
||||
ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
|
||||
Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
|
||||
Type: "tag",
|
||||
Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"),
|
||||
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md",
|
||||
|
||||
@@ -63,5 +63,5 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt
|
||||
if err != nil {
|
||||
return nil, ConcatenateError(err, stderr.String())
|
||||
}
|
||||
return repo.objectFormat.NewIDFromString(strings.TrimSpace(stdout.String()))
|
||||
return NewIDFromString(strings.TrimSpace(stdout.String()))
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
|
||||
idStr = res[:len(res)-1]
|
||||
}
|
||||
}
|
||||
id, err := repo.objectFormat.NewIDFromString(idStr)
|
||||
id, err := NewIDFromString(idStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
|
||||
idStr = res
|
||||
}
|
||||
}
|
||||
id, err := repo.objectFormat.NewIDFromString(idStr)
|
||||
id, err := NewIDFromString(idStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+3
-3
@@ -35,8 +35,8 @@ func (tag *Tag) Commit(gitRepo *Repository) (*Commit, error) {
|
||||
// \n\n separate headers from message
|
||||
func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) {
|
||||
tag := new(Tag)
|
||||
tag.ID = objectFormat.NewEmptyID()
|
||||
tag.Object = objectFormat.NewEmptyID()
|
||||
tag.ID = objectFormat.EmptyObjectID()
|
||||
tag.Object = objectFormat.EmptyObjectID()
|
||||
tag.Tagger = &Signature{}
|
||||
// we now have the contents of the commit object. Let's investigate...
|
||||
nextline := 0
|
||||
@@ -50,7 +50,7 @@ l:
|
||||
reftype := line[:spacepos]
|
||||
switch string(reftype) {
|
||||
case "object":
|
||||
id, err := objectFormat.NewIDFromString(string(line[spacepos+1:]))
|
||||
id, err := NewIDFromString(string(line[spacepos+1:]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ tagger Lucas Michot <lucas@semalead.com> 1484491741 +0100
|
||||
|
||||
`), tag: Tag{
|
||||
Name: "",
|
||||
ID: NewSha1(),
|
||||
ID: Sha1ObjectFormat.EmptyObjectID(),
|
||||
Object: &Sha1Hash{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a},
|
||||
Type: "commit",
|
||||
Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0)},
|
||||
@@ -39,7 +39,7 @@ o
|
||||
|
||||
ono`), tag: Tag{
|
||||
Name: "",
|
||||
ID: NewSha1(),
|
||||
ID: Sha1ObjectFormat.EmptyObjectID(),
|
||||
Object: &Sha1Hash{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc},
|
||||
Type: "commit",
|
||||
Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0)},
|
||||
@@ -49,7 +49,7 @@ ono`), tag: Tag{
|
||||
}
|
||||
|
||||
for _, test := range testData {
|
||||
tag, err := parseTagData(ObjectFormatFromID(Sha1), test.data)
|
||||
tag, err := parseTagData(Sha1ObjectFormat, test.data)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, test.tag.ID, tag.ID)
|
||||
assert.EqualValues(t, test.tag.Object, tag.Object)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
gohtml "html"
|
||||
"html/template"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -55,7 +56,7 @@ func NewContext() {
|
||||
}
|
||||
|
||||
// Code returns a HTML version of code string with chroma syntax highlighting classes and the matched lexer name
|
||||
func Code(fileName, language, code string) (string, string) {
|
||||
func Code(fileName, language, code string) (output template.HTML, lexerName string) {
|
||||
NewContext()
|
||||
|
||||
// diff view newline will be passed as empty, change to literal '\n' so it can be copied
|
||||
@@ -65,7 +66,7 @@ func Code(fileName, language, code string) (string, string) {
|
||||
}
|
||||
|
||||
if len(code) > sizeLimit {
|
||||
return code, ""
|
||||
return template.HTML(template.HTMLEscapeString(code)), ""
|
||||
}
|
||||
|
||||
var lexer chroma.Lexer
|
||||
@@ -102,13 +103,11 @@ func Code(fileName, language, code string) (string, string) {
|
||||
cache.Add(fileName, lexer)
|
||||
}
|
||||
|
||||
lexerName := formatLexerName(lexer.Config().Name)
|
||||
|
||||
return CodeFromLexer(lexer, code), lexerName
|
||||
return CodeFromLexer(lexer, code), formatLexerName(lexer.Config().Name)
|
||||
}
|
||||
|
||||
// CodeFromLexer returns a HTML version of code string with chroma syntax highlighting classes
|
||||
func CodeFromLexer(lexer chroma.Lexer, code string) string {
|
||||
func CodeFromLexer(lexer chroma.Lexer, code string) template.HTML {
|
||||
formatter := html.New(html.WithClasses(true),
|
||||
html.WithLineNumbers(false),
|
||||
html.PreventSurroundingPre(true),
|
||||
@@ -120,23 +119,23 @@ func CodeFromLexer(lexer chroma.Lexer, code string) string {
|
||||
iterator, err := lexer.Tokenise(nil, code)
|
||||
if err != nil {
|
||||
log.Error("Can't tokenize code: %v", err)
|
||||
return code
|
||||
return template.HTML(template.HTMLEscapeString(code))
|
||||
}
|
||||
// style not used for live site but need to pass something
|
||||
err = formatter.Format(htmlw, githubStyles, iterator)
|
||||
if err != nil {
|
||||
log.Error("Can't format code: %v", err)
|
||||
return code
|
||||
return template.HTML(template.HTMLEscapeString(code))
|
||||
}
|
||||
|
||||
_ = htmlw.Flush()
|
||||
// Chroma will add newlines for certain lexers in order to highlight them properly
|
||||
// Once highlighted, strip them here, so they don't cause copy/paste trouble in HTML output
|
||||
return strings.TrimSuffix(htmlbuf.String(), "\n")
|
||||
return template.HTML(strings.TrimSuffix(htmlbuf.String(), "\n"))
|
||||
}
|
||||
|
||||
// File returns a slice of chroma syntax highlighted HTML lines of code and the matched lexer name
|
||||
func File(fileName, language string, code []byte) ([]string, string, error) {
|
||||
func File(fileName, language string, code []byte) ([]template.HTML, string, error) {
|
||||
NewContext()
|
||||
|
||||
if len(code) > sizeLimit {
|
||||
@@ -183,14 +182,14 @@ func File(fileName, language string, code []byte) ([]string, string, error) {
|
||||
tokensLines := chroma.SplitTokensIntoLines(iterator.Tokens())
|
||||
htmlBuf := &bytes.Buffer{}
|
||||
|
||||
lines := make([]string, 0, len(tokensLines))
|
||||
lines := make([]template.HTML, 0, len(tokensLines))
|
||||
for _, tokens := range tokensLines {
|
||||
iterator = chroma.Literator(tokens...)
|
||||
err = formatter.Format(htmlBuf, githubStyles, iterator)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("can't format code: %w", err)
|
||||
}
|
||||
lines = append(lines, htmlBuf.String())
|
||||
lines = append(lines, template.HTML(htmlBuf.String()))
|
||||
htmlBuf.Reset()
|
||||
}
|
||||
|
||||
@@ -198,9 +197,9 @@ func File(fileName, language string, code []byte) ([]string, string, error) {
|
||||
}
|
||||
|
||||
// PlainText returns non-highlighted HTML for code
|
||||
func PlainText(code []byte) []string {
|
||||
func PlainText(code []byte) []template.HTML {
|
||||
r := bufio.NewReader(bytes.NewReader(code))
|
||||
m := make([]string, 0, bytes.Count(code, []byte{'\n'})+1)
|
||||
m := make([]template.HTML, 0, bytes.Count(code, []byte{'\n'})+1)
|
||||
for {
|
||||
content, err := r.ReadString('\n')
|
||||
if err != nil && err != io.EOF {
|
||||
@@ -210,7 +209,7 @@ func PlainText(code []byte) []string {
|
||||
if content == "" && err == io.EOF {
|
||||
break
|
||||
}
|
||||
s := gohtml.EscapeString(content)
|
||||
s := template.HTML(gohtml.EscapeString(content))
|
||||
m = append(m, s)
|
||||
}
|
||||
return m
|
||||
|
||||
@@ -4,21 +4,36 @@
|
||||
package highlight
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func lines(s string) []string {
|
||||
return strings.Split(strings.ReplaceAll(strings.TrimSpace(s), `\n`, "\n"), "\n")
|
||||
func lines(s string) (out []template.HTML) {
|
||||
// "" => [], "a" => ["a"], "a\n" => ["a\n"], "a\nb" => ["a\n", "b"] (each line always includes EOL "\n" if it exists)
|
||||
out = make([]template.HTML, 0)
|
||||
s = strings.ReplaceAll(strings.ReplaceAll(strings.TrimSpace(s), "\n", ""), `\n`, "\n")
|
||||
for {
|
||||
if p := strings.IndexByte(s, '\n'); p != -1 {
|
||||
out = append(out, template.HTML(s[:p+1]))
|
||||
s = s[p+1:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if s != "" {
|
||||
out = append(out, template.HTML(s))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestFile(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
code string
|
||||
want []string
|
||||
want []template.HTML
|
||||
lexerName string
|
||||
}{
|
||||
{
|
||||
@@ -99,10 +114,7 @@ c=2
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
out, lexerName, err := File(tt.name, "", []byte(tt.code))
|
||||
assert.NoError(t, err)
|
||||
expected := strings.Join(tt.want, "\n")
|
||||
actual := strings.Join(out, "\n")
|
||||
assert.Equal(t, strings.Count(actual, "<span"), strings.Count(actual, "</span>"))
|
||||
assert.EqualValues(t, expected, actual)
|
||||
assert.EqualValues(t, tt.want, out)
|
||||
assert.Equal(t, tt.lexerName, lexerName)
|
||||
})
|
||||
}
|
||||
@@ -112,7 +124,7 @@ func TestPlainText(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
code string
|
||||
want []string
|
||||
want []template.HTML
|
||||
}{
|
||||
{
|
||||
name: "empty.py",
|
||||
@@ -165,9 +177,7 @@ c=2`),
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
out := PlainText([]byte(tt.code))
|
||||
expected := strings.Join(tt.want, "\n")
|
||||
actual := strings.Join(out, "\n")
|
||||
assert.EqualValues(t, expected, actual)
|
||||
assert.EqualValues(t, tt.want, out)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package code
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"html/template"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/highlight"
|
||||
@@ -22,7 +23,7 @@ type Result struct {
|
||||
Language string
|
||||
Color string
|
||||
LineNumbers []int
|
||||
FormattedLines string
|
||||
FormattedLines template.HTML
|
||||
}
|
||||
|
||||
type SearchResultLanguages = internal.SearchResultLanguages
|
||||
|
||||
@@ -87,7 +87,7 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
|
||||
}
|
||||
lexer = chroma.Coalesce(lexer)
|
||||
|
||||
if _, err := w.WriteString(highlight.CodeFromLexer(lexer, source)); err != nil {
|
||||
if _, err := w.WriteString(string(highlight.CodeFromLexer(lexer, source))); err != nil {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ func TestCommitToPushCommit(t *testing.T) {
|
||||
When: now,
|
||||
}
|
||||
const hexString = "0123456789abcdef0123456789abcdef01234567"
|
||||
sha1, err := git.IDFromString(hexString)
|
||||
sha1, err := git.NewIDFromString(hexString)
|
||||
assert.NoError(t, err)
|
||||
pushCommit := CommitToPushCommit(&git.Commit{
|
||||
ID: sha1,
|
||||
@@ -169,12 +169,11 @@ func TestListToPushCommits(t *testing.T) {
|
||||
When: now,
|
||||
}
|
||||
|
||||
hashType := git.ObjectFormatFromID(git.Sha1)
|
||||
const hexString1 = "0123456789abcdef0123456789abcdef01234567"
|
||||
hash1, err := hashType.NewIDFromString(hexString1)
|
||||
hash1, err := git.NewIDFromString(hexString1)
|
||||
assert.NoError(t, err)
|
||||
const hexString2 = "fedcba9876543210fedcba9876543210fedcba98"
|
||||
hash2, err := hashType.NewIDFromString(hexString2)
|
||||
hash2, err := git.NewIDFromString(hexString2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
l := []*git.Commit{
|
||||
|
||||
@@ -224,7 +224,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
|
||||
}
|
||||
|
||||
// FIXME: fix the hash
|
||||
if err := git.InitRepository(ctx, tmpDir, false, git.ObjectFormatFromID(git.Sha1)); err != nil {
|
||||
if err := git.InitRepository(ctx, tmpDir, false, git.Sha1ObjectFormat.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
|
||||
}
|
||||
|
||||
// FIXME - fix the hash
|
||||
if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, git.ObjectFormatFromID(git.Sha1)); err != nil {
|
||||
if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, git.Sha1ObjectFormat.Name()); err != nil {
|
||||
return generateRepo, err
|
||||
}
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ func InitRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckInitRepository(ctx context.Context, owner, name string, objectFormat git.ObjectFormat) (err error) {
|
||||
func CheckInitRepository(ctx context.Context, owner, name, objectFormatName string) (err error) {
|
||||
// Somehow the directory could exist.
|
||||
repoPath := repo_model.RepoPath(owner, name)
|
||||
isExist, err := util.IsExist(repoPath)
|
||||
@@ -204,7 +204,7 @@ func CheckInitRepository(ctx context.Context, owner, name string, objectFormat g
|
||||
}
|
||||
|
||||
// Init git bare new repository.
|
||||
if err = git.InitRepository(ctx, repoPath, true, objectFormat); err != nil {
|
||||
if err = git.InitRepository(ctx, repoPath, true, objectFormatName); err != nil {
|
||||
return fmt.Errorf("git.InitRepository: %w", err)
|
||||
} else if err = CreateDelegateHooks(repoPath); err != nil {
|
||||
return fmt.Errorf("createDelegateHooks: %w", err)
|
||||
|
||||
@@ -20,13 +20,13 @@ type PushUpdateOptions struct {
|
||||
|
||||
// IsNewRef return true if it's a first-time push to a branch, tag or etc.
|
||||
func (opts *PushUpdateOptions) IsNewRef() bool {
|
||||
commitID, err := git.IDFromString(opts.OldCommitID)
|
||||
commitID, err := git.NewIDFromString(opts.OldCommitID)
|
||||
return err == nil && commitID.IsZero()
|
||||
}
|
||||
|
||||
// IsDelRef return true if it's a deletion to a branch or tag
|
||||
func (opts *PushUpdateOptions) IsDelRef() bool {
|
||||
commitID, err := git.IDFromString(opts.NewCommitID)
|
||||
commitID, err := git.NewIDFromString(opts.NewCommitID)
|
||||
return err == nil && commitID.IsZero()
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
// Cache represents cache settings
|
||||
type Cache struct {
|
||||
Enabled bool
|
||||
Adapter string
|
||||
Interval int
|
||||
Conn string
|
||||
@@ -24,23 +23,19 @@ var CacheService = struct {
|
||||
Cache `ini:"cache"`
|
||||
|
||||
LastCommit struct {
|
||||
Enabled bool
|
||||
TTL time.Duration `ini:"ITEM_TTL"`
|
||||
CommitsCount int64
|
||||
} `ini:"cache.last_commit"`
|
||||
}{
|
||||
Cache: Cache{
|
||||
Enabled: true,
|
||||
Adapter: "memory",
|
||||
Interval: 60,
|
||||
TTL: 16 * time.Hour,
|
||||
},
|
||||
LastCommit: struct {
|
||||
Enabled bool
|
||||
TTL time.Duration `ini:"ITEM_TTL"`
|
||||
CommitsCount int64
|
||||
}{
|
||||
Enabled: true,
|
||||
TTL: 8760 * time.Hour,
|
||||
CommitsCount: 1000,
|
||||
},
|
||||
@@ -65,30 +60,12 @@ func loadCacheFrom(rootCfg ConfigProvider) {
|
||||
if CacheService.Conn == "" {
|
||||
CacheService.Conn = "50000"
|
||||
}
|
||||
case "": // disable cache
|
||||
CacheService.Enabled = false
|
||||
default:
|
||||
log.Fatal("Unknown cache adapter: %s", CacheService.Adapter)
|
||||
}
|
||||
|
||||
if CacheService.Enabled {
|
||||
log.Info("Cache Service Enabled")
|
||||
} else {
|
||||
log.Warn("Cache Service Disabled so that captcha disabled too")
|
||||
// captcha depends on cache service
|
||||
Service.EnableCaptcha = false
|
||||
}
|
||||
|
||||
sec = rootCfg.Section("cache.last_commit")
|
||||
if !CacheService.Enabled {
|
||||
CacheService.LastCommit.Enabled = false
|
||||
}
|
||||
|
||||
CacheService.LastCommit.CommitsCount = sec.Key("COMMITS_COUNT").MustInt64(1000)
|
||||
|
||||
if CacheService.LastCommit.Enabled {
|
||||
log.Info("Last Commit Cache Service Enabled")
|
||||
}
|
||||
}
|
||||
|
||||
// TTLSeconds returns the TTLSeconds or unix timestamp for memcache
|
||||
|
||||
@@ -35,6 +35,8 @@ var UI = struct {
|
||||
OnlyShowRelevantRepos bool
|
||||
ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"`
|
||||
|
||||
AmbiguousUnicodeDetection bool
|
||||
|
||||
Notification struct {
|
||||
MinTimeout time.Duration
|
||||
TimeoutStep time.Duration
|
||||
@@ -82,6 +84,9 @@ var UI = struct {
|
||||
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
|
||||
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
|
||||
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
|
||||
|
||||
AmbiguousUnicodeDetection: true,
|
||||
|
||||
Notification: struct {
|
||||
MinTimeout time.Duration
|
||||
TimeoutStep time.Duration
|
||||
|
||||
@@ -15,9 +15,8 @@ type CreateUserOption struct {
|
||||
FullName string `json:"full_name" binding:"MaxSize(100)"`
|
||||
// required: true
|
||||
// swagger:strfmt email
|
||||
Email string `json:"email" binding:"Required;Email;MaxSize(254)"`
|
||||
// required: true
|
||||
Password string `json:"password" binding:"Required;MaxSize(255)"`
|
||||
Email string `json:"email" binding:"Required;Email;MaxSize(254)"`
|
||||
Password string `json:"password" binding:"MaxSize(255)"`
|
||||
MustChangePassword *bool `json:"must_change_password"`
|
||||
SendNotify bool `json:"send_notify"`
|
||||
Restricted *bool `json:"restricted"`
|
||||
|
||||
+12
-2
@@ -3,7 +3,7 @@
|
||||
|
||||
package util
|
||||
|
||||
import "github.com/yuin/goldmark/util"
|
||||
import "unsafe"
|
||||
|
||||
func isSnakeCaseUpper(c byte) bool {
|
||||
return 'A' <= c && c <= 'Z'
|
||||
@@ -83,5 +83,15 @@ func ToSnakeCase(input string) string {
|
||||
}
|
||||
}
|
||||
}
|
||||
return util.BytesToReadOnlyString(res)
|
||||
return UnsafeBytesToString(res)
|
||||
}
|
||||
|
||||
// UnsafeBytesToString uses Go's unsafe package to convert a byte slice to a string.
|
||||
// TODO: replace all "goldmark/util.BytesToReadOnlyString" with this official approach
|
||||
func UnsafeBytesToString(b []byte) string {
|
||||
return unsafe.String(unsafe.SliceData(b), len(b))
|
||||
}
|
||||
|
||||
func UnsafeStringToBytes(s string) []byte {
|
||||
return unsafe.Slice(unsafe.StringData(s), len(s))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user