@@ -69,6 +69,99 @@ const (
6969	tplMigrating     base.TplName  =  "repo/migrate/migrating" 
7070)
7171
72+ // locate a README for a tree in one of the supported paths. 
73+ // 
74+ // entries is passed to reduce calls to ListEntries(), so 
75+ // this has precondition: 
76+ // 
77+ //	entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries() 
78+ // 
79+ // FIXME: There has to be a more efficient way of doing this 
80+ func  findReadmeFileInEntries (ctx  * context.Context , entries  []* git.TreeEntry , tryWellKnownDirs  bool ) (string , * git.TreeEntry , error ) {
81+ 	// Create a list of extensions in priority order 
82+ 	// 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md 
83+ 	// 2. Txt files - e.g. README.txt 
84+ 	// 3. No extension - e.g. README 
85+ 	exts  :=  append (localizedExtensions (".md" , ctx .Locale .Language ()), ".txt" , "" ) // sorted by priority 
86+ 	extCount  :=  len (exts )
87+ 	readmeFiles  :=  make ([]* git.TreeEntry , extCount + 1 )
88+ 
89+ 	docsEntries  :=  make ([]* git.TreeEntry , 3 ) // (one of docs/, .gitea/ or .github/) 
90+ 	for  _ , entry  :=  range  entries  {
91+ 		if  tryWellKnownDirs  &&  entry .IsDir () {
92+ 			// as a special case for the top-level repo introduction README, 
93+ 			// fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ... 
94+ 			// (note that docsEntries is ignored unless we are at the root) 
95+ 			lowerName  :=  strings .ToLower (entry .Name ())
96+ 			switch  lowerName  {
97+ 			case  "docs" :
98+ 				if  entry .Name () ==  "docs"  ||  docsEntries [0 ] ==  nil  {
99+ 					docsEntries [0 ] =  entry 
100+ 				}
101+ 			case  ".gitea" :
102+ 				if  entry .Name () ==  ".gitea"  ||  docsEntries [1 ] ==  nil  {
103+ 					docsEntries [1 ] =  entry 
104+ 				}
105+ 			case  ".github" :
106+ 				if  entry .Name () ==  ".github"  ||  docsEntries [2 ] ==  nil  {
107+ 					docsEntries [2 ] =  entry 
108+ 				}
109+ 			}
110+ 			continue 
111+ 		}
112+ 		if  i , ok  :=  util .IsReadmeFileExtension (entry .Name (), exts ... ); ok  {
113+ 			log .Debug ("Potential readme file: %s" , entry .Name ())
114+ 			if  readmeFiles [i ] ==  nil  ||  base .NaturalSortLess (readmeFiles [i ].Name (), entry .Blob ().Name ()) {
115+ 				if  entry .IsLink () {
116+ 					target , err  :=  entry .FollowLinks ()
117+ 					if  err  !=  nil  &&  ! git .IsErrBadLink (err ) {
118+ 						return  "" , nil , err 
119+ 					} else  if  target  !=  nil  &&  (target .IsExecutable () ||  target .IsRegular ()) {
120+ 						readmeFiles [i ] =  entry 
121+ 					}
122+ 				} else  {
123+ 					readmeFiles [i ] =  entry 
124+ 				}
125+ 			}
126+ 		}
127+ 	}
128+ 	var  readmeFile  * git.TreeEntry 
129+ 	for  _ , f  :=  range  readmeFiles  {
130+ 		if  f  !=  nil  {
131+ 			readmeFile  =  f 
132+ 			break 
133+ 		}
134+ 	}
135+ 
136+ 	if  ctx .Repo .TreePath  ==  ""  &&  readmeFile  ==  nil  {
137+ 		for  _ , subTreeEntry  :=  range  docsEntries  {
138+ 			if  subTreeEntry  ==  nil  {
139+ 				continue 
140+ 			}
141+ 			subTree  :=  subTreeEntry .Tree ()
142+ 			if  subTree  ==  nil  {
143+ 				// this should be impossible; if subTreeEntry exists so should this. 
144+ 				continue 
145+ 			}
146+ 			var  err  error 
147+ 			childEntries , err  :=  subTree .ListEntries ()
148+ 			if  err  !=  nil  {
149+ 				return  "" , nil , err 
150+ 			}
151+ 
152+ 			subfolder , readmeFile , err  :=  findReadmeFileInEntries (ctx , childEntries , false )
153+ 			if  err  !=  nil  &&  ! git .IsErrNotExist (err ) {
154+ 				return  "" , nil , err 
155+ 			}
156+ 			if  readmeFile  !=  nil  {
157+ 				return  path .Join (subTreeEntry .Name (), subfolder ), readmeFile , nil 
158+ 			}
159+ 		}
160+ 	}
161+ 
162+ 	return  "" , readmeFile , nil 
163+ }
164+ 
72165func  renderDirectory (ctx  * context.Context ) {
73166	entries  :=  renderDirectoryFiles (ctx , 1 * time .Second )
74167	if  ctx .Written () {
@@ -80,15 +173,37 @@ func renderDirectory(ctx *context.Context) {
80173		ctx .Data ["Title" ] =  ctx .Tr ("repo.file.title" , ctx .Repo .Repository .Name + "/" + path .Base (ctx .Repo .TreePath ), ctx .Repo .RefName )
81174	}
82175
83- 	subfolder , readmeFile , err  :=  repo_service . FindFileInEntries ( util . FileTypeReadme ,  entries ,  ctx . Repo . TreePath ,  ctx . Locale . Language () , true )
176+ 	subfolder , readmeFile , err  :=  findReadmeFileInEntries ( ctx ,  entries , true )
84177	if  err  !=  nil  {
85- 		ctx .ServerError ("findFileInEntries " , err )
178+ 		ctx .ServerError ("findReadmeFileInEntries " , err )
86179		return 
87180	}
88181
89182	renderReadmeFile (ctx , subfolder , readmeFile )
90183}
91184
185+ // localizedExtensions prepends the provided language code with and without a 
186+ // regional identifier to the provided extension. 
187+ // Note: the language code will always be lower-cased, if a region is present it must be separated with a `-` 
188+ // Note: ext should be prefixed with a `.` 
189+ func  localizedExtensions (ext , languageCode  string ) (localizedExts  []string ) {
190+ 	if  len (languageCode ) <  1  {
191+ 		return  []string {ext }
192+ 	}
193+ 
194+ 	lowerLangCode  :=  "."  +  strings .ToLower (languageCode )
195+ 
196+ 	if  strings .Contains (lowerLangCode , "-" ) {
197+ 		underscoreLangCode  :=  strings .ReplaceAll (lowerLangCode , "-" , "_" )
198+ 		indexOfDash  :=  strings .Index (lowerLangCode , "-" )
199+ 		// e.g. [.zh-cn.md, .zh_cn.md, .zh.md, _zh.md, .md] 
200+ 		return  []string {lowerLangCode  +  ext , underscoreLangCode  +  ext , lowerLangCode [:indexOfDash ] +  ext , "_"  +  lowerLangCode [1 :indexOfDash ] +  ext , ext }
201+ 	}
202+ 
203+ 	// e.g. [.en.md, .md] 
204+ 	return  []string {lowerLangCode  +  ext , ext }
205+ }
206+ 
92207type  fileInfo  struct  {
93208	isTextFile  bool 
94209	isLFSFile   bool 
@@ -384,7 +499,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) {
384499		rd  :=  charset .ToUTF8WithFallbackReader (io .MultiReader (bytes .NewReader (buf ), dataRc ), charset.ConvertOpts {})
385500
386501		shouldRenderSource  :=  ctx .FormString ("display" ) ==  "source" 
387- 		readmeExist  :=  util .IsFileName (blob .Name (),  util . FileTypeReadme )
502+ 		readmeExist  :=  util .IsReadmeFileName (blob .Name ())
388503		ctx .Data ["ReadmeExist" ] =  readmeExist 
389504
390505		markupType  :=  markup .DetectMarkupTypeByFileName (blob .Name ())
@@ -963,11 +1078,7 @@ func renderHomeCode(ctx *context.Context) {
9631078	ctx .Data ["TreeLink" ] =  treeLink 
9641079	ctx .Data ["TreeNames" ] =  treeNames 
9651080	ctx .Data ["BranchLink" ] =  branchLink 
966- 	ctx .Data ["DetectedLicenseFileName" ], err  =  repo_service .GetDetectedLicenseFileName (ctx , ctx .Repo .Repository , ctx .Repo .Commit )
967- 	if  err  !=  nil  {
968- 		ctx .ServerError ("GetDetectedLicenseFileName" , err )
969- 		return 
970- 	}
1081+ 	ctx .Data ["LicenseFileName" ] =  repo_service .LicenseFileName 
9711082	ctx .HTML (http .StatusOK , tplRepoHome )
9721083}
9731084
0 commit comments