Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render READMEs in docs/ .gitea or .github from root #10361

Merged
merged 9 commits into from
Feb 21, 2020
1 change: 0 additions & 1 deletion integrations/sqlite.ini
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,3 @@ INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.O

[oauth2]
JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko

162 changes: 152 additions & 10 deletions routers/repo/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,91 @@ const (
tplMigrating base.TplName = "repo/migrating"
)

type namedBlob struct {
name string
blob *git.Blob
}

func followLinks(entry *git.TreeEntry) (*git.TreeEntry, error) {
var err error
for i := 0; i < 999; i++ {
if entry.IsLink() {
entry, err = entry.FollowLink()
if err != nil {
return nil, err
}
} else {
break
}
}
if entry.IsRegular() || entry.IsExecutable() {
return entry, nil
}
return nil, nil
}

// FIXME: There has to be a more efficient way of doing this
func getReadmeFileFromPath(commit *git.Commit, treePath string) (*namedBlob, error) {
tree, err := commit.SubTree(treePath)
if err != nil {
return nil, err
}

entries, err := tree.ListEntries()
if err != nil {
return nil, err
}

var readmeFiles [4]*namedBlob
var exts = []string{".md", ".txt", ""} // sorted by priority
for _, entry := range entries {
if entry.IsDir() {
continue
}
for i, ext := range exts {
if markup.IsReadmeFile(entry.Name(), ext) {
if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].name, entry.Blob().Name()) {
name := entry.Name()
entry, err := followLinks(entry)
if err != nil {
return nil, err
}
if entry != nil {
readmeFiles[i] = &namedBlob{
name,
entry.Blob(),
}
}
}
}
}

if markup.IsReadmeFile(entry.Name()) {
if readmeFiles[3] == nil || base.NaturalSortLess(readmeFiles[3].name, entry.Blob().Name()) {
name := entry.Name()
entry, err := followLinks(entry)
if err != nil {
return nil, err
}
if entry != nil {
readmeFiles[3] = &namedBlob{
name,
entry.Blob(),
}
}
}
}
}
var readmeFile *namedBlob
for _, f := range readmeFiles {
if f != nil {
readmeFile = f
break
}
}
return readmeFile, nil
}

func renderDirectory(ctx *context.Context, treeLink string) {
tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath)
if err != nil {
Expand Down Expand Up @@ -65,38 +150,95 @@ func renderDirectory(ctx *context.Context, treeLink string) {
// 3 for the extensions in exts[] in order
// the last one is for a readme that doesn't
// strictly match an extension
var readmeFiles [4]*git.Blob
var readmeFiles [4]*namedBlob
var docsEntries [3]*git.TreeEntry
var exts = []string{".md", ".txt", ""} // sorted by priority
for _, entry := range entries {
if entry.IsDir() {
lowerName := strings.ToLower(entry.Name())
switch lowerName {
case "docs":
if entry.Name() == "docs" || docsEntries[0] == nil {
docsEntries[0] = entry
}
case ".gitea":
if entry.Name() == ".gitea" || docsEntries[1] == nil {
docsEntries[1] = entry
}
case ".github":
if entry.Name() == ".github" || docsEntries[2] == nil {
docsEntries[2] = entry
}
}
continue
}

for i, ext := range exts {
if markup.IsReadmeFile(entry.Name(), ext) {
readmeFiles[i] = entry.Blob()
name := entry.Name()
entry, err := followLinks(entry)
if err != nil {
ctx.ServerError("FollowLinks", err)
return
}
if entry != nil {
readmeFiles[i] = &namedBlob{
name,
entry.Blob(),
}
}
}
}

if markup.IsReadmeFile(entry.Name()) {
readmeFiles[3] = entry.Blob()
name := entry.Name()
entry, err := followLinks(entry)
if err != nil {
ctx.ServerError("FollowLinks", err)
return
}
if entry != nil {
readmeFiles[3] = &namedBlob{
name,
entry.Blob(),
}
}
}
}

var readmeFile *git.Blob
var readmeFile *namedBlob
readmeTreelink := treeLink
for _, f := range readmeFiles {
if f != nil {
readmeFile = f
break
}
}

if ctx.Repo.TreePath == "" && readmeFile == nil {
for _, entry := range docsEntries {
if entry == nil {
continue
}
readmeFile, err = getReadmeFileFromPath(ctx.Repo.Commit, entry.GetSubJumpablePathName())
if err != nil {
ctx.ServerError("getReadmeFileFromPath", err)
return
}
if readmeFile != nil {
readmeFile.name = entry.Name() + "/" + readmeFile.name
readmeTreelink = treeLink + "/" + entry.GetSubJumpablePathName()
break
}
}
}

if readmeFile != nil {
ctx.Data["RawFileLink"] = ""
ctx.Data["ReadmeInList"] = true
ctx.Data["ReadmeExist"] = true

dataRc, err := readmeFile.DataAsync()
dataRc, err := readmeFile.blob.DataAsync()
if err != nil {
ctx.ServerError("Data", err)
return
Expand All @@ -109,7 +251,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {

isTextFile := base.IsTextFile(buf)
ctx.Data["FileIsText"] = isTextFile
ctx.Data["FileName"] = readmeFile.Name()
ctx.Data["FileName"] = readmeFile.name
fileSize := int64(0)
isLFSFile := false
ctx.Data["IsLFSFile"] = false
Expand Down Expand Up @@ -151,13 +293,13 @@ func renderDirectory(ctx *context.Context, treeLink string) {

fileSize = meta.Size
ctx.Data["FileSize"] = meta.Size
filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.Name()))
filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.name))
ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s.git/info/lfs/objects/%s/%s", setting.AppURL, ctx.Repo.Repository.FullName(), meta.Oid, filenameBase64)
}
}

if !isLFSFile {
fileSize = readmeFile.Size()
fileSize = readmeFile.blob.Size()
}

if isTextFile {
Expand All @@ -170,10 +312,10 @@ func renderDirectory(ctx *context.Context, treeLink string) {
d, _ := ioutil.ReadAll(dataRc)
buf = charset.ToUTF8WithFallback(append(buf, d...))

if markupType := markup.Type(readmeFile.Name()); markupType != "" {
if markupType := markup.Type(readmeFile.name); markupType != "" {
ctx.Data["IsMarkup"] = true
ctx.Data["MarkupType"] = string(markupType)
ctx.Data["FileContent"] = string(markup.Render(readmeFile.Name(), buf, treeLink, ctx.Repo.Repository.ComposeMetas()))
ctx.Data["FileContent"] = string(markup.Render(readmeFile.name, buf, readmeTreelink, ctx.Repo.Repository.ComposeMetas()))
} else {
ctx.Data["IsRenderedHTML"] = true
ctx.Data["FileContent"] = strings.Replace(
Expand Down