OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Snapshot Build Bisect Tool | 6 """Snapshot Build Bisect Tool |
7 | 7 |
8 This script bisects a snapshot archive using binary search. It starts at | 8 This script bisects a snapshot archive using binary search. It starts at |
9 a bad revision (it will try to guess HEAD) and asks for a last known-good | 9 a bad revision (it will try to guess HEAD) and asks for a last known-good |
10 revision. It will then binary search across this revision range by downloading, | 10 revision. It will then binary search across this revision range by downloading, |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 | 162 |
163 def ParseDirectoryIndex(self): | 163 def ParseDirectoryIndex(self): |
164 """Parses the Google Storage directory listing into a list of revision | 164 """Parses the Google Storage directory listing into a list of revision |
165 numbers.""" | 165 numbers.""" |
166 | 166 |
167 def _FetchAndParse(url): | 167 def _FetchAndParse(url): |
168 """Fetches a URL and returns a 2-Tuple of ([revisions], next-marker). If | 168 """Fetches a URL and returns a 2-Tuple of ([revisions], next-marker). If |
169 next-marker is not None, then the listing is a partial listing and another | 169 next-marker is not None, then the listing is a partial listing and another |
170 fetch should be performed with next-marker being the marker= GET | 170 fetch should be performed with next-marker being the marker= GET |
171 parameter.""" | 171 parameter.""" |
172 | |
Robert Sesek
2013/09/23 16:37:15
remove
kareng
2013/09/23 21:20:32
Done.
| |
172 handle = urllib.urlopen(url) | 173 handle = urllib.urlopen(url) |
173 document = ElementTree.parse(handle) | 174 document = ElementTree.parse(handle) |
174 | 175 |
175 # All nodes in the tree are namespaced. Get the root's tag name to extract | 176 # All nodes in the tree are namespaced. Get the root's tag name to extract |
176 # the namespace. Etree does namespaces as |{namespace}tag|. | 177 # the namespace. Etree does namespaces as |{namespace}tag|. |
177 root_tag = document.getroot().tag | 178 root_tag = document.getroot().tag |
178 end_ns_pos = root_tag.find('}') | 179 end_ns_pos = root_tag.find('}') |
179 if end_ns_pos == -1: | 180 if end_ns_pos == -1: |
180 raise Exception("Could not locate end namespace for directory index") | 181 raise Exception("Could not locate end namespace for directory index") |
181 namespace = root_tag[:end_ns_pos + 1] | 182 namespace = root_tag[:end_ns_pos + 1] |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
214 (new_revisions, next_marker) = _FetchAndParse(next_url) | 215 (new_revisions, next_marker) = _FetchAndParse(next_url) |
215 revisions.extend(new_revisions) | 216 revisions.extend(new_revisions) |
216 return revisions | 217 return revisions |
217 | 218 |
218 def GetRevList(self): | 219 def GetRevList(self): |
219 """Gets the list of revision numbers between self.good_revision and | 220 """Gets the list of revision numbers between self.good_revision and |
220 self.bad_revision.""" | 221 self.bad_revision.""" |
221 # Download the revlist and filter for just the range between good and bad. | 222 # Download the revlist and filter for just the range between good and bad. |
222 minrev = min(self.good_revision, self.bad_revision) | 223 minrev = min(self.good_revision, self.bad_revision) |
223 maxrev = max(self.good_revision, self.bad_revision) | 224 maxrev = max(self.good_revision, self.bad_revision) |
224 revlist = map(int, self.ParseDirectoryIndex()) | 225 revlist_all = map(int, self.ParseDirectoryIndex()) |
225 revlist = [x for x in revlist if x >= int(minrev) and x <= int(maxrev)] | 226 |
227 revlist = [x for x in revlist_all if x >= int(minrev) and x <= int(maxrev)] | |
226 revlist.sort() | 228 revlist.sort() |
227 return revlist | 229 |
230 # set good and bad revisions to be legit revisions | |
Robert Sesek
2013/09/23 16:37:15
Proper punctuation, capitalization, and grammar fo
kareng
2013/09/23 21:20:32
Done.
| |
231 if revlist: | |
232 if (self.good_revision < self.bad_revision): | |
Robert Sesek
2013/09/23 16:37:15
nit: no () around conditions unless necessary for
kareng
2013/09/23 21:20:32
Done.
| |
233 self.good_revision = revlist[0] | |
234 self.bad_revision = revlist[-1] | |
235 else: | |
236 self.bad_revision = revlist[0] | |
237 self.good_revision = revlist[-1] | |
238 | |
239 #fix chromium rev so that the deps blink revision matches VERSIONS file | |
Robert Sesek
2013/09/23 16:37:15
nit: same as above, but add a space after #
kareng
2013/09/23 21:20:32
Done.
| |
240 if (self.base_url == WEBKIT_BASE_URL): | |
241 revlist_all.sort() | |
242 self.good_revision, revlist = FixChromiumRevForBlink(revlist, | |
243 revlist_all, | |
244 self, | |
245 self.good_revision) | |
246 self.bad_revision, revlist = FixChromiumRevForBlink(revlist, | |
247 revlist_all, | |
248 self, | |
249 self.bad_revision) | |
250 return revlist | |
Michael Moss
2013/09/20 21:10:12
You probably want to always return 'revlist' (i.e.
kareng
2013/09/23 21:20:32
yes that was a mistake of tabbing. ty!
| |
228 | 251 |
229 def GetOfficialBuildsList(self): | 252 def GetOfficialBuildsList(self): |
230 """Gets the list of official build numbers between self.good_revision and | 253 """Gets the list of official build numbers between self.good_revision and |
231 self.bad_revision.""" | 254 self.bad_revision.""" |
232 # Download the revlist and filter for just the range between good and bad. | 255 # Download the revlist and filter for just the range between good and bad. |
233 minrev = min(self.good_revision, self.bad_revision) | 256 minrev = min(self.good_revision, self.bad_revision) |
234 maxrev = max(self.good_revision, self.bad_revision) | 257 maxrev = max(self.good_revision, self.bad_revision) |
235 handle = urllib.urlopen(OFFICIAL_BASE_URL) | 258 handle = urllib.urlopen(OFFICIAL_BASE_URL) |
236 dirindex = handle.read() | 259 dirindex = handle.read() |
237 handle.close() | 260 handle.close() |
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
601 os.unlink(f) | 624 os.unlink(f) |
602 except OSError: | 625 except OSError: |
603 pass | 626 pass |
604 sys.exit(0) | 627 sys.exit(0) |
605 | 628 |
606 rev = revlist[pivot] | 629 rev = revlist[pivot] |
607 | 630 |
608 return (revlist[minrev], revlist[maxrev]) | 631 return (revlist[minrev], revlist[maxrev]) |
609 | 632 |
610 | 633 |
634 def GetBlinkDEPSREvisionForChromiumRevision(rev): | |
Robert Sesek
2013/09/23 16:37:15
Lowercase the E in Revision
kareng
2013/09/23 21:20:32
Done.
| |
635 """Returns the blink revision that was in REVISIONS file at | |
636 chromium revision |rev|.""" | |
637 # . doesn't match newlines without re.DOTALL, so this is safe. | |
638 blink_re = re.compile(r'webkit_revision\D*(\d+)') | |
639 url = urllib.urlopen(DEPS_FILE % rev) | |
640 m = blink_re.search(url.read()) | |
641 url.close() | |
642 if m: | |
643 return int(m.group(1)) | |
644 else: | |
645 raise Exception('Could not get blink revision for cr rev %d' % rev) | |
Robert Sesek
2013/09/23 16:37:15
Capitalize Blink and spell out Chromium. This is a
kareng
2013/09/23 21:20:32
Done.
| |
646 | |
647 | |
611 def GetBlinkRevisionForChromiumRevision(self, rev): | 648 def GetBlinkRevisionForChromiumRevision(self, rev): |
612 """Returns the blink revision that was in REVISIONS file at | 649 """Returns the blink revision that was in REVISIONS file at |
613 chromium revision |rev|.""" | 650 chromium revision |rev|.""" |
614 # . doesn't match newlines without re.DOTALL, so this is safe. | |
615 file_url = "%s/%s%d/REVISIONS" % (self.base_url, | 651 file_url = "%s/%s%d/REVISIONS" % (self.base_url, |
616 self._listing_platform_dir, rev) | 652 self._listing_platform_dir, rev) |
617 url = urllib.urlopen(file_url) | 653 url = urllib.urlopen(file_url) |
618 data = json.loads(url.read()) | 654 data = json.loads(url.read()) |
619 url.close() | 655 url.close() |
620 if 'webkit_revision' in data: | 656 if 'webkit_revision' in data: |
621 return data['webkit_revision'] | 657 return data['webkit_revision'] |
622 else: | 658 else: |
623 raise Exception('Could not get blink revision for cr rev %d' % rev) | 659 raise Exception('Could not get blink revision for cr rev %d' % rev) |
624 | 660 |
661 def FixChromiumRevForBlink(revisions_final, revisions, self, rev): | |
662 """Returns the chromium revision that has the correct blink revision | |
663 for blink bisect, deps and REVISIONS file might not match since | |
664 blink snapshots point to tip of tree blink. | |
665 chromium revision |rev.""" | |
Michael Moss
2013/09/20 21:10:12
Last line in the comment looks like copy-paste err
kareng
2013/09/23 21:20:32
Done.
| |
666 | |
667 blink_deps_rev = GetBlinkDEPSREvisionForChromiumRevision(rev) | |
668 | |
669 while (GetBlinkRevisionForChromiumRevision(self, rev) > blink_deps_rev): | |
670 idx = revisions.index(rev) | |
671 rev = revisions[idx-1] | |
Michael Moss
2013/09/20 21:10:12
What happens if 'rev' is the first item in 'revisi
kareng
2013/09/23 21:20:32
heh good, point. i changed so now it doesn't conti
| |
672 if rev not in revisions_final: | |
673 revisions_final.insert(0, rev) | |
674 | |
675 revisions_final.sort() | |
676 return rev, revisions_final | |
Michael Moss
2013/09/20 21:10:12
It's probably worth noting that when you modify 'r
kareng
2013/09/23 21:20:32
so you think its better to copy and return the cop
Michael Moss
2013/09/23 22:01:56
Modifying in-place is fine with me, just make it e
| |
625 | 677 |
626 def GetChromiumRevision(url): | 678 def GetChromiumRevision(url): |
627 """Returns the chromium revision read from given URL.""" | 679 """Returns the chromium revision read from given URL.""" |
628 try: | 680 try: |
629 # Location of the latest build revision number | 681 # Location of the latest build revision number |
630 return int(urllib.urlopen(url).read()) | 682 return int(urllib.urlopen(url).read()) |
631 except Exception, e: | 683 except Exception, e: |
632 print('Could not determine latest revision. This could be bad...') | 684 print('Could not determine latest revision. This could be bad...') |
633 return 999999999 | 685 return 999999999 |
634 | 686 |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
765 print 'BLINK CHANGELOG URL:' | 817 print 'BLINK CHANGELOG URL:' |
766 print ' ' + BLINK_CHANGELOG_URL % (max_blink_rev, min_blink_rev) | 818 print ' ' + BLINK_CHANGELOG_URL % (max_blink_rev, min_blink_rev) |
767 print 'CHANGELOG URL:' | 819 print 'CHANGELOG URL:' |
768 if opts.official_builds: | 820 if opts.official_builds: |
769 print OFFICIAL_CHANGELOG_URL % (min_chromium_rev, max_chromium_rev) | 821 print OFFICIAL_CHANGELOG_URL % (min_chromium_rev, max_chromium_rev) |
770 else: | 822 else: |
771 print ' ' + CHANGELOG_URL % (min_chromium_rev, max_chromium_rev) | 823 print ' ' + CHANGELOG_URL % (min_chromium_rev, max_chromium_rev) |
772 | 824 |
773 if __name__ == '__main__': | 825 if __name__ == '__main__': |
774 sys.exit(main()) | 826 sys.exit(main()) |
OLD | NEW |