1 # vim:set encoding=utf-8:
2 ###############################################################################
4 # © 2006 Sanghyeon Seo <sanxiyn@gmail.com>
5 # © 2006 Pierre Habouzit <madcoder@debian.org>
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. The names of its contributors may not be used to endorse or promote
16 # products derived from this software without specific prior written
19 # THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
20 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
22 # EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 ###############################################################################
31 # @see http://projects.edgewall.com/trac/wiki/TracTickets
35 from BeautifulSoup import BeautifulSoup
36 from __init__ import *
38 any = re.compile(r'.*')
42 def __init__(self, page):
43 lines = page.split('\n');
46 keys = lines[0].split('\t')
47 vals = lines[1].split('\t')
48 dct = dict((keys[i], vals[i]) for i in range(0, len(keys)))
50 self.status = dct['status']
51 self.resolution = dct['resolution']
52 self.id = int(dct['id'])
53 self.reporter = dct['reporter']
54 self.owner = dct['owner']
55 self.summary = dct['summary']
56 self.milestone = dct['milestone']
57 self.version = dct['version']
58 self.priority = dct['priority']
59 self.description = dct['description'].replace("\\r\\n", "\r\n")
61 soup = BeautifulSoup(page)
63 status = soup.first(any, 'status')
65 self.status, self.resolution = self._process_status(status.strong.string)
69 self.status = soup.first(any, dict(headers='h_status')).string
70 resolution = soup.first(any, dict(headers='h_resolution')).string
71 self.resolution = (resolution != ' ' and resolution) or None
73 failwith(uri, "Probably error page")
75 def _process_status(self, text):
77 assert len(words) in (1, 2)
81 return [x.strip('()') for x in words]
85 def __init__(self, uri, id):
86 self.id = id or failwith(uri, "Trac: no id")
88 page = wget(uri + '?format=tab')
90 ticket = TracTicket(page)
92 self.status = ticket.status
93 self.resolution = ticket.resolution
96 failwith(uri, "Trac: no status")
98 if ticket.resolution == "duplicate":
102 class RemoteTrac(RemoteBts):
103 def __init__(self, cnf):
104 bugre = r"^%(uri)s/ticket/([0-9]+)$"
105 urifmt = "%(uri)s/ticket/%(id)s"
106 RemoteBts.__init__(self, cnf, bugre, urifmt, TracData)
108 def isClosing(self, status, resolution):
109 return status == 'closed' and resolution != 'wontfix'
111 def isWontfix(self, status, resolution):
112 return resolution == 'wontfix'
114 RemoteBts.register('trac', RemoteTrac)