Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Script that reads omahaproxy and gsutil to determine version of SDK to put | 6 """Script that reads omahaproxy and gsutil to determine version of SDK to put |
| 7 in manifest. | 7 in manifest. |
| 8 """ | 8 """ |
| 9 | 9 |
| 10 # pylint is convinced the email module is missing attributes | 10 # pylint is convinced the email module is missing attributes |
| 11 # pylint: disable=E1101 | 11 # pylint: disable=E1101 |
| 12 | 12 |
| 13 import buildbot_common | 13 import buildbot_common |
| 14 import csv | 14 import csv |
| 15 import cStringIO | 15 import cStringIO |
| 16 import difflib | 16 import difflib |
| 17 import email | 17 import email |
| 18 import json | |
| 19 import logging | 18 import logging |
| 20 import logging.handlers | 19 import logging.handlers |
| 21 import manifest_util | 20 import manifest_util |
| 22 import optparse | 21 import optparse |
| 23 import os | 22 import os |
| 24 import posixpath | 23 import posixpath |
| 25 import re | 24 import re |
| 26 import smtplib | 25 import smtplib |
| 27 import subprocess | 26 import subprocess |
| 28 import sys | 27 import sys |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 43 CANARY = 'canary' | 42 CANARY = 'canary' |
| 44 NACLPORTS_ARCHIVE_NAME = 'naclports.tar.bz2' | 43 NACLPORTS_ARCHIVE_NAME = 'naclports.tar.bz2' |
| 45 | 44 |
| 46 | 45 |
| 47 logger = logging.getLogger(__name__) | 46 logger = logging.getLogger(__name__) |
| 48 | 47 |
| 49 | 48 |
| 50 def SplitVersion(version_string): | 49 def SplitVersion(version_string): |
| 51 """Split a version string (e.g. "18.0.1025.163") into its components. | 50 """Split a version string (e.g. "18.0.1025.163") into its components. |
| 52 | 51 |
| 53 Note that this function doesn't handle versions in the form "trunk.###". | 52 e.g. |
| 53 SplitVersion("trunk.123456") => ("trunk", "123456") | |
| 54 SplitVersion("18.0.1025.163") => (18, 0, 1025, 163) | |
| 54 """ | 55 """ |
| 55 return tuple(map(int, version_string.split('.'))) | 56 parts = version_string.split('.') |
| 57 if parts[0] == 'trunk': | |
| 58 return (parts[0], int(parts[1])) | |
| 59 return map(int, parts) | |
|
Sam Clegg
2014/06/18 23:52:09
I prefer list comprehension but I guess its person
binji
2014/06/19 00:12:14
Done.
| |
| 60 | |
| 61 | |
| 62 def GetMajorVersion(version_string): | |
| 63 """Get the major version number from a version string (e.g. "18.0.1025.163"). | |
| 64 | |
| 65 e.g. | |
| 66 GetMajorVersion("trunk.123456") => "trunk" | |
| 67 GetMajorVersion("18.0.1025.163") => 18 | |
| 68 """ | |
| 69 return SplitVersion(version_string)[0] | |
| 70 | |
| 71 | |
| 72 def CompareVersions(version1, version2): | |
| 73 """Compare two version strings and return -1, 0, 1 (similar to cmp). | |
| 74 | |
| 75 Versions can only be compared if they are both trunk versions, or neither is. | |
| 76 | |
| 77 e.g. | |
| 78 CompareVersions("trunk.123", "trunk.456") => -1 | |
| 79 CompareVersions("18.0.1025.163", "37.0.2054.3") => -1 | |
| 80 CompareVersions("trunk.123", "18.0.1025.163") => Error | |
| 81 | |
| 82 """ | |
| 83 split1 = SplitVersion(version1) | |
| 84 split2 = SplitVersion(version2) | |
| 85 if split1[0] == split2[0]: | |
| 86 return cmp(split1[1:], split2[1:]) | |
| 87 | |
| 88 if split1 == 'trunk' or split2 == 'trunk': | |
| 89 raise Exception("Unable to compare versions %s and %s" % ( | |
| 90 version1, version2)) | |
| 91 | |
| 92 return cmp(split1, split2) | |
| 56 | 93 |
| 57 | 94 |
| 58 def JoinVersion(version_tuple): | 95 def JoinVersion(version_tuple): |
| 59 """Create a string from a version tuple. | 96 """Create a string from a version tuple. |
| 60 | 97 |
| 61 The tuple should be of the form (18, 0, 1025, 163). | 98 The tuple should be of the form (18, 0, 1025, 163). |
| 62 """ | 99 """ |
| 100 assert len(version_tuple) == 4 | |
| 101 assert version_tuple[0] != 'trunk' | |
| 63 return '.'.join(map(str, version_tuple)) | 102 return '.'.join(map(str, version_tuple)) |
| 64 | 103 |
| 65 | 104 |
| 66 def GetTimestampManifestName(): | 105 def GetTimestampManifestName(): |
| 67 """Create a manifest name with a timestamp. | 106 """Create a manifest name with a timestamp. |
| 68 | 107 |
| 69 Returns: | 108 Returns: |
| 70 A manifest name with an embedded date. This should make it easier to roll | 109 A manifest name with an embedded date. This should make it easier to roll |
| 71 back if necessary. | 110 back if necessary. |
| 72 """ | 111 """ |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 mac,stable,18.0.1025.168,2012-04-30 20:34:55.231141\n | 178 mac,stable,18.0.1025.168,2012-04-30 20:34:55.231141\n |
| 140 ... | 179 ... |
| 141 Where each line has comma separated values in the following format: | 180 Where each line has comma separated values in the following format: |
| 142 platform, channel, version, date/time\n | 181 platform, channel, version, date/time\n |
| 143 | 182 |
| 144 Returns: | 183 Returns: |
| 145 A list where each element is a line from the document, represented as a | 184 A list where each element is a line from the document, represented as a |
| 146 tuple.""" | 185 tuple.""" |
| 147 raise NotImplementedError() | 186 raise NotImplementedError() |
| 148 | 187 |
| 149 def GetTrunkRevision(self, version): | |
| 150 """Given a Chrome version, get its trunk revision. | |
| 151 | |
| 152 Args: | |
| 153 version: A version string of the form '18.0.1025.64' | |
| 154 Returns: | |
| 155 The revision number for that version, as a string.""" | |
| 156 raise NotImplementedError() | |
| 157 | |
| 158 def GsUtil_ls(self, url): | 188 def GsUtil_ls(self, url): |
| 159 """Runs gsutil ls |url| | 189 """Runs gsutil ls |url| |
| 160 | 190 |
| 161 Args: | 191 Args: |
| 162 url: The cloud storage url to list. | 192 url: The cloud storage url to list. |
| 163 Returns: | 193 Returns: |
| 164 A list of URLs, all with the gs:// schema.""" | 194 A list of URLs, all with the gs:// schema.""" |
| 165 raise NotImplementedError() | 195 raise NotImplementedError() |
| 166 | 196 |
| 167 def GsUtil_cat(self, url): | 197 def GsUtil_cat(self, url): |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 216 def GetHistory(self): | 246 def GetHistory(self): |
| 217 """See Delegate.GetHistory""" | 247 """See Delegate.GetHistory""" |
| 218 url_stream = urllib2.urlopen('https://omahaproxy.appspot.com/history') | 248 url_stream = urllib2.urlopen('https://omahaproxy.appspot.com/history') |
| 219 history = [(platform, channel, version, date) | 249 history = [(platform, channel, version, date) |
| 220 for platform, channel, version, date in csv.reader(url_stream)] | 250 for platform, channel, version, date in csv.reader(url_stream)] |
| 221 | 251 |
| 222 # The first line of this URL is the header: | 252 # The first line of this URL is the header: |
| 223 # os,channel,version,timestamp | 253 # os,channel,version,timestamp |
| 224 return history[1:] | 254 return history[1:] |
| 225 | 255 |
| 226 def GetTrunkRevision(self, version): | |
| 227 """See Delegate.GetTrunkRevision""" | |
| 228 url = 'http://omahaproxy.appspot.com/revision.json?version=%s' % (version,) | |
| 229 data = json.loads(urllib2.urlopen(url).read()) | |
| 230 return 'trunk.%s' % int(data['chromium_revision']) | |
| 231 | |
| 232 def GsUtil_ls(self, url): | 256 def GsUtil_ls(self, url): |
| 233 """See Delegate.GsUtil_ls""" | 257 """See Delegate.GsUtil_ls""" |
| 234 try: | 258 try: |
| 235 stdout = self._RunGsUtil(None, False, 'ls', url) | 259 stdout = self._RunGsUtil(None, False, 'ls', url) |
| 236 except subprocess.CalledProcessError: | 260 except subprocess.CalledProcessError: |
| 237 return [] | 261 return [] |
| 238 | 262 |
| 239 # filter out empty lines | 263 # filter out empty lines |
| 240 return filter(None, stdout.split('\n')) | 264 return filter(None, stdout.split('\n')) |
| 241 | 265 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 359 major_version: The major version of the pepper bundle, e.g. 19. | 383 major_version: The major version of the pepper bundle, e.g. 19. |
| 360 Returns: | 384 Returns: |
| 361 A tuple (version, channel, archives). The version is a string such as | 385 A tuple (version, channel, archives). The version is a string such as |
| 362 "19.0.1084.41". The channel is one of ('stable', 'beta', or 'dev'). | 386 "19.0.1084.41". The channel is one of ('stable', 'beta', or 'dev'). |
| 363 |archives| is a list of archive URLs.""" | 387 |archives| is a list of archive URLs.""" |
| 364 def GetPlatformHistory(platform): | 388 def GetPlatformHistory(platform): |
| 365 return self._GetPlatformMajorVersionHistory(major_version, platform) | 389 return self._GetPlatformMajorVersionHistory(major_version, platform) |
| 366 | 390 |
| 367 shared_version_generator = self._FindNextSharedVersion(self.platforms, | 391 shared_version_generator = self._FindNextSharedVersion(self.platforms, |
| 368 GetPlatformHistory) | 392 GetPlatformHistory) |
| 369 return self._DoGetMostRecentSharedVersion(shared_version_generator, | 393 return self._DoGetMostRecentSharedVersion(shared_version_generator) |
| 370 allow_trunk_revisions=False) | |
| 371 | 394 |
| 372 def GetMostRecentSharedCanary(self): | 395 def GetMostRecentSharedCanary(self): |
| 373 """Returns the most recent version of a canary pepper bundle that exists on | 396 """Returns the most recent version of a canary pepper bundle that exists on |
| 374 all given platforms. | 397 all given platforms. |
| 375 | 398 |
| 376 Canary is special-cased because we don't care about its major version; we | 399 Canary is special-cased because we don't care about its major version; we |
| 377 always use the most recent canary, regardless of major version. | 400 always use the most recent canary, regardless of major version. |
| 378 | 401 |
| 379 Returns: | 402 Returns: |
| 380 A tuple (version, channel, archives). The version is a string such as | 403 A tuple (version, channel, archives). The version is a string such as |
| 381 "19.0.1084.41". The channel is always 'canary'. |archives| is a list of | 404 "trunk.123456". The channel is always 'canary'. |archives| is a list of |
| 382 archive URLs.""" | 405 archive URLs.""" |
| 383 # Canary versions that differ in the last digit shouldn't be considered | 406 version_generator = self._FindNextTrunkVersion() |
| 384 # different; this number is typically used to represent an experiment, e.g. | 407 return self._DoGetMostRecentSharedVersion(version_generator) |
| 385 # using ASAN or aura. | |
| 386 def CanaryKey(version): | |
| 387 return version[:-1] | |
| 388 | 408 |
| 389 # We don't ship canary on Linux, so it won't appear in self.history. | 409 def GetAvailablePlatformArchivesFor(self, version): |
| 390 # Instead, we can use the matching Linux trunk build for that version. | |
| 391 shared_version_generator = self._FindNextSharedVersion( | |
| 392 set(self.platforms) - set(('linux',)), | |
| 393 self._GetPlatformCanaryHistory, CanaryKey) | |
| 394 return self._DoGetMostRecentSharedVersion(shared_version_generator, | |
| 395 allow_trunk_revisions=True) | |
| 396 | |
| 397 def GetAvailablePlatformArchivesFor(self, version, allow_trunk_revisions): | |
| 398 """Returns a sequence of archives that exist for a given version, on the | 410 """Returns a sequence of archives that exist for a given version, on the |
| 399 given platforms. | 411 given platforms. |
| 400 | 412 |
| 401 The second element of the returned tuple is a list of all platforms that do | 413 The second element of the returned tuple is a list of all platforms that do |
| 402 not have an archive for the given version. | 414 not have an archive for the given version. |
| 403 | 415 |
| 404 Args: | 416 Args: |
| 405 version: The version to find archives for. (e.g. "18.0.1025.164") | 417 version: The version to find archives for. (e.g. "18.0.1025.164") |
| 406 allow_trunk_revisions: If True, will search for archives using the | |
| 407 trunk revision that matches the branch version. | |
| 408 Returns: | 418 Returns: |
| 409 A tuple (archives, missing_archives). |archives| is a list of archive | 419 A tuple (archives, missing_archives). |archives| is a list of archive |
| 410 URLs, |missing_archives| is a list of archive names. | 420 URLs, |missing_archives| is a list of archive names. |
| 411 """ | 421 """ |
| 412 archive_urls = self._GetAvailableArchivesFor(version) | 422 archive_urls = self._GetAvailableArchivesFor(version) |
| 413 | 423 |
| 414 if self.is_bionic: | 424 if self.is_bionic: |
| 415 # Bionic currently is Linux-only. | 425 # Bionic currently is Linux-only. |
| 416 expected_archives = set([GetBionicArchiveName()]) | 426 expected_archives = set([GetBionicArchiveName()]) |
| 417 else: | 427 else: |
| 418 expected_archives = set(GetPlatformArchiveName(p) for p in self.platforms) | 428 expected_archives = set(GetPlatformArchiveName(p) for p in self.platforms) |
| 419 | 429 |
| 420 if self.extra_archives: | 430 if self.extra_archives: |
| 421 for extra_archive, extra_archive_min_version in self.extra_archives: | 431 for extra_archive, extra_archive_min_version in self.extra_archives: |
| 422 if SplitVersion(version) >= SplitVersion(extra_archive_min_version): | 432 if CompareVersions(version, extra_archive_min_version) >= 0: |
| 423 expected_archives.add(extra_archive) | 433 expected_archives.add(extra_archive) |
| 424 found_archives = set(GetCanonicalArchiveName(a) for a in archive_urls) | 434 found_archives = set(GetCanonicalArchiveName(a) for a in archive_urls) |
| 425 missing_archives = expected_archives - found_archives | 435 missing_archives = expected_archives - found_archives |
| 426 | 436 |
| 427 if allow_trunk_revisions and missing_archives: | |
| 428 # Try to find trunk versions of any missing archives. | |
| 429 trunk_version = self.delegate.GetTrunkRevision(version) | |
| 430 trunk_archives = self._GetAvailableArchivesFor(trunk_version) | |
| 431 for trunk_archive_url in trunk_archives: | |
| 432 trunk_archive = GetCanonicalArchiveName(trunk_archive_url) | |
| 433 if trunk_archive in missing_archives: | |
| 434 archive_urls.append(trunk_archive_url) | |
| 435 missing_archives.discard(trunk_archive) | |
| 436 | |
| 437 # Only return archives that are "expected". | 437 # Only return archives that are "expected". |
| 438 def IsExpected(url): | 438 def IsExpected(url): |
| 439 return GetCanonicalArchiveName(url) in expected_archives | 439 return GetCanonicalArchiveName(url) in expected_archives |
| 440 | 440 |
| 441 expected_archive_urls = [u for u in archive_urls if IsExpected(u)] | 441 expected_archive_urls = [u for u in archive_urls if IsExpected(u)] |
| 442 return expected_archive_urls, missing_archives | 442 return expected_archive_urls, missing_archives |
| 443 | 443 |
| 444 def _DoGetMostRecentSharedVersion(self, shared_version_generator, | 444 def _DoGetMostRecentSharedVersion(self, shared_version_generator): |
| 445 allow_trunk_revisions): | |
| 446 """Returns the most recent version of a pepper bundle that exists on all | 445 """Returns the most recent version of a pepper bundle that exists on all |
| 447 given platforms. | 446 given platforms. |
| 448 | 447 |
| 449 This function does the real work for the public GetMostRecentShared* above. | 448 This function does the real work for the public GetMostRecentShared* above. |
| 450 | 449 |
| 451 Args: | 450 Args: |
| 452 shared_version_generator: A generator that will yield (version, channel) | 451 shared_version_generator: A generator that will yield (version, channel) |
| 453 tuples in order of most recent to least recent. | 452 tuples in order of most recent to least recent. |
| 454 allow_trunk_revisions: If True, will search for archives using the | |
| 455 trunk revision that matches the branch version. | |
| 456 Returns: | 453 Returns: |
| 457 A tuple (version, channel, archives). The version is a string such as | 454 A tuple (version, channel, archives). The version is a string such as |
| 458 "19.0.1084.41". The channel is one of ('stable', 'beta', 'dev', | 455 "19.0.1084.41". The channel is one of ('stable', 'beta', 'dev', |
| 459 'canary'). |archives| is a list of archive URLs.""" | 456 'canary'). |archives| is a list of archive URLs.""" |
| 460 version = None | 457 version = None |
| 461 skipped_versions = [] | 458 skipped_versions = [] |
| 462 channel = '' | 459 channel = '' |
| 463 while True: | 460 while True: |
| 464 try: | 461 try: |
| 465 version, channel = shared_version_generator.next() | 462 version, channel = shared_version_generator.next() |
| 466 except StopIteration: | 463 except StopIteration: |
| 467 msg = 'No shared version for platforms: %s\n' % ( | 464 msg = 'No shared version for platforms: %s\n' % ( |
| 468 ', '.join(self.platforms)) | 465 ', '.join(self.platforms)) |
| 469 msg += 'Last version checked = %s.\n' % (version,) | 466 msg += 'Last version checked = %s.\n' % (version,) |
| 470 if skipped_versions: | 467 if skipped_versions: |
| 471 msg += 'Versions skipped due to missing archives:\n' | 468 msg += 'Versions skipped due to missing archives:\n' |
| 472 for version, channel, missing_archives in skipped_versions: | 469 for version, channel, missing_archives in skipped_versions: |
| 473 archive_msg = '(missing %s)' % (', '.join(missing_archives)) | 470 archive_msg = '(missing %s)' % (', '.join(missing_archives)) |
| 474 msg += ' %s (%s) %s\n' % (version, channel, archive_msg) | 471 msg += ' %s (%s) %s\n' % (version, channel, archive_msg) |
| 475 raise NoSharedVersionException(msg) | 472 raise NoSharedVersionException(msg) |
| 476 | 473 |
| 477 logger.info('Found shared version: %s, channel: %s' % ( | 474 logger.info('Found shared version: %s, channel: %s' % ( |
| 478 version, channel)) | 475 version, channel)) |
| 479 | 476 |
| 480 archives, missing_archives = self.GetAvailablePlatformArchivesFor( | 477 archives, missing_archives = self.GetAvailablePlatformArchivesFor(version) |
| 481 version, allow_trunk_revisions) | |
| 482 | 478 |
| 483 if not missing_archives: | 479 if not missing_archives: |
| 484 return version, channel, archives | 480 return version, channel, archives |
| 485 | 481 |
| 486 logger.info(' skipping. Missing archives: %s' % ( | 482 logger.info(' skipping. Missing archives: %s' % ( |
| 487 ', '.join(missing_archives))) | 483 ', '.join(missing_archives))) |
| 488 | 484 |
| 489 skipped_versions.append((version, channel, missing_archives)) | 485 skipped_versions.append((version, channel, missing_archives)) |
| 490 | 486 |
| 491 def _GetPlatformMajorVersionHistory(self, with_major_version, with_platform): | 487 def _GetPlatformMajorVersionHistory(self, with_major_version, with_platform): |
| 492 """Yields Chrome history for a given platform and major version. | 488 """Yields Chrome history for a given platform and major version. |
| 493 | 489 |
| 494 Args: | 490 Args: |
| 495 with_major_version: The major version to filter for. If 0, match all | 491 with_major_version: The major version to filter for. If 0, match all |
| 496 versions. | 492 versions. |
| 497 with_platform: The name of the platform to filter for. | 493 with_platform: The name of the platform to filter for. |
| 498 Returns: | 494 Returns: |
| 499 A generator that yields a tuple (channel, version) for each version that | 495 A generator that yields a tuple (channel, version) for each version that |
| 500 matches the platform and major version. The version returned is a tuple as | 496 matches the platform and major version. The version returned is a tuple as |
| 501 returned from SplitVersion. | 497 returned from SplitVersion. |
| 502 """ | 498 """ |
| 503 for platform, channel, version, _ in self.history: | 499 for platform, channel, version, _ in self.history: |
| 504 version = SplitVersion(version) | 500 version = SplitVersion(version) |
| 505 if (with_platform == platform and | 501 if (with_platform == platform and |
| 506 (with_major_version == 0 or with_major_version == version[0])): | 502 (with_major_version == 0 or with_major_version == version[0])): |
| 507 yield channel, version | 503 yield channel, version |
| 508 | 504 |
| 509 def _GetPlatformCanaryHistory(self, with_platform): | 505 def _FindNextSharedVersion(self, platforms, generator_func): |
| 510 """Yields Chrome history for a given platform, but only for canary | |
| 511 versions. | |
| 512 | |
| 513 Args: | |
| 514 with_platform: The name of the platform to filter for. | |
| 515 Returns: | |
| 516 A generator that yields a tuple (channel, version) for each version that | |
| 517 matches the platform and uses the canary channel. The version returned is | |
| 518 a tuple as returned from SplitVersion. | |
| 519 """ | |
| 520 for platform, channel, version, _ in self.history: | |
| 521 version = SplitVersion(version) | |
| 522 if with_platform == platform and channel == CANARY: | |
| 523 yield channel, version | |
| 524 | |
| 525 | |
| 526 def _FindNextSharedVersion(self, platforms, generator_func, key_func=None): | |
| 527 """Yields versions of Chrome that exist on all given platforms, in order of | 506 """Yields versions of Chrome that exist on all given platforms, in order of |
| 528 newest to oldest. | 507 newest to oldest. |
| 529 | 508 |
| 530 Versions are compared in reverse order of release. That is, the most | 509 Versions are compared in reverse order of release. That is, the most |
| 531 recently updated version will be tested first. | 510 recently updated version will be tested first. |
| 532 | 511 |
| 533 Args: | 512 Args: |
| 534 platforms: A sequence of platforms to consider, e.g. | 513 platforms: A sequence of platforms to consider, e.g. |
| 535 ('mac', 'linux', 'win') | 514 ('mac', 'linux', 'win') |
| 536 generator_func: A function which takes a platform and returns a | 515 generator_func: A function which takes a platform and returns a |
| 537 generator that yields (channel, version) tuples. | 516 generator that yields (channel, version) tuples. |
| 538 key_func: A function to convert the version into a value that should be | |
| 539 used for comparison. See python built-in sorted() or min(), for | |
| 540 an example. | |
| 541 Returns: | 517 Returns: |
| 542 A generator that yields a tuple (version, channel) for each version that | 518 A generator that yields a tuple (version, channel) for each version that |
| 543 matches all platforms and the major version. The version returned is a | 519 matches all platforms and the major version. The version returned is a |
| 544 string (e.g. "18.0.1025.164"). | 520 string (e.g. "18.0.1025.164"). |
| 545 """ | 521 """ |
| 546 if not key_func: | |
| 547 key_func = lambda x: x | |
| 548 | |
| 549 platform_generators = [] | 522 platform_generators = [] |
| 550 for platform in platforms: | 523 for platform in platforms: |
| 551 platform_generators.append(generator_func(platform)) | 524 platform_generators.append(generator_func(platform)) |
| 552 | 525 |
| 553 shared_version = None | 526 shared_version = None |
| 554 platform_versions = [] | 527 platform_versions = [] |
| 555 for platform_gen in platform_generators: | 528 for platform_gen in platform_generators: |
| 556 platform_versions.append(platform_gen.next()) | 529 platform_versions.append(platform_gen.next()) |
| 557 | 530 |
| 558 while True: | 531 while True: |
| 559 if logger.isEnabledFor(logging.INFO): | 532 if logger.isEnabledFor(logging.INFO): |
| 560 msg_info = [] | 533 msg_info = [] |
| 561 for i, platform in enumerate(platforms): | 534 for i, platform in enumerate(platforms): |
| 562 msg_info.append('%s: %s' % ( | 535 msg_info.append('%s: %s' % ( |
| 563 platform, JoinVersion(platform_versions[i][1]))) | 536 platform, JoinVersion(platform_versions[i][1]))) |
| 564 logger.info('Checking versions: %s' % ', '.join(msg_info)) | 537 logger.info('Checking versions: %s' % ', '.join(msg_info)) |
| 565 | 538 |
| 566 shared_version = min((v for c, v in platform_versions), key=key_func) | 539 shared_version = min((v for c, v in platform_versions)) |
| 567 | 540 |
| 568 if all(key_func(v) == key_func(shared_version) | 541 if all(v == shared_version for c, v in platform_versions): |
| 569 for c, v in platform_versions): | |
| 570 # The real shared_version should be the real minimum version. This will | |
| 571 # be different from shared_version above only if key_func compares two | |
| 572 # versions with different values as equal. | |
| 573 min_version = min((v for c, v in platform_versions)) | |
| 574 | |
| 575 # grab the channel from an arbitrary platform | 542 # grab the channel from an arbitrary platform |
| 576 first_platform = platform_versions[0] | 543 first_platform = platform_versions[0] |
| 577 channel = first_platform[0] | 544 channel = first_platform[0] |
| 578 yield JoinVersion(min_version), channel | 545 yield JoinVersion(shared_version), channel |
| 579 | 546 |
| 580 # force increment to next version for all platforms | 547 # force increment to next version for all platforms |
| 581 shared_version = None | 548 shared_version = None |
| 582 | 549 |
| 583 # Find the next version for any platform that isn't at the shared version. | 550 # Find the next version for any platform that isn't at the shared version. |
| 584 try: | 551 try: |
| 585 for i, platform_gen in enumerate(platform_generators): | 552 for i, platform_gen in enumerate(platform_generators): |
| 586 if platform_versions[i][1] != shared_version: | 553 if platform_versions[i][1] != shared_version: |
| 587 platform_versions[i] = platform_gen.next() | 554 platform_versions[i] = platform_gen.next() |
| 588 except StopIteration: | 555 except StopIteration: |
| 589 return | 556 return |
| 590 | 557 |
| 591 | 558 |
| 559 def _FindNextTrunkVersion(self): | |
| 560 """Yields all trunk versions that exist in the cloud storage bucket, newest | |
| 561 to oldest. | |
| 562 | |
| 563 Returns: | |
| 564 A generator that yields a tuple (version, channel) for each version that | |
| 565 matches all platforms and the major version. The version returned is a | |
| 566 string (e.g. "trunk.123456"). | |
| 567 """ | |
| 568 files = self.delegate.GsUtil_ls(GS_BUCKET_PATH) | |
| 569 assert all(f.startswith('gs://') for f in files) | |
| 570 | |
| 571 trunk_versions = [] | |
| 572 for f in files: | |
| 573 match = re.search(r'(trunk\.\d+)', f) | |
| 574 if match: | |
| 575 trunk_versions.append(match.group(1)) | |
| 576 | |
| 577 trunk_versions.sort(reverse=True) | |
| 578 | |
| 579 for version in trunk_versions: | |
| 580 yield version, 'canary' | |
| 581 | |
| 582 | |
| 592 def _GetAvailableArchivesFor(self, version_string): | 583 def _GetAvailableArchivesFor(self, version_string): |
| 593 """Downloads a list of all available archives for a given version. | 584 """Downloads a list of all available archives for a given version. |
| 594 | 585 |
| 595 Args: | 586 Args: |
| 596 version_string: The version to find archives for. (e.g. "18.0.1025.164") | 587 version_string: The version to find archives for. (e.g. "18.0.1025.164") |
| 597 Returns: | 588 Returns: |
| 598 A list of strings, each of which is a platform-specific archive URL. (e.g. | 589 A list of strings, each of which is a platform-specific archive URL. (e.g. |
| 599 "gs://nativeclient_mirror/nacl/nacl_sdk/18.0.1025.164/" | 590 "gs://nativeclient_mirror/nacl/nacl_sdk/18.0.1025.164/" |
| 600 "naclsdk_linux.tar.bz2"). | 591 "naclsdk_linux.tar.bz2"). |
| 601 | 592 |
| 602 All returned URLs will use the gs:// schema.""" | 593 All returned URLs will use the gs:// schema.""" |
| 603 files = self.delegate.GsUtil_ls(GS_BUCKET_PATH + version_string) | 594 files = self.delegate.GsUtil_ls(GS_BUCKET_PATH + version_string) |
| 604 | 595 |
| 605 assert all(file.startswith('gs://') for file in files) | 596 assert all(f.startswith('gs://') for f in files) |
| 606 | 597 |
| 607 archives = [f for f in files if not f.endswith('.json')] | 598 archives = [f for f in files if not f.endswith('.json')] |
| 608 manifests = [f for f in files if f.endswith('.json')] | 599 manifests = [f for f in files if f.endswith('.json')] |
| 609 | 600 |
| 610 # don't include any archives that don't have an associated manifest. | 601 # don't include any archives that don't have an associated manifest. |
| 611 return filter(lambda a: a + '.json' in manifests, archives) | 602 return filter(lambda a: a + '.json' in manifests, archives) |
| 612 | 603 |
| 613 | 604 |
| 614 class UnknownLockedBundleException(Exception): | 605 class UnknownLockedBundleException(Exception): |
| 615 pass | 606 pass |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 650 | 641 |
| 651 Note that bundles will not be updated if the current version is newer. | 642 Note that bundles will not be updated if the current version is newer. |
| 652 That is, the updater will never automatically update to an older version of | 643 That is, the updater will never automatically update to an older version of |
| 653 a bundle. | 644 a bundle. |
| 654 | 645 |
| 655 Args: | 646 Args: |
| 656 manifest: The manifest used as a template for updating. Only pepper | 647 manifest: The manifest used as a template for updating. Only pepper |
| 657 bundles that contain no archives will be considered for auto-updating.""" | 648 bundles that contain no archives will be considered for auto-updating.""" |
| 658 # Make sure there is only one stable branch: the one with the max version. | 649 # Make sure there is only one stable branch: the one with the max version. |
| 659 # All others are post-stable. | 650 # All others are post-stable. |
| 660 stable_major_versions = [SplitVersion(version)[0] for _, version, channel, _ | 651 stable_major_versions = [GetMajorVersion(version) for _, version, channel, _ |
| 661 in self.versions_to_update if channel == 'stable'] | 652 in self.versions_to_update if channel == 'stable'] |
| 662 # Add 0 in case there are no stable versions. | 653 # Add 0 in case there are no stable versions. |
| 663 max_stable_version = max([0] + stable_major_versions) | 654 max_stable_version = max([0] + stable_major_versions) |
| 664 | 655 |
| 665 # Ensure that all locked bundles exist in the online manifest. | 656 # Ensure that all locked bundles exist in the online manifest. |
| 666 for bundle_name in self.locked_bundles: | 657 for bundle_name in self.locked_bundles: |
| 667 online_bundle = self.online_manifest.GetBundle(bundle_name) | 658 online_bundle = self.online_manifest.GetBundle(bundle_name) |
| 668 if online_bundle: | 659 if online_bundle: |
| 669 manifest.SetBundle(online_bundle) | 660 manifest.SetBundle(online_bundle) |
| 670 else: | 661 else: |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 690 bundle = manifest.GetBundle(bundle_name) | 681 bundle = manifest.GetBundle(bundle_name) |
| 691 for archive in archives: | 682 for archive in archives: |
| 692 platform_bundle = self._GetPlatformArchiveBundle(archive) | 683 platform_bundle = self._GetPlatformArchiveBundle(archive) |
| 693 # Normally the manifest snippet's bundle name matches our bundle name. | 684 # Normally the manifest snippet's bundle name matches our bundle name. |
| 694 # pepper_canary, however is called "pepper_###" in the manifest | 685 # pepper_canary, however is called "pepper_###" in the manifest |
| 695 # snippet. | 686 # snippet. |
| 696 platform_bundle.name = bundle_name | 687 platform_bundle.name = bundle_name |
| 697 bundle.MergeWithBundle(platform_bundle) | 688 bundle.MergeWithBundle(platform_bundle) |
| 698 | 689 |
| 699 # Fix the stability and recommended values | 690 # Fix the stability and recommended values |
| 700 major_version = SplitVersion(version)[0] | 691 major_version = GetMajorVersion(version) |
| 701 if major_version < max_stable_version: | 692 if major_version < max_stable_version: |
| 702 bundle.stability = 'post_stable' | 693 bundle.stability = 'post_stable' |
| 703 else: | 694 else: |
| 704 bundle.stability = channel | 695 bundle.stability = channel |
| 705 # We always recommend the stable version. | 696 # We always recommend the stable version. |
| 706 if bundle.stability == 'stable': | 697 if bundle.stability == 'stable': |
| 707 bundle.recommended = 'yes' | 698 bundle.recommended = 'yes' |
| 708 else: | 699 else: |
| 709 bundle.recommended = 'no' | 700 bundle.recommended = 'no' |
| 710 | 701 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 825 if not auto_update_bundles: | 816 if not auto_update_bundles: |
| 826 logger.info('No versions need auto-updating.') | 817 logger.info('No versions need auto-updating.') |
| 827 return | 818 return |
| 828 | 819 |
| 829 updater = Updater(delegate) | 820 updater = Updater(delegate) |
| 830 | 821 |
| 831 for bundle in auto_update_bundles: | 822 for bundle in auto_update_bundles: |
| 832 try: | 823 try: |
| 833 if bundle.name == BIONIC_CANARY_BUNDLE_NAME: | 824 if bundle.name == BIONIC_CANARY_BUNDLE_NAME: |
| 834 logger.info('>>> Looking for most recent bionic_canary...') | 825 logger.info('>>> Looking for most recent bionic_canary...') |
| 835 version_finder = VersionFinder(delegate, platforms, extra_archives, | 826 # Ignore extra_archives on bionic; There is no naclports bundle yet. |
| 827 version_finder = VersionFinder(delegate, platforms, None, | |
| 836 is_bionic=True) | 828 is_bionic=True) |
| 837 version, channel, archives = version_finder.GetMostRecentSharedCanary() | 829 version, channel, archives = version_finder.GetMostRecentSharedCanary() |
| 838 elif bundle.name == CANARY_BUNDLE_NAME: | 830 elif bundle.name == CANARY_BUNDLE_NAME: |
| 839 logger.info('>>> Looking for most recent pepper_canary...') | 831 logger.info('>>> Looking for most recent pepper_canary...') |
| 840 version_finder = VersionFinder(delegate, platforms, extra_archives) | 832 version_finder = VersionFinder(delegate, platforms, extra_archives) |
| 841 version, channel, archives = version_finder.GetMostRecentSharedCanary() | 833 version, channel, archives = version_finder.GetMostRecentSharedCanary() |
| 842 else: | 834 else: |
| 843 logger.info('>>> Looking for most recent pepper_%s...' % | 835 logger.info('>>> Looking for most recent pepper_%s...' % |
| 844 bundle.version) | 836 bundle.version) |
| 845 version_finder = VersionFinder(delegate, platforms, extra_archives) | 837 version_finder = VersionFinder(delegate, platforms, extra_archives) |
| 846 version, channel, archives = version_finder.GetMostRecentSharedVersion( | 838 version, channel, archives = version_finder.GetMostRecentSharedVersion( |
| 847 bundle.version) | 839 bundle.version) |
| 848 except NoSharedVersionException: | 840 except NoSharedVersionException: |
| 849 # If we can't find a shared version, make sure that there is an uploaded | 841 # If we can't find a shared version, make sure that there is an uploaded |
| 850 # bundle with that name already. | 842 # bundle with that name already. |
| 851 updater.AddLockedBundle(bundle.name) | 843 updater.AddLockedBundle(bundle.name) |
| 852 continue | 844 continue |
| 853 | 845 |
| 854 if bundle.name in fixed_bundle_versions: | 846 if bundle.name in fixed_bundle_versions: |
| 855 # Ensure this version is valid for all platforms. | 847 # Ensure this version is valid for all platforms. |
| 856 # If it is, use the channel found above (because the channel for this | 848 # If it is, use the channel found above (because the channel for this |
| 857 # version may not be in the history.) | 849 # version may not be in the history.) |
| 858 version = fixed_bundle_versions[bundle.name] | 850 version = fixed_bundle_versions[bundle.name] |
| 859 logger.info('Fixed bundle version: %s, %s' % (bundle.name, version)) | 851 logger.info('Fixed bundle version: %s, %s' % (bundle.name, version)) |
| 860 allow_trunk_revisions = bundle.name == CANARY_BUNDLE_NAME | 852 archives, missing = \ |
| 861 archives, missing = version_finder.GetAvailablePlatformArchivesFor( | 853 version_finder.GetAvailablePlatformArchivesFor(version) |
| 862 version, allow_trunk_revisions) | |
| 863 if missing: | 854 if missing: |
| 864 logger.warn( | 855 logger.warn( |
| 865 'Some archives for version %s of bundle %s don\'t exist: ' | 856 'Some archives for version %s of bundle %s don\'t exist: ' |
| 866 'Missing %s' % (version, bundle.name, ', '.join(missing))) | 857 'Missing %s' % (version, bundle.name, ', '.join(missing))) |
| 867 return | 858 return |
| 868 | 859 |
| 869 updater.AddVersionToUpdate(bundle.name, version, channel, archives) | 860 updater.AddVersionToUpdate(bundle.name, version, channel, archives) |
| 870 | 861 |
| 871 updater.Update(manifest) | 862 updater.Update(manifest) |
| 872 | 863 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 962 gsutil_logging_handler.upload() | 953 gsutil_logging_handler.upload() |
| 963 except manifest_util.Error as e: | 954 except manifest_util.Error as e: |
| 964 if options.debug: | 955 if options.debug: |
| 965 raise | 956 raise |
| 966 sys.stderr.write(str(e) + '\n') | 957 sys.stderr.write(str(e) + '\n') |
| 967 return 1 | 958 return 1 |
| 968 | 959 |
| 969 | 960 |
| 970 if __name__ == '__main__': | 961 if __name__ == '__main__': |
| 971 sys.exit(main(sys.argv)) | 962 sys.exit(main(sys.argv)) |
| OLD | NEW |