10d24de9dSSimon Glass#!/usr/bin/python 20d24de9dSSimon Glass# 30d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors. 40d24de9dSSimon Glass# 50d24de9dSSimon Glass# See file CREDITS for list of people who contributed to this 60d24de9dSSimon Glass# project. 70d24de9dSSimon Glass# 80d24de9dSSimon Glass# This program is free software; you can redistribute it and/or 90d24de9dSSimon Glass# modify it under the terms of the GNU General Public License as 100d24de9dSSimon Glass# published by the Free Software Foundation; either version 2 of 110d24de9dSSimon Glass# the License, or (at your option) any later version. 120d24de9dSSimon Glass# 130d24de9dSSimon Glass# This program is distributed in the hope that it will be useful, 140d24de9dSSimon Glass# but WITHOUT ANY WARRANTY; without even the implied warranty of 150d24de9dSSimon Glass# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 160d24de9dSSimon Glass# GNU General Public License for more details. 170d24de9dSSimon Glass# 180d24de9dSSimon Glass# You should have received a copy of the GNU General Public License 190d24de9dSSimon Glass# along with this program; if not, write to the Free Software 200d24de9dSSimon Glass# Foundation, Inc., 59 Temple Place, Suite 330, Boston, 210d24de9dSSimon Glass# MA 02111-1307 USA 220d24de9dSSimon Glass# 230d24de9dSSimon Glass 240d24de9dSSimon Glass"""See README for more information""" 250d24de9dSSimon Glass 260d24de9dSSimon Glassfrom optparse import OptionParser 270d24de9dSSimon Glassimport os 280d24de9dSSimon Glassimport re 290d24de9dSSimon Glassimport sys 300d24de9dSSimon Glassimport unittest 310d24de9dSSimon Glass 320d24de9dSSimon Glass# Our modules 330d24de9dSSimon Glassimport checkpatch 340d24de9dSSimon Glassimport command 350d24de9dSSimon Glassimport gitutil 360d24de9dSSimon Glassimport patchstream 37*8568baedSDoug Andersonimport settings 380d24de9dSSimon Glassimport terminal 390d24de9dSSimon Glassimport test 400d24de9dSSimon Glass 410d24de9dSSimon Glass 420d24de9dSSimon Glassparser = OptionParser() 430d24de9dSSimon Glassparser.add_option('-H', '--full-help', action='store_true', dest='full_help', 440d24de9dSSimon Glass default=False, help='Display the README file') 450d24de9dSSimon Glassparser.add_option('-c', '--count', dest='count', type='int', 460d24de9dSSimon Glass default=-1, help='Automatically create patches from top n commits') 470d24de9dSSimon Glassparser.add_option('-i', '--ignore-errors', action='store_true', 480d24de9dSSimon Glass dest='ignore_errors', default=False, 490d24de9dSSimon Glass help='Send patches email even if patch errors are found') 500d24de9dSSimon Glassparser.add_option('-n', '--dry-run', action='store_true', dest='dry_run', 510d24de9dSSimon Glass default=False, help="Do a try run (create but don't email patches)") 520d24de9dSSimon Glassparser.add_option('-s', '--start', dest='start', type='int', 530d24de9dSSimon Glass default=0, help='Commit to start creating patches from (0 = HEAD)') 540d24de9dSSimon Glassparser.add_option('-t', '--test', action='store_true', dest='test', 550d24de9dSSimon Glass default=False, help='run tests') 560d24de9dSSimon Glassparser.add_option('-v', '--verbose', action='store_true', dest='verbose', 570d24de9dSSimon Glass default=False, help='Verbose output of errors and warnings') 580d24de9dSSimon Glassparser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store', 590d24de9dSSimon Glass default=None, help='Output cc list for patch file (used by git)') 600d24de9dSSimon Glassparser.add_option('--no-tags', action='store_false', dest='process_tags', 610d24de9dSSimon Glass default=True, help="Don't process subject tags as aliaes") 620d24de9dSSimon Glass 630d24de9dSSimon Glassparser.usage = """patman [options] 640d24de9dSSimon Glass 650d24de9dSSimon GlassCreate patches from commits in a branch, check them and email them as 660d24de9dSSimon Glassspecified by tags you place in the commits. Use -n to """ 670d24de9dSSimon Glass 68*8568baedSDoug Anderson 69*8568baedSDoug Andersonsettings.Setup(parser, '') 700d24de9dSSimon Glass(options, args) = parser.parse_args() 710d24de9dSSimon Glass 720d24de9dSSimon Glass# Run our meagre tests 730d24de9dSSimon Glassif options.test: 740d24de9dSSimon Glass import doctest 750d24de9dSSimon Glass 760d24de9dSSimon Glass sys.argv = [sys.argv[0]] 770d24de9dSSimon Glass suite = unittest.TestLoader().loadTestsFromTestCase(test.TestPatch) 780d24de9dSSimon Glass result = unittest.TestResult() 790d24de9dSSimon Glass suite.run(result) 800d24de9dSSimon Glass 810d24de9dSSimon Glass suite = doctest.DocTestSuite('gitutil') 820d24de9dSSimon Glass suite.run(result) 830d24de9dSSimon Glass 840d24de9dSSimon Glass # TODO: Surely we can just 'print' result? 850d24de9dSSimon Glass print result 860d24de9dSSimon Glass for test, err in result.errors: 870d24de9dSSimon Glass print err 880d24de9dSSimon Glass for test, err in result.failures: 890d24de9dSSimon Glass print err 900d24de9dSSimon Glass 910d24de9dSSimon Glass# Called from git with a patch filename as argument 920d24de9dSSimon Glass# Printout a list of additional CC recipients for this patch 930d24de9dSSimon Glasselif options.cc_cmd: 940d24de9dSSimon Glass fd = open(options.cc_cmd, 'r') 950d24de9dSSimon Glass re_line = re.compile('(\S*) (.*)') 960d24de9dSSimon Glass for line in fd.readlines(): 970d24de9dSSimon Glass match = re_line.match(line) 980d24de9dSSimon Glass if match and match.group(1) == args[0]: 990d24de9dSSimon Glass for cc in match.group(2).split(', '): 1000d24de9dSSimon Glass cc = cc.strip() 1010d24de9dSSimon Glass if cc: 1020d24de9dSSimon Glass print cc 1030d24de9dSSimon Glass fd.close() 1040d24de9dSSimon Glass 1050d24de9dSSimon Glasselif options.full_help: 1060d24de9dSSimon Glass pager = os.getenv('PAGER') 1070d24de9dSSimon Glass if not pager: 1080d24de9dSSimon Glass pager = 'more' 1090d24de9dSSimon Glass fname = os.path.join(os.path.dirname(sys.argv[0]), 'README') 1100d24de9dSSimon Glass command.Run(pager, fname) 1110d24de9dSSimon Glass 1120d24de9dSSimon Glass# Process commits, produce patches files, check them, email them 1130d24de9dSSimon Glasselse: 1140d24de9dSSimon Glass gitutil.Setup() 1150d24de9dSSimon Glass 1160d24de9dSSimon Glass if options.count == -1: 1170d24de9dSSimon Glass # Work out how many patches to send if we can 1180d24de9dSSimon Glass options.count = gitutil.CountCommitsToBranch() - options.start 1190d24de9dSSimon Glass 1200d24de9dSSimon Glass col = terminal.Color() 1210d24de9dSSimon Glass if not options.count: 1220d24de9dSSimon Glass str = 'No commits found to process - please use -c flag' 1230d24de9dSSimon Glass print col.Color(col.RED, str) 1240d24de9dSSimon Glass sys.exit(1) 1250d24de9dSSimon Glass 1260d24de9dSSimon Glass # Read the metadata from the commits 1270d24de9dSSimon Glass if options.count: 1280d24de9dSSimon Glass series = patchstream.GetMetaData(options.start, options.count) 1290d24de9dSSimon Glass cover_fname, args = gitutil.CreatePatches(options.start, options.count, 1300d24de9dSSimon Glass series) 1310d24de9dSSimon Glass 1320d24de9dSSimon Glass # Fix up the patch files to our liking, and insert the cover letter 1330d24de9dSSimon Glass series = patchstream.FixPatches(series, args) 1340d24de9dSSimon Glass if series and cover_fname and series.get('cover'): 1350d24de9dSSimon Glass patchstream.InsertCoverLetter(cover_fname, series, options.count) 1360d24de9dSSimon Glass 1370d24de9dSSimon Glass # Do a few checks on the series 1380d24de9dSSimon Glass series.DoChecks() 1390d24de9dSSimon Glass 1400d24de9dSSimon Glass # Check the patches, and run them through 'git am' just to be sure 1410d24de9dSSimon Glass ok = checkpatch.CheckPatches(options.verbose, args) 1420d24de9dSSimon Glass if not gitutil.ApplyPatches(options.verbose, args, 1430d24de9dSSimon Glass options.count + options.start): 1440d24de9dSSimon Glass ok = False 1450d24de9dSSimon Glass 14631187255SDoug Anderson cc_file = series.MakeCcFile(options.process_tags, cover_fname) 147d94566a1SDoug Anderson 1480d24de9dSSimon Glass # Email the patches out (giving the user time to check / cancel) 1490d24de9dSSimon Glass cmd = '' 1500d24de9dSSimon Glass if ok or options.ignore_errors: 1510d24de9dSSimon Glass cmd = gitutil.EmailPatches(series, cover_fname, args, 1520d24de9dSSimon Glass options.dry_run, cc_file) 1530d24de9dSSimon Glass 1540d24de9dSSimon Glass # For a dry run, just show our actions as a sanity check 1550d24de9dSSimon Glass if options.dry_run: 1560d24de9dSSimon Glass series.ShowActions(args, cmd, options.process_tags) 157d94566a1SDoug Anderson 158d94566a1SDoug Anderson os.remove(cc_file) 159