OLD | NEW |
(Empty) | |
| 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 # |
| 5 # Adapted from portage/getbinpkg.py -- Portage binary-package helper functions |
| 6 # Copyright 2003-2004 Gentoo Foundation |
| 7 # Distributed under the terms of the GNU General Public License v2 |
| 8 |
| 9 import operator |
| 10 import os |
| 11 import time |
| 12 import urllib2 |
| 13 |
| 14 class PackageIndex(object): |
| 15 |
| 16 def __init__(self): |
| 17 """Constructor.""" |
| 18 self.header = {} |
| 19 self.packages = [] |
| 20 self.modified = False |
| 21 |
| 22 def _ReadPkgIndex(self, pkgfile): |
| 23 """Read entry from packages file. |
| 24 |
| 25 Args: |
| 26 pkgfile: A python file object. |
| 27 """ |
| 28 d = {} |
| 29 for line in pkgfile: |
| 30 line = line.rstrip('\n') |
| 31 if not line: |
| 32 break |
| 33 line = line.split(': ', 1) |
| 34 if len(line) == 2: |
| 35 k, v = line |
| 36 d[k] = v |
| 37 return d |
| 38 |
| 39 def _WritePkgIndex(self, pkgfile, items): |
| 40 """Write entry to packages file. |
| 41 |
| 42 Args: |
| 43 pkgfile: A python file object. |
| 44 items: A list of tuples containing the entries to write. |
| 45 """ |
| 46 for k, v in items: |
| 47 pkgfile.write('%s: %s\n' % (k, v)) |
| 48 pkgfile.write('\n') |
| 49 |
| 50 def Read(self, pkgfile): |
| 51 """Read entire packages file. |
| 52 |
| 53 Args: |
| 54 pkgfile: A python file object. |
| 55 """ |
| 56 self.ReadHeader(pkgfile) |
| 57 self.ReadBody(pkgfile) |
| 58 |
| 59 def ReadHeader(self, pkgfile): |
| 60 """Read header of packages file. |
| 61 |
| 62 Args: |
| 63 pkgfile: A python file object. |
| 64 """ |
| 65 self.header.update(self._ReadPkgIndex(pkgfile)) |
| 66 |
| 67 def ReadBody(self, pkgfile): |
| 68 """Read body of packages file. |
| 69 |
| 70 Args: |
| 71 pkgfile: A python file object. |
| 72 """ |
| 73 while True: |
| 74 d = self._ReadPkgIndex(pkgfile) |
| 75 if not d: |
| 76 break |
| 77 if d.get('CPV'): |
| 78 self.packages.append(d) |
| 79 |
| 80 def Write(self, pkgfile): |
| 81 """Write a packages file to disk. |
| 82 |
| 83 Args: |
| 84 pkgfile: A python file object. |
| 85 """ |
| 86 if self.modified: |
| 87 self.header['TIMESTAMP'] = str(long(time.time())) |
| 88 self.header['PACKAGES'] = str(len(self.packages)) |
| 89 keys = list(self.header) |
| 90 keys.sort() |
| 91 self._WritePkgIndex(pkgfile, [(k, self.header[k]) \ |
| 92 for k in keys if self.header[k]]) |
| 93 for metadata in sorted(self.packages, key=operator.itemgetter('CPV')): |
| 94 cpv = metadata['CPV'] |
| 95 keys = list(metadata) |
| 96 keys.sort() |
| 97 self._WritePkgIndex(pkgfile, |
| 98 [(k, metadata[k]) for k in keys if metadata[k]]) |
| 99 |
| 100 |
| 101 def GrabRemotePackageIndex(binhost_url): |
| 102 """Grab the latest binary package database from the specified URL. |
| 103 |
| 104 Args: |
| 105 binhost_url: Base URL of remote packages (PORTAGE_BINHOST). |
| 106 |
| 107 Returns: |
| 108 A PackageIndex object |
| 109 """ |
| 110 |
| 111 def _RetryUrlOpen(url, tries=3): |
| 112 """Open the specified url, retrying if we run into temporary errors. |
| 113 |
| 114 We retry for both network errors and 5xx Server Errors. We do not retry |
| 115 for HTTP errors with a non-5xx code. |
| 116 |
| 117 Args: |
| 118 url: The specified url. |
| 119 tries: The number of times to try. |
| 120 |
| 121 Returns: |
| 122 The result of urllib2.urlopen(url). |
| 123 """ |
| 124 for i in range(tries): |
| 125 try: |
| 126 return urllib2.urlopen(url) |
| 127 except urllib2.HTTPError as e: |
| 128 if i + 1 >= tries or e.code < 500: |
| 129 raise |
| 130 else: |
| 131 print 'Cannot GET %s: %s' % (url, str(e)) |
| 132 except urllib2.URLError as e: |
| 133 if i + 1 >= tries: |
| 134 raise |
| 135 else: |
| 136 print 'Cannot GET %s: %s' % (url, str(e)) |
| 137 print "Sleeping for 10 seconds before retrying..." |
| 138 time.sleep(10) |
| 139 |
| 140 url = os.path.join(binhost_url, 'Packages') |
| 141 try: |
| 142 f = _RetryUrlOpen(url) |
| 143 except urllib2.HTTPError as e: |
| 144 if e.code == 404: |
| 145 return None |
| 146 raise |
| 147 |
| 148 pkgindex = PackageIndex() |
| 149 pkgindex.Read(f) |
| 150 f.close() |
| 151 return pkgindex |
| 152 |
| 153 |
OLD | NEW |