15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import json 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import logging 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import operator 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from appengine_url_fetcher import AppEngineUrlFetcher 10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)import url_constants 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 12424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)class ChannelInfo(object): 14424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) '''Represents a Chrome channel with three pieces of information. |channel| is 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci one of 'stable', 'beta', 'dev', or 'master'. |branch| and |version| correspond 16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) with each other, and represent different releases of Chrome. Note that 17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) |branch| and |version| can occasionally be the same for separate channels 18424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) (i.e. 'beta' and 'dev'), so all three fields are required to uniquely 19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) identify a channel. 20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ''' 21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) def __init__(self, channel, branch, version): 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) assert isinstance(channel, basestring), channel 244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) assert isinstance(branch, basestring), branch 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) # TODO(kalman): Assert that this is a string. One day Chromium will probably 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) # be served out of a git repository and the versions will no longer be ints. 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci assert isinstance(version, int) or version == 'master', version 287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) self.channel = channel 297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) self.branch = branch 307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) self.version = version 317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 32424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) def __eq__(self, other): 33424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return self.__dict__ == other.__dict__ 34424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 35424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) def __ne__(self, other): 36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return not (self == other) 37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def __repr__(self): 394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return '%s%s' % (type(self).__name__, repr(self.__dict__)) 404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def __str__(self): 424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return repr(self) 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 44424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BranchUtility(object): 46424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) '''Provides methods for working with Chrome channel, branch, and version 47424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) data served from OmahaProxy. 48424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ''' 49424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) def __init__(self, fetch_url, history_url, fetcher, object_store_creator): 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._fetcher = fetcher 52ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch def create_object_store(category): 53ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return object_store_creator.Create(BranchUtility, category=category) 54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch self._branch_object_store = create_object_store('branch') 55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch self._version_object_store = create_object_store('version') 567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) self._fetch_result = self._fetcher.FetchAsync(fetch_url) 577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) self._history_result = self._fetcher.FetchAsync(history_url) 587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) @staticmethod 60424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) def Create(object_store_creator): 61424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return BranchUtility(url_constants.OMAHA_PROXY_URL, 62424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) url_constants.OMAHA_DEV_HISTORY, 63424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) AppEngineUrlFetcher(), 64424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) object_store_creator) 65424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 66424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) @staticmethod 677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) def GetAllChannelNames(): 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return ('stable', 'beta', 'dev', 'master') 697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) @staticmethod 717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) def NewestChannel(channels): 72ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch channels = set(channels) 737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for channel in reversed(BranchUtility.GetAllChannelNames()): 747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if channel in channels: 757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return channel 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 77424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) def Newer(self, channel_info): 78424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) '''Given a ChannelInfo object, returns a new ChannelInfo object 79424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) representing the next most recent Chrome version/branch combination. 80424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ''' 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if channel_info.channel == 'master': 82424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return None 83424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if channel_info.channel == 'stable': 84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) stable_info = self.GetChannelInfo('stable') 85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if channel_info.version < stable_info.version: 86424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return self.GetStableChannelInfo(channel_info.version + 1) 87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) names = self.GetAllChannelNames() 88424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return self.GetAllChannelInfo()[names.index(channel_info.channel) + 1] 89424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 90424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) def Older(self, channel_info): 91424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) '''Given a ChannelInfo object, returns a new ChannelInfo object 92424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) representing the previous Chrome version/branch combination. 93424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ''' 94424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if channel_info.channel == 'stable': 95424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if channel_info.version <= 5: 96424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) # BranchUtility can't access branch data from before Chrome version 5. 97424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return None 98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return self.GetStableChannelInfo(channel_info.version - 1) 99424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) names = self.GetAllChannelNames() 100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return self.GetAllChannelInfo()[names.index(channel_info.channel) - 1] 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 102b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @staticmethod 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def SplitChannelNameFromPath(path): 1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) '''Splits the channel name out of |path|, returning the tuple 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (channel_name, real_path). If the channel cannot be determined then returns 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (None, path). 1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ''' 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if '/' in path: 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first, second = path.split('/', 1) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first, second = (path, '') 1127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if first in BranchUtility.GetAllChannelNames(): 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return (first, second) 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return (None, path) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 116424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) def GetAllBranches(self): 117424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return tuple((channel, self.GetChannelInfo(channel).branch) 1187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for channel in BranchUtility.GetAllChannelNames()) 1197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 120424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) def GetAllVersions(self): 121424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return tuple(self.GetChannelInfo(channel).version 1227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for channel in BranchUtility.GetAllChannelNames()) 1237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) def GetAllChannelInfo(self): 125424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return tuple(self.GetChannelInfo(channel) 1267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for channel in BranchUtility.GetAllChannelNames()) 1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) def GetChannelInfo(self, channel): 1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) version = self._ExtractFromVersionJson(channel, 'version') 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if version != 'master': 1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) version = int(version) 1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return ChannelInfo(channel, 1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) self._ExtractFromVersionJson(channel, 'branch'), 1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) version) 1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 137424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) def GetStableChannelInfo(self, version): 138424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) '''Given a |version| corresponding to a 'stable' version of Chrome, returns 139424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) a ChannelInfo object representing that version. 140424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ''' 141424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return ChannelInfo('stable', self.GetBranchForVersion(version), version) 142424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) def _ExtractFromVersionJson(self, channel_name, data_type): 1447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) '''Returns the branch or version number for a channel name. 1457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ''' 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if channel_name == 'master': 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return 'master' 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if data_type == 'branch': 1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) object_store = self._branch_object_store 1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) elif data_type == 'version': 1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) object_store = self._version_object_store 1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) data = object_store.Get(channel_name).Get() 1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if data is not None: 1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return data 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) try: 1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) version_json = json.loads(self._fetch_result.Get().content) 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) except Exception as e: 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # This can happen if omahaproxy is misbehaving, which we've seen before. 1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci # Quick hack fix: just serve from master until it's fixed. 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) logging.error('Failed to fetch or parse branch from omahaproxy: %s! ' 1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'Falling back to "master".' % e) 1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return 'master' 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) numbers = {} 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for entry in version_json: 16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if entry['os'] not in ('win', 'linux', 'mac', 'cros'): 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for version in entry['versions']: 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if version['channel'] != channel_name: 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if data_type == 'branch': 1757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) number = version['version'].split('.')[2] 1767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) elif data_type == 'version': 1777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) number = version['version'].split('.')[0] 1787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if number not in numbers: 1797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) numbers[number] = 0 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) numbers[number] += 1 1827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) sorted_numbers = sorted(numbers.iteritems(), 1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) key=operator.itemgetter(1), 1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reverse=True) 1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) object_store.Set(channel_name, sorted_numbers[0][0]) 1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return sorted_numbers[0][0] 1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) def GetBranchForVersion(self, version): 1907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) '''Returns the most recent branch for a given chrome version number using 1917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) data stored on omahaproxy (see url_constants). 1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ''' 1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if version == 'master': 1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return 'master' 1957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 196a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) branch = self._branch_object_store.Get(str(version)).Get() 1977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if branch is not None: 1987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return branch 1997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) version_json = json.loads(self._history_result.Get().content) 20146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) for entry in version_json: 20246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) version_title = entry['version'].split('.') 2037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if version_title[0] == str(version): 2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._branch_object_store.Set(str(version), version_title[2]) 2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return version_title[2] 2067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch raise ValueError('The branch for %s could not be found.' % version) 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def GetChannelForVersion(self, version): 210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch '''Returns the name of the development channel corresponding to a given 211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch version number. 212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ''' 213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for channel_info in self.GetAllChannelInfo(): 214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if channel_info.channel == 'stable' and version <= channel_info.version: 215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return channel_info.channel 216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if version == channel_info.version: 217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return channel_info.channel 2187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) def GetLatestVersionNumber(self): 2207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) '''Returns the most recent version number found using data stored on 2217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) omahaproxy. 2227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ''' 2237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) latest_version = self._version_object_store.Get('latest').Get() 2247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if latest_version is not None: 2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return latest_version 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) version_json = json.loads(self._history_result.Get().content) 2287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) latest_version = 0 22946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) for entry in version_json: 23046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) version_title = entry['version'].split('.') 2317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) version = int(version_title[0]) 2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if version > latest_version: 2337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) latest_version = version 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) self._version_object_store.Set('latest', latest_version) 2367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return latest_version 237