diff options
Diffstat (limited to 'release-notes/trac.py')
-rw-r--r-- | release-notes/trac.py | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/release-notes/trac.py b/release-notes/trac.py new file mode 100644 index 0000000..91e781a --- /dev/null +++ b/release-notes/trac.py @@ -0,0 +1,136 @@ +# +# RTEMS Tools Project (http://www.rtems.org/) +# Copyright 2022 Chris Johns (chris@contemporary.software) +# All rights reserved. +# +# This file is part of the RTEMS Tools package in 'rtems-tools'. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +import pickle +import os +import urllib.request + + +class cache(object): + + def __init__(self, milestone, path, force): + self.milestone = milestone + self.path = path + self.force = force + self.checked = False + self.cache_valid = False + + @staticmethod + def _milestone(url): + path, options = url.split('?', 1) + opts = options.split('&') + for o in opts: + if 'milestone' in o: + label, milestone = o.split('=', 1) + return milestone + raise RuntimeError('milestone not found: ' + url) + + def _tickets_path(self): + return os.path.join(self.path, + 'tickets-%s' % (self.milestone) + '.ppk') + + def _ticket_path(self, url): + path, options = url.split('?', 1) + opts = options.split('&') + fmt = None + for o in opts: + if 'format' in o: + label, fmt = o.split('=', 1) + if not fmt: + raise RuntimeError('ticket format not found: ' + url) + if '/' in path: + ticket_id = path[path.rfind('/') + 1:] + return os.path.join(self.path, '%s.%s' % (ticket_id, fmt)) + raise RuntimeError('ticket id not found: ' + url) + + def _query_path(self): + return os.path.join(self.path, 'query-%s' % (self.milestone) + '.csv') + + def check(self): + if not self.checked: + self.checked = True + if self.path: + if os.path.exists(self.path): + if not os.path.isdir(self.path): + raise RuntimeError('cache is not a directory:' + + self.path) + else: + os.mkdir(self.path) + self.cache_valid = True + return self.cache_valid + + def open_page(self, url): + url_path = None + if self.check(): + if 'query' in url: + url_path = self._query_path() + else: + url_path = self._ticket_path(url) + if not self.force and os.path.exists(url_path): + return open(url_path, 'rb') + # Open the URL + delay = 1 + tries = 6 + backoff = 2 + while tries > 0: + try: + page = urllib.request.urlopen(url) + if url_path: + with open(url_path, 'wb') as f: + f.write(page.read()) + return open(url_path, 'rb') + return page + except OSError: + tries -= 1 + time.sleep(delay) + delay *= backoff + raise RuntimeError('cannot open url:' + url) + + def load(self): + if self.check(): + ticket_cache = self._tickets_path() + if os.path.exists(ticket_cache): + if not self.force: + try: + with open(ticket_cache, 'rb') as f: + tickets = pickle.load(f) + print('%d tickets loaded from cache: %s' % + (len(tickets['tickets']), ticket_cache)) + return tickets + except: + print('cache corrupted: ' + ticket_cache) + os.remove(ticket_cache) + return None + + def unload(self, tickets): + if self.check(): + ticket_cache = self._tickets_path() + with open(ticket_cache, 'wb') as f: + pickle.dump(tickets, f) |