blob: c6754ae381a016af107180eaac589bcbea302d36 [file] [log] [blame]
Chris Sosadad0d322011-01-31 16:37:33 -08001#!/usr/bin/python
2
3# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""This module uprevs Chrome for cbuildbot.
8
9After calling, it prints outs CHROME_VERSION_ATOM=(version atom string). A
10caller could then use this atom with emerge to build the newly uprevved version
11of Chrome e.g.
12
13./cros_mark_chrome_as_stable tot
14Returns chrome-base/chromeos-chrome-8.0.552.0_alpha_r1
15
16emerge-x86-generic =chrome-base/chromeos-chrome-8.0.552.0_alpha_r1
17"""
18
Ryan Cui05a31ba2011-05-31 17:47:37 -070019import constants
Chris Sosa8be39132011-04-14 12:09:24 -070020import filecmp
Chris Sosadad0d322011-01-31 16:37:33 -080021import optparse
22import os
23import re
24import sys
25import urllib
26
Chris Sosadad0d322011-01-31 16:37:33 -080027import cros_mark_as_stable
Chris Sosadad0d322011-01-31 16:37:33 -080028from cros_build_lib import RunCommand, Info, Warning
29
Chris Sosad44c3f92011-05-10 16:05:25 -070030BASE_CHROME_SVN_URL = 'svn://svn.chromium.org/chrome/'
Chris Sosadad0d322011-01-31 16:37:33 -080031
Chris Sosadad0d322011-01-31 16:37:33 -080032# Helper regex's for finding ebuilds.
33_CHROME_VERSION_REGEX = '\d+\.\d+\.\d+\.\d+'
34_NON_STICKY_REGEX = '%s[(_rc.*)|(_alpha.*)]+' % _CHROME_VERSION_REGEX
35
36# Dir where all the action happens.
37_CHROME_OVERLAY_DIR = ('%(srcroot)s/third_party/chromiumos-overlay'
38 '/chromeos-base/chromeos-chrome')
39
40_GIT_COMMIT_MESSAGE = ('Marking %(chrome_rev)s for chrome ebuild with version '
41 '%(chrome_version)s as stable.')
42
43
44def _GetSvnUrl():
45 """Returns the path to the svn url for the given chrome branch."""
46 return os.path.join(BASE_CHROME_SVN_URL, 'trunk')
47
48
49def _GetTipOfTrunkSvnRevision():
50 """Returns the current svn revision for the chrome tree."""
51 svn_url = _GetSvnUrl()
52 svn_info = RunCommand(['svn', 'info', svn_url], redirect_stdout=True)
53
54 revision_re = re.compile('^Revision:\s+(\d+).*')
55 for line in svn_info.splitlines():
56 match = revision_re.search(line)
57 if match:
58 svn_revision = match.group(1)
59 Info('Using SVN Revision %s' % svn_revision)
60 return svn_revision
61
62 raise Exception('Could not find revision information from %s' % svn_url)
63
64
65def _GetTipOfTrunkVersion():
66 """Returns the current Chrome version."""
Chris Sosad44c3f92011-05-10 16:05:25 -070067 svn_url = os.path.join(_GetSvnUrl(), 'src', 'chrome', 'VERSION')
68 chrome_version_info = RunCommand(
69 ['svn', 'cat', svn_url],
70 redirect_stdout=True,
71 error_message='Could not read version file at %s.' % svn_url)
Chris Sosadad0d322011-01-31 16:37:33 -080072
73 chrome_version_array = []
Chris Sosadad0d322011-01-31 16:37:33 -080074 for line in chrome_version_info.splitlines():
75 chrome_version_array.append(line.rpartition('=')[2])
76
77 return '.'.join(chrome_version_array)
78
79
80def _GetLatestRelease(branch=None):
81 """Gets the latest release version from the buildspec_url for the branch.
82
83 Args:
84 branch: If set, gets the latest release for branch, otherwise latest
85 release.
86 Returns:
87 Latest version string.
88 """
Chris Sosad44c3f92011-05-10 16:05:25 -070089 buildspec_url = os.path.join(BASE_CHROME_SVN_URL, 'releases')
Chris Sosadad0d322011-01-31 16:37:33 -080090 svn_ls = RunCommand(['svn', 'ls', buildspec_url], redirect_stdout=True)
91 sorted_ls = RunCommand(['sort', '--version-sort'], input=svn_ls,
92 redirect_stdout=True)
93 if branch:
94 chrome_version_re = re.compile('^%s\.\d+.*' % branch)
95 else:
96 chrome_version_re = re.compile('^[0-9]+\..*')
97 for chrome_version in sorted_ls.splitlines():
98 if chrome_version_re.match(chrome_version):
99 current_version = chrome_version
100
101 return current_version.rstrip('/')
102
103
104def _GetStickyEBuild(stable_ebuilds):
105 """Returns the sticky ebuild."""
106 sticky_ebuilds = []
107 non_sticky_re = re.compile(_NON_STICKY_REGEX)
108 for ebuild in stable_ebuilds:
109 if not non_sticky_re.match(ebuild.version):
110 sticky_ebuilds.append(ebuild)
111
112 if not sticky_ebuilds:
113 raise Exception('No sticky ebuilds found')
114 elif len(sticky_ebuilds) > 1:
115 Warning('More than one sticky ebuild found')
116
117 return cros_mark_as_stable.BestEBuild(sticky_ebuilds)
118
119
120class ChromeEBuild(cros_mark_as_stable.EBuild):
121 """Thin sub-class of EBuild that adds a chrome_version field."""
122 chrome_version_re = re.compile('.*chromeos-chrome-(%s|9999).*' % (
123 _CHROME_VERSION_REGEX))
124 chrome_version = ''
125
126 def __init__(self, path):
127 cros_mark_as_stable.EBuild.__init__(self, path)
128 re_match = self.chrome_version_re.match(self.ebuild_path_no_revision)
129 if re_match:
130 self.chrome_version = re_match.group(1)
131
132 def __cmp__(self, other):
133 """Use ebuild paths for comparison."""
134 if self.ebuild_path == other.ebuild_path:
135 return 0
136 elif self.ebuild_path > other.ebuild_path:
137 return 1
138 else:
139 return (-1)
140
141 def __str__(self):
142 return self.ebuild_path
143
144
145def FindChromeCandidates(overlay_dir):
146 """Return a tuple of chrome's unstable ebuild and stable ebuilds.
147
148 Args:
149 overlay_dir: The path to chrome's portage overlay dir.
150 Returns:
151 Tuple [unstable_ebuild, stable_ebuilds].
152 Raises:
153 Exception: if no unstable ebuild exists for Chrome.
154 """
155 stable_ebuilds = []
156 unstable_ebuilds = []
157 for path in [
158 os.path.join(overlay_dir, entry) for entry in os.listdir(overlay_dir)]:
159 if path.endswith('.ebuild'):
160 ebuild = ChromeEBuild(path)
161 if not ebuild.chrome_version:
162 Warning('Poorly formatted ebuild found at %s' % path)
163 else:
164 if '9999' in ebuild.version:
165 unstable_ebuilds.append(ebuild)
166 else:
167 stable_ebuilds.append(ebuild)
168
169 # Apply some sanity checks.
170 if not unstable_ebuilds:
171 raise Exception('Missing 9999 ebuild for %s' % overlay_dir)
172 if not stable_ebuilds:
173 Warning('Missing stable ebuild for %s' % overlay_dir)
174
175 return cros_mark_as_stable.BestEBuild(unstable_ebuilds), stable_ebuilds
176
177
178def FindChromeUprevCandidate(stable_ebuilds, chrome_rev, sticky_branch):
179 """Finds the Chrome uprev candidate for the given chrome_rev.
180
181 Using the pre-flight logic, this means the stable ebuild you are uprevving
182 from. The difference here is that the version could be different and in
183 that case we want to find it to delete it.
184
185 Args:
186 stable_ebuilds: A list of stable ebuilds.
187 chrome_rev: The chrome_rev designating which candidate to find.
188 sticky_branch: The the branch that is currently sticky with Major/Minor
189 components. For example: 9.0.553
190 Returns:
191 Returns the EBuild, otherwise None if none found.
192 """
193 candidates = []
Ryan Cuic6e097d2011-06-16 12:23:14 -0700194 if chrome_rev == constants.CHROME_REV_TOT:
Chris Sosadad0d322011-01-31 16:37:33 -0800195 chrome_branch_re = re.compile('%s.*_alpha.*' % _CHROME_VERSION_REGEX)
196 for ebuild in stable_ebuilds:
197 if chrome_branch_re.search(ebuild.version):
198 candidates.append(ebuild)
199
Ryan Cuic6e097d2011-06-16 12:23:14 -0700200 elif chrome_rev == constants.CHROME_REV_STICKY:
Chris Sosadad0d322011-01-31 16:37:33 -0800201 chrome_branch_re = re.compile('%s\..*' % sticky_branch)
202 for ebuild in stable_ebuilds:
203 if chrome_branch_re.search(ebuild.version):
204 candidates.append(ebuild)
205
206 else:
207 chrome_branch_re = re.compile('%s.*_rc.*' % _CHROME_VERSION_REGEX)
208 for ebuild in stable_ebuilds:
209 if chrome_branch_re.search(ebuild.version) and (
210 not ebuild.chrome_version.startswith(sticky_branch)):
211 candidates.append(ebuild)
212
213 if candidates:
214 return cros_mark_as_stable.BestEBuild(candidates)
215 else:
216 return None
217
218
219def MarkChromeEBuildAsStable(stable_candidate, unstable_ebuild, chrome_rev,
220 chrome_version, commit, overlay_dir,
221 sticky_ebuild):
222 """Uprevs the chrome ebuild specified by chrome_rev.
223
224 This is the main function that uprevs the chrome_rev from a stable candidate
225 to its new version.
226
227 Args:
228 stable_candidate: ebuild that corresponds to the stable ebuild we are
229 revving from. If None, builds the a new ebuild given the version
230 and logic for chrome_rev type with revision set to 1.
231 unstable_ebuild: ebuild corresponding to the unstable ebuild for chrome.
Ryan Cuic6e097d2011-06-16 12:23:14 -0700232 chrome_rev: one of constants.VALID_CHROME_REVISIONS
233 constants.CHROME_REV_TOT - Requires commit value. Revs the ebuild for
234 the TOT version and uses the portage suffix of _alpha.
235 constants.CHROME_REV_LATEST - This uses the portage suffix of _rc as they
236 are release candidates for the next sticky version.
237 constants.CHROME_REV_STICKY - Revs the sticky version.
Chris Sosadad0d322011-01-31 16:37:33 -0800238 chrome_version: The \d.\d.\d.\d version of Chrome.
Ryan Cuic6e097d2011-06-16 12:23:14 -0700239 commit: Used with constants.CHROME_REV_TOT. The svn revision of chrome.
Chris Sosadad0d322011-01-31 16:37:33 -0800240 overlay_dir: Path to the chromeos-chrome package dir.
241 sticky_ebuild: EBuild class for the sticky ebuild.
242 Returns:
243 Full portage version atom (including rc's, etc) that was revved.
244 """
Chris Sosa8be39132011-04-14 12:09:24 -0700245 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
246 """Returns True if the new ebuild is redundant.
247
248 This is True if there if the current stable ebuild is the exact same copy
249 of the new one OR the chrome versions are the same and we're revving
Ryan Cuic6e097d2011-06-16 12:23:14 -0700250 constants.CHROME_REV_LATEST (as we don't care about 9999 changes for it).
Chris Sosa8be39132011-04-14 12:09:24 -0700251 """
252 if not stable_ebuild:
253 return False
254
255 if stable_candidate.chrome_version == new_ebuild.chrome_version:
Ryan Cuic6e097d2011-06-16 12:23:14 -0700256 if chrome_rev == constants.CHROME_REV_LATEST:
Chris Sosa8be39132011-04-14 12:09:24 -0700257 return True
258 else:
259 return filecmp.cmp(
260 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False)
261
Chris Sosadad0d322011-01-31 16:37:33 -0800262 base_path = os.path.join(overlay_dir, 'chromeos-chrome-%s' % chrome_version)
263 # Case where we have the last stable candidate with same version just rev.
264 if stable_candidate and stable_candidate.chrome_version == chrome_version:
265 new_ebuild_path = '%s-r%d.ebuild' % (
266 stable_candidate.ebuild_path_no_revision,
267 stable_candidate.current_revision + 1)
268 else:
Ryan Cuic6e097d2011-06-16 12:23:14 -0700269 if chrome_rev == constants.CHROME_REV_TOT:
Chris Sosadad0d322011-01-31 16:37:33 -0800270 portage_suffix = '_alpha'
271 else:
272 portage_suffix = '_rc'
273
274 new_ebuild_path = base_path + ('%s-r1.ebuild' % portage_suffix)
275
276 # Mark latest release and sticky branches as stable.
Ryan Cuic6e097d2011-06-16 12:23:14 -0700277 mark_stable = chrome_rev != constants.CHROME_REV_TOT
Chris Sosadad0d322011-01-31 16:37:33 -0800278
279 cros_mark_as_stable.EBuildStableMarker.MarkAsStable(
280 unstable_ebuild.ebuild_path, new_ebuild_path, 'CROS_SVN_COMMIT', commit,
281 make_stable=mark_stable)
282 new_ebuild = ChromeEBuild(new_ebuild_path)
Chris Sosa8be39132011-04-14 12:09:24 -0700283
284 # Determine whether this is ebuild is redundant.
285 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
286 Info('Previous ebuild with same version found and ebuild is redundant.')
287 os.unlink(new_ebuild_path)
288 return None
Chris Sosadad0d322011-01-31 16:37:33 -0800289
290 RunCommand(['git', 'add', new_ebuild_path])
291 if stable_candidate and stable_candidate != sticky_ebuild:
292 RunCommand(['git', 'rm', stable_candidate.ebuild_path])
293
294 cros_mark_as_stable.EBuildStableMarker.CommitChange(
295 _GIT_COMMIT_MESSAGE % {'chrome_rev': chrome_rev,
296 'chrome_version': chrome_version})
297
298 new_ebuild = ChromeEBuild(new_ebuild_path)
299 return '%s-%s' % (new_ebuild.package, new_ebuild.version)
300
301
302def main():
Ryan Cuic6e097d2011-06-16 12:23:14 -0700303 usage_options = '|'.join(constants.VALID_CHROME_REVISIONS)
304 usage = '%s OPTIONS [%s]' % (__file__, usage_options)
Chris Sosadad0d322011-01-31 16:37:33 -0800305 parser = optparse.OptionParser(usage)
Chris Sosabf153872011-04-28 14:21:09 -0700306 parser.add_option('-b', '--board', default='x86-generic')
Chris Sosadad0d322011-01-31 16:37:33 -0800307 parser.add_option('-s', '--srcroot', default=os.path.join(os.environ['HOME'],
308 'trunk', 'src'),
309 help='Path to the src directory')
310 parser.add_option('-t', '--tracking_branch', default='cros/master',
311 help='Branch we are tracking changes against')
312 (options, args) = parser.parse_args()
313
Ryan Cuic6e097d2011-06-16 12:23:14 -0700314 if len(args) != 1 or args[0] not in constants.VALID_CHROME_REVISIONS:
315 parser.error('Commit requires arg set to one of %s.'
316 % constants.VALID_CHROME_REVISIONS)
Chris Sosadad0d322011-01-31 16:37:33 -0800317
318 overlay_dir = os.path.abspath(_CHROME_OVERLAY_DIR %
319 {'srcroot': options.srcroot})
320 chrome_rev = args[0]
321 version_to_uprev = None
322 commit_to_use = None
323
324 (unstable_ebuild, stable_ebuilds) = FindChromeCandidates(overlay_dir)
325 sticky_ebuild = _GetStickyEBuild(stable_ebuilds)
326 sticky_version = sticky_ebuild.chrome_version
327 sticky_branch = sticky_version.rpartition('.')[0]
328
Ryan Cuic6e097d2011-06-16 12:23:14 -0700329 if chrome_rev == constants.CHROME_REV_TOT:
Chris Sosadad0d322011-01-31 16:37:33 -0800330 version_to_uprev = _GetTipOfTrunkVersion()
331 commit_to_use = _GetTipOfTrunkSvnRevision()
Ryan Cuic6e097d2011-06-16 12:23:14 -0700332 elif chrome_rev == constants.CHROME_REV_LATEST:
Chris Sosadad0d322011-01-31 16:37:33 -0800333 version_to_uprev = _GetLatestRelease()
334 # Don't rev on stable branch for latest_release.
335 if re.match('%s\.\d+' % sticky_branch, version_to_uprev):
336 Info('Latest release is sticky branch. Nothing to do.')
337 return
338 else:
339 version_to_uprev = _GetLatestRelease(sticky_branch)
340
341 stable_candidate = FindChromeUprevCandidate(stable_ebuilds, chrome_rev,
342 sticky_branch)
343
344 if stable_candidate:
345 Info('Stable candidate found %s' % stable_candidate)
346 else:
347 Info('No stable candidate found.')
348
Chris Sosa8049f3b2011-05-02 20:09:28 -0700349 tracking_branch = 'remotes/m/%s' % os.path.basename(options.tracking_branch)
Chris Sosadad0d322011-01-31 16:37:33 -0800350 os.chdir(overlay_dir)
Ryan Cui05a31ba2011-05-31 17:47:37 -0700351 work_branch = cros_mark_as_stable.GitBranch(constants.STABLE_EBUILD_BRANCH,
352 tracking_branch)
Chris Sosadad0d322011-01-31 16:37:33 -0800353 work_branch.CreateBranch()
354 chrome_version_atom = MarkChromeEBuildAsStable(
355 stable_candidate, unstable_ebuild, chrome_rev, version_to_uprev,
356 commit_to_use, overlay_dir, sticky_ebuild)
357 # Explicit print to communicate to caller.
358 if chrome_version_atom:
Chris Sosabf153872011-04-28 14:21:09 -0700359 cros_mark_as_stable.CleanStalePackages(options.board, [chrome_version_atom])
Chris Sosadad0d322011-01-31 16:37:33 -0800360 print 'CHROME_VERSION_ATOM=%s' % chrome_version_atom
361
362
363if __name__ == '__main__':
364 main()