Replace repo.namedBlob
by git.TreeEntry
. (#22898)
`namedBlob` turned out to be a poor imitation of a `TreeEntry`. Using the latter directly shortens this code. This partially undoes https://github.com/go-gitea/gitea/pull/23152/, which I found a merge conflict with, and also expands the test it added to cover the subtle README-in-a-subfolder case.
This commit is contained in:
parent
19cbd5c3d9
commit
6aef9e0a2f
6 changed files with 74 additions and 50 deletions
|
@ -25,7 +25,7 @@
|
||||||
fork_id: 0
|
fork_id: 0
|
||||||
is_template: false
|
is_template: false
|
||||||
template_id: 0
|
template_id: 0
|
||||||
size: 7028
|
size: 7320
|
||||||
is_fsck_enabled: true
|
is_fsck_enabled: true
|
||||||
close_issues_via_commit_in_any_branch: false
|
close_issues_via_commit_in_any_branch: false
|
||||||
|
|
||||||
|
|
|
@ -50,12 +50,6 @@ const (
|
||||||
tplMigrating base.TplName = "repo/migrate/migrating"
|
tplMigrating base.TplName = "repo/migrate/migrating"
|
||||||
)
|
)
|
||||||
|
|
||||||
type namedBlob struct {
|
|
||||||
name string
|
|
||||||
isSymlink bool
|
|
||||||
blob *git.Blob
|
|
||||||
}
|
|
||||||
|
|
||||||
// locate a README for a tree in one of the supported paths.
|
// locate a README for a tree in one of the supported paths.
|
||||||
//
|
//
|
||||||
// entries is passed to reduce calls to ListEntries(), so
|
// entries is passed to reduce calls to ListEntries(), so
|
||||||
|
@ -64,14 +58,14 @@ type namedBlob struct {
|
||||||
// entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries()
|
// entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries()
|
||||||
//
|
//
|
||||||
// FIXME: There has to be a more efficient way of doing this
|
// FIXME: There has to be a more efficient way of doing this
|
||||||
func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry) (*namedBlob, error) {
|
func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry) (string, *git.TreeEntry, error) {
|
||||||
// Create a list of extensions in priority order
|
// Create a list of extensions in priority order
|
||||||
// 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
|
// 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
|
||||||
// 2. Txt files - e.g. README.txt
|
// 2. Txt files - e.g. README.txt
|
||||||
// 3. No extension - e.g. README
|
// 3. No extension - e.g. README
|
||||||
exts := append(localizedExtensions(".md", ctx.Language()), ".txt", "") // sorted by priority
|
exts := append(localizedExtensions(".md", ctx.Language()), ".txt", "") // sorted by priority
|
||||||
extCount := len(exts)
|
extCount := len(exts)
|
||||||
readmeFiles := make([]*namedBlob, extCount+1)
|
readmeFiles := make([]*git.TreeEntry, extCount+1)
|
||||||
|
|
||||||
docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/)
|
docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/)
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
|
@ -98,28 +92,21 @@ func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry) (*n
|
||||||
}
|
}
|
||||||
if i, ok := util.IsReadmeFileExtension(entry.Name(), exts...); ok {
|
if i, ok := util.IsReadmeFileExtension(entry.Name(), exts...); ok {
|
||||||
log.Debug("Potential readme file: %s", entry.Name())
|
log.Debug("Potential readme file: %s", entry.Name())
|
||||||
if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].name, entry.Blob().Name()) {
|
if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].Name(), entry.Blob().Name()) {
|
||||||
name := entry.Name()
|
if entry.IsLink() {
|
||||||
isSymlink := entry.IsLink()
|
target, err := entry.FollowLinks()
|
||||||
target := entry
|
|
||||||
if isSymlink {
|
|
||||||
var err error
|
|
||||||
target, err = entry.FollowLinks()
|
|
||||||
if err != nil && !git.IsErrBadLink(err) {
|
if err != nil && !git.IsErrBadLink(err) {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
} else if target != nil && (target.IsExecutable() || target.IsRegular()) {
|
||||||
}
|
readmeFiles[i] = entry
|
||||||
if target != nil && (target.IsExecutable() || target.IsRegular()) {
|
|
||||||
readmeFiles[i] = &namedBlob{
|
|
||||||
name,
|
|
||||||
isSymlink,
|
|
||||||
target.Blob(),
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
readmeFiles[i] = entry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var readmeFile *namedBlob
|
var readmeFile *git.TreeEntry
|
||||||
for _, f := range readmeFiles {
|
for _, f := range readmeFiles {
|
||||||
if f != nil {
|
if f != nil {
|
||||||
readmeFile = f
|
readmeFile = f
|
||||||
|
@ -140,20 +127,20 @@ func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry) (*n
|
||||||
var err error
|
var err error
|
||||||
childEntries, err := subTree.ListEntries()
|
childEntries, err := subTree.ListEntries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
readmeFile, err = findReadmeFileInEntries(ctx, childEntries)
|
|
||||||
|
subfolder, readmeFile, err := findReadmeFileInEntries(ctx, childEntries)
|
||||||
if err != nil && !git.IsErrNotExist(err) {
|
if err != nil && !git.IsErrNotExist(err) {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
if readmeFile != nil {
|
if readmeFile != nil {
|
||||||
readmeFile.name = subTreeEntry.Name() + "/" + readmeFile.name
|
return path.Join(subTreeEntry.Name(), subfolder), readmeFile, nil
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return readmeFile, nil
|
return "", readmeFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderDirectory(ctx *context.Context, treeLink string) {
|
func renderDirectory(ctx *context.Context, treeLink string) {
|
||||||
|
@ -177,16 +164,13 @@ func renderDirectory(ctx *context.Context, treeLink string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
readmeFile, err := findReadmeFileInEntries(ctx, entries)
|
subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("findReadmeFileInEntries", err)
|
ctx.ServerError("findReadmeFileInEntries", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if readmeFile == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
renderReadmeFile(ctx, readmeFile, fmt.Sprintf("%s/%s", treeLink, readmeFile.name))
|
renderReadmeFile(ctx, subfolder, readmeFile, treeLink)
|
||||||
}
|
}
|
||||||
|
|
||||||
// localizedExtensions prepends the provided language code with and without a
|
// localizedExtensions prepends the provided language code with and without a
|
||||||
|
@ -270,13 +254,23 @@ func getFileReader(repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileIn
|
||||||
return buf, dataRc, &fileInfo{st.IsText(), true, meta.Size, &meta.Pointer, st}, nil
|
return buf, dataRc, &fileInfo{st.IsText(), true, meta.Size, &meta.Pointer, st}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelink string) {
|
func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.TreeEntry, readmeTreelink string) {
|
||||||
|
target := readmeFile
|
||||||
|
if readmeFile != nil && readmeFile.IsLink() {
|
||||||
|
target, _ = readmeFile.FollowLinks()
|
||||||
|
}
|
||||||
|
if target == nil {
|
||||||
|
// if findReadmeFile() failed and/or gave us a broken symlink (which it shouldn't)
|
||||||
|
// simply skip rendering the README
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Data["RawFileLink"] = ""
|
ctx.Data["RawFileLink"] = ""
|
||||||
ctx.Data["ReadmeInList"] = true
|
ctx.Data["ReadmeInList"] = true
|
||||||
ctx.Data["ReadmeExist"] = true
|
ctx.Data["ReadmeExist"] = true
|
||||||
ctx.Data["FileIsSymlink"] = readmeFile.isSymlink
|
ctx.Data["FileIsSymlink"] = readmeFile.IsLink()
|
||||||
|
|
||||||
buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, readmeFile.blob)
|
buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, target.Blob())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("getFileReader", err)
|
ctx.ServerError("getFileReader", err)
|
||||||
return
|
return
|
||||||
|
@ -284,11 +278,11 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
|
||||||
defer dataRc.Close()
|
defer dataRc.Close()
|
||||||
|
|
||||||
ctx.Data["FileIsText"] = fInfo.isTextFile
|
ctx.Data["FileIsText"] = fInfo.isTextFile
|
||||||
ctx.Data["FileName"] = readmeFile.name
|
ctx.Data["FileName"] = path.Join(subfolder, readmeFile.Name())
|
||||||
ctx.Data["IsLFSFile"] = fInfo.isLFSFile
|
ctx.Data["IsLFSFile"] = fInfo.isLFSFile
|
||||||
|
|
||||||
if fInfo.isLFSFile {
|
if fInfo.isLFSFile {
|
||||||
filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.name))
|
filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.Name()))
|
||||||
ctx.Data["RawFileLink"] = fmt.Sprintf("%s.git/info/lfs/objects/%s/%s", ctx.Repo.Repository.Link(), url.PathEscape(fInfo.lfsMeta.Oid), url.PathEscape(filenameBase64))
|
ctx.Data["RawFileLink"] = fmt.Sprintf("%s.git/info/lfs/objects/%s/%s", ctx.Repo.Repository.Link(), url.PathEscape(fInfo.lfsMeta.Oid), url.PathEscape(filenameBase64))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,19 +300,19 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
|
||||||
|
|
||||||
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
|
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
|
||||||
|
|
||||||
if markupType := markup.Type(readmeFile.name); markupType != "" {
|
if markupType := markup.Type(readmeFile.Name()); markupType != "" {
|
||||||
ctx.Data["IsMarkup"] = true
|
ctx.Data["IsMarkup"] = true
|
||||||
ctx.Data["MarkupType"] = markupType
|
ctx.Data["MarkupType"] = markupType
|
||||||
|
|
||||||
ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{
|
ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{
|
||||||
Ctx: ctx,
|
Ctx: ctx,
|
||||||
RelativePath: path.Join(ctx.Repo.TreePath, readmeFile.name), // ctx.Repo.TreePath is the directory not the Readme so we must append the Readme filename (and path).
|
RelativePath: path.Join(ctx.Repo.TreePath, readmeFile.Name()), // ctx.Repo.TreePath is the directory not the Readme so we must append the Readme filename (and path).
|
||||||
URLPrefix: path.Dir(readmeTreelink),
|
URLPrefix: path.Join(readmeTreelink, subfolder),
|
||||||
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
|
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
|
||||||
GitRepo: ctx.Repo.GitRepo,
|
GitRepo: ctx.Repo.GitRepo,
|
||||||
}, 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)
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
ctx.Data["EscapeStatus"], _ = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
|
ctx.Data["EscapeStatus"], _ = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
|
||||||
ctx.Data["FileContent"] = buf.String()
|
ctx.Data["FileContent"] = buf.String()
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,4 @@
|
||||||
|
x<01><>QJÅ0EýÎ*f>¦<>¤I@DÁ‡_ú!n`šL^‹mòhSîÞ ®ÀÏ÷^Î
e]ç
|
||||||
|
½3wu<13>nˆzr‘,²Ö]ò.6Ô‹îýÀCçƒÎ$uåMrëÒèÑ
|
||||||
|
1zaÑI\’„„Îê 㘺<10>(>êT6xŸÃ¼:ɹáéò‡Oײ|¯u9~l"Öi$cîÑ ªðkZ[ëÿêSö
|
||||||
|
S¹ÁÇùùåí¼C;Ûä¼òEv¸M’!•#G˜30ìǘÊÒêy³]
|
|
@ -0,0 +1 @@
|
||||||
|
4649299398e4d39a5c09eb4f534df6f1e1eb87cc
|
|
@ -362,7 +362,7 @@ func TestViewRepoDirectoryReadme(t *testing.T) {
|
||||||
missing("symlink-loop", "/user2/readme-test/src/branch/symlink-loop/")
|
missing("symlink-loop", "/user2/readme-test/src/branch/symlink-loop/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarkDownImage(t *testing.T) {
|
func TestMarkDownReadmeImage(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
|
@ -371,13 +371,38 @@ func TestMarkDownImage(t *testing.T) {
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
_, exists := htmlDoc.doc.Find(`img[src="/user2/repo1/media/branch/home-md-img-check/test-fake-img.jpg"]`).Attr("src")
|
src, exists := htmlDoc.doc.Find(`.markdown img`).Attr("src")
|
||||||
assert.True(t, exists, "Repo home page markdown image link check failed")
|
assert.True(t, exists, "Image not found in README")
|
||||||
|
assert.Equal(t, src, "/user2/repo1/media/branch/home-md-img-check/test-fake-img.jpg")
|
||||||
|
|
||||||
req = NewRequest(t, "GET", "/user2/repo1/src/branch/home-md-img-check/README.md")
|
req = NewRequest(t, "GET", "/user2/repo1/src/branch/home-md-img-check/README.md")
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||||
_, exists = htmlDoc.doc.Find(`img[src="/user2/repo1/media/branch/home-md-img-check/test-fake-img.jpg"]`).Attr("src")
|
src, exists = htmlDoc.doc.Find(`.markdown img`).Attr("src")
|
||||||
assert.True(t, exists, "Repo src page markdown image link check failed")
|
assert.True(t, exists, "Image not found in markdown file")
|
||||||
|
assert.Equal(t, src, "/user2/repo1/media/branch/home-md-img-check/test-fake-img.jpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarkDownReadmeImageSubfolder(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
|
||||||
|
// this branch has the README in the special docs/README.md location
|
||||||
|
req := NewRequest(t, "GET", "/user2/repo1/src/branch/sub-home-md-img-check")
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
src, exists := htmlDoc.doc.Find(`.markdown img`).Attr("src")
|
||||||
|
assert.True(t, exists, "Image not found in README")
|
||||||
|
assert.Equal(t, src, "/user2/repo1/media/branch/sub-home-md-img-check/docs/test-fake-img.jpg")
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", "/user2/repo1/src/branch/sub-home-md-img-check/docs/README.md")
|
||||||
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||||
|
src, exists = htmlDoc.doc.Find(`.markdown img`).Attr("src")
|
||||||
|
assert.True(t, exists, "Image not found in markdown file")
|
||||||
|
assert.Equal(t, src, "/user2/repo1/media/branch/sub-home-md-img-check/docs/test-fake-img.jpg")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue