branch_utility.py revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1# Copyright (c) 2012 The Chromium 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
5import json
6import logging
7
8import object_store
9import operator
10
11class BranchUtility(object):
12  def __init__(self, base_path, fetcher, object_store):
13    self._base_path = base_path
14    self._fetcher = fetcher
15    self._object_store = object_store
16
17  @staticmethod
18  def GetAllBranchNames():
19    return ['stable', 'beta', 'dev', 'trunk']
20
21  def GetAllBranchNumbers(self):
22    return [(branch, self.GetBranchNumberForChannelName(branch))
23            for branch in BranchUtility.GetAllBranchNames()]
24
25  def SplitChannelNameFromPath(self, path):
26    """Splits the channel name out of |path|, returning the tuple
27    (channel_name, real_path). If the channel cannot be determined then returns
28    (None, path).
29    """
30    if '/' in path:
31      first, second = path.split('/', 1)
32    else:
33      first, second = (path, '')
34    if first in ['trunk', 'dev', 'beta', 'stable']:
35      return (first, second)
36    return (None, path)
37
38  def GetBranchNumberForChannelName(self, channel_name):
39    """Returns the branch number for a channel name.
40    """
41    if channel_name == 'trunk':
42      return 'trunk'
43
44    branch_number = self._object_store.Get(channel_name + '.' + self._base_path,
45                                           object_store.BRANCH_UTILITY).Get()
46    if branch_number is not None:
47      return branch_number
48
49    try:
50      version_json = json.loads(self._fetcher.Fetch(self._base_path).content)
51    except Exception as e:
52      # This can happen if omahaproxy is misbehaving, which we've seen before.
53      # Quick hack fix: just serve from trunk until it's fixed.
54      logging.error('Failed to fetch or parse branch from omahaproxy: %s! '
55                    'Falling back to "trunk".' % e)
56      return 'trunk'
57
58    branch_numbers = {}
59    for entry in version_json:
60      if entry['os'] not in ['win', 'linux', 'mac', 'cros']:
61        continue
62      for version in entry['versions']:
63        if version['channel'] != channel_name:
64          continue
65        branch = version['version'].split('.')[2]
66        if branch not in branch_numbers:
67          branch_numbers[branch] = 0
68        else:
69          branch_numbers[branch] += 1
70
71    sorted_branches = sorted(branch_numbers.iteritems(),
72                             None,
73                             operator.itemgetter(1),
74                             True)
75    self._object_store.Set(channel_name + '.' + self._base_path,
76                           sorted_branches[0][0],
77                           object_store.BRANCH_UTILITY)
78
79    return sorted_branches[0][0]
80