Revision 1297:0a574315af3e .svn/pristine/a2

View differences:

.svn/pristine/a2/a228c3d0b7910e4eb07f95e583bb22e9efe2f4c4.svn-base
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

  
10
To test this extension, please try::
11

  
12
    $ hg --config extensions.redminehelper=redminehelper.py rhsummary
13

  
14
I/O encoding:
15

  
16
:file path: urlencoded, raw string
17
:tag name: utf-8
18
:branch name: utf-8
19
:node: 12-digits (short) hex string
20

  
21
Output example of rhsummary::
22

  
23
    <?xml version="1.0"?>
24
    <rhsummary>
25
      <repository root="/foo/bar">
26
        <tip revision="1234" node="abcdef0123..."/>
27
        <tag revision="123" node="34567abc..." name="1.1.1"/>
28
        <branch .../>
29
        ...
30
      </repository>
31
    </rhsummary>
32

  
33
Output example of rhmanifest::
34

  
35
    <?xml version="1.0"?>
36
    <rhmanifest>
37
      <repository root="/foo/bar">
38
        <manifest revision="1234" path="lib">
39
          <file name="diff.rb" revision="123" node="34567abc..." time="12345"
40
                 size="100"/>
41
          ...
42
          <dir name="redmine"/>
43
          ...
44
        </manifest>
45
      </repository>
46
    </rhmanifest>
47
"""
48
import re, time, cgi, urllib
49
from mercurial import cmdutil, commands, node, error, hg
50

  
51
_x = cgi.escape
52
_u = lambda s: cgi.escape(urllib.quote(s))
53

  
54
def _tip(ui, repo):
55
    # see mercurial/commands.py:tip
56
    def tiprev():
57
        try:
58
            return len(repo) - 1
59
        except TypeError:  # Mercurial < 1.1
60
            return repo.changelog.count() - 1
61
    tipctx = repo.changectx(tiprev())
62
    ui.write('<tip revision="%d" node="%s"/>\n'
63
             % (tipctx.rev(), _x(node.short(tipctx.node()))))
64

  
65
_SPECIAL_TAGS = ('tip',)
66

  
67
def _tags(ui, repo):
68
    # see mercurial/commands.py:tags
69
    for t, n in reversed(repo.tagslist()):
70
        if t in _SPECIAL_TAGS:
71
            continue
72
        try:
73
            r = repo.changelog.rev(n)
74
        except error.LookupError:
75
            continue
76
        ui.write('<tag revision="%d" node="%s" name="%s"/>\n'
77
                 % (r, _x(node.short(n)), _x(t)))
78

  
79
def _branches(ui, repo):
80
    # see mercurial/commands.py:branches
81
    def iterbranches():
82
        for t, n in repo.branchtags().iteritems():
83
            yield t, n, repo.changelog.rev(n)
84
    def branchheads(branch):
85
        try:
86
            return repo.branchheads(branch, closed=False)
87
        except TypeError:  # Mercurial < 1.2
88
            return repo.branchheads(branch)
89
    for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True):
90
        if repo.lookup(r) in branchheads(t):
91
            ui.write('<branch revision="%d" node="%s" name="%s"/>\n'
92
                     % (r, _x(node.short(n)), _x(t)))
93

  
94
def _manifest(ui, repo, path, rev):
95
    ctx = repo.changectx(rev)
96
    ui.write('<manifest revision="%d" path="%s">\n'
97
             % (ctx.rev(), _u(path)))
98

  
99
    known = set()
100
    pathprefix = (path.rstrip('/') + '/').lstrip('/')
101
    for f, n in sorted(ctx.manifest().iteritems(), key=lambda e: e[0]):
102
        if not f.startswith(pathprefix):
103
            continue
104
        name = re.sub(r'/.*', '/', f[len(pathprefix):])
105
        if name in known:
106
            continue
107
        known.add(name)
108

  
109
        if name.endswith('/'):
110
            ui.write('<dir name="%s"/>\n'
111
                     % _x(urllib.quote(name[:-1])))
112
        else:
113
            fctx = repo.filectx(f, fileid=n)
114
            tm, tzoffset = fctx.date()
115
            ui.write('<file name="%s" revision="%d" node="%s" '
116
                     'time="%d" size="%d"/>\n'
117
                     % (_u(name), fctx.rev(), _x(node.short(fctx.node())),
118
                        tm, fctx.size(), ))
119

  
120
    ui.write('</manifest>\n')
121

  
122
def rhannotate(ui, repo, *pats, **opts):
123
    rev = urllib.unquote_plus(opts.pop('rev', None))
124
    opts['rev'] = rev
125
    return commands.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts)
126

  
127
def rhcat(ui, repo, file1, *pats, **opts):
128
    rev = urllib.unquote_plus(opts.pop('rev', None))
129
    opts['rev'] = rev
130
    return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts)
131

  
132
def rhdiff(ui, repo, *pats, **opts):
133
    """diff repository (or selected files)"""
134
    change = opts.pop('change', None)
135
    if change:  # add -c option for Mercurial<1.1
136
        base = repo.changectx(change).parents()[0].rev()
137
        opts['rev'] = [str(base), change]
138
    opts['nodates'] = True
139
    return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)
140

  
141
def rhlog(ui, repo, *pats, **opts):
142
    rev      = opts.pop('rev')
143
    bra0     = opts.pop('branch')
144
    from_rev = urllib.unquote_plus(opts.pop('from', None))
145
    to_rev   = urllib.unquote_plus(opts.pop('to'  , None))
146
    bra      = urllib.unquote_plus(opts.pop('rhbranch', None))
147
    from_rev = from_rev.replace('"', '\\"')
148
    to_rev   = to_rev.replace('"', '\\"')
149
    if hg.util.version() >= '1.6':
150
      opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)]
151
    else:
152
      opts['rev'] = ['%s:%s' % (from_rev, to_rev)]
153
    opts['branch'] = [bra]
154
    return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts)
155

  
156
def rhmanifest(ui, repo, path='', **opts):
157
    """output the sub-manifest of the specified directory"""
158
    ui.write('<?xml version="1.0"?>\n')
159
    ui.write('<rhmanifest>\n')
160
    ui.write('<repository root="%s">\n' % _u(repo.root))
161
    try:
162
        _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev')))
163
    finally:
164
        ui.write('</repository>\n')
165
        ui.write('</rhmanifest>\n')
166

  
167
def rhsummary(ui, repo, **opts):
168
    """output the summary of the repository"""
169
    ui.write('<?xml version="1.0"?>\n')
170
    ui.write('<rhsummary>\n')
171
    ui.write('<repository root="%s">\n' % _u(repo.root))
172
    try:
173
        _tip(ui, repo)
174
        _tags(ui, repo)
175
        _branches(ui, repo)
176
        # TODO: bookmarks in core (Mercurial>=1.8)
177
    finally:
178
        ui.write('</repository>\n')
179
        ui.write('</rhsummary>\n')
180

  
181
cmdtable = {
182
    'rhannotate': (rhannotate,
183
         [('r', 'rev', '', 'revision'),
184
          ('u', 'user', None, 'list the author (long with -v)'),
185
          ('n', 'number', None, 'list the revision number (default)'),
186
          ('c', 'changeset', None, 'list the changeset'),
187
         ],
188
         'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...'),
189
    'rhcat': (rhcat,
190
               [('r', 'rev', '', 'revision')],
191
               'hg rhcat ([-r REV] ...) FILE...'),
192
    'rhdiff': (rhdiff,
193
               [('r', 'rev', [], 'revision'),
194
                ('c', 'change', '', 'change made by revision')],
195
               'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'),
196
    'rhlog': (rhlog,
197
                   [
198
                    ('r', 'rev', [], 'show the specified revision'),
199
                    ('b', 'branch', [],
200
                       'show changesets within the given named branch'),
201
                    ('l', 'limit', '',
202
                         'limit number of changes displayed'),
203
                    ('d', 'date', '',
204
                         'show revisions matching date spec'),
205
                    ('u', 'user', [],
206
                      'revisions committed by user'),
207
                    ('', 'from', '',
208
                      ''),
209
                    ('', 'to', '',
210
                      ''),
211
                    ('', 'rhbranch', '',
212
                      ''),
213
                    ('', 'template', '',
214
                       'display with template')],
215
                   'hg rhlog [OPTION]... [FILE]'),
216
    'rhmanifest': (rhmanifest,
217
                   [('r', 'rev', '', 'show the specified revision')],
218
                   'hg rhmanifest [-r REV] [PATH]'),
219
    'rhsummary': (rhsummary, [], 'hg rhsummary'),
220
}
.svn/pristine/a2/a268aadf60b30880792c7f50cf7c1f07f63819c9.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2012  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.expand_path('../../../test_helper', __FILE__)
19

  
20
class ApiTest::JsonpTest < ActionController::IntegrationTest
21
  fixtures :trackers
22

  
23
  def test_jsonp_should_accept_callback_param
24
    get '/trackers.json?callback=handler'
25

  
26
    assert_response :success
27
    assert_match %r{^handler\(\{"trackers":.+\}\)$}, response.body
28
    assert_equal 'application/javascript; charset=utf-8', response.headers['Content-Type']
29
  end
30

  
31
  def test_jsonp_should_accept_jsonp_param
32
    get '/trackers.json?jsonp=handler'
33

  
34
    assert_response :success
35
    assert_match %r{^handler\(\{"trackers":.+\}\)$}, response.body
36
    assert_equal 'application/javascript; charset=utf-8', response.headers['Content-Type']
37
  end
38

  
39
  def test_jsonp_should_strip_invalid_characters_from_callback
40
    get '/trackers.json?callback=+-aA$1_'
41

  
42
    assert_response :success
43
    assert_match %r{^aA1_\(\{"trackers":.+\}\)$}, response.body
44
    assert_equal 'application/javascript; charset=utf-8', response.headers['Content-Type']
45
  end
46

  
47
  def test_jsonp_without_callback_should_return_json
48
    get '/trackers.json?callback='
49

  
50
    assert_response :success
51
    assert_match %r{^\{"trackers":.+\}$}, response.body
52
    assert_equal 'application/json; charset=utf-8', response.headers['Content-Type']
53
  end
54
end

Also available in: Unified diff