Compare commits

..

No commits in common. "69f2b698c5000a566bc04267f7e9bd387b880109" and "7fb6b5147038649bfaa26147a6173cf99b322a30" have entirely different histories.

71 changed files with 352 additions and 304 deletions

View File

@ -1212,9 +1212,6 @@ LEVEL = Info
;; Max size of files to be displayed (default is 8MiB) ;; Max size of files to be displayed (default is 8MiB)
;MAX_DISPLAY_FILE_SIZE = 8388608 ;MAX_DISPLAY_FILE_SIZE = 8388608
;; ;;
;; Detect ambiguous unicode characters in file contents and show warnings on the UI
;AMBIGUOUS_UNICODE_DETECTION = true
;;
;; Whether the email of the user should be shown in the Explore Users page ;; Whether the email of the user should be shown in the Explore Users page
;SHOW_USER_EMAIL = true ;SHOW_USER_EMAIL = true
;; ;;

View File

@ -220,7 +220,6 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes. - `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes.
regardless of the value of `DEFAULT_THEME`. regardless of the value of `DEFAULT_THEME`.
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB) - `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB)
- `AMBIGUOUS_UNICODE_DETECTION`: **true**: Detect ambiguous unicode characters in file contents and show warnings on the UI
- `REACTIONS`: All available reactions users can choose on issues/prs and comments - `REACTIONS`: All available reactions users can choose on issues/prs and comments
Values can be emoji alias (:smile:) or a unicode emoji. Values can be emoji alias (:smile:) or a unicode emoji.
For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png

View File

@ -20,7 +20,6 @@ import (
func TestAddDeletedBranch(t *testing.T) { func TestAddDeletedBranch(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
assert.EqualValues(t, git.Sha1ObjectFormat.Name(), repo.ObjectFormatName)
firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1}) firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1})
assert.True(t, firstBranch.IsDeleted) assert.True(t, firstBranch.IsDeleted)
@ -30,9 +29,8 @@ func TestAddDeletedBranch(t *testing.T) {
secondBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo.ID, Name: "branch2"}) secondBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo.ID, Name: "branch2"})
assert.True(t, secondBranch.IsDeleted) assert.True(t, secondBranch.IsDeleted)
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName)
commit := &git.Commit{ commit := &git.Commit{
ID: objectFormat.MustIDFromString(secondBranch.CommitID), ID: repo.ObjectFormat.MustIDFromString(secondBranch.CommitID),
CommitMessage: secondBranch.CommitMessage, CommitMessage: secondBranch.CommitMessage,
Committer: &git.Signature{ Committer: &git.Signature{
When: secondBranch.CommitTime.AsLocalTime(), When: secondBranch.CommitTime.AsLocalTime(),

View File

@ -180,7 +180,7 @@ type Repository struct {
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"` IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"` CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
Topics []string `xorm:"TEXT JSON"` Topics []string `xorm:"TEXT JSON"`
ObjectFormatName string `xorm:"-"` ObjectFormat git.ObjectFormat `xorm:"-"`
TrustModel TrustModelType TrustModel TrustModelType
@ -277,9 +277,7 @@ func (repo *Repository) AfterLoad() {
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns
// this is a temporary behaviour to support old repos, next step is to store the object format in the database repo.ObjectFormat = git.ObjectFormatFromID(git.Sha1)
// and read from database so this line could be removed. To not depend on git module, we use a constant variable here
repo.ObjectFormatName = "sha1"
} }
// LoadAttributes loads attributes of the repository. // LoadAttributes loads attributes of the repository.

View File

@ -8,12 +8,11 @@
package charset package charset
import ( import (
"html/template" "bufio"
"io" "io"
"strings" "strings"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
) )
@ -21,18 +20,20 @@ import (
const RuneNBSP = 0xa0 const RuneNBSP = 0xa0
// EscapeControlHTML escapes the unicode control sequences in a provided html document // EscapeControlHTML escapes the unicode control sequences in a provided html document
func EscapeControlHTML(html template.HTML, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output template.HTML) { func EscapeControlHTML(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) {
sb := &strings.Builder{} sb := &strings.Builder{}
escaped, _ = EscapeControlReader(strings.NewReader(string(html)), sb, locale, allowed...) // err has been handled in EscapeControlReader outputStream := &HTMLStreamerWriter{Writer: sb}
return escaped, template.HTML(sb.String()) 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()
} }
// 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 // 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
func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) { 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} outputStream := &HTMLStreamerWriter{Writer: writer}
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer) streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
@ -42,3 +43,41 @@ func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.
} }
return streamer.escaped, err 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()
}

View File

@ -64,7 +64,7 @@ func (e *escapeStreamer) Text(data string) error {
until, next = nextIdxs[0]+pos, nextIdxs[1]+pos until, next = nextIdxs[0]+pos, nextIdxs[1]+pos
} }
// from pos until we know that the runes are not \r\t\n or even ' ' // from pos until until we know that the runes are not \r\t\n or even ' '
runes := make([]rune, 0, next-until) runes := make([]rune, 0, next-until)
positions := make([]int, 0, next-until+1) positions := make([]int, 0, next-until+1)

View File

@ -4,14 +4,11 @@
package charset package charset
import ( import (
"reflect"
"strings" "strings"
"testing" "testing"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
"github.com/stretchr/testify/assert"
) )
type escapeControlTest struct { type escapeControlTest struct {
@ -135,8 +132,22 @@ 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) { func TestEscapeControlReader(t *testing.T) {
// add some control characters to the tests // lets add some control characters to the tests
tests := make([]escapeControlTest, 0, len(escapeControlTests)*3) tests := make([]escapeControlTest, 0, len(escapeControlTests)*3)
copy(tests, escapeControlTests) copy(tests, escapeControlTests)
@ -158,20 +169,29 @@ func TestEscapeControlReader(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
input := strings.NewReader(tt.text)
output := &strings.Builder{} output := &strings.Builder{}
status, err := EscapeControlReader(strings.NewReader(tt.text), output, &translation.MockLocale{}) status, err := EscapeControlReader(input, output, &translation.MockLocale{})
assert.NoError(t, err) result := output.String()
assert.Equal(t, tt.status, *status) if err != nil {
assert.Equal(t, tt.result, output.String()) 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)
}
}) })
} }
} }
func TestSettingAmbiguousUnicodeDetection(t *testing.T) { func TestEscapeControlReader_panic(t *testing.T) {
defer test.MockVariableValue(&setting.UI.AmbiguousUnicodeDetection, true)() bs := make([]byte, 0, 20479)
_, out := EscapeControlHTML("a test", &translation.MockLocale{}) bs = append(bs, 'A')
assert.EqualValues(t, `a<span class="escaped-code-point" data-escaped="[U+00A0]"><span class="char"> </span></span>test`, out) for i := 0; i < 6826; i++ {
setting.UI.AmbiguousUnicodeDetection = false bs = append(bs, []byte("—")...)
_, out = EscapeControlHTML("a test", &translation.MockLocale{}) }
assert.EqualValues(t, `a test`, out) _, _ = EscapeControlString(string(bs), &translation.MockLocale{})
} }

View File

@ -39,7 +39,7 @@ func TestReadingBlameOutput(t *testing.T) {
} }
for _, bypass := range []bool{false, true} { 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.NoError(t, err)
assert.NotNil(t, blameReader) assert.NotNil(t, blameReader)
defer blameReader.Close() defer blameReader.Close()

View File

@ -14,6 +14,7 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"time" "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/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" "code.gitea.io/gitea/modules/log"
@ -388,11 +389,15 @@ func (r *runStdError) IsExitCode(code int) bool {
return false 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). // 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) { func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
stdoutBytes, stderrBytes, err := c.RunStdBytes(opts) stdoutBytes, stderrBytes, err := c.RunStdBytes(opts)
stdout = util.UnsafeBytesToString(stdoutBytes) stdout = bytesToString(stdoutBytes)
stderr = util.UnsafeBytesToString(stderrBytes) stderr = bytesToString(stderrBytes)
if err != nil { if err != nil {
return stdout, stderr, &runStdError{err: err, stderr: stderr} return stdout, stderr, &runStdError{err: err, stderr: stderr}
} }
@ -427,7 +432,7 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS
err := c.Run(newOpts) err := c.Run(newOpts)
stderr = stderrBuf.Bytes() stderr = stderrBuf.Bytes()
if err != nil { if err != nil {
return nil, stderr, &runStdError{err: err, stderr: util.UnsafeBytesToString(stderr)} return nil, stderr, &runStdError{err: err, stderr: bytesToString(stderr)}
} }
// even if there is no err, there could still be some stderr output // even if there is no err, there could still be some stderr output
return stdoutBuf.Bytes(), stderr, nil return stdoutBuf.Bytes(), stderr, nil

View File

@ -236,7 +236,7 @@ func (c *Commit) IsForcePush(oldCommitID string) (bool, error) {
if err != nil { if err != nil {
return false, err return false, err
} }
if oldCommitID == objectFormat.EmptyObjectID().String() { if oldCommitID == objectFormat.Empty().String() {
return false, nil return false, nil
} }

View File

@ -5,17 +5,26 @@ package git
import ( import (
"crypto/sha1" "crypto/sha1"
"fmt"
"regexp" "regexp"
"strings"
)
type ObjectFormatID int
const (
Sha1 ObjectFormatID = iota
) )
// sha1Pattern can be used to determine if a string is an valid sha // sha1Pattern can be used to determine if a string is an valid sha
var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`) var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
type ObjectFormat interface { type ObjectFormat interface {
// Name returns the name of the object format ID() ObjectFormatID
Name() string String() string
// EmptyObjectID creates a new empty ObjectID from an object format hash name
EmptyObjectID() ObjectID // Empty is the hash of empty git
Empty() ObjectID
// EmptyTree is the hash of an empty tree // EmptyTree is the hash of an empty tree
EmptyTree() ObjectID EmptyTree() ObjectID
// FullLength is the length of the hash's hex string // FullLength is the length of the hash's hex string
@ -26,71 +35,67 @@ type ObjectFormat interface {
MustIDFromString(s string) ObjectID MustIDFromString(s string) ObjectID
NewID(b []byte) (ObjectID, error) NewID(b []byte) (ObjectID, error)
NewIDFromString(s string) (ObjectID, error) NewIDFromString(s string) (ObjectID, error)
NewEmptyID() ObjectID
NewHasher() HasherInterface NewHasher() HasherInterface
} }
type Sha1ObjectFormatImpl struct{} type Sha1ObjectFormat struct{}
var ( func (*Sha1ObjectFormat) ID() ObjectFormatID { return Sha1 }
emptyObjectID = &Sha1Hash{} func (*Sha1ObjectFormat) String() string { return "sha1" }
emptyTree = &Sha1Hash{ func (*Sha1ObjectFormat) Empty() ObjectID { return &Sha1Hash{} }
func (*Sha1ObjectFormat) EmptyTree() ObjectID {
return &Sha1Hash{
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04, 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 (Sha1ObjectFormatImpl) EmptyTree() ObjectID { func (*Sha1ObjectFormat) IsValid(input string) bool {
return emptyTree
}
func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
func (Sha1ObjectFormatImpl) IsValid(input string) bool {
return sha1Pattern.MatchString(input) return sha1Pattern.MatchString(input)
} }
func (Sha1ObjectFormatImpl) MustID(b []byte) ObjectID { func (*Sha1ObjectFormat) MustID(b []byte) ObjectID {
var id Sha1Hash var id Sha1Hash
copy(id[0:20], b) copy(id[0:20], b)
return &id return &id
} }
func (h Sha1ObjectFormatImpl) MustIDFromString(s string) ObjectID { func (h *Sha1ObjectFormat) MustIDFromString(s string) ObjectID {
return MustIDFromString(h, s) return MustIDFromString(h, s)
} }
func (h Sha1ObjectFormatImpl) NewID(b []byte) (ObjectID, error) { func (h *Sha1ObjectFormat) NewID(b []byte) (ObjectID, error) {
return IDFromRaw(h, b) return IDFromRaw(h, b)
} }
func (h Sha1ObjectFormatImpl) NewIDFromString(s string) (ObjectID, error) { func (h *Sha1ObjectFormat) NewIDFromString(s string) (ObjectID, error) {
return genericIDFromString(h, s) return genericIDFromString(h, s)
} }
func (h Sha1ObjectFormatImpl) NewHasher() HasherInterface { func (*Sha1ObjectFormat) NewEmptyID() ObjectID {
return NewSha1()
}
func (h *Sha1ObjectFormat) NewHasher() HasherInterface {
return &Sha1Hasher{sha1.New()} return &Sha1Hasher{sha1.New()}
} }
var Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{} func ObjectFormatFromID(id ObjectFormatID) ObjectFormat {
switch id {
var SupportedObjectFormats = []ObjectFormat{ case Sha1:
Sha1ObjectFormat, return &Sha1ObjectFormat{}
// TODO: add sha256
}
func ObjectFormatFromName(name string) ObjectFormat {
for _, objectFormat := range SupportedObjectFormats {
if name == objectFormat.Name() {
return objectFormat
}
} }
return nil return nil
} }
func IsValidObjectFormat(name string) bool { func ObjectFormatFromString(hash string) (ObjectFormat, error) {
return ObjectFormatFromName(name) != nil switch strings.ToLower(hash) {
case "sha1":
return &Sha1ObjectFormat{}, nil
}
return nil, fmt.Errorf("unknown hash type: %s", hash)
} }

View File

@ -31,15 +31,18 @@ func (h *Sha1Hash) IsZero() bool {
return bytes.Equal(empty[:], h[:]) return bytes.Equal(empty[:], h[:])
} }
func (h *Sha1Hash) RawValue() []byte { return h[:] } func (h *Sha1Hash) RawValue() []byte { return h[:] }
func (*Sha1Hash) Type() ObjectFormat { return Sha1ObjectFormat } func (*Sha1Hash) Type() ObjectFormat { return &Sha1ObjectFormat{} }
var _ ObjectID = &Sha1Hash{} func NewSha1() *Sha1Hash {
return &Sha1Hash{}
}
// EmptyObjectID creates a new ObjectID from an object format hash name // NewHash is for generic implementations
func EmptyObjectID(objectFormatName string) (ObjectID, error) { func NewHash(hash string) (ObjectID, error) {
objectFormat := ObjectFormatFromName(objectFormatName) hash = strings.ToLower(hash)
if objectFormat != nil { switch hash {
return objectFormat.EmptyObjectID(), nil case "sha1":
return &Sha1Hash{}, nil
} }
return nil, errors.New("unsupported hash type") return nil, errors.New("unsupported hash type")
@ -47,7 +50,7 @@ func EmptyObjectID(objectFormatName string) (ObjectID, error) {
func IDFromRaw(h ObjectFormat, b []byte) (ObjectID, error) { func IDFromRaw(h ObjectFormat, b []byte) (ObjectID, error) {
if len(b) != h.FullLength()/2 { if len(b) != h.FullLength()/2 {
return h.EmptyObjectID(), fmt.Errorf("length must be %d: %v", h.FullLength(), b) return h.Empty(), fmt.Errorf("length must be %d: %v", h.FullLength(), b)
} }
return h.MustID(b), nil return h.MustID(b), nil
} }
@ -60,20 +63,24 @@ func MustIDFromString(h ObjectFormat, s string) ObjectID {
func genericIDFromString(h ObjectFormat, s string) (ObjectID, error) { func genericIDFromString(h ObjectFormat, s string) (ObjectID, error) {
s = strings.TrimSpace(s) s = strings.TrimSpace(s)
if len(s) != h.FullLength() { if len(s) != h.FullLength() {
return h.EmptyObjectID(), fmt.Errorf("length must be %d: %s", h.FullLength(), s) return h.Empty(), fmt.Errorf("length must be %d: %s", h.FullLength(), s)
} }
b, err := hex.DecodeString(s) b, err := hex.DecodeString(s)
if err != nil { if err != nil {
return h.EmptyObjectID(), err return h.Empty(), err
} }
return h.NewID(b) return h.NewID(b)
} }
func IDFromString(hexHash string) (ObjectID, error) { func IDFromString(hexHash string) (ObjectID, error) {
for _, objectFormat := range SupportedObjectFormats { switch len(hexHash) {
if len(hexHash) == objectFormat.FullLength() { case 40:
return objectFormat.NewIDFromString(hexHash) hashType := Sha1ObjectFormat{}
h, err := hashType.NewIDFromString(hexHash)
if err != nil {
return nil, err
} }
return h, nil
} }
return nil, fmt.Errorf("invalid hash hex string: '%s' len: %d", hexHash, len(hexHash)) return nil, fmt.Errorf("invalid hash hex string: '%s' len: %d", hexHash, len(hexHash))

View File

@ -12,7 +12,7 @@ import (
func ParseGogitHash(h plumbing.Hash) ObjectID { func ParseGogitHash(h plumbing.Hash) ObjectID {
switch hash.Size { switch hash.Size {
case 20: case 20:
return Sha1ObjectFormat.MustID(h[:]) return ObjectFormatFromID(Sha1).MustID(h[:])
} }
return nil return nil

View File

@ -10,7 +10,7 @@ import (
) )
func TestIsValidSHAPattern(t *testing.T) { func TestIsValidSHAPattern(t *testing.T) {
h := Sha1ObjectFormat h := NewSha1().Type()
assert.True(t, h.IsValid("fee1")) assert.True(t, h.IsValid("fee1"))
assert.True(t, h.IsValid("abc000")) assert.True(t, h.IsValid("abc000"))
assert.True(t, h.IsValid("9023902390239023902390239023902390239023")) assert.True(t, h.IsValid("9023902390239023902390239023902390239023"))

View File

@ -28,9 +28,9 @@ func TestParseTreeEntries(t *testing.T) {
Input: "100644 blob 61ab7345a1a3bbc590068ccae37b8515cfc5843c 1022\texample/file2.txt\n", Input: "100644 blob 61ab7345a1a3bbc590068ccae37b8515cfc5843c 1022\texample/file2.txt\n",
Expected: []*TreeEntry{ Expected: []*TreeEntry{
{ {
ID: Sha1ObjectFormat.MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
gogitTreeEntry: &object.TreeEntry{ gogitTreeEntry: &object.TreeEntry{
Hash: plumbing.Hash(Sha1ObjectFormat.MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
Name: "example/file2.txt", Name: "example/file2.txt",
Mode: filemode.Regular, Mode: filemode.Regular,
}, },
@ -44,9 +44,9 @@ func TestParseTreeEntries(t *testing.T) {
"040000 tree 1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8 -\texample\n", "040000 tree 1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8 -\texample\n",
Expected: []*TreeEntry{ Expected: []*TreeEntry{
{ {
ID: Sha1ObjectFormat.MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
gogitTreeEntry: &object.TreeEntry{ gogitTreeEntry: &object.TreeEntry{
Hash: plumbing.Hash(Sha1ObjectFormat.MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
Name: "example/\n.txt", Name: "example/\n.txt",
Mode: filemode.Symlink, Mode: filemode.Symlink,
}, },
@ -54,10 +54,10 @@ func TestParseTreeEntries(t *testing.T) {
sized: true, sized: true,
}, },
{ {
ID: Sha1ObjectFormat.MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"), ID: ObjectFormatFromID(Sha1).MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"),
sized: true, sized: true,
gogitTreeEntry: &object.TreeEntry{ gogitTreeEntry: &object.TreeEntry{
Hash: plumbing.Hash(Sha1ObjectFormat.MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8").RawValue()), Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8").RawValue()),
Name: "example", Name: "example",
Mode: filemode.Dir, Mode: filemode.Dir,
}, },
@ -67,7 +67,7 @@ func TestParseTreeEntries(t *testing.T) {
} }
for _, testCase := range testCases { for _, testCase := range testCases {
entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte(testCase.Input)) entries, err := ParseTreeEntries(ObjectFormatFromID(Sha1), []byte(testCase.Input))
assert.NoError(t, err) assert.NoError(t, err)
if len(entries) > 1 { if len(entries) > 1 {
fmt.Println(testCase.Expected[0].ID) fmt.Println(testCase.Expected[0].ID)

View File

@ -12,7 +12,7 @@ import (
) )
func TestParseTreeEntriesLong(t *testing.T) { func TestParseTreeEntriesLong(t *testing.T) {
objectFormat := Sha1ObjectFormat objectFormat := ObjectFormatFromID(Sha1)
testCases := []struct { testCases := []struct {
Input string Input string
@ -66,7 +66,7 @@ func TestParseTreeEntriesLong(t *testing.T) {
} }
func TestParseTreeEntriesShort(t *testing.T) { func TestParseTreeEntriesShort(t *testing.T) {
objectFormat := Sha1ObjectFormat objectFormat := ObjectFormatFromID(Sha1)
testCases := []struct { testCases := []struct {
Input string Input string
@ -102,7 +102,7 @@ func TestParseTreeEntriesShort(t *testing.T) {
func TestParseTreeEntriesInvalid(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 // there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315
entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af")) entries, err := ParseTreeEntries(ObjectFormatFromID(Sha1), []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af"))
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, entries, 0) assert.Len(t, entries, 0)
} }

View File

@ -205,7 +205,7 @@ func RefURL(repoURL, ref string) string {
return repoURL + "/src/branch/" + refName return repoURL + "/src/branch/" + refName
case refFullName.IsTag(): case refFullName.IsTag():
return repoURL + "/src/tag/" + refName return repoURL + "/src/tag/" + refName
case !Sha1ObjectFormat.IsValid(ref): case !ObjectFormatFromID(Sha1).IsValid(ref):
// assume they mean a branch // assume they mean a branch
return repoURL + "/src/branch/" + refName return repoURL + "/src/branch/" + refName
default: default:

View File

@ -90,7 +90,7 @@ func GetObjectFormatOfRepo(ctx context.Context, repoPath string) (ObjectFormat,
} }
// InitRepository initializes a new Git repository. // InitRepository initializes a new Git repository.
func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormatName string) error { func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormat ObjectFormat) error {
err := os.MkdirAll(repoPath, os.ModePerm) err := os.MkdirAll(repoPath, os.ModePerm)
if err != nil { if err != nil {
return err return err
@ -98,13 +98,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
cmd := NewCommand(ctx, "init") cmd := NewCommand(ctx, "init")
if SupportHashSha256 { if SupportHashSha256 {
if objectFormatName == "" { cmd.AddOptionValues("--object-format", objectFormat.String())
objectFormatName = Sha1ObjectFormat.Name()
}
if !IsValidObjectFormat(objectFormatName) {
return fmt.Errorf("invalid object format: %s", objectFormatName)
}
cmd.AddOptionValues("--object-format", objectFormatName)
} }
if bare { if bare {
cmd.AddArguments("--bare") cmd.AddArguments("--bare")

View File

@ -54,9 +54,9 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
if err != nil { if err != nil {
if strings.Contains(err.Error(), "unknown revision or path") || if strings.Contains(err.Error(), "unknown revision or path") ||
strings.Contains(err.Error(), "fatal: Needed a single revision") { strings.Contains(err.Error(), "fatal: Needed a single revision") {
return objectFormat.EmptyObjectID(), ErrNotExist{commitID, ""} return objectFormat.Empty(), ErrNotExist{commitID, ""}
} }
return objectFormat.EmptyObjectID(), err return objectFormat.Empty(), err
} }
return objectFormat.NewIDFromString(actualCommitID) return objectFormat.NewIDFromString(actualCommitID)

View 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 // 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) { func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, error) {
cmd := NewCommand(repo.Ctx, "diff-tree", "--name-only", "--root", "--no-commit-id", "-r", "-z") cmd := NewCommand(repo.Ctx, "diff-tree", "--name-only", "--root", "--no-commit-id", "-r", "-z")
if base == repo.objectFormat.EmptyObjectID().String() { if base == repo.objectFormat.Empty().String() {
cmd.AddDynamicArguments(head) cmd.AddDynamicArguments(head)
} else { } else {
cmd.AddDynamicArguments(base, head) cmd.AddDynamicArguments(base, head)

View File

@ -131,12 +131,12 @@ func TestGetCommitFilesChanged(t *testing.T) {
files []string files []string
}{ }{
{ {
repo.objectFormat.EmptyObjectID().String(), repo.objectFormat.Empty().String(),
"95bb4d39648ee7e325106df01a621c530863a653", "95bb4d39648ee7e325106df01a621c530863a653",
[]string{"file1.txt"}, []string{"file1.txt"},
}, },
{ {
repo.objectFormat.EmptyObjectID().String(), repo.objectFormat.Empty().String(),
"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
[]string{"file2.txt"}, []string{"file2.txt"},
}, },

View File

@ -101,7 +101,7 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
for _, file := range filenames { for _, file := range filenames {
if file != "" { if file != "" {
buffer.WriteString("0 ") buffer.WriteString("0 ")
buffer.WriteString(repo.objectFormat.EmptyObjectID().String()) buffer.WriteString(repo.objectFormat.Empty().String())
buffer.WriteByte('\t') buffer.WriteByte('\t')
buffer.WriteString(file) buffer.WriteString(file)
buffer.WriteByte('\000') buffer.WriteByte('\000')

View File

@ -194,7 +194,7 @@ func TestRepository_GetAnnotatedTag(t *testing.T) {
} }
func TestRepository_parseTagRef(t *testing.T) { func TestRepository_parseTagRef(t *testing.T) {
sha1 := Sha1ObjectFormat sha1 := ObjectFormatFromID(Sha1)
tests := []struct { tests := []struct {
name string name string

View File

@ -35,8 +35,8 @@ func (tag *Tag) Commit(gitRepo *Repository) (*Commit, error) {
// \n\n separate headers from message // \n\n separate headers from message
func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) { func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) {
tag := new(Tag) tag := new(Tag)
tag.ID = objectFormat.EmptyObjectID() tag.ID = objectFormat.NewEmptyID()
tag.Object = objectFormat.EmptyObjectID() tag.Object = objectFormat.NewEmptyID()
tag.Tagger = &Signature{} tag.Tagger = &Signature{}
// we now have the contents of the commit object. Let's investigate... // we now have the contents of the commit object. Let's investigate...
nextline := 0 nextline := 0

View File

@ -22,7 +22,7 @@ tagger Lucas Michot <lucas@semalead.com> 1484491741 +0100
`), tag: Tag{ `), tag: Tag{
Name: "", Name: "",
ID: Sha1ObjectFormat.EmptyObjectID(), ID: NewSha1(),
Object: &Sha1Hash{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a}, Object: &Sha1Hash{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a},
Type: "commit", Type: "commit",
Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0)}, Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0)},
@ -39,7 +39,7 @@ o
ono`), tag: Tag{ ono`), tag: Tag{
Name: "", Name: "",
ID: Sha1ObjectFormat.EmptyObjectID(), ID: NewSha1(),
Object: &Sha1Hash{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc}, Object: &Sha1Hash{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc},
Type: "commit", Type: "commit",
Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0)}, 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 { for _, test := range testData {
tag, err := parseTagData(Sha1ObjectFormat, test.data) tag, err := parseTagData(ObjectFormatFromID(Sha1), test.data)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, test.tag.ID, tag.ID) assert.EqualValues(t, test.tag.ID, tag.ID)
assert.EqualValues(t, test.tag.Object, tag.Object) assert.EqualValues(t, test.tag.Object, tag.Object)

View File

@ -9,7 +9,6 @@ import (
"bytes" "bytes"
"fmt" "fmt"
gohtml "html" gohtml "html"
"html/template"
"io" "io"
"path/filepath" "path/filepath"
"strings" "strings"
@ -56,7 +55,7 @@ func NewContext() {
} }
// Code returns a HTML version of code string with chroma syntax highlighting classes and the matched lexer name // Code returns a HTML version of code string with chroma syntax highlighting classes and the matched lexer name
func Code(fileName, language, code string) (output template.HTML, lexerName string) { func Code(fileName, language, code string) (string, string) {
NewContext() NewContext()
// diff view newline will be passed as empty, change to literal '\n' so it can be copied // diff view newline will be passed as empty, change to literal '\n' so it can be copied
@ -66,7 +65,7 @@ func Code(fileName, language, code string) (output template.HTML, lexerName stri
} }
if len(code) > sizeLimit { if len(code) > sizeLimit {
return template.HTML(template.HTMLEscapeString(code)), "" return code, ""
} }
var lexer chroma.Lexer var lexer chroma.Lexer
@ -103,11 +102,13 @@ func Code(fileName, language, code string) (output template.HTML, lexerName stri
cache.Add(fileName, lexer) cache.Add(fileName, lexer)
} }
return CodeFromLexer(lexer, code), formatLexerName(lexer.Config().Name) lexerName := formatLexerName(lexer.Config().Name)
return CodeFromLexer(lexer, code), lexerName
} }
// CodeFromLexer returns a HTML version of code string with chroma syntax highlighting classes // CodeFromLexer returns a HTML version of code string with chroma syntax highlighting classes
func CodeFromLexer(lexer chroma.Lexer, code string) template.HTML { func CodeFromLexer(lexer chroma.Lexer, code string) string {
formatter := html.New(html.WithClasses(true), formatter := html.New(html.WithClasses(true),
html.WithLineNumbers(false), html.WithLineNumbers(false),
html.PreventSurroundingPre(true), html.PreventSurroundingPre(true),
@ -119,23 +120,23 @@ func CodeFromLexer(lexer chroma.Lexer, code string) template.HTML {
iterator, err := lexer.Tokenise(nil, code) iterator, err := lexer.Tokenise(nil, code)
if err != nil { if err != nil {
log.Error("Can't tokenize code: %v", err) log.Error("Can't tokenize code: %v", err)
return template.HTML(template.HTMLEscapeString(code)) return code
} }
// style not used for live site but need to pass something // style not used for live site but need to pass something
err = formatter.Format(htmlw, githubStyles, iterator) err = formatter.Format(htmlw, githubStyles, iterator)
if err != nil { if err != nil {
log.Error("Can't format code: %v", err) log.Error("Can't format code: %v", err)
return template.HTML(template.HTMLEscapeString(code)) return code
} }
_ = htmlw.Flush() _ = htmlw.Flush()
// Chroma will add newlines for certain lexers in order to highlight them properly // 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 // Once highlighted, strip them here, so they don't cause copy/paste trouble in HTML output
return template.HTML(strings.TrimSuffix(htmlbuf.String(), "\n")) return strings.TrimSuffix(htmlbuf.String(), "\n")
} }
// File returns a slice of chroma syntax highlighted HTML lines of code and the matched lexer name // File returns a slice of chroma syntax highlighted HTML lines of code and the matched lexer name
func File(fileName, language string, code []byte) ([]template.HTML, string, error) { func File(fileName, language string, code []byte) ([]string, string, error) {
NewContext() NewContext()
if len(code) > sizeLimit { if len(code) > sizeLimit {
@ -182,14 +183,14 @@ func File(fileName, language string, code []byte) ([]template.HTML, string, erro
tokensLines := chroma.SplitTokensIntoLines(iterator.Tokens()) tokensLines := chroma.SplitTokensIntoLines(iterator.Tokens())
htmlBuf := &bytes.Buffer{} htmlBuf := &bytes.Buffer{}
lines := make([]template.HTML, 0, len(tokensLines)) lines := make([]string, 0, len(tokensLines))
for _, tokens := range tokensLines { for _, tokens := range tokensLines {
iterator = chroma.Literator(tokens...) iterator = chroma.Literator(tokens...)
err = formatter.Format(htmlBuf, githubStyles, iterator) err = formatter.Format(htmlBuf, githubStyles, iterator)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("can't format code: %w", err) return nil, "", fmt.Errorf("can't format code: %w", err)
} }
lines = append(lines, template.HTML(htmlBuf.String())) lines = append(lines, htmlBuf.String())
htmlBuf.Reset() htmlBuf.Reset()
} }
@ -197,9 +198,9 @@ func File(fileName, language string, code []byte) ([]template.HTML, string, erro
} }
// PlainText returns non-highlighted HTML for code // PlainText returns non-highlighted HTML for code
func PlainText(code []byte) []template.HTML { func PlainText(code []byte) []string {
r := bufio.NewReader(bytes.NewReader(code)) r := bufio.NewReader(bytes.NewReader(code))
m := make([]template.HTML, 0, bytes.Count(code, []byte{'\n'})+1) m := make([]string, 0, bytes.Count(code, []byte{'\n'})+1)
for { for {
content, err := r.ReadString('\n') content, err := r.ReadString('\n')
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
@ -209,7 +210,7 @@ func PlainText(code []byte) []template.HTML {
if content == "" && err == io.EOF { if content == "" && err == io.EOF {
break break
} }
s := template.HTML(gohtml.EscapeString(content)) s := gohtml.EscapeString(content)
m = append(m, s) m = append(m, s)
} }
return m return m

View File

@ -4,36 +4,21 @@
package highlight package highlight
import ( import (
"html/template"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func lines(s string) (out []template.HTML) { func lines(s string) []string {
// "" => [], "a" => ["a"], "a\n" => ["a\n"], "a\nb" => ["a\n", "b"] (each line always includes EOL "\n" if it exists) return strings.Split(strings.ReplaceAll(strings.TrimSpace(s), `\n`, "\n"), "\n")
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) { func TestFile(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
code string code string
want []template.HTML want []string
lexerName string lexerName string
}{ }{
{ {
@ -114,7 +99,10 @@ c=2
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
out, lexerName, err := File(tt.name, "", []byte(tt.code)) out, lexerName, err := File(tt.name, "", []byte(tt.code))
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, tt.want, out) 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.Equal(t, tt.lexerName, lexerName) assert.Equal(t, tt.lexerName, lexerName)
}) })
} }
@ -124,7 +112,7 @@ func TestPlainText(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
code string code string
want []template.HTML want []string
}{ }{
{ {
name: "empty.py", name: "empty.py",
@ -177,7 +165,9 @@ c=2`),
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
out := PlainText([]byte(tt.code)) out := PlainText([]byte(tt.code))
assert.EqualValues(t, tt.want, out) expected := strings.Join(tt.want, "\n")
actual := strings.Join(out, "\n")
assert.EqualValues(t, expected, actual)
}) })
} }
} }

View File

@ -6,7 +6,6 @@ package code
import ( import (
"bytes" "bytes"
"context" "context"
"html/template"
"strings" "strings"
"code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/highlight"
@ -23,7 +22,7 @@ type Result struct {
Language string Language string
Color string Color string
LineNumbers []int LineNumbers []int
FormattedLines template.HTML FormattedLines string
} }
type SearchResultLanguages = internal.SearchResultLanguages type SearchResultLanguages = internal.SearchResultLanguages

View File

@ -87,7 +87,7 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
} }
lexer = chroma.Coalesce(lexer) lexer = chroma.Coalesce(lexer)
if _, err := w.WriteString(string(highlight.CodeFromLexer(lexer, source))); err != nil { if _, err := w.WriteString(highlight.CodeFromLexer(lexer, source)); err != nil {
return "" return ""
} }
} }

View File

@ -169,7 +169,7 @@ func TestListToPushCommits(t *testing.T) {
When: now, When: now,
} }
hashType := git.Sha1ObjectFormat hashType := git.ObjectFormatFromID(git.Sha1)
const hexString1 = "0123456789abcdef0123456789abcdef01234567" const hexString1 = "0123456789abcdef0123456789abcdef01234567"
hash1, err := hashType.NewIDFromString(hexString1) hash1, err := hashType.NewIDFromString(hexString1)
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -224,7 +224,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
} }
// FIXME: fix the hash // FIXME: fix the hash
if err := git.InitRepository(ctx, tmpDir, false, git.Sha1ObjectFormat.Name()); err != nil { if err := git.InitRepository(ctx, tmpDir, false, git.ObjectFormatFromID(git.Sha1)); err != nil {
return err return err
} }
@ -358,7 +358,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
} }
// FIXME - fix the hash // FIXME - fix the hash
if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, git.Sha1ObjectFormat.Name()); err != nil { if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, git.ObjectFormatFromID(git.Sha1)); err != nil {
return generateRepo, err return generateRepo, err
} }

View File

@ -188,7 +188,7 @@ func InitRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
return nil return nil
} }
func CheckInitRepository(ctx context.Context, owner, name, objectFormatName string) (err error) { func CheckInitRepository(ctx context.Context, owner, name string, objectFormat git.ObjectFormat) (err error) {
// Somehow the directory could exist. // Somehow the directory could exist.
repoPath := repo_model.RepoPath(owner, name) repoPath := repo_model.RepoPath(owner, name)
isExist, err := util.IsExist(repoPath) isExist, err := util.IsExist(repoPath)
@ -204,7 +204,7 @@ func CheckInitRepository(ctx context.Context, owner, name, objectFormatName stri
} }
// Init git bare new repository. // Init git bare new repository.
if err = git.InitRepository(ctx, repoPath, true, objectFormatName); err != nil { if err = git.InitRepository(ctx, repoPath, true, objectFormat); err != nil {
return fmt.Errorf("git.InitRepository: %w", err) return fmt.Errorf("git.InitRepository: %w", err)
} else if err = CreateDelegateHooks(repoPath); err != nil { } else if err = CreateDelegateHooks(repoPath); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err) return fmt.Errorf("createDelegateHooks: %w", err)

View File

@ -35,8 +35,6 @@ var UI = struct {
OnlyShowRelevantRepos bool OnlyShowRelevantRepos bool
ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"` ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"`
AmbiguousUnicodeDetection bool
Notification struct { Notification struct {
MinTimeout time.Duration MinTimeout time.Duration
TimeoutStep time.Duration TimeoutStep time.Duration
@ -84,9 +82,6 @@ var UI = struct {
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`}, CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"}, CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
AmbiguousUnicodeDetection: true,
Notification: struct { Notification: struct {
MinTimeout time.Duration MinTimeout time.Duration
TimeoutStep time.Duration TimeoutStep time.Duration

View File

@ -3,7 +3,7 @@
package util package util
import "unsafe" import "github.com/yuin/goldmark/util"
func isSnakeCaseUpper(c byte) bool { func isSnakeCaseUpper(c byte) bool {
return 'A' <= c && c <= 'Z' return 'A' <= c && c <= 'Z'
@ -83,15 +83,5 @@ func ToSnakeCase(input string) string {
} }
} }
} }
return UnsafeBytesToString(res) return util.BytesToReadOnlyString(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))
} }

View File

@ -888,7 +888,7 @@ webauthn_nickname=ニックネーム
webauthn_delete_key=セキュリティキーの登録解除 webauthn_delete_key=セキュリティキーの登録解除
webauthn_delete_key_desc=セキュリティキーの登録を解除すると、今後そのセキュリティキーでサインインすることはできなくなります。 続行しますか? webauthn_delete_key_desc=セキュリティキーの登録を解除すると、今後そのセキュリティキーでサインインすることはできなくなります。 続行しますか?
webauthn_key_loss_warning=セキュリティキーを紛失すると、アカウントへのアクセスを失います。 webauthn_key_loss_warning=セキュリティキーを紛失すると、アカウントへのアクセスを失います。
webauthn_alternative_tip=もうひとつ別の認証方法も設定しておくと良いでしょう webauthn_alternative_tip=もうひとつ別の認証方法も設定すると良いかもしれません
manage_account_links=連携アカウントの管理 manage_account_links=連携アカウントの管理
manage_account_links_desc=これらの外部アカウントがGiteaアカウントと連携されています。 manage_account_links_desc=これらの外部アカウントがGiteaアカウントと連携されています。
@ -3457,7 +3457,7 @@ owner.settings.chef.keypair.description=Chefレジストリの認証にはキー
[secrets] [secrets]
secrets=シークレット secrets=シークレット
description=シークレットは特定のActionsに渡されます。 それ以外で読み出されることはありません。 description=シークレットは特定のActionsに渡されます。 それ以外で読み出されることはありません。
none=シークレットはまだありません。 none=まだシークレットはありません。
creation=シークレットを追加 creation=シークレットを追加
creation.name_placeholder=大文字小文字の区別なし、英数字とアンダースコアのみ、GITEA_ や GITHUB_ で始まるものは不可 creation.name_placeholder=大文字小文字の区別なし、英数字とアンダースコアのみ、GITEA_ や GITHUB_ で始まるものは不可
creation.value_placeholder=内容を入力してください。前後の空白は除去されます。 creation.value_placeholder=内容を入力してください。前後の空白は除去されます。

View File

@ -242,18 +242,18 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
} }
repo, err := repo_service.CreateRepository(ctx, ctx.Doer, owner, repo_service.CreateRepoOptions{ repo, err := repo_service.CreateRepository(ctx, ctx.Doer, owner, repo_service.CreateRepoOptions{
Name: opt.Name, Name: opt.Name,
Description: opt.Description, Description: opt.Description,
IssueLabels: opt.IssueLabels, IssueLabels: opt.IssueLabels,
Gitignores: opt.Gitignores, Gitignores: opt.Gitignores,
License: opt.License, License: opt.License,
Readme: opt.Readme, Readme: opt.Readme,
IsPrivate: opt.Private, IsPrivate: opt.Private,
AutoInit: opt.AutoInit, AutoInit: opt.AutoInit,
DefaultBranch: opt.DefaultBranch, DefaultBranch: opt.DefaultBranch,
TrustModel: repo_model.ToTrustModel(opt.TrustModel), TrustModel: repo_model.ToTrustModel(opt.TrustModel),
IsTemplate: opt.Template, IsTemplate: opt.Template,
ObjectFormatName: git.Sha1ObjectFormat.Name(), ObjectFormat: git.ObjectFormatFromID(git.Sha1),
}) })
if err != nil { if err != nil {
if repo_model.IsErrRepoAlreadyExist(err) { if repo_model.IsErrRepoAlreadyExist(err) {

View File

@ -81,7 +81,7 @@ func ConvertToObjectID(ctx gocontext.Context, repo *context.Repository, commitID
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.Repository.RepoPath()) gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.Repository.RepoPath())
if err != nil { if err != nil {
return objectFormat.EmptyObjectID(), fmt.Errorf("RepositoryFromContextOrOpen: %w", err) return objectFormat.Empty(), fmt.Errorf("RepositoryFromContextOrOpen: %w", err)
} }
defer closer.Close() defer closer.Close()

View File

@ -147,7 +147,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
gitRepo := ctx.Repo.GitRepo gitRepo := ctx.Repo.GitRepo
objectFormat, _ := gitRepo.GetObjectFormat() objectFormat, _ := gitRepo.GetObjectFormat()
if branchName == repo.DefaultBranch && newCommitID == objectFormat.EmptyObjectID().String() { if branchName == repo.DefaultBranch && newCommitID == objectFormat.Empty().String() {
log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo) log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{ ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName), UserMsg: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName),
@ -175,7 +175,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
// First of all we need to enforce absolutely: // First of all we need to enforce absolutely:
// //
// 1. Detect and prevent deletion of the branch // 1. Detect and prevent deletion of the branch
if newCommitID == objectFormat.EmptyObjectID().String() { if newCommitID == objectFormat.Empty().String() {
log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo) log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{ ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is protected from deletion", branchName), UserMsg: fmt.Sprintf("branch %s is protected from deletion", branchName),
@ -184,7 +184,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
} }
// 2. Disallow force pushes to protected branches // 2. Disallow force pushes to protected branches
if oldCommitID != objectFormat.EmptyObjectID().String() { if oldCommitID != objectFormat.Empty().String() {
output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1").AddDynamicArguments(oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env}) output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1").AddDynamicArguments(oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env})
if err != nil { if err != nil {
log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err) log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err)

View File

@ -30,7 +30,7 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
var command *git.Command var command *git.Command
objectFormat, _ := repo.GetObjectFormat() objectFormat, _ := repo.GetObjectFormat()
if oldCommitID == objectFormat.EmptyObjectID().String() { if oldCommitID == objectFormat.Empty().String() {
// When creating a new branch, the oldCommitID is empty, by using "newCommitID --not --all": // When creating a new branch, the oldCommitID is empty, by using "newCommitID --not --all":
// List commits that are reachable by following the newCommitID, exclude "all" existing heads/tags commits // List commits that are reachable by following the newCommitID, exclude "all" existing heads/tags commits
// So, it only lists the new commits received, doesn't list the commits already present in the receiving repository // So, it only lists the new commits received, doesn't list the commits already present in the receiving repository

View File

@ -30,9 +30,9 @@ func TestVerifyCommits(t *testing.T) {
verified bool verified bool
}{ }{
{"72920278f2f999e3005801e5d5b8ab8139d3641c", "d766f2917716d45be24bfa968b8409544941be32", true}, {"72920278f2f999e3005801e5d5b8ab8139d3641c", "d766f2917716d45be24bfa968b8409544941be32", true},
{objectFormat.EmptyObjectID().String(), "93eac826f6188f34646cea81bf426aa5ba7d3bfe", true}, // New branch with verified commit {objectFormat.Empty().String(), "93eac826f6188f34646cea81bf426aa5ba7d3bfe", true}, // New branch with verified commit
{"9779d17a04f1e2640583d35703c62460b2d86e0a", "72920278f2f999e3005801e5d5b8ab8139d3641c", false}, {"9779d17a04f1e2640583d35703c62460b2d86e0a", "72920278f2f999e3005801e5d5b8ab8139d3641c", false},
{objectFormat.EmptyObjectID().String(), "9ce3f779ae33f31fce17fac3c512047b75d7498b", false}, // New branch with unverified commit {objectFormat.Empty().String(), "9ce3f779ae33f31fce17fac3c512047b75d7498b", false}, // New branch with unverified commit
} }
for _, tc := range testCases { for _, tc := range testCases {

View File

@ -315,7 +315,8 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
lexerName = lexerNameForLine lexerName = lexerNameForLine
} }
br.EscapeStatus, br.Code = charset.EscapeControlHTML(line, ctx.Locale) br.EscapeStatus, line = charset.EscapeControlHTML(line, ctx.Locale)
br.Code = gotemplate.HTML(line)
rows = append(rows, br) rows = append(rows, br)
escapeStatus = escapeStatus.Or(br.EscapeStatus) escapeStatus = escapeStatus.Or(br.EscapeStatus)
} }

View File

@ -158,7 +158,7 @@ func RestoreBranchPost(ctx *context.Context) {
if err := repo_service.PushUpdate( if err := repo_service.PushUpdate(
&repo_module.PushUpdateOptions{ &repo_module.PushUpdateOptions{
RefFullName: git.RefNameFromBranch(deletedBranch.Name), RefFullName: git.RefNameFromBranch(deletedBranch.Name),
OldCommitID: objectFormat.EmptyObjectID().String(), OldCommitID: objectFormat.Empty().String(),
NewCommitID: deletedBranch.CommitID, NewCommitID: deletedBranch.CommitID,
PusherID: ctx.Doer.ID, PusherID: ctx.Doer.ID,
PusherName: ctx.Doer.Name, PusherName: ctx.Doer.Name,

View File

@ -317,7 +317,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
ci.BaseBranch = baseCommit.ID.String() ci.BaseBranch = baseCommit.ID.String()
ctx.Data["BaseBranch"] = ci.BaseBranch ctx.Data["BaseBranch"] = ci.BaseBranch
baseIsCommit = true baseIsCommit = true
} else if ci.BaseBranch == objectFormat.EmptyObjectID().String() { } else if ci.BaseBranch == objectFormat.Empty().String() {
if isSameRepo { if isSameRepo {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch)) ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch))
} else { } else {

View File

@ -329,7 +329,7 @@ func dummyInfoRefs(ctx *context.Context) {
} }
}() }()
if err := git.InitRepository(ctx, tmpDir, true, git.Sha1ObjectFormat.Name()); err != nil { if err := git.InitRepository(ctx, tmpDir, true, git.ObjectFormatFromID(git.Sha1)); 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)
return return
} }

View File

@ -278,18 +278,18 @@ func CreatePost(ctx *context.Context) {
} }
} else { } else {
repo, err = repo_service.CreateRepository(ctx, ctx.Doer, ctxUser, repo_service.CreateRepoOptions{ repo, err = repo_service.CreateRepository(ctx, ctx.Doer, ctxUser, repo_service.CreateRepoOptions{
Name: form.RepoName, Name: form.RepoName,
Description: form.Description, Description: form.Description,
Gitignores: form.Gitignores, Gitignores: form.Gitignores,
IssueLabels: form.IssueLabels, IssueLabels: form.IssueLabels,
License: form.License, License: form.License,
Readme: form.Readme, Readme: form.Readme,
IsPrivate: form.Private || setting.Repository.ForcePrivate, IsPrivate: form.Private || setting.Repository.ForcePrivate,
DefaultBranch: form.DefaultBranch, DefaultBranch: form.DefaultBranch,
AutoInit: form.AutoInit, AutoInit: form.AutoInit,
IsTemplate: form.Template, IsTemplate: form.Template,
TrustModel: repo_model.ToTrustModel(form.TrustModel), TrustModel: repo_model.ToTrustModel(form.TrustModel),
ObjectFormatName: form.ObjectFormatName, ObjectFormat: form.ObjectFormat,
}) })
if err == nil { if err == nil {
log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name) log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)

View File

@ -662,7 +662,7 @@ func TestWebhook(ctx *context.Context) {
return return
} }
commit = &git.Commit{ commit = &git.Commit{
ID: objectFormat.EmptyObjectID(), ID: objectFormat.NewEmptyID(),
Author: ghost.NewGitSig(), Author: ghost.NewGitSig(),
Committer: ghost.NewGitSig(), Committer: ghost.NewGitSig(),
CommitMessage: "This is a fake commit", CommitMessage: "This is a fake commit",

View File

@ -9,7 +9,6 @@ import (
gocontext "context" gocontext "context"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"html/template"
"image" "image"
"io" "io"
"net/http" "net/http"
@ -318,18 +317,19 @@ func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.Tr
}, rd) }, rd)
if err != nil { if err != nil {
log.Error("Render failed for %s in %-v: %v Falling back to rendering source", readmeFile.Name(), ctx.Repo.Repository, err) log.Error("Render failed for %s in %-v: %v Falling back to rendering source", readmeFile.Name(), ctx.Repo.Repository, err)
delete(ctx.Data, "IsMarkup") buf := &bytes.Buffer{}
ctx.Data["EscapeStatus"], _ = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
ctx.Data["FileContent"] = buf.String()
} }
} } else {
if ctx.Data["IsMarkup"] != true {
ctx.Data["IsPlainText"] = true ctx.Data["IsPlainText"] = true
content, err := io.ReadAll(rd) buf := &bytes.Buffer{}
ctx.Data["EscapeStatus"], err = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
if err != nil { if err != nil {
log.Error("Read readme content failed: %v", err) log.Error("Read failed: %v", err)
} }
contentEscaped := template.HTMLEscapeString(util.UnsafeBytesToString(content))
ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlHTML(template.HTML(contentEscaped), ctx.Locale) ctx.Data["FileContent"] = buf.String()
} }
if !fInfo.isLFSFile && ctx.Repo.CanEnableEditor(ctx, ctx.Doer) { if !fInfo.isLFSFile && ctx.Repo.CanEnableEditor(ctx, ctx.Doer) {
@ -493,7 +493,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
buf, _ := io.ReadAll(rd) buf, _ := io.ReadAll(rd)
// The Open Group Base Specification: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html // The Open Group Base Specification: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html
// empty: 0 lines; "a": 1 incomplete-line; "a\n": 1 line; "a\nb": 1 line, 1 incomplete-line; // empty: 0 lines; "a": 1 line, 1 incomplete-line; "a\n": 1 line; "a\nb": 1 line, 1 incomplete-line;
// Gitea uses the definition (like most modern editors): // Gitea uses the definition (like most modern editors):
// empty: 0 lines; "a": 1 line; "a\n": 2 lines; "a\nb": 2 lines; // empty: 0 lines; "a": 1 line; "a\n": 2 lines; "a\nb": 2 lines;
// When rendering, the last empty line is not rendered in UI, while the line-number is still counted, to tell users that the file contains a trailing EOL. // When rendering, the last empty line is not rendered in UI, while the line-number is still counted, to tell users that the file contains a trailing EOL.
@ -620,7 +620,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
} }
} }
func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input io.Reader) (escaped *charset.EscapeStatus, output template.HTML, err error) { func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input io.Reader) (escaped *charset.EscapeStatus, output string, err error) {
markupRd, markupWr := io.Pipe() markupRd, markupWr := io.Pipe()
defer markupWr.Close() defer markupWr.Close()
done := make(chan struct{}) done := make(chan struct{})
@ -628,7 +628,7 @@ func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input i
sb := &strings.Builder{} sb := &strings.Builder{}
// We allow NBSP here this is rendered // We allow NBSP here this is rendered
escaped, _ = charset.EscapeControlReader(markupRd, sb, ctx.Locale, charset.RuneNBSP) escaped, _ = charset.EscapeControlReader(markupRd, sb, ctx.Locale, charset.RuneNBSP)
output = template.HTML(sb.String()) output = sb.String()
close(done) close(done)
}() }()
err = markup.Render(renderCtx, input, markupWr) err = markup.Render(renderCtx, input, markupWr)

View File

@ -39,7 +39,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
objectFormat, _ := gitRepo.GetObjectFormat() objectFormat, _ := gitRepo.GetObjectFormat()
for i := range opts.OldCommitIDs { for i := range opts.OldCommitIDs {
if opts.NewCommitIDs[i] == objectFormat.EmptyObjectID().String() { if opts.NewCommitIDs[i] == objectFormat.Empty().String() {
results = append(results, private.HookProcReceiveRefResult{ results = append(results, private.HookProcReceiveRefResult{
OriginalRef: opts.RefFullNames[i], OriginalRef: opts.RefFullNames[i],
OldOID: opts.OldCommitIDs[i], OldOID: opts.OldCommitIDs[i],
@ -153,7 +153,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
results = append(results, private.HookProcReceiveRefResult{ results = append(results, private.HookProcReceiveRefResult{
Ref: pr.GetGitRefName(), Ref: pr.GetGitRefName(),
OriginalRef: opts.RefFullNames[i], OriginalRef: opts.RefFullNames[i],
OldOID: objectFormat.EmptyObjectID().String(), OldOID: objectFormat.Empty().String(),
NewOID: opts.NewCommitIDs[i], NewOID: opts.NewCommitIDs[i],
}) })
continue continue

View File

@ -19,12 +19,12 @@ import (
func TestToCommitMeta(t *testing.T) { func TestToCommitMeta(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
sha1 := git.Sha1ObjectFormat sha1 := git.ObjectFormatFromID(git.Sha1)
signature := &git.Signature{Name: "Test Signature", Email: "test@email.com", When: time.Unix(0, 0)} signature := &git.Signature{Name: "Test Signature", Email: "test@email.com", When: time.Unix(0, 0)}
tag := &git.Tag{ tag := &git.Tag{
Name: "Test Tag", Name: "Test Tag",
ID: sha1.EmptyObjectID(), ID: sha1.Empty(),
Object: sha1.EmptyObjectID(), Object: sha1.Empty(),
Type: "Test Type", Type: "Test Type",
Tagger: signature, Tagger: signature,
Message: "Test Message", Message: "Test Message",
@ -34,8 +34,8 @@ func TestToCommitMeta(t *testing.T) {
assert.NotNil(t, commitMeta) assert.NotNil(t, commitMeta)
assert.EqualValues(t, &api.CommitMeta{ assert.EqualValues(t, &api.CommitMeta{
SHA: sha1.EmptyObjectID().String(), SHA: sha1.Empty().String(),
URL: util.URLJoin(headRepo.APIURL(), "git/commits", sha1.EmptyObjectID().String()), URL: util.URLJoin(headRepo.APIURL(), "git/commits", sha1.Empty().String()),
Created: time.Unix(0, 0), Created: time.Unix(0, 0),
}, commitMeta) }, commitMeta)
} }

View File

@ -13,6 +13,7 @@ import (
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
project_model "code.gitea.io/gitea/models/project" project_model "code.gitea.io/gitea/models/project"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"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/web/middleware" "code.gitea.io/gitea/modules/web/middleware"
@ -53,7 +54,7 @@ type CreateRepoForm struct {
TrustModel string TrustModel string
ForkSingleBranch string ForkSingleBranch string
ObjectFormatName string ObjectFormat git.ObjectFormat
} }
// Validate validates the fields // Validate validates the fields

View File

@ -285,15 +285,15 @@ type DiffInline struct {
// DiffInlineWithUnicodeEscape makes a DiffInline with hidden unicode characters escaped // DiffInlineWithUnicodeEscape makes a DiffInline with hidden unicode characters escaped
func DiffInlineWithUnicodeEscape(s template.HTML, locale translation.Locale) DiffInline { func DiffInlineWithUnicodeEscape(s template.HTML, locale translation.Locale) DiffInline {
status, content := charset.EscapeControlHTML(s, locale) status, content := charset.EscapeControlHTML(string(s), locale)
return DiffInline{EscapeStatus: status, Content: content} return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
} }
// DiffInlineWithHighlightCode makes a DiffInline with code highlight and hidden unicode characters escaped // DiffInlineWithHighlightCode makes a DiffInline with code highlight and hidden unicode characters escaped
func DiffInlineWithHighlightCode(fileName, language, code string, locale translation.Locale) DiffInline { func DiffInlineWithHighlightCode(fileName, language, code string, locale translation.Locale) DiffInline {
highlighted, _ := highlight.Code(fileName, language, code) highlighted, _ := highlight.Code(fileName, language, code)
status, content := charset.EscapeControlHTML(highlighted, locale) status, content := charset.EscapeControlHTML(highlighted, locale)
return DiffInline{EscapeStatus: status, Content: content} return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
} }
// GetComputedInlineDiffFor computes inline diff for the given line. // GetComputedInlineDiffFor computes inline diff for the given line.
@ -1120,7 +1120,7 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
return nil, err return nil, err
} }
if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String()) && commit.ParentCount() == 0 { if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.Empty().String()) && commit.ParentCount() == 0 {
cmdDiff.AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"). cmdDiff.AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M").
AddArguments(opts.WhitespaceBehavior...). AddArguments(opts.WhitespaceBehavior...).
AddDynamicArguments(objectFormat.EmptyTree().String()). AddDynamicArguments(objectFormat.EmptyTree().String()).
@ -1229,7 +1229,7 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
} }
diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID} diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String() { if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.Empty().String() {
diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID} diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID}
} }
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...) diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...)
@ -1267,7 +1267,7 @@ func GetPullDiffStats(gitRepo *git.Repository, opts *DiffOptions) (*PullDiffStat
} }
diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID} diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String() { if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.Empty().String() {
diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID} diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID}
} }

View File

@ -93,10 +93,10 @@ func (hcd *highlightCodeDiff) diffWithHighlight(filename, language, codeA, codeB
highlightCodeA, _ := highlight.Code(filename, language, codeA) highlightCodeA, _ := highlight.Code(filename, language, codeA)
highlightCodeB, _ := highlight.Code(filename, language, codeB) highlightCodeB, _ := highlight.Code(filename, language, codeB)
convertedCodeA := hcd.convertToPlaceholders(string(highlightCodeA)) highlightCodeA = hcd.convertToPlaceholders(highlightCodeA)
convertedCodeB := hcd.convertToPlaceholders(string(highlightCodeB)) highlightCodeB = hcd.convertToPlaceholders(highlightCodeB)
diffs := diffMatchPatch.DiffMain(convertedCodeA, convertedCodeB, true) diffs := diffMatchPatch.DiffMain(highlightCodeA, highlightCodeB, true)
diffs = diffMatchPatch.DiffCleanupEfficiency(diffs) diffs = diffMatchPatch.DiffCleanupEfficiency(diffs)
for i := range diffs { for i := range diffs {

View File

@ -49,7 +49,7 @@ func CheckAndEnsureSafePR(pr *base.PullRequest, commonCloneBaseURL string, g bas
// SECURITY: SHAs Must be a SHA // SECURITY: SHAs Must be a SHA
// FIXME: hash only a SHA1 // FIXME: hash only a SHA1
CommitType := git.Sha1ObjectFormat CommitType := git.ObjectFormatFromID(git.Sha1)
if pr.MergeCommitSHA != "" && !CommitType.IsValid(pr.MergeCommitSHA) { if pr.MergeCommitSHA != "" && !CommitType.IsValid(pr.MergeCommitSHA) {
WarnAndNotice("PR #%d in %s has invalid MergeCommitSHA: %s", pr.Number, g, pr.MergeCommitSHA) WarnAndNotice("PR #%d in %s has invalid MergeCommitSHA: %s", pr.Number, g, pr.MergeCommitSHA)
pr.MergeCommitSHA = "" pr.MergeCommitSHA = ""

View File

@ -232,7 +232,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
// //
fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
baseRef := "master" baseRef := "master"
assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false, fromRepo.ObjectFormatName)) assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false, fromRepo.ObjectFormat))
err := git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()}) err := git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()})
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644)) assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644))

View File

@ -484,7 +484,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
} }
notify_service.SyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{ notify_service.SyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{
RefFullName: result.refName, RefFullName: result.refName,
OldCommitID: objectFormat.EmptyObjectID().String(), OldCommitID: objectFormat.Empty().String(),
NewCommitID: commitID, NewCommitID: commitID,
}, repo_module.NewPushCommits()) }, repo_module.NewPushCommits())
notify_service.SyncCreateRef(ctx, m.Repo.MustOwner(ctx), m.Repo, result.refName, commitID) notify_service.SyncCreateRef(ctx, m.Repo.MustOwner(ctx), m.Repo, result.refName, commitID)

View File

@ -271,7 +271,7 @@ func alterRepositoryContent(ctx context.Context, doer *user_model.User, repo *re
if !git.IsErrBranchNotExist(err) || !repo.IsEmpty { if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
return err return err
} }
if err := t.Init(repo.ObjectFormatName); err != nil { if err := t.Init(repo.ObjectFormat); err != nil {
return err return err
} }
} else { } else {

View File

@ -328,7 +328,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string,
if err == nil { if err == nil {
for _, pr := range prs { for _, pr := range prs {
objectFormat, _ := git.GetObjectFormatOfRepo(ctx, pr.BaseRepo.RepoPath()) objectFormat, _ := git.GetObjectFormatOfRepo(ctx, pr.BaseRepo.RepoPath())
if newCommitID != "" && newCommitID != objectFormat.EmptyObjectID().String() { if newCommitID != "" && newCommitID != objectFormat.Empty().String() {
changed, err := checkIfPRContentChanged(ctx, pr, oldCommitID, newCommitID) changed, err := checkIfPRContentChanged(ctx, pr, oldCommitID, newCommitID)
if err != nil { if err != nil {
log.Error("checkIfPRContentChanged: %v", err) log.Error("checkIfPRContentChanged: %v", err)

View File

@ -93,8 +93,14 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
baseRepoPath := pr.BaseRepo.RepoPath() baseRepoPath := pr.BaseRepo.RepoPath()
headRepoPath := pr.HeadRepo.RepoPath() headRepoPath := pr.HeadRepo.RepoPath()
objectFormat, err := git.GetObjectFormatOfRepo(ctx, baseRepoPath)
if err != nil {
log.Error("Unable to fetch ObjectFormat of repository %s: %v", baseRepoPath, err)
cancel()
return nil, nil, err
}
if err := git.InitRepository(ctx, tmpBasePath, false, pr.BaseRepo.ObjectFormatName); err != nil { if err := git.InitRepository(ctx, tmpBasePath, false, objectFormat); err != nil {
log.Error("Unable to init tmpBasePath for %-v: %v", pr, err) log.Error("Unable to init tmpBasePath for %-v: %v", pr, err)
cancel() cancel()
return nil, nil, err return nil, nil, err
@ -168,7 +174,6 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
} }
trackingBranch := "tracking" trackingBranch := "tracking"
objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName)
// Fetch head branch // Fetch head branch
var headBranch string var headBranch string
if pr.Flow == issues_model.PullRequestFlowGithub { if pr.Flow == issues_model.PullRequestFlowGithub {

View File

@ -89,14 +89,14 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel
objectFormat, _ := gitRepo.GetObjectFormat() objectFormat, _ := gitRepo.GetObjectFormat()
commits := repository.NewPushCommits() commits := repository.NewPushCommits()
commits.HeadCommit = repository.CommitToPushCommit(commit) commits.HeadCommit = repository.CommitToPushCommit(commit)
commits.CompareURL = rel.Repo.ComposeCompareURL(objectFormat.EmptyObjectID().String(), commit.ID.String()) commits.CompareURL = rel.Repo.ComposeCompareURL(objectFormat.Empty().String(), commit.ID.String())
refFullName := git.RefNameFromTag(rel.TagName) refFullName := git.RefNameFromTag(rel.TagName)
notify_service.PushCommits( notify_service.PushCommits(
ctx, rel.Publisher, rel.Repo, ctx, rel.Publisher, rel.Repo,
&repository.PushUpdateOptions{ &repository.PushUpdateOptions{
RefFullName: refFullName, RefFullName: refFullName,
OldCommitID: objectFormat.EmptyObjectID().String(), OldCommitID: objectFormat.Empty().String(),
NewCommitID: commit.ID.String(), NewCommitID: commit.ID.String(),
}, commits) }, commits)
notify_service.CreateRef(ctx, rel.Publisher, rel.Repo, refFullName, commit.ID.String()) notify_service.CreateRef(ctx, rel.Publisher, rel.Repo, refFullName, commit.ID.String())
@ -335,7 +335,7 @@ func DeleteReleaseByID(ctx context.Context, repo *repo_model.Repository, rel *re
&repository.PushUpdateOptions{ &repository.PushUpdateOptions{
RefFullName: refName, RefFullName: refName,
OldCommitID: rel.Sha1, OldCommitID: rel.Sha1,
NewCommitID: objectFormat.EmptyObjectID().String(), NewCommitID: objectFormat.Empty().String(),
}, repository.NewPushCommits()) }, repository.NewPushCommits())
notify_service.DeleteRef(ctx, doer, repo, refName) notify_service.DeleteRef(ctx, doer, repo, refName)

View File

@ -408,7 +408,7 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
&repo_module.PushUpdateOptions{ &repo_module.PushUpdateOptions{
RefFullName: git.RefNameFromBranch(branchName), RefFullName: git.RefNameFromBranch(branchName),
OldCommitID: commit.ID.String(), OldCommitID: commit.ID.String(),
NewCommitID: objectFormat.EmptyObjectID().String(), NewCommitID: objectFormat.Empty().String(),
PusherID: doer.ID, PusherID: doer.ID,
PusherName: doer.Name, PusherName: doer.Name,
RepoUserName: repo.OwnerName, RepoUserName: repo.OwnerName,

View File

@ -192,7 +192,7 @@ func ReinitMissingRepositories(ctx context.Context) error {
default: default:
} }
log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID) log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
if err := git.InitRepository(ctx, repo.RepoPath(), true, repo.ObjectFormatName); err != nil { if err := git.InitRepository(ctx, repo.RepoPath(), true, repo.ObjectFormat); err != nil {
log.Error("Unable (re)initialize repository %d at %s. Error: %v", repo.ID, repo.RepoPath(), err) log.Error("Unable (re)initialize repository %d at %s. Error: %v", repo.ID, repo.RepoPath(), err)
if err2 := system_model.CreateRepositoryNotice("InitRepository [%d]: %v", repo.ID, err); err2 != nil { if err2 := system_model.CreateRepositoryNotice("InitRepository [%d]: %v", repo.ID, err); err2 != nil {
log.Error("CreateRepositoryNotice: %v", err2) log.Error("CreateRepositoryNotice: %v", err2)

View File

@ -27,23 +27,23 @@ import (
// CreateRepoOptions contains the create repository options // CreateRepoOptions contains the create repository options
type CreateRepoOptions struct { type CreateRepoOptions struct {
Name string Name string
Description string Description string
OriginalURL string OriginalURL string
GitServiceType api.GitServiceType GitServiceType api.GitServiceType
Gitignores string Gitignores string
IssueLabels string IssueLabels string
License string License string
Readme string Readme string
DefaultBranch string DefaultBranch string
IsPrivate bool IsPrivate bool
IsMirror bool IsMirror bool
IsTemplate bool IsTemplate bool
AutoInit bool AutoInit bool
Status repo_model.RepositoryStatus Status repo_model.RepositoryStatus
TrustModel repo_model.TrustModelType TrustModel repo_model.TrustModelType
MirrorInterval string MirrorInterval string
ObjectFormatName string ObjectFormat git.ObjectFormat
} }
func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, repoPath string, opts CreateRepoOptions) error { func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {
@ -135,7 +135,7 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
// InitRepository initializes README and .gitignore if needed. // InitRepository initializes README and .gitignore if needed.
func initRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, opts CreateRepoOptions) (err error) { func initRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, opts CreateRepoOptions) (err error) {
if err = repo_module.CheckInitRepository(ctx, repo.OwnerName, repo.Name, opts.ObjectFormatName); err != nil { if err = repo_module.CheckInitRepository(ctx, repo.OwnerName, repo.Name, opts.ObjectFormat); err != nil {
return err return err
} }
@ -210,6 +210,10 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
opts.DefaultBranch = setting.Repository.DefaultBranch opts.DefaultBranch = setting.Repository.DefaultBranch
} }
if opts.ObjectFormat == nil {
opts.ObjectFormat = git.ObjectFormatFromID(git.Sha1)
}
// Check if label template exist // Check if label template exist
if len(opts.IssueLabels) > 0 { if len(opts.IssueLabels) > 0 {
if _, err := repo_module.LoadTemplateLabelsByDisplayName(opts.IssueLabels); err != nil { if _, err := repo_module.LoadTemplateLabelsByDisplayName(opts.IssueLabels); err != nil {
@ -235,7 +239,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
TrustModel: opts.TrustModel, TrustModel: opts.TrustModel,
IsMirror: opts.IsMirror, IsMirror: opts.IsMirror,
DefaultBranch: opts.DefaultBranch, DefaultBranch: opts.DefaultBranch,
ObjectFormatName: opts.ObjectFormatName, ObjectFormat: opts.ObjectFormat,
} }
var rollbackRepo *repo_model.Repository var rollbackRepo *repo_model.Repository

View File

@ -11,7 +11,6 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/services/pull" "code.gitea.io/gitea/services/pull"
@ -67,7 +66,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
} }
parent, err := commit.ParentID(0) parent, err := commit.ParentID(0)
if err != nil { if err != nil {
parent = git.ObjectFormatFromName(repo.ObjectFormatName).EmptyTree() parent = repo.ObjectFormat.EmptyTree()
} }
base, right := parent.String(), commit.ID.String() base, right := parent.String(), commit.ID.String()

View File

@ -77,8 +77,8 @@ func (t *TemporaryUploadRepository) Clone(branch string) error {
} }
// Init the repository // Init the repository
func (t *TemporaryUploadRepository) Init(objectFormatName string) error { func (t *TemporaryUploadRepository) Init(objectFormat git.ObjectFormat) error {
if err := git.InitRepository(t.ctx, t.basePath, false, objectFormatName); err != nil { if err := git.InitRepository(t.ctx, t.basePath, false, objectFormat); err != nil {
return err return err
} }
gitRepo, err := git.OpenRepository(t.ctx, t.basePath) gitRepo, err := git.OpenRepository(t.ctx, t.basePath)

View File

@ -155,7 +155,8 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
if !git.IsErrBranchNotExist(err) || !repo.IsEmpty { if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
return nil, err return nil, err
} }
if err := t.Init(repo.ObjectFormatName); err != nil { objectFormat, _ := gitRepo.GetObjectFormat()
if err := t.Init(objectFormat); err != nil {
return nil, err return nil, err
} }
hasOldBranch = false hasOldBranch = false

View File

@ -91,7 +91,7 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
if !git.IsErrBranchNotExist(err) || !repo.IsEmpty { if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
return err return err
} }
if err = t.Init(repo.ObjectFormatName); err != nil { if err = t.Init(repo.ObjectFormat); err != nil {
return err return err
} }
hasOldBranch = false hasOldBranch = false

View File

@ -111,7 +111,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
log.Trace("pushUpdates: %-v %s %s %s", repo, opts.OldCommitID, opts.NewCommitID, opts.RefFullName) log.Trace("pushUpdates: %-v %s %s %s", repo, opts.OldCommitID, opts.NewCommitID, opts.RefFullName)
if opts.IsNewRef() && opts.IsDelRef() { if opts.IsNewRef() && opts.IsDelRef() {
return fmt.Errorf("old and new revisions are both %s", objectFormat.EmptyObjectID()) return fmt.Errorf("old and new revisions are both %s", objectFormat.Empty())
} }
if opts.RefFullName.IsTag() { if opts.RefFullName.IsTag() {
if pusher == nil || pusher.ID != opts.PusherID { if pusher == nil || pusher.ID != opts.PusherID {
@ -131,7 +131,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
&repo_module.PushUpdateOptions{ &repo_module.PushUpdateOptions{
RefFullName: git.RefNameFromTag(tagName), RefFullName: git.RefNameFromTag(tagName),
OldCommitID: opts.OldCommitID, OldCommitID: opts.OldCommitID,
NewCommitID: objectFormat.EmptyObjectID().String(), NewCommitID: objectFormat.Empty().String(),
}, repo_module.NewPushCommits()) }, repo_module.NewPushCommits())
delTags = append(delTags, tagName) delTags = append(delTags, tagName)
@ -144,13 +144,13 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
commits := repo_module.NewPushCommits() commits := repo_module.NewPushCommits()
commits.HeadCommit = repo_module.CommitToPushCommit(newCommit) commits.HeadCommit = repo_module.CommitToPushCommit(newCommit)
commits.CompareURL = repo.ComposeCompareURL(objectFormat.EmptyObjectID().String(), opts.NewCommitID) commits.CompareURL = repo.ComposeCompareURL(objectFormat.Empty().String(), opts.NewCommitID)
notify_service.PushCommits( notify_service.PushCommits(
ctx, pusher, repo, ctx, pusher, repo,
&repo_module.PushUpdateOptions{ &repo_module.PushUpdateOptions{
RefFullName: opts.RefFullName, RefFullName: opts.RefFullName,
OldCommitID: objectFormat.EmptyObjectID().String(), OldCommitID: objectFormat.Empty().String(),
NewCommitID: opts.NewCommitID, NewCommitID: opts.NewCommitID,
}, commits) }, commits)
@ -234,7 +234,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
} }
oldCommitID := opts.OldCommitID oldCommitID := opts.OldCommitID
if oldCommitID == objectFormat.EmptyObjectID().String() && len(commits.Commits) > 0 { if oldCommitID == objectFormat.Empty().String() && len(commits.Commits) > 0 {
oldCommit, err := gitRepo.GetCommit(commits.Commits[len(commits.Commits)-1].Sha1) oldCommit, err := gitRepo.GetCommit(commits.Commits[len(commits.Commits)-1].Sha1)
if err != nil && !git.IsErrNotExist(err) { if err != nil && !git.IsErrNotExist(err) {
log.Error("unable to GetCommit %s from %-v: %v", oldCommitID, repo, err) log.Error("unable to GetCommit %s from %-v: %v", oldCommitID, repo, err)
@ -250,11 +250,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
} }
} }
if oldCommitID == objectFormat.EmptyObjectID().String() && repo.DefaultBranch != branch { if oldCommitID == objectFormat.Empty().String() && repo.DefaultBranch != branch {
oldCommitID = repo.DefaultBranch oldCommitID = repo.DefaultBranch
} }
if oldCommitID != objectFormat.EmptyObjectID().String() { if oldCommitID != objectFormat.Empty().String() {
commits.CompareURL = repo.ComposeCompareURL(oldCommitID, opts.NewCommitID) commits.CompareURL = repo.ComposeCompareURL(oldCommitID, opts.NewCommitID)
} else { } else {
commits.CompareURL = "" commits.CompareURL = ""

View File

@ -36,7 +36,7 @@ func InitWiki(ctx context.Context, repo *repo_model.Repository) error {
return nil return nil
} }
if err := git.InitRepository(ctx, repo.WikiPath(), true, repo.ObjectFormatName); err != nil { if err := git.InitRepository(ctx, repo.WikiPath(), true, git.ObjectFormatFromID(git.Sha1)); err != nil {
return fmt.Errorf("InitRepository: %w", err) return fmt.Errorf("InitRepository: %w", err)
} else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil { } else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err) return fmt.Errorf("createDelegateHooks: %w", err)

View File

@ -302,7 +302,7 @@ func TestPrepareWikiFileName_FirstPage(t *testing.T) {
// Now create a temporaryDirectory // Now create a temporaryDirectory
tmpDir := t.TempDir() tmpDir := t.TempDir()
err := git.InitRepository(git.DefaultContext, tmpDir, true, git.Sha1ObjectFormat.Name()) err := git.InitRepository(git.DefaultContext, tmpDir, true, git.ObjectFormatFromID(git.Sha1))
assert.NoError(t, err) assert.NoError(t, err)
gitRepo, err := git.OpenRepository(git.DefaultContext, tmpDir) gitRepo, err := git.OpenRepository(git.DefaultContext, tmpDir)

View File

@ -74,9 +74,9 @@
{{end}} {{end}}
<div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextSource}} code-view{{end}}"> <div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextSource}} code-view{{end}}">
{{if .IsMarkup}} {{if .IsMarkup}}
{{if .FileContent}}{{.FileContent}}{{end}} {{if .FileContent}}{{.FileContent | Safe}}{{end}}
{{else if .IsPlainText}} {{else if .IsPlainText}}
<pre>{{if .FileContent}}{{.FileContent}}{{end}}</pre> <pre>{{if .FileContent}}{{.FileContent | Safe}}{{end}}</pre>
{{else if not .IsTextSource}} {{else if not .IsTextSource}}
<div class="view-raw"> <div class="view-raw">
{{if .IsImageFile}} {{if .IsImageFile}}
@ -114,7 +114,7 @@
{{if $.EscapeStatus.Escaped}} {{if $.EscapeStatus.Escaped}}
<td class="lines-escape">{{if (index $.LineEscapeStatus $idx).Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{if (index $.LineEscapeStatus $idx).HasInvisible}}{{ctx.Locale.Tr "repo.invisible_runes_line"}} {{end}}{{if (index $.LineEscapeStatus $idx).HasAmbiguous}}{{ctx.Locale.Tr "repo.ambiguous_runes_line"}}{{end}}"></button>{{end}}</td> <td class="lines-escape">{{if (index $.LineEscapeStatus $idx).Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{if (index $.LineEscapeStatus $idx).HasInvisible}}{{ctx.Locale.Tr "repo.invisible_runes_line"}} {{end}}{{if (index $.LineEscapeStatus $idx).HasAmbiguous}}{{ctx.Locale.Tr "repo.ambiguous_runes_line"}}{{end}}"></button>{{end}}</td>
{{end}} {{end}}
<td rel="L{{$line}}" class="lines-code chroma"><code class="code-inner">{{$code}}</code></td> <td rel="L{{$line}}" class="lines-code chroma"><code class="code-inner">{{$code | Safe}}</code></td>
</tr> </tr>
{{end}} {{end}}
</tbody> </tbody>

View File

@ -120,7 +120,7 @@ func doGitCloneFail(u *url.URL) func(*testing.T) {
func doGitInitTestRepository(dstPath string) func(*testing.T) { func doGitInitTestRepository(dstPath string) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
// Init repository in dstPath // Init repository in dstPath
assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false, git.Sha1ObjectFormat.Name())) assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false, git.ObjectFormatFromID(git.Sha1)))
// forcibly set default branch to master // forcibly set default branch to master
_, _, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: dstPath}) _, _, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)