1935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org#!/usr/bin/env python 2935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# Copyright 2013 the V8 project authors. All rights reserved. 3935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# Redistribution and use in source and binary forms, with or without 4935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# modification, are permitted provided that the following conditions are 5935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# met: 6935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# 7935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# * Redistributions of source code must retain the above copyright 8935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# notice, this list of conditions and the following disclaimer. 9935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# * Redistributions in binary form must reproduce the above 10935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# copyright notice, this list of conditions and the following 11935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# disclaimer in the documentation and/or other materials provided 12935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# with the distribution. 13935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# * Neither the name of Google Inc. nor the names of its 14935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# contributors may be used to endorse or promote products derived 15935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# from this software without specific prior written permission. 16935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# 17935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 29bc176057ae476990672de915df235c9aeadc8521titzer@chromium.orgimport argparse 30ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.orgimport datetime 31c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.orgimport httplib 3242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.orgimport glob 339e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.orgimport imp 34f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgimport json 35935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgimport os 36935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgimport re 3742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.orgimport shutil 38935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgimport subprocess 39935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgimport sys 409af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.orgimport textwrap 418a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.orgimport time 42c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.orgimport urllib 4390dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.orgimport urllib2 44935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 45f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgfrom git_recipes import GitRecipesMixin 465b080567cf135f6dbaf23973ba6b6fa1d6af83b3machenbach@chromium.orgfrom git_recipes import GitFailedException 47f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 4806b2696801712948b665372a38f96b1f10be6997machenbach@chromium.orgVERSION_FILE = os.path.join("src", "version.cc") 49935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 5042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org# V8 base directory. 5142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.orgDEFAULT_CWD = os.path.dirname( 5242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 5342ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org 54935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 55935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgdef TextToFile(text, file_name): 56935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org with open(file_name, "w") as f: 57935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org f.write(text) 58935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 59935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 60935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgdef AppendToFile(text, file_name): 61935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org with open(file_name, "a") as f: 62935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org f.write(text) 63935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 64935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 65935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgdef LinesInFile(file_name): 66935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org with open(file_name) as f: 67935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org for line in f: 68935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org yield line 69935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 70935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 71935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgdef FileToText(file_name): 72935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org with open(file_name) as f: 73935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org return f.read() 74935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 75935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 76935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgdef MSub(rexp, replacement, text): 77935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org return re.sub(rexp, replacement, text, flags=re.MULTILINE) 78935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 79935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 809af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.orgdef Fill80(line): 8190dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org # Replace tabs and remove surrounding space. 8290dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org line = re.sub(r"\t", r" ", line.strip()) 8390dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org 8490dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org # Format with 8 characters indentation and line width 80. 859af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org return textwrap.fill(line, width=80, initial_indent=" ", 869af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org subsequent_indent=" ") 879af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 889af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 897ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.orgdef MakeComment(text): 907ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org return MSub(r"^( ?)", "#", text) 917ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org 927ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org 937ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.orgdef StripComments(text): 947ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org # Use split not splitlines to keep terminal newlines. 957ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org return "\n".join(filter(lambda x: not x.startswith("#"), text.split("\n"))) 967ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org 977ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org 987ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.orgdef MakeChangeLogBody(commit_messages, auto_format=False): 99af9cfcbed5daf6e636e189bce451c6fafdbb127dmachenbach@chromium.org result = "" 1007ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org added_titles = set() 1017ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org for (title, body, author) in commit_messages: 10237be408adf363bbe682921a4a690752fa0ec33femachenbach@chromium.org # TODO(machenbach): Better check for reverts. A revert should remove the 10337be408adf363bbe682921a4a690752fa0ec33femachenbach@chromium.org # original CL from the actual log entry. 10490dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org title = title.strip() 1057ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org if auto_format: 1067ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org # Only add commits that set the LOG flag correctly. 107ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org log_exp = r"^[ \t]*LOG[ \t]*=[ \t]*(?:(?:Y(?:ES)?)|TRUE)" 1087ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org if not re.search(log_exp, body, flags=re.I | re.M): 1097ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org continue 1107ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org # Never include reverts. 1117ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org if title.startswith("Revert "): 1127ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org continue 1137ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org # Don't include duplicates. 1147ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org if title in added_titles: 1157ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org continue 1167ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org 11737be408adf363bbe682921a4a690752fa0ec33femachenbach@chromium.org # Add and format the commit's title and bug reference. Move dot to the end. 1187ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org added_titles.add(title) 11937be408adf363bbe682921a4a690752fa0ec33femachenbach@chromium.org raw_title = re.sub(r"(\.|\?|!)$", "", title) 12037be408adf363bbe682921a4a690752fa0ec33femachenbach@chromium.org bug_reference = MakeChangeLogBugReference(body) 12137be408adf363bbe682921a4a690752fa0ec33femachenbach@chromium.org space = " " if bug_reference else "" 12237be408adf363bbe682921a4a690752fa0ec33femachenbach@chromium.org result += "%s\n" % Fill80("%s%s%s." % (raw_title, space, bug_reference)) 123af9cfcbed5daf6e636e189bce451c6fafdbb127dmachenbach@chromium.org 1247ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org # Append the commit's author for reference if not in auto-format mode. 1257ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org if not auto_format: 12690dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org result += "%s\n" % Fill80("(%s)" % author.strip()) 1277ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org 1287ff7607c2315ea91e4d13330ce14125e4bb4851amachenbach@chromium.org result += "\n" 129af9cfcbed5daf6e636e189bce451c6fafdbb127dmachenbach@chromium.org return result 130af9cfcbed5daf6e636e189bce451c6fafdbb127dmachenbach@chromium.org 131af9cfcbed5daf6e636e189bce451c6fafdbb127dmachenbach@chromium.org 1329af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.orgdef MakeChangeLogBugReference(body): 1339af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org """Grep for "BUG=xxxx" lines in the commit message and convert them to 1349af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org "(issue xxxx)". 1359af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org """ 1369af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org crbugs = [] 1379af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org v8bugs = [] 1389af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 1399af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org def AddIssues(text): 1409af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org ref = re.match(r"^BUG[ \t]*=[ \t]*(.+)$", text.strip()) 1419af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org if not ref: 1429af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org return 1439af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org for bug in ref.group(1).split(","): 1449af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org bug = bug.strip() 1459af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org match = re.match(r"^v8:(\d+)$", bug) 1469af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org if match: v8bugs.append(int(match.group(1))) 1479af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org else: 1489af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org match = re.match(r"^(?:chromium:)?(\d+)$", bug) 1499af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org if match: crbugs.append(int(match.group(1))) 1509af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 1519af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org # Add issues to crbugs and v8bugs. 1529af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org map(AddIssues, body.splitlines()) 1539af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 1549af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org # Filter duplicates, sort, stringify. 1559af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org crbugs = map(str, sorted(set(crbugs))) 1569af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org v8bugs = map(str, sorted(set(v8bugs))) 1579af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 1589af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org bug_groups = [] 1599af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org def FormatIssues(prefix, bugs): 1609af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org if len(bugs) > 0: 1619af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org plural = "s" if len(bugs) > 1 else "" 1629af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org bug_groups.append("%sissue%s %s" % (prefix, plural, ", ".join(bugs))) 1639af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 1649af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org FormatIssues("", v8bugs) 1659af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org FormatIssues("Chromium ", crbugs) 1669af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 1679af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org if len(bug_groups) > 0: 16837be408adf363bbe682921a4a690752fa0ec33femachenbach@chromium.org return "(%s)" % ", ".join(bug_groups) 1699af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org else: 1709af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org return "" 1719af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 1729af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 1734c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.orgdef SortingKey(version): 1744c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org """Key for sorting version number strings: '3.11' > '3.2.1.1'""" 1754c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org version_keys = map(int, version.split(".")) 1764c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org # Fill up to full version numbers to normalize comparison. 1774c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org while len(version_keys) < 4: # pragma: no cover 1784c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org version_keys.append(0) 1794c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org # Fill digits. 1804c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org return ".".join(map("{0:04d}".format, version_keys)) 1814c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org 1824c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org 183935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# Some commands don't like the pipe, e.g. calling vi from within the script or 184935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# from subscripts like git cl upload. 18542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.orgdef Command(cmd, args="", prefix="", pipe=True, cwd=None): 18642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org cwd = cwd or os.getcwd() 1878a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org # TODO(machenbach): Use timeout. 188935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org cmd_line = "%s %s %s" % (prefix, cmd, args) 189935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print "Command: %s" % cmd_line 19042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org print "in %s" % cwd 191af6f699b0be532b73bc2f6c9e1cf40a57fa7e234machenbach@chromium.org sys.stdout.flush() 192935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org try: 193935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org if pipe: 19442ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org return subprocess.check_output(cmd_line, shell=True, cwd=cwd) 195935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org else: 19642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org return subprocess.check_call(cmd_line, shell=True, cwd=cwd) 197935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org except subprocess.CalledProcessError: 198935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org return None 199af6f699b0be532b73bc2f6c9e1cf40a57fa7e234machenbach@chromium.org finally: 200af6f699b0be532b73bc2f6c9e1cf40a57fa7e234machenbach@chromium.org sys.stdout.flush() 201af6f699b0be532b73bc2f6c9e1cf40a57fa7e234machenbach@chromium.org sys.stderr.flush() 202935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 203935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 204935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org# Wrapper for side effects. 205486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.orgclass SideEffectHandler(object): # pragma: no cover 20643c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org def Call(self, fun, *args, **kwargs): 20743c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org return fun(*args, **kwargs) 20843c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org 20942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org def Command(self, cmd, args="", prefix="", pipe=True, cwd=None): 21042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org return Command(cmd, args, prefix, pipe, cwd=cwd) 211935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 212935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def ReadLine(self): 213935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org return sys.stdin.readline().strip() 214935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 21526ca35cc4ec47151d9c6d3890b0f052fc79cb8afmachenbach@chromium.org def ReadURL(self, url, params=None): 21690dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org # pylint: disable=E1121 21726ca35cc4ec47151d9c6d3890b0f052fc79cb8afmachenbach@chromium.org url_fh = urllib2.urlopen(url, params, 60) 21890dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org try: 21990dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org return url_fh.read() 22090dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org finally: 22190dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org url_fh.close() 22290dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org 223c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org def ReadClusterFuzzAPI(self, api_key, **params): 224c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org params["api_key"] = api_key.strip() 225c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org params = urllib.urlencode(params) 226c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org 227c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org headers = {"Content-type": "application/x-www-form-urlencoded"} 228c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org 229c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org conn = httplib.HTTPSConnection("backend-dot-cluster-fuzz.appspot.com") 230c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org conn.request("POST", "/_api/", params, headers) 231c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org 232c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org response = conn.getresponse() 233c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org data = response.read() 234c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org 235c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org try: 236c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org return json.loads(data) 237c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org except: 238c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org print data 239c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org print "ERROR: Could not read response. Is your key valid?" 240c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org raise 241c3564d8de4ebfc4fa3dc009fc9f6f18968ffcbd7machenbach@chromium.org 242ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org def Sleep(self, seconds): 2438a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org time.sleep(seconds) 2448a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org 245ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org def GetDate(self): 246ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org return datetime.date.today().strftime("%Y-%m-%d") 247ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org 248474e8b19cf12dc057572a8543864dd6586ee0a65machenbach@chromium.org def GetUTCStamp(self): 249f2af15a6b44ea6276bdd609ee122babe52842a42machenbach@chromium.org return time.mktime(datetime.datetime.utcnow().timetuple()) 250474e8b19cf12dc057572a8543864dd6586ee0a65machenbach@chromium.org 251935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgDEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler() 252935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 253935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 25480108f7c5afc50b5289595a9384e7d2f085cb679hpayer@chromium.orgclass NoRetryException(Exception): 25580108f7c5afc50b5289595a9384e7d2f085cb679hpayer@chromium.org pass 25680108f7c5afc50b5289595a9384e7d2f085cb679hpayer@chromium.org 2579cbaabda8b4daeb06759ace10c926ab55bb69d7bulan@chromium.org 258f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.orgclass Step(GitRecipesMixin): 25906b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org def __init__(self, text, number, config, state, options, handler): 260935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self._text = text 261935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self._number = number 262935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self._config = config 263935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self._state = state 264935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self._options = options 265935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self._side_effect_handler = handler 26642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org 26742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org # The testing configuration might set a different default cwd. 26842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org self.default_cwd = self._config.get("DEFAULT_CWD") or DEFAULT_CWD 26942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org 27090dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org assert self._number >= 0 27190dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org assert self._config is not None 27290dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org assert self._state is not None 27390dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org assert self._side_effect_handler is not None 274935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 275f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org def __getitem__(self, key): 276f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org # Convenience method to allow direct [] access on step classes for 277f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org # manipulating the backed state dict. 278f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org return self._state[key] 279f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 280f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org def __setitem__(self, key, value): 281f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org # Convenience method to allow direct [] access on step classes for 282f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org # manipulating the backed state dict. 283f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org self._state[key] = value 284f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 285935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def Config(self, key): 286935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org return self._config[key] 287935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 288935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def Run(self): 289f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org # Restore state. 29006b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org state_file = "%s-state.json" % self._config["PERSISTFILE_BASENAME"] 291f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org if not self._state and os.path.exists(state_file): 292f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org self._state.update(json.loads(FileToText(state_file))) 293f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 294935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print ">>> Step %d: %s" % (self._number, self._text) 2954edebd5691ee147fa134ad8aaf6cc3c939831b93machenbach@chromium.org try: 2964edebd5691ee147fa134ad8aaf6cc3c939831b93machenbach@chromium.org return self.RunStep() 2974edebd5691ee147fa134ad8aaf6cc3c939831b93machenbach@chromium.org finally: 2984edebd5691ee147fa134ad8aaf6cc3c939831b93machenbach@chromium.org # Persist state. 2994edebd5691ee147fa134ad8aaf6cc3c939831b93machenbach@chromium.org TextToFile(json.dumps(self._state), state_file) 300f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 301486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.org def RunStep(self): # pragma: no cover 302935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org raise NotImplementedError 303935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 3048a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org def Retry(self, cb, retry_on=None, wait_plan=None): 3058a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org """ Retry a function. 3068a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org Params: 3078a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org cb: The function to retry. 3088a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org retry_on: A callback that takes the result of the function and returns 3098a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org True if the function should be retried. A function throwing an 3108a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org exception is always retried. 3118a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org wait_plan: A list of waiting delays between retries in seconds. The 3128a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org maximum number of retries is len(wait_plan). 3138a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org """ 3148a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org retry_on = retry_on or (lambda x: False) 3158a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org wait_plan = list(wait_plan or []) 3168a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org wait_plan.reverse() 3178a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org while True: 3188a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org got_exception = False 3198a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org try: 3208a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org result = cb() 3219aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org except NoRetryException as e: 32280108f7c5afc50b5289595a9384e7d2f085cb679hpayer@chromium.org raise e 3239aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org except Exception as e: 3249aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org got_exception = e 3258a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org if got_exception or retry_on(result): 326486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.org if not wait_plan: # pragma: no cover 3279aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org raise Exception("Retried too often. Giving up. Reason: %s" % 3289aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org str(got_exception)) 3298a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org wait_time = wait_plan.pop() 3308a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org print "Waiting for %f seconds." % wait_time 3318a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org self._side_effect_handler.Sleep(wait_time) 3328a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org print "Retrying..." 3338a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org else: 3348a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org return result 3358a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org 3369af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org def ReadLine(self, default=None): 3379af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org # Don't prompt in forced mode. 33880108f7c5afc50b5289595a9384e7d2f085cb679hpayer@chromium.org if self._options.force_readline_defaults and default is not None: 3399af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org print "%s (forced)" % default 3409af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org return default 3419af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org else: 3429af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org return self._side_effect_handler.ReadLine() 343935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 34442ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org def Command(self, name, args, cwd=None): 34542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org cmd = lambda: self._side_effect_handler.Command( 34642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org name, args, "", True, cwd=cwd or self.default_cwd) 34742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org return self.Retry(cmd, None, [5]) 34842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org 34942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org def Git(self, args="", prefix="", pipe=True, retry_on=None, cwd=None): 35042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org cmd = lambda: self._side_effect_handler.Command( 35142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org "git", args, prefix, pipe, cwd=cwd or self.default_cwd) 352f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org result = self.Retry(cmd, retry_on, [5, 30]) 353f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org if result is None: 354f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org raise GitFailedException("'git %s' failed." % args) 355f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org return result 356f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 35742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org def SVN(self, args="", prefix="", pipe=True, retry_on=None, cwd=None): 35842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org cmd = lambda: self._side_effect_handler.Command( 35942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org "svn", args, prefix, pipe, cwd=cwd or self.default_cwd) 360d91c2cb3b3e3a5e4d2eed51586755c9d747e9508machenbach@chromium.org return self.Retry(cmd, retry_on, [5, 30]) 361d91c2cb3b3e3a5e4d2eed51586755c9d747e9508machenbach@chromium.org 362935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def Editor(self, args): 36380108f7c5afc50b5289595a9384e7d2f085cb679hpayer@chromium.org if self._options.requires_editor: 36442ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org return self._side_effect_handler.Command( 36542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org os.environ["EDITOR"], 36642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org args, 36742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org pipe=False, 36842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org cwd=self.default_cwd) 369935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 37026ca35cc4ec47151d9c6d3890b0f052fc79cb8afmachenbach@chromium.org def ReadURL(self, url, params=None, retry_on=None, wait_plan=None): 3718a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org wait_plan = wait_plan or [3, 60, 600] 37226ca35cc4ec47151d9c6d3890b0f052fc79cb8afmachenbach@chromium.org cmd = lambda: self._side_effect_handler.ReadURL(url, params) 3738a58f6420f995bb19fff9babb261458d49d90cb1machenbach@chromium.org return self.Retry(cmd, retry_on, wait_plan) 37490dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org 375ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org def GetDate(self): 376ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org return self._side_effect_handler.GetDate() 377ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org 378935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def Die(self, msg=""): 379935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org if msg != "": 380935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print "Error: %s" % msg 381935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print "Exiting" 382935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org raise Exception(msg) 383935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 384ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org def DieNoManualMode(self, msg=""): 385486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.org if not self._options.manual: # pragma: no cover 386ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org msg = msg or "Only available in manual mode." 3879af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org self.Die(msg) 3889af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 389935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def Confirm(self, msg): 390935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print "%s [Y/n] " % msg, 3919af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org answer = self.ReadLine(default="Y") 392935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org return answer == "" or answer == "Y" or answer == "y" 393935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 394935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def DeleteBranch(self, name): 395f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org for line in self.GitBranch().splitlines(): 3964c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org if re.match(r"\*?\s*%s$" % re.escape(name), line): 397935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org msg = "Branch %s exists, do you want to delete it?" % name 398935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org if self.Confirm(msg): 399f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org self.GitDeleteBranch(name) 400935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print "Branch %s deleted." % name 401935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org else: 402935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org msg = "Can't continue. Please delete branch %s and try again." % name 403935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self.Die(msg) 404935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 405a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org def InitialEnvironmentChecks(self, cwd): 406935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org # Cancel if this is not a git checkout. 407a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org if not os.path.exists(os.path.join(cwd, ".git")): # pragma: no cover 408935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self.Die("This is not a git checkout, this script won't work for you.") 409935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 410935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org # Cancel if EDITOR is unset or not executable. 41180108f7c5afc50b5289595a9384e7d2f085cb679hpayer@chromium.org if (self._options.requires_editor and (not os.environ.get("EDITOR") or 41242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org self.Command( 41342ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org "which", os.environ["EDITOR"]) is None)): # pragma: no cover 414935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self.Die("Please set your EDITOR environment variable, you'll need it.") 415935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 416935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def CommonPrepare(self): 417935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org # Check for a clean workdir. 418486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.org if not self.GitIsWorkdirClean(): # pragma: no cover 419935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self.Die("Workspace is not clean. Please commit or undo your changes.") 420935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 421935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org # Persist current branch. 422f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org self["current_branch"] = self.GitCurrentBranch() 423935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 424935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org # Fetch unfetched revisions. 425f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org self.GitSVNFetch() 426935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 427af9cfcbed5daf6e636e189bce451c6fafdbb127dmachenbach@chromium.org def PrepareBranch(self): 428935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org # Delete the branch that will be created later if it exists already. 42906b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org self.DeleteBranch(self._config["BRANCHNAME"]) 430935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 431935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def CommonCleanup(self): 432f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org self.GitCheckout(self["current_branch"]) 43306b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org if self._config["BRANCHNAME"] != self["current_branch"]: 43406b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org self.GitDeleteBranch(self._config["BRANCHNAME"]) 435935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 436935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org # Clean up all temporary files. 43706b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org for f in glob.iglob("%s*" % self._config["PERSISTFILE_BASENAME"]): 43842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org if os.path.isfile(f): 43942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org os.remove(f) 44042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org if os.path.isdir(f): 44142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org shutil.rmtree(f) 442935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 443935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def ReadAndPersistVersion(self, prefix=""): 444935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def ReadAndPersist(var_name, def_name): 445935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org match = re.match(r"^#define %s\s+(\d*)" % def_name, line) 446935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org if match: 447935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org value = match.group(1) 448f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org self["%s%s" % (prefix, var_name)] = value 44906b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org for line in LinesInFile(os.path.join(self.default_cwd, VERSION_FILE)): 450935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org for (var_name, def_name) in [("major", "MAJOR_VERSION"), 451935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org ("minor", "MINOR_VERSION"), 452935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org ("build", "BUILD_NUMBER"), 453935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org ("patch", "PATCH_LEVEL")]: 454935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org ReadAndPersist(var_name, def_name) 455935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 456935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def WaitForLGTM(self): 457935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print ("Please wait for an LGTM, then type \"LGTM<Return>\" to commit " 458935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org "your change. (If you need to iterate on the patch or double check " 459935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org "that it's sane, do so in another shell, but remember to not " 460935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org "change the headline of the uploaded CL.") 461935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org answer = "" 462935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org while answer != "LGTM": 463935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print "> ", 46480108f7c5afc50b5289595a9384e7d2f085cb679hpayer@chromium.org answer = self.ReadLine(None if self._options.wait_for_lgtm else "LGTM") 465935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org if answer != "LGTM": 466935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print "That was not 'LGTM'." 467935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 468935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def WaitForResolvingConflicts(self, patch_file): 469935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print("Applying the patch \"%s\" failed. Either type \"ABORT<Return>\", " 470935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org "or resolve the conflicts, stage *all* touched files with " 471935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org "'git add', and type \"RESOLVED<Return>\"") 472ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org self.DieNoManualMode() 473935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org answer = "" 474935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org while answer != "RESOLVED": 475935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org if answer == "ABORT": 476935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self.Die("Applying the patch failed.") 477935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org if answer != "": 478935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print "That was not 'RESOLVED' or 'ABORT'." 479935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org print "> ", 480935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org answer = self.ReadLine() 481935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 482935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org # Takes a file containing the patch to apply as first argument. 483f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org def ApplyPatch(self, patch_file, revert=False): 484f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org try: 485f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org self.GitApplyPatch(patch_file, revert) 486f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org except GitFailedException: 487935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org self.WaitForResolvingConflicts(patch_file) 488935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 4899aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org def FindLastTrunkPush( 4909aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org self, parent_hash="", branch="", include_patches=False): 4918f8fe81d7a9cced7a0d30e56124c0428d1a6d229machenbach@chromium.org push_pattern = "^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*" 4928f8fe81d7a9cced7a0d30e56124c0428d1a6d229machenbach@chromium.org if not include_patches: 4938f8fe81d7a9cced7a0d30e56124c0428d1a6d229machenbach@chromium.org # Non-patched versions only have three numbers followed by the "(based 4948f8fe81d7a9cced7a0d30e56124c0428d1a6d229machenbach@chromium.org # on...) comment." 4958f8fe81d7a9cced7a0d30e56124c0428d1a6d229machenbach@chromium.org push_pattern += " (based" 4969aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org branch = "" if parent_hash else branch or "svn/trunk" 497f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org return self.GitLog(n=1, format="%H", grep=push_pattern, 498f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org parent_hash=parent_hash, branch=branch) 499f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 5004c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org def ArrayToVersion(self, prefix): 5014c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org return ".".join([self[prefix + "major"], 5024c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org self[prefix + "minor"], 5034c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org self[prefix + "build"], 5044c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org self[prefix + "patch"]]) 5054c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org 5064c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org def SetVersion(self, version_file, prefix): 5074c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org output = "" 5084c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org for line in FileToText(version_file).splitlines(): 5094c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org if line.startswith("#define MAJOR_VERSION"): 5104c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org line = re.sub("\d+$", self[prefix + "major"], line) 5114c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org elif line.startswith("#define MINOR_VERSION"): 5124c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org line = re.sub("\d+$", self[prefix + "minor"], line) 5134c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org elif line.startswith("#define BUILD_NUMBER"): 5144c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org line = re.sub("\d+$", self[prefix + "build"], line) 5154c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org elif line.startswith("#define PATCH_LEVEL"): 5164c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org line = re.sub("\d+$", self[prefix + "patch"], line) 5174c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org output += "%s\n" % line 5184c3ce7c3fd2802da8f91c6516a9c9aea3cd93f1emachenbach@chromium.org TextToFile(output, version_file) 519935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 52042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org def SVNCommit(self, root, commit_message): 52142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org patch = self.GitDiff("HEAD^", "HEAD") 52206b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org TextToFile(patch, self._config["PATCH_FILE"]) 52342ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org self.Command("svn", "update", cwd=self._options.svn) 52442ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org if self.Command("svn", "status", cwd=self._options.svn) != "": 52542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org self.Die("SVN checkout not clean.") 52642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org if not self.Command("patch", "-d %s -p1 -i %s" % 52706b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org (root, self._config["PATCH_FILE"]), 52842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org cwd=self._options.svn): 52942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org self.Die("Could not apply patch.") 53042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org self.Command( 53142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org "svn", 53242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org "commit --non-interactive --username=%s --config-dir=%s -m \"%s\"" % 53342ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org (self._options.author, self._options.svn_config, commit_message), 53442ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org cwd=self._options.svn) 53542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org 53642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org 537935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.orgclass UploadStep(Step): 53890dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org MESSAGE = "Upload for code review." 539935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org 540935a7790c70d49e252069bc2d34eaa72f8c6677fmachenbach@chromium.org def RunStep(self): 541f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org if self._options.reviewer: 542f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org print "Using account %s for review." % self._options.reviewer 543f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org reviewer = self._options.reviewer 5449af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org else: 5459af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org print "Please enter the email address of a V8 reviewer for your patch: ", 546ddf3811f8018dfe9e8ec7d1b8f4a8be1122fd767machenbach@chromium.org self.DieNoManualMode("A reviewer must be specified in forced mode.") 5479af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org reviewer = self.ReadLine() 5482c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org self.GitUpload(reviewer, self._options.author, self._options.force_upload, 5492c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org bypass_hooks=self._options.bypass_upload_hooks) 550af9cfcbed5daf6e636e189bce451c6fafdbb127dmachenbach@chromium.org 551af9cfcbed5daf6e636e189bce451c6fafdbb127dmachenbach@chromium.org 5529e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.orgclass DetermineV8Sheriff(Step): 5539e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org MESSAGE = "Determine the V8 sheriff for code review." 5549e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org 5559e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org def RunStep(self): 5569e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org self["sheriff"] = None 5579e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org if not self._options.sheriff: # pragma: no cover 5589e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org return 5599e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org 5609e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org try: 5619e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org # The googlers mapping maps @google.com accounts to @chromium.org 5629e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org # accounts. 5639e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org googlers = imp.load_source('googlers_mapping', 5649e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org self._options.googlers_mapping) 5659e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org googlers = googlers.list_to_dict(googlers.get_list()) 5669e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org except: # pragma: no cover 5679e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org print "Skip determining sheriff without googler mapping." 5689e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org return 5699e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org 5709e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org # The sheriff determined by the rotation on the waterfall has a 5719e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org # @google.com account. 5729e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org url = "https://chromium-build.appspot.com/p/chromium/sheriff_v8.js" 5739e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org match = re.match(r"document\.write\('(\w+)'\)", self.ReadURL(url)) 5749e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org 5759e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org # If "channel is sheriff", we can't match an account. 5769e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org if match: 5779e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org g_name = match.group(1) 5789e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org self["sheriff"] = googlers.get(g_name + "@google.com", 5799e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org g_name + "@chromium.org") 5809e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org self._options.reviewer = self["sheriff"] 5819e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org print "Found active sheriff: %s" % self["sheriff"] 5829e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org else: 5839e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org print "No active sheriff found." 5849e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org 5859e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org 58690dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.orgdef MakeStep(step_class=Step, number=0, state=None, config=None, 58790dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 58890dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org # Allow to pass in empty dictionaries. 58990dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org state = state if state is not None else {} 59090dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org config = config if config is not None else {} 59190dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org 59290dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org try: 59390dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org message = step_class.MESSAGE 59490dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org except AttributeError: 59590dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org message = step_class.__name__ 59690dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org 59706b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org return step_class(message, number=number, config=config, 59890dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org state=state, options=options, 59990dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org handler=side_effect_handler) 60090dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org 60190dca01eac542464c29011d239bf18f26e0b8f00machenbach@chromium.org 602bc176057ae476990672de915df235c9aeadc8521titzer@chromium.orgclass ScriptsBase(object): 603bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org # TODO(machenbach): Move static config here. 60406b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org def __init__(self, 60506b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org config=None, 60606b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER, 607bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org state=None): 60806b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org self._config = config or self._Config() 609bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org self._side_effect_handler = side_effect_handler 610bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org self._state = state if state is not None else {} 611bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 612bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org def _Description(self): 613bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org return None 614bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 615bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org def _PrepareOptions(self, parser): 616bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org pass 617bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 618bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org def _ProcessOptions(self, options): 619bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org return True 620bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 621486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.org def _Steps(self): # pragma: no cover 622bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org raise Exception("Not implemented.") 623bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 62406b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org def _Config(self): 62506b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org return {} 62606b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org 627bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org def MakeOptions(self, args=None): 628bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org parser = argparse.ArgumentParser(description=self._Description()) 629bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org parser.add_argument("-a", "--author", default="", 630bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org help="The author email used for rietveld.") 6319aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org parser.add_argument("--dry-run", default=False, action="store_true", 6329aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org help="Perform only read-only actions.") 6339e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org parser.add_argument("-g", "--googlers-mapping", 6349e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org help="Path to the script mapping google accounts.") 635bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org parser.add_argument("-r", "--reviewer", default="", 636bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org help="The account name to be used for reviews.") 6379e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org parser.add_argument("--sheriff", default=False, action="store_true", 6389e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org help=("Determine current sheriff to review CLs. On " 6399e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org "success, this will overwrite the reviewer " 6409e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org "option.")) 64142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org parser.add_argument("--svn", 64242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org help=("Optional full svn checkout for the commit." 64342ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org "The folder needs to be the svn root.")) 64442ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org parser.add_argument("--svn-config", 64542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org help=("Optional folder used as svn --config-dir.")) 646bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org parser.add_argument("-s", "--step", 6479e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org help="Specify the step where to start work. Default: 0.", 6489e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org default=0, type=int) 649bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org self._PrepareOptions(parser) 650bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 651486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.org if args is None: # pragma: no cover 652bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options = parser.parse_args() 653bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org else: 654bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options = parser.parse_args(args) 655bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 656bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org # Process common options. 657486536df718553960f9700559e80e5b10b0d5994dslomov@chromium.org if options.step < 0: # pragma: no cover 658bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org print "Bad step number %d" % options.step 659bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org parser.print_help() 660bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org return None 6619e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org if options.sheriff and not options.googlers_mapping: # pragma: no cover 6629e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org print "To determine the current sheriff, requires the googler mapping" 6639e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org parser.print_help() 6649e41f9ecf5042292a9efcb36e264b37621199553machenbach@chromium.org return None 66542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org if options.svn and not options.svn_config: 66642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org print "Using pure svn for committing requires also --svn-config" 66742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org parser.print_help() 66842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org return None 669bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 670bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org # Defaults for options, common to all scripts. 671bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options.manual = getattr(options, "manual", True) 672bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options.force = getattr(options, "force", False) 6732c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org options.bypass_upload_hooks = False 674bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 675bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org # Derived options. 676bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options.requires_editor = not options.force 677bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options.wait_for_lgtm = not options.force 678bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options.force_readline_defaults = not options.manual 679bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options.force_upload = not options.manual 680bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 681bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org # Process script specific options. 682bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org if not self._ProcessOptions(options): 683bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org parser.print_help() 684bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org return None 685bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org return options 686bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 687bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org def RunSteps(self, step_classes, args=None): 688bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options = self.MakeOptions(args) 689bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org if not options: 690bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org return 1 691bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 69206b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org state_file = "%s-state.json" % self._config["PERSISTFILE_BASENAME"] 693bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org if options.step == 0 and os.path.exists(state_file): 694bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org os.remove(state_file) 695bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 696bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org steps = [] 697bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org for (number, step_class) in enumerate(step_classes): 698bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org steps.append(MakeStep(step_class, number, self._state, self._config, 699bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org options, self._side_effect_handler)) 700bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org for step in steps[options.step:]: 7014edebd5691ee147fa134ad8aaf6cc3c939831b93machenbach@chromium.org if step.Run(): 7021af4d9551ad496a28c342004b1a4e2a3840228f7machenbach@chromium.org return 0 703bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org return 0 704bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org 705bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org def Run(self, args=None): 706bc176057ae476990672de915df235c9aeadc8521titzer@chromium.org return self.RunSteps(self._Steps(), args) 707