184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold# Use of this source code is governed by a BSD-style license that can be 384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold# found in the LICENSE file. 484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold"""Modules for obtaining Chrome OS release info.""" 684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnoldimport ConfigParser 984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnoldimport bisect 1084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnoldimport os 1184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 1284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 1347c8a9a7cf24e33dc66fccf64d7679646f9030b6Chris Sosa_RELEASE_CONFIG_FILE = os.path.join(os.path.dirname(__file__), 1447c8a9a7cf24e33dc66fccf64d7679646f9030b6Chris Sosa 'release_config.ini') 1584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 1684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold# Prefix for brachpoint definitions in the config file. 1784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold_CONF_BRANCH_SECTION = 'BRANCH' 1884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold_CONF_BRANCH_POINTS_OPT = 'branch_points' 1984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold_CONF_BRANCH_POINT_OPT_PREFIX = 'bp_' 2084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold_CONF_NEXT_BRANCH_OPT = 'next_branch' 2184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 2284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 2384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnoldclass ReleaseError(BaseException): 2484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """Errors related to release and branch inference.""" 2584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold pass 2684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 2784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 2884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnoldclass ReleaseInfo(object): 2984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """Provides reference information about Chrome OS releases. 3084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 3184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold Currently, this class serves for mapping between releases and branches / 3284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold release milestones. The information lives in a .ini file at the current 3384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold directory, which has a single section [BRANCH] containing 3484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 3584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold branch_points: comma-separated list of release branches (e.g. R10, R11, 3684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold ...) 3784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 3884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold bp_XYZ: for each branch listed above, a variable that maps to the Chrome 3984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold OS release at that branchpoint (e.g. bp_r10: 0.10.156.0). Note that .ini 4084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold file variables are case-insensitive. 4184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 4284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold next_branch: the name of the current (unforked) branch (e.g. R24) 4384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 44c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold It is also worth noting that a branch point X.Y.Z (alternatively, W.X.Y.Z) 45c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold of some branch R denotes the build number X (repsectively, W) that 46c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold constitutes the said branch. Therefore, it is only from build X+1 (W+1) and 47c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold onward that releases will be tagged with R+1. 48c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold 4984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """ 5084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold def __init__(self): 5184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._release_config = None 5284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._branchpoint_dict = None 5384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._next_branch = None 5484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._sorted_branchpoint_list = None 55c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold self._sorted_shifted_branchpoint_rel_key_list = None 5684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 5784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold def initialize(self): 5884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """Read release config and initialize lookup data structures.""" 5984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._release_config = ConfigParser.ConfigParser() 6084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold try: 6184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._release_config.readfp(open(_RELEASE_CONFIG_FILE)) 6284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 6384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold # Build branchpoint dictionary. 6484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold branchpoint_list_str = self._release_config.get( 6584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold _CONF_BRANCH_SECTION, _CONF_BRANCH_POINTS_OPT) 6684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold if branchpoint_list_str: 6784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold branchpoint_list = map(str.strip, 6884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold branchpoint_list_str.split(',')) 6984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold else: 7084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold branchpoint_list = [] 7184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 7284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._branchpoint_dict = {} 7384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold for branchpoint in branchpoint_list: 7484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._branchpoint_dict[branchpoint] = ( 7584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._release_config.get( 7684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold _CONF_BRANCH_SECTION, 7784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold _CONF_BRANCH_POINT_OPT_PREFIX + branchpoint)) 7884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 7984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold # Get next branch name. 8084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._next_branch = self._release_config.get(_CONF_BRANCH_SECTION, 8184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold _CONF_NEXT_BRANCH_OPT) 8284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold if not self._next_branch: 8384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold raise ReleaseError("missing `%s' option" % 8484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold _CONF_NEXT_BRANCH_OPT) 8584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold except IOError, e: 8684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold raise ReleaseError('failed to open release config file (%s): %s' % 8703901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold (_RELEASE_CONFIG_FILE, e)) 8884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold except ConfigParser.Error, e: 8903901089c0db27508a6b2ff61ae8b75eba77cf37Gilad Arnold raise ReleaseError('failed to load release config: %s' % e) 9084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 9184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold # Infer chronologically sorted list of branchpoints. 9284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._sorted_branchpoint_list = self._branchpoint_dict.items() 9384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._sorted_branchpoint_list.append((self._next_branch, '99999.0.0')) 9484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._sorted_branchpoint_list.sort( 9584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold key=lambda (branch, release): self._release_key(release)) 9684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 9784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold # Also store a sorted list of branchpoint release keys, for easy lookup. 98c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold self._sorted_shifted_branchpoint_rel_key_list = [ 99c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold self._release_key(self._next_build_number_release(release)) 100c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold for (branch, release) in self._sorted_branchpoint_list] 101c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold 102c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold 103c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold def _next_build_number_release(self, release): 104c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold """Returns the release of the next build following a given release. 105c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold 106c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold Given a release number 'X.Y.Z' (new scheme) or '0.X.Y.Z' (old scheme) 107c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold it will return 'X+1.0.0' or '0.X+1.0.0', respectively. 108c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold 109c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold @param release: the release number in dotted notation (string) 110c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold 111c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold @return The release number of the next build. 112c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold 113c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold @raise ReleaseError if the release is malformed. 114c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold 115c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold """ 116c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold release_components = release.split('.') 117c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold if len(release_components) == 4 and release_components[0] == '0': 118c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold prepend = '0.' 119c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold x = int(release_components[1]) 120c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold elif len(release_components) != 3: 121c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold raise ReleaseError('invalid release number: %s' % release) 122c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold else: 123c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold prepend = '' 124c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold x = int(release_components[0]) 125c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold 126c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold return '%s%s.0.0' % (prepend, x + 1) 12784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 12884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 12984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold def _release_key(self, release): 13084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """Convert a Chrome OS release string into an integer key. 13184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 13284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold This translates a release string 'X.Y.Z' (new scheme) or 'W.X.Y.Z' (old 13384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold scheme where W = 0) into an integer whose value equals X * 10^7 + Y * 13484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 10^3 + Z, assuming that Y < 10^4 and Z < 10^3, and will scale safely to 13584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold any foreseeable major release number (X). 13684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 13784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold @param release: the release number in dotted notation (string) 13884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 13984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold @return A unique integer key representing the release. 14084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 14184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold @raise ReleaseError if the release is malformed. 14284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 14384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """ 14484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold release_components = release.split('.') 14584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold if len(release_components) == 4 and release_components[0] == '0': 14684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold release_components = release_components[1:] 14784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold elif len(release_components) != 3: 14884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold raise ReleaseError('invalid release number: %s' % release) 14984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold x, y, z = [int(s) for s in release_components] 15084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold return x * 10000000 + y * 1000 + z 15184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 15284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 15384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold def get_branch_list(self): 15484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """Retruns chronologically sorted list of branch names.""" 15584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold return [branch for (branch, release) in self._sorted_branchpoint_list] 15684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 15784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 15884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold def get_branch(self, release): 15984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """Returns the branch name of a given release version. """ 160c33f648ebe4c7b1f4f304dbfcbc1f0c80597becdGilad Arnold i = bisect.bisect_left(self._sorted_shifted_branchpoint_rel_key_list, 16184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold self._release_key(release)) 16284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold return self._sorted_branchpoint_list[i][0] if i else None 16384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 16484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 16584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold def get_branchpoint_release(self, branch): 16684eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """Returns the branchpoint release of a given branch. 16784eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 16884eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold Returns None if given name is the next branch. 16984eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 17084eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold @raise KeyError if branch name not known 17184eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold 17284eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold """ 17384eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold if branch == self._next_branch: 17484eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold return None 17584eb60cb5d66d6052407ebae4f1aa38000c9cbcfGilad Arnold return self._branchpoint_dict[branch] 176