146 'url': url, |
146 'url': url, |
147 }) |
147 }) |
148 |
148 |
149 return archives |
149 return archives |
150 |
150 |
|
151 def rawindexentries(ui, repos, wsgireq, req, subdir='', **map): |
|
152 descend = ui.configbool('web', 'descend') |
|
153 collapse = ui.configbool('web', 'collapse') |
|
154 seenrepos = set() |
|
155 seendirs = set() |
|
156 for name, path in repos: |
|
157 |
|
158 if not name.startswith(subdir): |
|
159 continue |
|
160 name = name[len(subdir):] |
|
161 directory = False |
|
162 |
|
163 if '/' in name: |
|
164 if not descend: |
|
165 continue |
|
166 |
|
167 nameparts = name.split('/') |
|
168 rootname = nameparts[0] |
|
169 |
|
170 if not collapse: |
|
171 pass |
|
172 elif rootname in seendirs: |
|
173 continue |
|
174 elif rootname in seenrepos: |
|
175 pass |
|
176 else: |
|
177 directory = True |
|
178 name = rootname |
|
179 |
|
180 # redefine the path to refer to the directory |
|
181 discarded = '/'.join(nameparts[1:]) |
|
182 |
|
183 # remove name parts plus accompanying slash |
|
184 path = path[:-len(discarded) - 1] |
|
185 |
|
186 try: |
|
187 r = hg.repository(ui, path) |
|
188 directory = False |
|
189 except (IOError, error.RepoError): |
|
190 pass |
|
191 |
|
192 parts = [name] |
|
193 parts.insert(0, '/' + subdir.rstrip('/')) |
|
194 if wsgireq.env['SCRIPT_NAME']: |
|
195 parts.insert(0, wsgireq.env['SCRIPT_NAME']) |
|
196 url = re.sub(r'/+', '/', '/'.join(parts) + '/') |
|
197 |
|
198 # show either a directory entry or a repository |
|
199 if directory: |
|
200 # get the directory's time information |
|
201 try: |
|
202 d = (get_mtime(path), dateutil.makedate()[1]) |
|
203 except OSError: |
|
204 continue |
|
205 |
|
206 # add '/' to the name to make it obvious that |
|
207 # the entry is a directory, not a regular repository |
|
208 row = {'contact': "", |
|
209 'contact_sort': "", |
|
210 'name': name + '/', |
|
211 'name_sort': name, |
|
212 'url': url, |
|
213 'description': "", |
|
214 'description_sort': "", |
|
215 'lastchange': d, |
|
216 'lastchange_sort': d[1] - d[0], |
|
217 'archives': [], |
|
218 'isdirectory': True, |
|
219 'labels': [], |
|
220 } |
|
221 |
|
222 seendirs.add(name) |
|
223 yield row |
|
224 continue |
|
225 |
|
226 u = ui.copy() |
|
227 try: |
|
228 u.readconfig(os.path.join(path, '.hg', 'hgrc')) |
|
229 except Exception as e: |
|
230 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e)) |
|
231 continue |
|
232 |
|
233 def get(section, name, default=uimod._unset): |
|
234 return u.config(section, name, default, untrusted=True) |
|
235 |
|
236 if u.configbool("web", "hidden", untrusted=True): |
|
237 continue |
|
238 |
|
239 if not readallowed(u, req): |
|
240 continue |
|
241 |
|
242 # update time with local timezone |
|
243 try: |
|
244 r = hg.repository(ui, path) |
|
245 except IOError: |
|
246 u.warn(_('error accessing repository at %s\n') % path) |
|
247 continue |
|
248 except error.RepoError: |
|
249 u.warn(_('error accessing repository at %s\n') % path) |
|
250 continue |
|
251 try: |
|
252 d = (get_mtime(r.spath), dateutil.makedate()[1]) |
|
253 except OSError: |
|
254 continue |
|
255 |
|
256 contact = get_contact(get) |
|
257 description = get("web", "description") |
|
258 seenrepos.add(name) |
|
259 name = get("web", "name", name) |
|
260 row = {'contact': contact or "unknown", |
|
261 'contact_sort': contact.upper() or "unknown", |
|
262 'name': name, |
|
263 'name_sort': name, |
|
264 'url': url, |
|
265 'description': description or "unknown", |
|
266 'description_sort': description.upper() or "unknown", |
|
267 'lastchange': d, |
|
268 'lastchange_sort': d[1] - d[0], |
|
269 'archives': archivelist(u, "tip", url), |
|
270 'isdirectory': None, |
|
271 'labels': u.configlist('web', 'labels', untrusted=True), |
|
272 } |
|
273 |
|
274 yield row |
|
275 |
151 class hgwebdir(object): |
276 class hgwebdir(object): |
152 """HTTP server for multiple repositories. |
277 """HTTP server for multiple repositories. |
153 |
278 |
154 Given a configuration, different repositories will be served depending |
279 Given a configuration, different repositories will be served depending |
155 on the request path. |
280 on the request path. |
345 tmpl = None |
470 tmpl = None |
346 |
471 |
347 def makeindex(self, wsgireq, tmpl, subdir=""): |
472 def makeindex(self, wsgireq, tmpl, subdir=""): |
348 req = wsgireq.req |
473 req = wsgireq.req |
349 |
474 |
350 def rawentries(subdir="", **map): |
|
351 |
|
352 descend = self.ui.configbool('web', 'descend') |
|
353 collapse = self.ui.configbool('web', 'collapse') |
|
354 seenrepos = set() |
|
355 seendirs = set() |
|
356 for name, path in self.repos: |
|
357 |
|
358 if not name.startswith(subdir): |
|
359 continue |
|
360 name = name[len(subdir):] |
|
361 directory = False |
|
362 |
|
363 if '/' in name: |
|
364 if not descend: |
|
365 continue |
|
366 |
|
367 nameparts = name.split('/') |
|
368 rootname = nameparts[0] |
|
369 |
|
370 if not collapse: |
|
371 pass |
|
372 elif rootname in seendirs: |
|
373 continue |
|
374 elif rootname in seenrepos: |
|
375 pass |
|
376 else: |
|
377 directory = True |
|
378 name = rootname |
|
379 |
|
380 # redefine the path to refer to the directory |
|
381 discarded = '/'.join(nameparts[1:]) |
|
382 |
|
383 # remove name parts plus accompanying slash |
|
384 path = path[:-len(discarded) - 1] |
|
385 |
|
386 try: |
|
387 r = hg.repository(self.ui, path) |
|
388 directory = False |
|
389 except (IOError, error.RepoError): |
|
390 pass |
|
391 |
|
392 parts = [name] |
|
393 parts.insert(0, '/' + subdir.rstrip('/')) |
|
394 if wsgireq.env['SCRIPT_NAME']: |
|
395 parts.insert(0, wsgireq.env['SCRIPT_NAME']) |
|
396 url = re.sub(r'/+', '/', '/'.join(parts) + '/') |
|
397 |
|
398 # show either a directory entry or a repository |
|
399 if directory: |
|
400 # get the directory's time information |
|
401 try: |
|
402 d = (get_mtime(path), dateutil.makedate()[1]) |
|
403 except OSError: |
|
404 continue |
|
405 |
|
406 # add '/' to the name to make it obvious that |
|
407 # the entry is a directory, not a regular repository |
|
408 row = {'contact': "", |
|
409 'contact_sort': "", |
|
410 'name': name + '/', |
|
411 'name_sort': name, |
|
412 'url': url, |
|
413 'description': "", |
|
414 'description_sort': "", |
|
415 'lastchange': d, |
|
416 'lastchange_sort': d[1]-d[0], |
|
417 'archives': [], |
|
418 'isdirectory': True, |
|
419 'labels': [], |
|
420 } |
|
421 |
|
422 seendirs.add(name) |
|
423 yield row |
|
424 continue |
|
425 |
|
426 u = self.ui.copy() |
|
427 try: |
|
428 u.readconfig(os.path.join(path, '.hg', 'hgrc')) |
|
429 except Exception as e: |
|
430 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e)) |
|
431 continue |
|
432 def get(section, name, default=uimod._unset): |
|
433 return u.config(section, name, default, untrusted=True) |
|
434 |
|
435 if u.configbool("web", "hidden", untrusted=True): |
|
436 continue |
|
437 |
|
438 if not readallowed(u, req): |
|
439 continue |
|
440 |
|
441 # update time with local timezone |
|
442 try: |
|
443 r = hg.repository(self.ui, path) |
|
444 except IOError: |
|
445 u.warn(_('error accessing repository at %s\n') % path) |
|
446 continue |
|
447 except error.RepoError: |
|
448 u.warn(_('error accessing repository at %s\n') % path) |
|
449 continue |
|
450 try: |
|
451 d = (get_mtime(r.spath), dateutil.makedate()[1]) |
|
452 except OSError: |
|
453 continue |
|
454 |
|
455 contact = get_contact(get) |
|
456 description = get("web", "description") |
|
457 seenrepos.add(name) |
|
458 name = get("web", "name", name) |
|
459 row = {'contact': contact or "unknown", |
|
460 'contact_sort': contact.upper() or "unknown", |
|
461 'name': name, |
|
462 'name_sort': name, |
|
463 'url': url, |
|
464 'description': description or "unknown", |
|
465 'description_sort': description.upper() or "unknown", |
|
466 'lastchange': d, |
|
467 'lastchange_sort': d[1]-d[0], |
|
468 'archives': archivelist(u, "tip", url), |
|
469 'isdirectory': None, |
|
470 'labels': u.configlist('web', 'labels', untrusted=True), |
|
471 } |
|
472 |
|
473 yield row |
|
474 |
|
475 sortdefault = None, False |
475 sortdefault = None, False |
476 def entries(sortcolumn="", descending=False, subdir="", **map): |
476 def entries(sortcolumn="", descending=False, subdir="", **map): |
477 rows = rawentries(subdir=subdir, **map) |
477 rows = rawindexentries(self.ui, self.repos, wsgireq, req, |
|
478 subdir=subdir, **map) |
478 |
479 |
479 if sortcolumn and sortdefault != (sortcolumn, descending): |
480 if sortcolumn and sortdefault != (sortcolumn, descending): |
480 sortkey = '%s_sort' % sortcolumn |
481 sortkey = '%s_sort' % sortcolumn |
481 rows = sorted(rows, key=lambda x: x[sortkey], |
482 rows = sorted(rows, key=lambda x: x[sortkey], |
482 reverse=descending) |
483 reverse=descending) |