Project

General

Profile

Feature #33784 » 33784_Redmine_5.0.3.patch

Olivier Houdas, 2022-12-14 09:16

View differences:

lib/redmine/scm/adapters/mercurial/redminehelper.py
5 5
#
6 6
# This software may be used and distributed according to the terms of the
7 7
# GNU General Public License version 2 or any later version.
8

  
9
# [Nomadia-changes] Patch from Redmine.org #33784 : adapt to Python 3.0
10

  
8 11
"""helper commands for Redmine to reduce the number of hg calls
9 12

  
10 13
To test this extension, please try::
......
45 48
      </repository>
46 49
    </rhmanifest>
47 50
"""
48
import re, time, cgi, urllib
51
import re, time, html, urllib
49 52
from mercurial import cmdutil, commands, node, error, hg, registrar
50 53

  
51 54
cmdtable = {}
52 55
command = registrar.command(cmdtable) if hasattr(registrar, 'command') else cmdutil.command(cmdtable)
53 56

  
54
_x = cgi.escape
55
_u = lambda s: cgi.escape(urllib.quote(s))
57
_x = lambda s: html.escape(s.decode('utf-8')).encode('utf-8')
58
_u = lambda s: html.escape(urllib.parse.quote(s)).encode('utf-8')
59

  
60
def unquoteplus(*args, **kwargs):
61
    return urllib.parse.unquote_to_bytes(*args, **kwargs).replace(b'+', b' ')
56 62

  
57 63
def _changectx(repo, rev):
58
    if isinstance(rev, str):
64
    if isinstance(rev, bytes):
59 65
       rev = repo.lookup(rev)
60 66
    if hasattr(repo, 'changectx'):
61 67
        return repo.changectx(rev)
......
70 76
        except TypeError:  # Mercurial < 1.1
71 77
            return repo.changelog.count() - 1
72 78
    tipctx = _changectx(repo, tiprev())
73
    ui.write('<tip revision="%d" node="%s"/>\n'
79
    ui.write(b'<tip revision="%d" node="%s"/>\n'
74 80
             % (tipctx.rev(), _x(node.hex(tipctx.node()))))
75 81

  
76
_SPECIAL_TAGS = ('tip',)
82
_SPECIAL_TAGS = (b'tip',)
77 83

  
78 84
def _tags(ui, repo):
79 85
    # see mercurial/commands.py:tags
......
84 90
            r = repo.changelog.rev(n)
85 91
        except error.LookupError:
86 92
            continue
87
        ui.write('<tag revision="%d" node="%s" name="%s"/>\n'
93
        ui.write(b'<tag revision="%d" node="%s" name="%s"/>\n'
88 94
                 % (r, _x(node.hex(n)), _u(t)))
89 95

  
90 96
def _branches(ui, repo):
......
104 110
            return repo.branchheads(branch)
105 111
    def lookup(rev, n):
106 112
        try:
107
            return repo.lookup(rev)
113
            return repo.lookup(str(rev).encode('utf-8'))
108 114
        except RuntimeError:
109 115
            return n
110 116
    for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True):
111 117
        if lookup(r, n) in branchheads(t):
112
            ui.write('<branch revision="%d" node="%s" name="%s"/>\n'
118
            ui.write(b'<branch revision="%d" node="%s" name="%s"/>\n'
113 119
                     % (r, _x(node.hex(n)), _u(t)))
114 120

  
115 121
def _manifest(ui, repo, path, rev):
116 122
    ctx = _changectx(repo, rev)
117
    ui.write('<manifest revision="%d" path="%s">\n'
123
    ui.write(b'<manifest revision="%d" path="%s">\n'
118 124
             % (ctx.rev(), _u(path)))
119 125

  
120 126
    known = set()
121
    pathprefix = (path.rstrip('/') + '/').lstrip('/')
127
    pathprefix = (path.decode('utf-8').rstrip('/') + '/').lstrip('/')
122 128
    for f, n in sorted(ctx.manifest().iteritems(), key=lambda e: e[0]):
123
        if not f.startswith(pathprefix):
124
            continue
125
        name = re.sub(r'/.*', '/', f[len(pathprefix):])
129
        fstr = f.decode('cp1252')
130
        if not fstr.startswith(pathprefix):
131
             continue
132
        name = re.sub(r'/.*', '/', fstr[len(pathprefix):])
126 133
        if name in known:
127 134
            continue
128 135
        known.add(name)
129 136

  
130 137
        if name.endswith('/'):
131
            ui.write('<dir name="%s"/>\n'
132
                     % _x(urllib.quote(name[:-1])))
138
            ui.write(b'<dir name="%s"/>\n'
139
                     % _x(urllib.parse.quote(name[:-1]).encode('utf-8')))
133 140
        else:
134 141
            fctx = repo.filectx(f, fileid=n)
135 142
            tm, tzoffset = fctx.date()
136
            ui.write('<file name="%s" revision="%d" node="%s" '
137
                     'time="%d" size="%d"/>\n'
143
            ui.write(b'<file name="%s" revision="%d" node="%s" '
144
                     b'time="%d" size="%d"/>\n'
138 145
                     % (_u(name), fctx.rev(), _x(node.hex(fctx.node())),
139 146
                        tm, fctx.size(), ))
140 147

  
141
    ui.write('</manifest>\n')
148
    ui.write(b'</manifest>\n')
142 149

  
143
@command('rhannotate',
144
         [('r', 'rev', '', 'revision'),
145
          ('u', 'user', None, 'list the author (long with -v)'),
146
          ('n', 'number', None, 'list the revision number (default)'),
147
          ('c', 'changeset', None, 'list the changeset'),
150
@command(b'rhannotate',
151
         [(b'r', b'rev', b'', b'revision'),
152
          (b'u', b'user', None, b'list the author (long with -v)'),
153
          (b'n', b'number', None, b'list the revision number (default)'),
154
          (b'c', b'changeset', None, b'list the changeset'),
148 155
         ],
149
         'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...')
156
         b'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...')
150 157
def rhannotate(ui, repo, *pats, **opts):
151
    rev = urllib.unquote_plus(opts.pop('rev', None))
158
    rev = unquoteplus(opts.pop('rev', b''))
152 159
    opts['rev'] = rev
153
    return commands.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts)
160
    return commands.annotate(ui, repo, *map(unquoteplus, pats), **opts)
154 161

  
155
@command('rhcat',
156
               [('r', 'rev', '', 'revision')],
157
               'hg rhcat ([-r REV] ...) FILE...')
162
@command(b'rhcat',
163
               [(b'r', b'rev', b'', b'revision')],
164
               b'hg rhcat ([-r REV] ...) FILE...')
158 165
def rhcat(ui, repo, file1, *pats, **opts):
159
    rev = urllib.unquote_plus(opts.pop('rev', None))
166
    rev = unquoteplus(opts.pop('rev', b''))
160 167
    opts['rev'] = rev
161
    return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts)
168
    return commands.cat(ui, repo, unquoteplus(file1), *map(unquoteplus, pats), **opts)
162 169

  
163
@command('rhdiff',
164
               [('r', 'rev', [], 'revision'),
165
                ('c', 'change', '', 'change made by revision')],
166
               'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...')
170
@command(b'rhdiff',
171
               [(b'r', b'rev', [], b'revision'),
172
                (b'c', b'change', b'', b'change made by revision')],
173
               b'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...')
167 174
def rhdiff(ui, repo, *pats, **opts):
168 175
    """diff repository (or selected files)"""
169 176
    change = opts.pop('change', None)
170 177
    if change:  # add -c option for Mercurial<1.1
171 178
        base = _changectx(repo, change).parents()[0].rev()
172
        opts['rev'] = [str(base), change]
179
        opts['rev'] = [base, change]
173 180
    opts['nodates'] = True
174
    return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)
181
    return commands.diff(ui, repo, *map(unquoteplus, pats), **opts)
175 182

  
176
@command('rhlog',
183
@command(b'rhlog',
177 184
                   [
178
                    ('r', 'rev', [], 'show the specified revision'),
179
                    ('b', 'branch', [],
180
                       'show changesets within the given named branch'),
181
                    ('l', 'limit', '',
182
                         'limit number of changes displayed'),
183
                    ('d', 'date', '',
184
                         'show revisions matching date spec'),
185
                    ('u', 'user', [],
186
                      'revisions committed by user'),
187
                    ('', 'from', '',
188
                      ''),
189
                    ('', 'to', '',
190
                      ''),
191
                    ('', 'rhbranch', '',
192
                      ''),
193
                    ('', 'template', '',
194
                       'display with template')],
195
                   'hg rhlog [OPTION]... [FILE]')
185
                    (b'r', b'rev', [], b'show the specified revision'),
186
                    (b'b', b'branch', [],
187
                       b'show changesets within the given named branch'),
188
                    (b'l', b'limit', b'',
189
                         b'limit number of changes displayed'),
190
                    (b'd', b'date', b'',
191
                         b'show revisions matching date spec'),
192
                    (b'u', b'user', [],
193
                      b'revisions committed by user'),
194
                    (b'', b'from', b'',
195
                      b''),
196
                    (b'', b'to', b'',
197
                      b''),
198
                    (b'', b'rhbranch', b'',
199
                      b''),
200
                    (b'', b'template', b'',
201
                       b'display with template')],
202
                   b'hg rhlog [OPTION]... [FILE]')
196 203
def rhlog(ui, repo, *pats, **opts):
197 204
    rev      = opts.pop('rev')
198 205
    bra0     = opts.pop('branch')
199
    from_rev = urllib.unquote_plus(opts.pop('from', None))
200
    to_rev   = urllib.unquote_plus(opts.pop('to'  , None))
201
    bra      = urllib.unquote_plus(opts.pop('rhbranch', None))
202
    from_rev = from_rev.replace('"', '\\"')
203
    to_rev   = to_rev.replace('"', '\\"')
204
    if hg.util.version() >= '1.6':
205
      opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)]
206
    else:
207
      opts['rev'] = ['%s:%s' % (from_rev, to_rev)]
208
    opts['branch'] = [bra]
209
    return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts)
210

  
211
@command('rhmanifest',
212
                   [('r', 'rev', '', 'show the specified revision')],
213
                   'hg rhmanifest [-r REV] [PATH]')
214
def rhmanifest(ui, repo, path='', **opts):
206
    from_rev = unquoteplus(opts.pop('from', b''))
207
    to_rev   = unquoteplus(opts.pop('to'  , b''))
208
    bra      = unquoteplus(opts.pop('rhbranch', b''))
209
    from_rev = from_rev.replace(b'"', b'\\"')
210
    to_rev   = to_rev.replace(b'"', b'\\"')
211
    if (from_rev != b'') or (to_rev != b''):
212
        if from_rev != b'':
213
            quotefrom = b'"%s"' % (from_rev)
214
        else:
215
            quotefrom = from_rev
216
        if to_rev != b'':
217
            quoteto = b'"%s"' % (to_rev)
218
        else:
219
            quoteto = to_rev
220
        opts['rev'] = [b'%s:%s' % (quotefrom, quoteto)]
221
        opts['rev'] = rev
222
    if (bra != b''):
223
        opts['branch'] = [bra]
224
    return commands.log(ui, repo, *map(unquoteplus, pats), **opts)
225

  
226
@command(b'rhmanifest',
227
                   [(b'r', b'rev', b'', b'show the specified revision')],
228
                   b'hg rhmanifest -r REV [PATH]')
229
def rhmanifest(ui, repo, path=b'', **opts):
215 230
    """output the sub-manifest of the specified directory"""
216
    ui.write('<?xml version="1.0"?>\n')
217
    ui.write('<rhmanifest>\n')
218
    ui.write('<repository root="%s">\n' % _u(repo.root))
231
    ui.write(b'<?xml version="1.0"?>\n')
232
    ui.write(b'<rhmanifest>\n')
233
    ui.write(b'<repository root="%s">\n' % _u(repo.root))
219 234
    try:
220
        _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev')))
235
        _manifest(ui, repo, unquoteplus(path), unquoteplus(opts.get('rev')))
221 236
    finally:
222
        ui.write('</repository>\n')
223
        ui.write('</rhmanifest>\n')
237
        ui.write(b'</repository>\n')
238
        ui.write(b'</rhmanifest>\n')
224 239

  
225
@command('rhsummary',[], 'hg rhsummary')
240
@command(b'rhsummary', [], b'hg rhsummary')
226 241
def rhsummary(ui, repo, **opts):
227 242
    """output the summary of the repository"""
228
    ui.write('<?xml version="1.0"?>\n')
229
    ui.write('<rhsummary>\n')
230
    ui.write('<repository root="%s">\n' % _u(repo.root))
243
    ui.write(b'<?xml version="1.0"?>\n')
244
    ui.write(b'<rhsummary>\n')
245
    ui.write(b'<repository root="%s">\n' % _u(repo.root))
231 246
    try:
232 247
        _tip(ui, repo)
233 248
        _tags(ui, repo)
234 249
        _branches(ui, repo)
235 250
        # TODO: bookmarks in core (Mercurial>=1.8)
236 251
    finally:
237
        ui.write('</repository>\n')
238
        ui.write('</rhsummary>\n')
252
        ui.write(b'</repository>\n')
253
        ui.write(b'</rhsummary>\n')
239 254

  
(1-1/3)