blob: 6eab4a7197a57934d9fedaf62b8782945d147ebc [file] [log] [blame]
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Module for CrOS ToT manager."""
import re
import build_lib
import constants
import rest_client
def check_branch_specs(branch_specs, tot_manager):
"""Make sure entries in the branch_specs list are correctly formed.
It accepts any of BARE_BRANCHES in |branch_specs|, one numeric string of
the form '>=RXX' or '==RXX', where 'RXX' is a CrOS milestone number, or
one numeric string of the form '**tot**', like '>=tot-2'.
Args:
branch_specs: an iterable of branch specifiers, like ['>=tot-1'].
tot_manager: a TotMilestoneManager to convert tot string.
Returns:
True if branch_specs check is passed.
Raises:
ValueError: when parsing non-valid branch_spec or there're more than one
numeric string in branch_specs.
"""
only_one_numeric_constraint = False
for branch in branch_specs:
if branch in build_lib.BARE_BRANCHES:
continue
if not only_one_numeric_constraint:
# '<=' is dropped
if branch.startswith('>=R') or branch.startswith('==R'):
only_one_numeric_constraint = True
elif 'tot' in branch:
tot_manager.convert_tot_spec(branch[branch.index('tot'):])
only_one_numeric_constraint = True
if only_one_numeric_constraint:
continue
raise ValueError("%s isn't a valid branch spec." % branch)
return True
class TotMilestoneManager(object):
"""A class capable of converting tot string to milestone numbers.
This class is used as a cache for the tot milestone, so we don't
repeatedly hit google storage for all O(100) tasks in suite
scheduler's ini file.
"""
def __init__(self, is_sanity=False):
"""Initialize a manager for getting/calculating the Tot milestone.
Args:
is_sanity: True if suite_scheduler is running for sanity check.
When it's set to True, the code won't make gsutil call to
get the actual tot milestone to avoid dependency on the
installation of gsutil to run sanity check. By default it's
False.
"""
self.is_sanity = is_sanity
self.storage_client = rest_client.StorageRestClient(
rest_client.BaseRestClient(
constants.RestClient.STORAGE_CLIENT.scopes,
constants.RestClient.STORAGE_CLIENT.service_name,
constants.RestClient.STORAGE_CLIENT.service_version))
self.tot = self._tot_milestone()
def convert_tot_spec(self, tot_spec):
"""Convert a tot spec to the appropriate milestone.
Assume tot is R40:
tot -> R40
tot-1 -> R39
tot-2 -> R38
tot-(any other numbers) -> R40
With the last option one assumes that a malformed configuration
that has 'tot' in it, wants at least tot.
Args:
tot_spec: A string representing the tot spec.
Returns:
A milestone string, like 'R40'.
Raises:
ValueError: If the tot_spec doesn't match the expected format.
"""
tot_spec = tot_spec.lower()
match = re.match('(tot)[-]?(1$|2$)?', tot_spec)
if not match:
raise ValueError('%s is not a valid branch spec.' % tot_spec)
tot_mstone = self.tot
num_back = match.groups()[1]
if num_back:
tot_mstone_num = tot_mstone.lstrip('R')
tot_mstone = tot_mstone.replace(
tot_mstone_num, str(int(tot_mstone_num) - int(num_back)))
return tot_mstone
def _tot_milestone(self):
"""Get the tot milestone, eg: R40.
Returns:
A string representing the Tot milestone.
Raises:
build_lib.NoBuildError: if no milestone is found.
"""
if self.is_sanity:
return 'R40'
response = build_lib.get_latest_cros_build_from_gs(
self.storage_client)
return response.split('-')[0]