blob: 399d511172d19a87a4e30d624901b70af0a28760 [file] [log] [blame]
xixuand7b7b7b2017-08-15 15:07:35 -07001# Copyright 2017 The Chromium OS 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
5"""Module for CrOS ToT manager."""
6
7import re
8
9import build_lib
10import constants
11import rest_client
12
13
14def check_branch_specs(branch_specs, tot_manager):
15 """Make sure entries in the branch_specs list are correctly formed.
16
17 It accepts any of BARE_BRANCHES in |branch_specs|, one numeric string of
18 the form '>=RXX' or '==RXX', where 'RXX' is a CrOS milestone number, or
19 one numeric string of the form '**tot**', like '>=tot-2'.
20
21 Args:
22 branch_specs: an iterable of branch specifiers, like ['>=tot-1'].
23 tot_manager: a TotMilestoneManager to convert tot string.
24
25 Returns:
26 True if branch_specs check is passed.
27
28 Raises:
29 ValueError: when parsing non-valid branch_spec or there're more than one
30 numeric string in branch_specs.
31 """
32 only_one_numeric_constraint = False
33 for branch in branch_specs:
34 if branch in build_lib.BARE_BRANCHES:
35 continue
36
37 if not only_one_numeric_constraint:
38 # '<=' is dropped
39 if branch.startswith('>=R') or branch.startswith('==R'):
40 only_one_numeric_constraint = True
41 elif 'tot' in branch:
42 tot_manager.convert_tot_spec(branch[branch.index('tot'):])
43 only_one_numeric_constraint = True
44
45 if only_one_numeric_constraint:
46 continue
47
48 raise ValueError("%s isn't a valid branch spec." % branch)
49
50 return True
51
52
53class TotMilestoneManager(object):
54 """A class capable of converting tot string to milestone numbers.
55
56 This class is used as a cache for the tot milestone, so we don't
57 repeatedly hit google storage for all O(100) tasks in suite
58 scheduler's ini file.
59 """
60
61 def __init__(self, is_sanity=False):
62 """Initialize a manager for getting/calculating the Tot milestone.
63
64 Args:
65 is_sanity: True if suite_scheduler is running for sanity check.
66 When it's set to True, the code won't make gsutil call to
67 get the actual tot milestone to avoid dependency on the
68 installation of gsutil to run sanity check. By default it's
69 False.
70 """
71 self.is_sanity = is_sanity
Xinan Lin33937d62020-04-14 14:41:23 -070072 if not self.is_sanity:
73 self.storage_client = rest_client.StorageRestClient(
74 rest_client.BaseRestClient(
75 constants.RestClient.STORAGE_CLIENT.scopes,
76 constants.RestClient.STORAGE_CLIENT.service_name,
77 constants.RestClient.STORAGE_CLIENT.service_version))
xixuand7b7b7b2017-08-15 15:07:35 -070078 self.tot = self._tot_milestone()
79
80 def convert_tot_spec(self, tot_spec):
81 """Convert a tot spec to the appropriate milestone.
82
83 Assume tot is R40:
84 tot -> R40
85 tot-1 -> R39
86 tot-2 -> R38
87 tot-(any other numbers) -> R40
88
89 With the last option one assumes that a malformed configuration
90 that has 'tot' in it, wants at least tot.
91
92 Args:
93 tot_spec: A string representing the tot spec.
94
95 Returns:
96 A milestone string, like 'R40'.
97
98 Raises:
99 ValueError: If the tot_spec doesn't match the expected format.
100 """
101 tot_spec = tot_spec.lower()
102 match = re.match('(tot)[-]?(1$|2$)?', tot_spec)
103 if not match:
104 raise ValueError('%s is not a valid branch spec.' % tot_spec)
105
106 tot_mstone = self.tot
107 num_back = match.groups()[1]
108 if num_back:
109 tot_mstone_num = tot_mstone.lstrip('R')
110 tot_mstone = tot_mstone.replace(
111 tot_mstone_num, str(int(tot_mstone_num) - int(num_back)))
112
113 return tot_mstone
114
115 def _tot_milestone(self):
116 """Get the tot milestone, eg: R40.
117
118 Returns:
119 A string representing the Tot milestone.
120
121 Raises:
122 build_lib.NoBuildError: if no milestone is found.
123 """
124 if self.is_sanity:
125 return 'R40'
126
127 response = build_lib.get_latest_cros_build_from_gs(
128 self.storage_client)
129 return response.split('-')[0]