@@ -56,35 +56,54 @@ type namedBlob struct {
56
56
blob * git.Blob
57
57
}
58
58
59
+ // locate a README for a tree in one of the supported paths.
60
+ //
61
+ // entries is passed to reduce calls to ListEntries(), so
62
+ // this has precondition:
63
+ //
64
+ // entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries()
65
+ //
59
66
// FIXME: There has to be a more efficient way of doing this
60
- func getReadmeFileFromPath (ctx * context.Context , commit * git.Commit , treePath string ) (* namedBlob , error ) {
61
- tree , err := commit .SubTree (treePath )
62
- if err != nil {
63
- return nil , err
64
- }
65
-
66
- entries , err := tree .ListEntries ()
67
- if err != nil {
68
- return nil , err
69
- }
70
-
67
+ func findReadmeFileInEntries (ctx * context.Context , entries []* git.TreeEntry ) (* namedBlob , error ) {
71
68
// Create a list of extensions in priority order
72
69
// 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
73
70
// 2. Txt files - e.g. README.txt
74
71
// 3. No extension - e.g. README
75
72
exts := append (localizedExtensions (".md" , ctx .Language ()), ".txt" , "" ) // sorted by priority
76
73
extCount := len (exts )
77
74
readmeFiles := make ([]* namedBlob , extCount + 1 )
75
+
76
+ docsEntries := make ([]* git.TreeEntry , 3 ) // (one of docs/, .gitea/ or .github/)
78
77
for _ , entry := range entries {
79
78
if entry .IsDir () {
79
+ // as a special case for the top-level repo introduction README,
80
+ // fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ...
81
+ // (note that docsEntries is ignored unless we are at the root)
82
+ lowerName := strings .ToLower (entry .Name ())
83
+ switch lowerName {
84
+ case "docs" :
85
+ if entry .Name () == "docs" || docsEntries [0 ] == nil {
86
+ docsEntries [0 ] = entry
87
+ }
88
+ case ".gitea" :
89
+ if entry .Name () == ".gitea" || docsEntries [1 ] == nil {
90
+ docsEntries [1 ] = entry
91
+ }
92
+ case ".github" :
93
+ if entry .Name () == ".github" || docsEntries [2 ] == nil {
94
+ docsEntries [2 ] = entry
95
+ }
96
+ }
80
97
continue
81
98
}
82
99
if i , ok := markup .IsReadmeFileExtension (entry .Name (), exts ... ); ok {
100
+ log .Debug ("Potential readme file: %s" , entry .Name ())
83
101
if readmeFiles [i ] == nil || base .NaturalSortLess (readmeFiles [i ].name , entry .Blob ().Name ()) {
84
102
name := entry .Name ()
85
103
isSymlink := entry .IsLink ()
86
104
target := entry
87
105
if isSymlink {
106
+ var err error
88
107
target , err = entry .FollowLinks ()
89
108
if err != nil && ! git .IsErrBadLink (err ) {
90
109
return nil , err
@@ -107,6 +126,33 @@ func getReadmeFileFromPath(ctx *context.Context, commit *git.Commit, treePath st
107
126
break
108
127
}
109
128
}
129
+
130
+ if ctx .Repo .TreePath == "" && readmeFile == nil {
131
+ for _ , subTreeEntry := range docsEntries {
132
+ if subTreeEntry == nil {
133
+ continue
134
+ }
135
+ subTree := subTreeEntry .Tree ()
136
+ if subTree == nil {
137
+ // this should be impossible; if subTreeEntry exists so should this.
138
+ continue
139
+ }
140
+ var err error
141
+ childEntries , err := subTree .ListEntries ()
142
+ if err != nil {
143
+ return nil , err
144
+ }
145
+ readmeFile , err = findReadmeFileInEntries (ctx , childEntries )
146
+ if err != nil && ! git .IsErrNotExist (err ) {
147
+ return nil , err
148
+ }
149
+ if readmeFile != nil {
150
+ readmeFile .name = subTreeEntry .Name () + "/" + readmeFile .name
151
+ break
152
+ }
153
+ }
154
+ }
155
+
110
156
return readmeFile , nil
111
157
}
112
158
@@ -127,12 +173,20 @@ func renderDirectory(ctx *context.Context, treeLink string) {
127
173
ctx .Data ["CanUploadFile" ] = setting .Repository .Upload .Enabled && ! ctx .Repo .Repository .IsArchived
128
174
}
129
175
130
- readmeFile , readmeTreelink := findReadmeFile (ctx , entries , treeLink )
131
- if ctx .Written () || readmeFile == nil {
176
+ if ctx .Written () {
177
+ return
178
+ }
179
+
180
+ readmeFile , err := findReadmeFileInEntries (ctx , entries )
181
+ if err != nil {
182
+ ctx .ServerError ("findReadmeFileInEntries" , err )
183
+ return
184
+ }
185
+ if readmeFile == nil {
132
186
return
133
187
}
134
188
135
- renderReadmeFile (ctx , readmeFile , readmeTreelink )
189
+ renderReadmeFile (ctx , readmeFile , treeLink )
136
190
}
137
191
138
192
// localizedExtensions prepends the provided language code with and without a
@@ -157,89 +211,6 @@ func localizedExtensions(ext, languageCode string) (localizedExts []string) {
157
211
return []string {lowerLangCode + ext , ext }
158
212
}
159
213
160
- func findReadmeFile (ctx * context.Context , entries git.Entries , treeLink string ) (* namedBlob , string ) {
161
- // Create a list of extensions in priority order
162
- // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
163
- // 2. Txt files - e.g. README.txt
164
- // 3. No extension - e.g. README
165
- exts := append (localizedExtensions (".md" , ctx .Language ()), ".txt" , "" ) // sorted by priority
166
- extCount := len (exts )
167
- readmeFiles := make ([]* namedBlob , extCount + 1 )
168
-
169
- docsEntries := make ([]* git.TreeEntry , 3 ) // (one of docs/, .gitea/ or .github/)
170
- for _ , entry := range entries {
171
- if entry .IsDir () {
172
- lowerName := strings .ToLower (entry .Name ())
173
- switch lowerName {
174
- case "docs" :
175
- if entry .Name () == "docs" || docsEntries [0 ] == nil {
176
- docsEntries [0 ] = entry
177
- }
178
- case ".gitea" :
179
- if entry .Name () == ".gitea" || docsEntries [1 ] == nil {
180
- docsEntries [1 ] = entry
181
- }
182
- case ".github" :
183
- if entry .Name () == ".github" || docsEntries [2 ] == nil {
184
- docsEntries [2 ] = entry
185
- }
186
- }
187
- continue
188
- }
189
-
190
- if i , ok := markup .IsReadmeFileExtension (entry .Name (), exts ... ); ok {
191
- log .Debug ("Potential readme file: %s" , entry .Name ())
192
- name := entry .Name ()
193
- isSymlink := entry .IsLink ()
194
- target := entry
195
- if isSymlink {
196
- var err error
197
- target , err = entry .FollowLinks ()
198
- if err != nil && ! git .IsErrBadLink (err ) {
199
- ctx .ServerError ("FollowLinks" , err )
200
- return nil , ""
201
- }
202
- }
203
- if target != nil && (target .IsExecutable () || target .IsRegular ()) {
204
- readmeFiles [i ] = & namedBlob {
205
- name ,
206
- isSymlink ,
207
- target .Blob (),
208
- }
209
- }
210
- }
211
- }
212
-
213
- var readmeFile * namedBlob
214
- readmeTreelink := treeLink
215
- for _ , f := range readmeFiles {
216
- if f != nil {
217
- readmeFile = f
218
- break
219
- }
220
- }
221
-
222
- if ctx .Repo .TreePath == "" && readmeFile == nil {
223
- for _ , entry := range docsEntries {
224
- if entry == nil {
225
- continue
226
- }
227
- var err error
228
- readmeFile , err = getReadmeFileFromPath (ctx , ctx .Repo .Commit , entry .GetSubJumpablePathName ())
229
- if err != nil {
230
- ctx .ServerError ("getReadmeFileFromPath" , err )
231
- return nil , ""
232
- }
233
- if readmeFile != nil {
234
- readmeFile .name = entry .Name () + "/" + readmeFile .name
235
- readmeTreelink = treeLink + "/" + util .PathEscapeSegments (entry .GetSubJumpablePathName ())
236
- break
237
- }
238
- }
239
- }
240
- return readmeFile , readmeTreelink
241
- }
242
-
243
214
type fileInfo struct {
244
215
isTextFile bool
245
216
isLFSFile bool
@@ -342,7 +313,7 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
342
313
ctx .Data ["EscapeStatus" ], ctx .Data ["FileContent" ], err = markupRender (ctx , & markup.RenderContext {
343
314
Ctx : ctx ,
344
315
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).
345
- URLPrefix : readmeTreelink ,
316
+ URLPrefix : path . Dir ( readmeTreelink ) ,
346
317
Metas : ctx .Repo .Repository .ComposeDocumentMetas (),
347
318
GitRepo : ctx .Repo .GitRepo ,
348
319
}, rd )
0 commit comments