mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-03 21:08:25 +00:00 
			
		
		
		
	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:
		@@ -25,7 +25,7 @@
 | 
			
		||||
  fork_id: 0
 | 
			
		||||
  is_template: false
 | 
			
		||||
  template_id: 0
 | 
			
		||||
  size: 7028
 | 
			
		||||
  size: 7320
 | 
			
		||||
  is_fsck_enabled: true
 | 
			
		||||
  close_issues_via_commit_in_any_branch: false
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -50,12 +50,6 @@ const (
 | 
			
		||||
	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.
 | 
			
		||||
//
 | 
			
		||||
// 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()
 | 
			
		||||
//
 | 
			
		||||
// 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
 | 
			
		||||
	// 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
 | 
			
		||||
	// 2. Txt files - e.g. README.txt
 | 
			
		||||
	// 3. No extension - e.g. README
 | 
			
		||||
	exts := append(localizedExtensions(".md", ctx.Language()), ".txt", "") // sorted by priority
 | 
			
		||||
	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/)
 | 
			
		||||
	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 {
 | 
			
		||||
			log.Debug("Potential readme file: %s", entry.Name())
 | 
			
		||||
			if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].name, entry.Blob().Name()) {
 | 
			
		||||
				name := entry.Name()
 | 
			
		||||
				isSymlink := entry.IsLink()
 | 
			
		||||
				target := entry
 | 
			
		||||
				if isSymlink {
 | 
			
		||||
					var err error
 | 
			
		||||
					target, err = entry.FollowLinks()
 | 
			
		||||
			if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].Name(), entry.Blob().Name()) {
 | 
			
		||||
				if entry.IsLink() {
 | 
			
		||||
					target, err := entry.FollowLinks()
 | 
			
		||||
					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 {
 | 
			
		||||
		if f != nil {
 | 
			
		||||
			readmeFile = f
 | 
			
		||||
@@ -140,20 +127,20 @@ func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry) (*n
 | 
			
		||||
			var err error
 | 
			
		||||
			childEntries, err := subTree.ListEntries()
 | 
			
		||||
			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) {
 | 
			
		||||
				return nil, err
 | 
			
		||||
				return "", nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if readmeFile != nil {
 | 
			
		||||
				readmeFile.name = subTreeEntry.Name() + "/" + readmeFile.name
 | 
			
		||||
				break
 | 
			
		||||
				return path.Join(subTreeEntry.Name(), subfolder), readmeFile, nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return readmeFile, nil
 | 
			
		||||
	return "", readmeFile, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func renderDirectory(ctx *context.Context, treeLink string) {
 | 
			
		||||
@@ -177,16 +164,13 @@ func renderDirectory(ctx *context.Context, treeLink string) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	readmeFile, err := findReadmeFileInEntries(ctx, entries)
 | 
			
		||||
	subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("findReadmeFileInEntries", err)
 | 
			
		||||
		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
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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["ReadmeInList"] = 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 {
 | 
			
		||||
		ctx.ServerError("getFileReader", err)
 | 
			
		||||
		return
 | 
			
		||||
@@ -284,11 +278,11 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
 | 
			
		||||
	defer dataRc.Close()
 | 
			
		||||
 | 
			
		||||
	ctx.Data["FileIsText"] = fInfo.isTextFile
 | 
			
		||||
	ctx.Data["FileName"] = readmeFile.name
 | 
			
		||||
	ctx.Data["FileName"] = path.Join(subfolder, readmeFile.Name())
 | 
			
		||||
	ctx.Data["IsLFSFile"] = 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))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -306,19 +300,19 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
 | 
			
		||||
 | 
			
		||||
	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["MarkupType"] = markupType
 | 
			
		||||
 | 
			
		||||
		ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{
 | 
			
		||||
			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).
 | 
			
		||||
			URLPrefix:    path.Dir(readmeTreelink),
 | 
			
		||||
			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.Join(readmeTreelink, subfolder),
 | 
			
		||||
			Metas:        ctx.Repo.Repository.ComposeDocumentMetas(),
 | 
			
		||||
			GitRepo:      ctx.Repo.GitRepo,
 | 
			
		||||
		}, rd)
 | 
			
		||||
		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{}
 | 
			
		||||
			ctx.Data["EscapeStatus"], _ = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
 | 
			
		||||
			ctx.Data["FileContent"] = buf.String()
 | 
			
		||||
 
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
x<01><>QJ<51>0E<><45>*f><3E><><EFBFBD>I@D<><44>_<EFBFBD>!n`<60>L^<5E>m<EFBFBD>hS<1E><> <20><><EFBFBD><03>^<5E>
 | 
			
		||||
e]<5D>
 | 
			
		||||
<EFBFBD>3wu<13>n<18>zr<7A>,<2C><>]<5D>.6ԋ<36><D48B><EFBFBD>C<EFBFBD><43><0E>$u<>Mr<05><><EFBFBD><EFBFBD>
 | 
			
		||||
1za<7A>I\<5C><><EFBFBD><EFBFBD><EFBFBD> 㘺<10>(><3E>T6x<36><78><17><1E>:<3A><0F><><EFBFBD><EFBFBD><EFBFBD>Oײ|<7C>u9~l"<22>i$c<10><> <20><>kZ[<5B><><1B>S<EFBFBD>
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
4649299398e4d39a5c09eb4f534df6f1e1eb87cc
 | 
			
		||||
@@ -362,7 +362,7 @@ func TestViewRepoDirectoryReadme(t *testing.T) {
 | 
			
		||||
	missing("symlink-loop", "/user2/readme-test/src/branch/symlink-loop/")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMarkDownImage(t *testing.T) {
 | 
			
		||||
func TestMarkDownReadmeImage(t *testing.T) {
 | 
			
		||||
	defer tests.PrepareTestEnv(t)()
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, "user2")
 | 
			
		||||
@@ -371,13 +371,38 @@ func TestMarkDownImage(t *testing.T) {
 | 
			
		||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
 | 
			
		||||
	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")
 | 
			
		||||
	assert.True(t, exists, "Repo home page markdown image link check failed")
 | 
			
		||||
	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/home-md-img-check/test-fake-img.jpg")
 | 
			
		||||
 | 
			
		||||
	req = NewRequest(t, "GET", "/user2/repo1/src/branch/home-md-img-check/README.md")
 | 
			
		||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
 | 
			
		||||
	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")
 | 
			
		||||
	assert.True(t, exists, "Repo src page markdown image link check failed")
 | 
			
		||||
	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/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")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user