PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/redmine/scm/adapters/mercurial/redminehelper.py

https://gitlab.com/ba0f3/redmine
Python | 222 lines | 200 code | 0 blank | 22 comment | 0 complexity | b1f9ccea6b8fa7f2963e1389f3982872 MD5 | raw file
  1. # redminehelper: Redmine helper extension for Mercurial
  2. #
  3. # Copyright 2010 Alessio Franceschelli (alefranz.net)
  4. # Copyright 2010-2011 Yuya Nishihara <yuya@tcha.org>
  5. #
  6. # This software may be used and distributed according to the terms of the
  7. # GNU General Public License version 2 or any later version.
  8. """helper commands for Redmine to reduce the number of hg calls
  9. To test this extension, please try::
  10. $ hg --config extensions.redminehelper=redminehelper.py rhsummary
  11. I/O encoding:
  12. :file path: urlencoded, raw string
  13. :tag name: utf-8
  14. :branch name: utf-8
  15. :node: 12-digits (short) hex string
  16. Output example of rhsummary::
  17. <?xml version="1.0"?>
  18. <rhsummary>
  19. <repository root="/foo/bar">
  20. <tip revision="1234" node="abcdef0123..."/>
  21. <tag revision="123" node="34567abc..." name="1.1.1"/>
  22. <branch .../>
  23. ...
  24. </repository>
  25. </rhsummary>
  26. Output example of rhmanifest::
  27. <?xml version="1.0"?>
  28. <rhmanifest>
  29. <repository root="/foo/bar">
  30. <manifest revision="1234" path="lib">
  31. <file name="diff.rb" revision="123" node="34567abc..." time="12345"
  32. size="100"/>
  33. ...
  34. <dir name="redmine"/>
  35. ...
  36. </manifest>
  37. </repository>
  38. </rhmanifest>
  39. """
  40. import re, time, cgi, urllib
  41. from mercurial import cmdutil, commands, node, error, hg
  42. _x = cgi.escape
  43. _u = lambda s: cgi.escape(urllib.quote(s))
  44. def _tip(ui, repo):
  45. # see mercurial/commands.py:tip
  46. def tiprev():
  47. try:
  48. return len(repo) - 1
  49. except TypeError: # Mercurial < 1.1
  50. return repo.changelog.count() - 1
  51. tipctx = repo.changectx(tiprev())
  52. ui.write('<tip revision="%d" node="%s"/>\n'
  53. % (tipctx.rev(), _x(node.short(tipctx.node()))))
  54. _SPECIAL_TAGS = ('tip',)
  55. def _tags(ui, repo):
  56. # see mercurial/commands.py:tags
  57. for t, n in reversed(repo.tagslist()):
  58. if t in _SPECIAL_TAGS:
  59. continue
  60. try:
  61. r = repo.changelog.rev(n)
  62. except error.LookupError:
  63. continue
  64. ui.write('<tag revision="%d" node="%s" name="%s"/>\n'
  65. % (r, _x(node.short(n)), _x(t)))
  66. def _branches(ui, repo):
  67. # see mercurial/commands.py:branches
  68. def iterbranches():
  69. for t, n in repo.branchtags().iteritems():
  70. yield t, n, repo.changelog.rev(n)
  71. def branchheads(branch):
  72. try:
  73. return repo.branchheads(branch, closed=False)
  74. except TypeError: # Mercurial < 1.2
  75. return repo.branchheads(branch)
  76. for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True):
  77. if repo.lookup(r) in branchheads(t):
  78. ui.write('<branch revision="%d" node="%s" name="%s"/>\n'
  79. % (r, _x(node.short(n)), _x(t)))
  80. def _manifest(ui, repo, path, rev):
  81. ctx = repo.changectx(rev)
  82. ui.write('<manifest revision="%d" path="%s">\n'
  83. % (ctx.rev(), _u(path)))
  84. known = set()
  85. pathprefix = (path.rstrip('/') + '/').lstrip('/')
  86. for f, n in sorted(ctx.manifest().iteritems(), key=lambda e: e[0]):
  87. if not f.startswith(pathprefix):
  88. continue
  89. name = re.sub(r'/.*', '/', f[len(pathprefix):])
  90. if name in known:
  91. continue
  92. known.add(name)
  93. if name.endswith('/'):
  94. ui.write('<dir name="%s"/>\n'
  95. % _x(urllib.quote(name[:-1])))
  96. else:
  97. fctx = repo.filectx(f, fileid=n)
  98. tm, tzoffset = fctx.date()
  99. ui.write('<file name="%s" revision="%d" node="%s" '
  100. 'time="%d" size="%d"/>\n'
  101. % (_u(name), fctx.rev(), _x(node.short(fctx.node())),
  102. tm, fctx.size(), ))
  103. ui.write('</manifest>\n')
  104. def rhannotate(ui, repo, *pats, **opts):
  105. rev = urllib.unquote_plus(opts.pop('rev', None))
  106. opts['rev'] = rev
  107. return commands.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts)
  108. def rhcat(ui, repo, file1, *pats, **opts):
  109. rev = urllib.unquote_plus(opts.pop('rev', None))
  110. opts['rev'] = rev
  111. return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts)
  112. def rhdiff(ui, repo, *pats, **opts):
  113. """diff repository (or selected files)"""
  114. change = opts.pop('change', None)
  115. if change: # add -c option for Mercurial<1.1
  116. base = repo.changectx(change).parents()[0].rev()
  117. opts['rev'] = [str(base), change]
  118. opts['nodates'] = True
  119. return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)
  120. def rhlog(ui, repo, *pats, **opts):
  121. rev = opts.pop('rev')
  122. bra0 = opts.pop('branch')
  123. from_rev = urllib.unquote_plus(opts.pop('from', None))
  124. to_rev = urllib.unquote_plus(opts.pop('to' , None))
  125. bra = urllib.unquote_plus(opts.pop('rhbranch', None))
  126. from_rev = from_rev.replace('"', '\\"')
  127. to_rev = to_rev.replace('"', '\\"')
  128. if hg.util.version() >= '1.6':
  129. opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)]
  130. else:
  131. opts['rev'] = ['%s:%s' % (from_rev, to_rev)]
  132. opts['branch'] = [bra]
  133. return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts)
  134. def rhmanifest(ui, repo, path='', **opts):
  135. """output the sub-manifest of the specified directory"""
  136. ui.write('<?xml version="1.0"?>\n')
  137. ui.write('<rhmanifest>\n')
  138. ui.write('<repository root="%s">\n' % _u(repo.root))
  139. try:
  140. _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev')))
  141. finally:
  142. ui.write('</repository>\n')
  143. ui.write('</rhmanifest>\n')
  144. def rhsummary(ui, repo, **opts):
  145. """output the summary of the repository"""
  146. ui.write('<?xml version="1.0"?>\n')
  147. ui.write('<rhsummary>\n')
  148. ui.write('<repository root="%s">\n' % _u(repo.root))
  149. try:
  150. _tip(ui, repo)
  151. _tags(ui, repo)
  152. _branches(ui, repo)
  153. # TODO: bookmarks in core (Mercurial>=1.8)
  154. finally:
  155. ui.write('</repository>\n')
  156. ui.write('</rhsummary>\n')
  157. # This extension should be compatible with Mercurial 0.9.5.
  158. # Note that Mercurial 0.9.5 doesn't have extensions.wrapfunction().
  159. cmdtable = {
  160. 'rhannotate': (rhannotate,
  161. [('r', 'rev', '', 'revision'),
  162. ('u', 'user', None, 'list the author (long with -v)'),
  163. ('n', 'number', None, 'list the revision number (default)'),
  164. ('c', 'changeset', None, 'list the changeset'),
  165. ],
  166. 'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...'),
  167. 'rhcat': (rhcat,
  168. [('r', 'rev', '', 'revision')],
  169. 'hg rhcat ([-r REV] ...) FILE...'),
  170. 'rhdiff': (rhdiff,
  171. [('r', 'rev', [], 'revision'),
  172. ('c', 'change', '', 'change made by revision')],
  173. 'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'),
  174. 'rhlog': (rhlog,
  175. [
  176. ('r', 'rev', [], 'show the specified revision'),
  177. ('b', 'branch', [],
  178. 'show changesets within the given named branch'),
  179. ('l', 'limit', '',
  180. 'limit number of changes displayed'),
  181. ('d', 'date', '',
  182. 'show revisions matching date spec'),
  183. ('u', 'user', [],
  184. 'revisions committed by user'),
  185. ('', 'from', '',
  186. ''),
  187. ('', 'to', '',
  188. ''),
  189. ('', 'rhbranch', '',
  190. ''),
  191. ('', 'template', '',
  192. 'display with template')],
  193. 'hg rhlog [OPTION]... [FILE]'),
  194. 'rhmanifest': (rhmanifest,
  195. [('r', 'rev', '', 'show the specified revision')],
  196. 'hg rhmanifest [-r REV] [PATH]'),
  197. 'rhsummary': (rhsummary, [], 'hg rhsummary'),
  198. }