Revert "Merge tag 'dm-pull-20jul20' of git://git.denx.de/u-boot-dm"

This reverts commit 5d3a21df6694ebd66d5c34c9d62a26edc7456fc7, reversing
changes made to 56d37f1c564107e27d873181d838571b7d7860e7.

Unfortunately this is causing CI failures:
https://travis-ci.org/github/trini/u-boot/jobs/711313649

Signed-off-by: Tom Rini <trini@konsulko.com>
diff --git a/tools/patman/checkpatch.py b/tools/patman/checkpatch.py
index 263bac3..07c3e27 100644
--- a/tools/patman/checkpatch.py
+++ b/tools/patman/checkpatch.py
@@ -41,12 +41,6 @@
 def CheckPatch(fname, verbose=False, show_types=False):
     """Run checkpatch.pl on a file.
 
-    Args:
-        fname: Filename to check
-        verbose: True to print out every line of the checkpatch output as it is
-            parsed
-        show_types: Tell checkpatch to show the type (number) of each message
-
     Returns:
         namedtuple containing:
             ok: False=failure, True=ok
diff --git a/tools/patman/commit.py b/tools/patman/commit.py
index 8d583c4..48d0529 100644
--- a/tools/patman/commit.py
+++ b/tools/patman/commit.py
@@ -2,7 +2,6 @@
 # Copyright (c) 2011 The Chromium OS Authors.
 #
 
-import collections
 import re
 
 # Separates a tag: at the beginning of the subject from the rest of it
@@ -24,9 +23,6 @@
         notes: List of lines in the commit (not series) notes
         change_id: the Change-Id: tag that was stripped from this commit
             and can be used to generate the Message-Id.
-        rtags: Response tags (e.g. Reviewed-by) collected by the commit, dict:
-            key: rtag type (e.g. 'Reviewed-by')
-            value: Set of people who gave that rtag, each a name/email string
     """
     def __init__(self, hash):
         self.hash = hash
@@ -37,7 +33,6 @@
         self.signoff_set = set()
         self.notes = []
         self.change_id = None
-        self.rtags = collections.defaultdict(set)
 
     def AddChange(self, version, info):
         """Add a new change line to the change list for a version.
@@ -93,12 +88,3 @@
           return False
         self.signoff_set.add(signoff)
         return True
-
-    def AddRtag(self, rtag_type, who):
-        """Add a response tag to a commit
-
-        Args:
-            key: rtag type (e.g. 'Reviewed-by')
-            who: Person who gave that rtag, e.g. 'Fred Bloggs <fred@bloggs.org>'
-        """
-        self.rtags[rtag_type].add(who)
diff --git a/tools/patman/control.py b/tools/patman/control.py
deleted file mode 100644
index 67e8f39..0000000
--- a/tools/patman/control.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-#
-# Copyright 2020 Google LLC
-#
-"""Handles the main control logic of patman
-
-This module provides various functions called by the main program to implement
-the features of patman.
-"""
-
-import os
-import sys
-
-from patman import checkpatch
-from patman import gitutil
-from patman import patchstream
-from patman import terminal
-
-def setup():
-    """Do required setup before doing anything"""
-    gitutil.Setup()
-
-def prepare_patches(col, branch, count, start, end, ignore_binary):
-    """Figure out what patches to generate, then generate them
-
-    The patch files are written to the current directory, e.g. 0001_xxx.patch
-    0002_yyy.patch
-
-    Args:
-        col (terminal.Color): Colour output object
-        branch (str): Branch to create patches from (None = current)
-        count (int): Number of patches to produce, or -1 to produce patches for
-            the current branch back to the upstream commit
-        start (int): Start partch to use (0=first / top of branch)
-        end (int): End patch to use (0=last one in series, 1=one before that,
-            etc.)
-        ignore_binary (bool): Don't generate patches for binary files
-
-    Returns:
-        Tuple:
-            Series object for this series (set of patches)
-            Filename of the cover letter as a string (None if none)
-            patch_files: List of patch filenames, each a string, e.g.
-                ['0001_xxx.patch', '0002_yyy.patch']
-    """
-    if count == -1:
-        # Work out how many patches to send if we can
-        count = (gitutil.CountCommitsToBranch(branch) - start)
-
-    if not count:
-        str = 'No commits found to process - please use -c flag, or run:\n' \
-              '  git branch --set-upstream-to remote/branch'
-        sys.exit(col.Color(col.RED, str))
-
-    # Read the metadata from the commits
-    to_do = count - end
-    series = patchstream.GetMetaData(branch, start, to_do)
-    cover_fname, patch_files = gitutil.CreatePatches(
-        branch, start, to_do, ignore_binary, series)
-
-    # Fix up the patch files to our liking, and insert the cover letter
-    patchstream.FixPatches(series, patch_files)
-    if cover_fname and series.get('cover'):
-        patchstream.InsertCoverLetter(cover_fname, series, to_do)
-    return series, cover_fname, patch_files
-
-def check_patches(series, patch_files, run_checkpatch, verbose):
-    """Run some checks on a set of patches
-
-    This santiy-checks the patman tags like Series-version and runs the patches
-    through checkpatch
-
-    Args:
-        series (Series): Series object for this series (set of patches)
-        patch_files (list): List of patch filenames, each a string, e.g.
-            ['0001_xxx.patch', '0002_yyy.patch']
-        run_checkpatch (bool): True to run checkpatch.pl
-        verbose (bool): True to print out every line of the checkpatch output as
-            it is parsed
-
-    Returns:
-        bool: True if the patches had no errors, False if they did
-    """
-    # Do a few checks on the series
-    series.DoChecks()
-
-    # Check the patches, and run them through 'git am' just to be sure
-    if run_checkpatch:
-        ok = checkpatch.CheckPatches(verbose, patch_files)
-    else:
-        ok = True
-    return ok
-
-
-def email_patches(col, series, cover_fname, patch_files, process_tags, its_a_go,
-                  ignore_bad_tags, add_maintainers, limit, dry_run, in_reply_to,
-                  thread, smtp_server):
-    """Email patches to the recipients
-
-    This emails out the patches and cover letter using 'git send-email'. Each
-    patch is copied to recipients identified by the patch tag and output from
-    the get_maintainer.pl script. The cover letter is copied to all recipients
-    of any patch.
-
-    To make this work a CC file is created holding the recipients for each patch
-    and the cover letter. See the main program 'cc_cmd' for this logic.
-
-    Args:
-        col (terminal.Color): Colour output object
-        series (Series): Series object for this series (set of patches)
-        cover_fname (str): Filename of the cover letter as a string (None if
-            none)
-        patch_files (list): List of patch filenames, each a string, e.g.
-            ['0001_xxx.patch', '0002_yyy.patch']
-        process_tags (bool): True to process subject tags in each patch, e.g.
-            for 'dm: spi: Add SPI support' this would be 'dm' and 'spi'. The
-            tags are looked up in the configured sendemail.aliasesfile and also
-            in ~/.patman (see README)
-        its_a_go (bool): True if we are going to actually send the patches,
-            False if the patches have errors and will not be sent unless
-            @ignore_errors
-        ignore_bad_tags (bool): True to just print a warning for unknown tags,
-            False to halt with an error
-        add_maintainers (bool): Run the get_maintainer.pl script for each patch
-        limit (int): Limit on the number of people that can be cc'd on a single
-            patch or the cover letter (None if no limit)
-        dry_run (bool): Don't actually email the patches, just print out what
-            would be sent
-        in_reply_to (str): If not None we'll pass this to git as --in-reply-to.
-            Should be a message ID that this is in reply to.
-        thread (bool): True to add --thread to git send-email (make all patches
-            reply to cover-letter or first patch in series)
-        smtp_server (str): SMTP server to use to send patches (None for default)
-    """
-    cc_file = series.MakeCcFile(process_tags, cover_fname, not ignore_bad_tags,
-                                add_maintainers, limit)
-
-    # Email the patches out (giving the user time to check / cancel)
-    cmd = ''
-    if its_a_go:
-        cmd = gitutil.EmailPatches(
-            series, cover_fname, patch_files, dry_run, not ignore_bad_tags,
-            cc_file, in_reply_to=in_reply_to, thread=thread,
-            smtp_server=smtp_server)
-    else:
-        print(col.Color(col.RED, "Not sending emails due to errors/warnings"))
-
-    # For a dry run, just show our actions as a sanity check
-    if dry_run:
-        series.ShowActions(patch_files, cmd, process_tags)
-        if not its_a_go:
-            print(col.Color(col.RED, "Email would not be sent"))
-
-    os.remove(cc_file)
-
-def send(args):
-    """Create, check and send patches by email
-
-    Args:
-        args (argparse.Namespace): Arguments to patman
-    """
-    setup()
-    col = terminal.Color()
-    series, cover_fname, patch_files = prepare_patches(
-        col, args.branch, args.count, args.start, args.end,
-        args.ignore_binary)
-    ok = check_patches(series, patch_files, args.check_patch,
-                       args.verbose)
-
-    ok = ok and gitutil.CheckSuppressCCConfig()
-
-    its_a_go = ok or args.ignore_errors
-    if its_a_go:
-        email_patches(
-            col, series, cover_fname, patch_files, args.process_tags,
-            its_a_go, args.ignore_bad_tags, args.add_maintainers,
-            args.limit, args.dry_run, args.in_reply_to, args.thread,
-            args.smtp_server)
diff --git a/tools/patman/func_test.py b/tools/patman/func_test.py
index 810af9c..dc30078 100644
--- a/tools/patman/func_test.py
+++ b/tools/patman/func_test.py
@@ -14,23 +14,15 @@
 
 from io import StringIO
 
-from patman import control
 from patman import gitutil
 from patman import patchstream
 from patman import settings
-from patman import terminal
 from patman import tools
-from patman.test_util import capture_sys_output
-
-try:
-    import pygit2
-    HAVE_PYGIT2= True
-except ModuleNotFoundError:
-    HAVE_PYGIT2 = False
 
 
 @contextlib.contextmanager
 def capture():
+    import sys
     oldout,olderr = sys.stdout, sys.stderr
     try:
         out=[StringIO(), StringIO()]
@@ -45,8 +37,6 @@
 class TestFunctional(unittest.TestCase):
     def setUp(self):
         self.tmpdir = tempfile.mkdtemp(prefix='patman.')
-        self.gitdir = os.path.join(self.tmpdir, 'git')
-        self.repo = None
 
     def tearDown(self):
         shutil.rmtree(self.tmpdir)
@@ -296,160 +286,3 @@
             if expected:
                 expected = expected.splitlines()
                 self.assertEqual(expected, lines[start:(start+len(expected))])
-
-    def make_commit_with_file(self, subject, body, fname, text):
-        """Create a file and add it to the git repo with a new commit
-
-        Args:
-            subject (str): Subject for the commit
-            body (str): Body text of the commit
-            fname (str): Filename of file to create
-            text (str): Text to put into the file
-        """
-        path = os.path.join(self.gitdir, fname)
-        tools.WriteFile(path, text, binary=False)
-        index = self.repo.index
-        index.add(fname)
-        author =  pygit2.Signature('Test user', 'test@email.com')
-        committer = author
-        tree = index.write_tree()
-        message = subject + '\n' + body
-        self.repo.create_commit('HEAD', author, committer, message, tree,
-                                [self.repo.head.target])
-
-    def make_git_tree(self):
-        """Make a simple git tree suitable for testing
-
-        It has three branches:
-            'base' has two commits: PCI, main
-            'first' has base as upstream and two more commits: I2C, SPI
-            'second' has base as upstream and three more: video, serial, bootm
-
-        Returns:
-            pygit2 repository
-        """
-        repo = pygit2.init_repository(self.gitdir)
-        self.repo = repo
-        new_tree = repo.TreeBuilder().write()
-
-        author = pygit2.Signature('Test user', 'test@email.com')
-        committer = author
-        commit = repo.create_commit('HEAD', author, committer,
-                                         'Created master', new_tree, [])
-
-        self.make_commit_with_file('Initial commit', '''
-Add a README
-
-''', 'README', '''This is the README file
-describing this project
-in very little detail''')
-
-        self.make_commit_with_file('pci: PCI implementation', '''
-Here is a basic PCI implementation
-
-''', 'pci.c', '''This is a file
-it has some contents
-and some more things''')
-        self.make_commit_with_file('main: Main program', '''
-Hello here is the second commit.
-''', 'main.c', '''This is the main file
-there is very little here
-but we can always add more later
-if we want to
-
-Series-to: u-boot
-Series-cc: Barry Crump <bcrump@whataroa.nz>
-''')
-        base_target = repo.revparse_single('HEAD')
-        self.make_commit_with_file('i2c: I2C things', '''
-This has some stuff to do with I2C
-''', 'i2c.c', '''And this is the file contents
-with some I2C-related things in it''')
-        self.make_commit_with_file('spi: SPI fixes', '''
-SPI needs some fixes
-and here they are
-''', 'spi.c', '''Some fixes for SPI in this
-file to make SPI work
-better than before''')
-        first_target = repo.revparse_single('HEAD')
-
-        target = repo.revparse_single('HEAD~2')
-        repo.reset(target.oid, pygit2.GIT_CHECKOUT_FORCE)
-        self.make_commit_with_file('video: Some video improvements', '''
-Fix up the video so that
-it looks more purple. Purple is
-a very nice colour.
-''', 'video.c', '''More purple here
-Purple and purple
-Even more purple
-Could not be any more purple''')
-        self.make_commit_with_file('serial: Add a serial driver', '''
-Here is the serial driver
-for my chip.
-
-Cover-letter:
-Series for my board
-This series implements support
-for my glorious board.
-END
-''', 'serial.c', '''The code for the
-serial driver is here''')
-        self.make_commit_with_file('bootm: Make it boot', '''
-This makes my board boot
-with a fix to the bootm
-command
-''', 'bootm.c', '''Fix up the bootm
-command to make the code as
-complicated as possible''')
-        second_target = repo.revparse_single('HEAD')
-
-        repo.branches.local.create('first', first_target)
-        repo.config.set_multivar('branch.first.remote', '', '.')
-        repo.config.set_multivar('branch.first.merge', '', 'refs/heads/base')
-
-        repo.branches.local.create('second', second_target)
-        repo.config.set_multivar('branch.second.remote', '', '.')
-        repo.config.set_multivar('branch.second.merge', '', 'refs/heads/base')
-
-        repo.branches.local.create('base', base_target)
-        return repo
-
-    @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
-    def testBranch(self):
-        """Test creating patches from a branch"""
-        repo = self.make_git_tree()
-        target = repo.lookup_reference('refs/heads/first')
-        self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
-        control.setup()
-        try:
-            orig_dir = os.getcwd()
-            os.chdir(self.gitdir)
-
-            # Check that it can detect the current branch
-            self.assertEqual(2, gitutil.CountCommitsToBranch(None))
-            col = terminal.Color()
-            with capture_sys_output() as _:
-                _, cover_fname, patch_files = control.prepare_patches(
-                    col, branch=None, count=-1, start=0, end=0,
-                    ignore_binary=False)
-            self.assertIsNone(cover_fname)
-            self.assertEqual(2, len(patch_files))
-
-            # Check that it can detect a different branch
-            self.assertEqual(3, gitutil.CountCommitsToBranch('second'))
-            with capture_sys_output() as _:
-                _, cover_fname, patch_files = control.prepare_patches(
-                    col, branch='second', count=-1, start=0, end=0,
-                    ignore_binary=False)
-            self.assertIsNotNone(cover_fname)
-            self.assertEqual(3, len(patch_files))
-
-            # Check that it can skip patches at the end
-            with capture_sys_output() as _:
-                _, cover_fname, patch_files = control.prepare_patches(
-                    col, branch='second', count=-1, start=0, end=1,
-                    ignore_binary=False)
-            self.assertIsNotNone(cover_fname)
-            self.assertEqual(2, len(patch_files))
-        finally:
-            os.chdir(orig_dir)
diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py
index 192d8e6..5189840 100644
--- a/tools/patman/gitutil.py
+++ b/tools/patman/gitutil.py
@@ -49,24 +49,17 @@
     cmd.append('--')
     return cmd
 
-def CountCommitsToBranch(branch):
+def CountCommitsToBranch():
     """Returns number of commits between HEAD and the tracking branch.
 
     This looks back to the tracking branch and works out the number of commits
     since then.
 
-    Args:
-        branch: Branch to count from (None for current branch)
-
     Return:
         Number of patches that exist on top of the branch
     """
-    if branch:
-        us, msg = GetUpstream('.git', branch)
-        rev_range = '%s..%s' % (us, branch)
-    else:
-        rev_range = '@{upstream}..'
-    pipe = [LogCmd(rev_range, oneline=True), ['wc', '-l']]
+    pipe = [LogCmd('@{upstream}..', oneline=True),
+            ['wc', '-l']]
     stdout = command.RunPipe(pipe, capture=True, oneline=True).stdout
     patch_count = int(stdout)
     return patch_count
@@ -259,20 +252,17 @@
     if result.return_code != 0:
         raise OSError('git fetch: %s' % result.stderr)
 
-def CreatePatches(branch, start, count, ignore_binary, series):
+def CreatePatches(start, count, ignore_binary, series):
     """Create a series of patches from the top of the current branch.
 
     The patch files are written to the current directory using
     git format-patch.
 
     Args:
-        branch: Branch to create patches from (None for current branch)
         start: Commit to start from: 0=HEAD, 1=next one, etc.
         count: number of commits to include
-        ignore_binary: Don't generate patches for binary files
-        series: Series object for this series (set of patches)
     Return:
-        Filename of cover letter (None if none)
+        Filename of cover letter
         List of filenames of patch files
     """
     if series.get('version'):
@@ -285,8 +275,7 @@
     prefix = series.GetPatchPrefix()
     if prefix:
         cmd += ['--subject-prefix=%s' % prefix]
-    brname = branch or 'HEAD'
-    cmd += ['%s~%d..%s~%d' % (brname, start + count, brname, start)]
+    cmd += ['HEAD~%d..HEAD~%d' % (start + count, start)]
 
     stdout = command.RunList(cmd)
     files = stdout.splitlines()
@@ -344,31 +333,6 @@
         return ['%s %s%s%s' % (tag, quote, email, quote) for email in result]
     return result
 
-def CheckSuppressCCConfig():
-    """Check if sendemail.suppresscc is configured correctly.
-
-    Returns:
-        True if the option is configured correctly, False otherwise.
-    """
-    suppresscc = command.OutputOneLine('git', 'config', 'sendemail.suppresscc',
-                                       raise_on_error=False)
-
-    # Other settings should be fine.
-    if suppresscc == 'all' or suppresscc == 'cccmd':
-        col = terminal.Color()
-
-        print((col.Color(col.RED, "error") +
-            ": git config sendemail.suppresscc set to %s\n"  % (suppresscc)) +
-            "  patman needs --cc-cmd to be run to set the cc list.\n" +
-            "  Please run:\n" +
-            "    git config --unset sendemail.suppresscc\n" +
-            "  Or read the man page:\n" +
-            "    git send-email --help\n" +
-            "  and set an option that runs --cc-cmd\n")
-        return False
-
-    return True
-
 def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
         self_only=False, alias=None, in_reply_to=None, thread=False,
         smtp_server=None):
diff --git a/tools/patman/main.py b/tools/patman/main.py
index b960008..28a9a26 100755
--- a/tools/patman/main.py
+++ b/tools/patman/main.py
@@ -6,11 +6,10 @@
 
 """See README for more information"""
 
-from argparse import ArgumentParser
+from optparse import OptionParser
 import os
 import re
 import sys
-import traceback
 import unittest
 
 if __name__ == "__main__":
@@ -19,93 +18,76 @@
     sys.path.append(os.path.join(our_path, '..'))
 
 # Our modules
+from patman import checkpatch
 from patman import command
-from patman import control
 from patman import gitutil
+from patman import patchstream
 from patman import project
 from patman import settings
 from patman import terminal
-from patman import test_util
 from patman import test_checkpatch
 
-def AddCommonArgs(parser):
-    parser.add_argument('-b', '--branch', type=str,
-        help="Branch to process (by default, the current branch)")
-    parser.add_argument('-c', '--count', dest='count', type=int,
-        default=-1, help='Automatically create patches from top n commits')
-    parser.add_argument('-e', '--end', type=int, default=0,
-        help='Commits to skip at end of patch list')
-    parser.add_argument('-D', '--debug', action='store_true',
-        help='Enabling debugging (provides a full traceback on error)')
-    parser.add_argument('-s', '--start', dest='start', type=int,
-        default=0, help='Commit to start creating patches from (0 = HEAD)')
 
-epilog = '''Create patches from commits in a branch, check them and email them
-as specified by tags you place in the commits. Use -n to do a dry run first.'''
-
-parser = ArgumentParser(epilog=epilog)
-subparsers = parser.add_subparsers(dest='cmd')
-send = subparsers.add_parser('send')
-send.add_argument('-H', '--full-help', action='store_true', dest='full_help',
+parser = OptionParser()
+parser.add_option('-H', '--full-help', action='store_true', dest='full_help',
        default=False, help='Display the README file')
-send.add_argument('-i', '--ignore-errors', action='store_true',
+parser.add_option('-c', '--count', dest='count', type='int',
+       default=-1, help='Automatically create patches from top n commits')
+parser.add_option('-i', '--ignore-errors', action='store_true',
        dest='ignore_errors', default=False,
        help='Send patches email even if patch errors are found')
-send.add_argument('-l', '--limit-cc', dest='limit', type=int, default=None,
-       help='Limit the cc list to LIMIT entries [default: %(default)s]')
-send.add_argument('-m', '--no-maintainers', action='store_false',
+parser.add_option('-l', '--limit-cc', dest='limit', type='int',
+       default=None, help='Limit the cc list to LIMIT entries [default: %default]')
+parser.add_option('-m', '--no-maintainers', action='store_false',
        dest='add_maintainers', default=True,
        help="Don't cc the file maintainers automatically")
-send.add_argument('-n', '--dry-run', action='store_true', dest='dry_run',
+parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
        default=False, help="Do a dry run (create but don't email patches)")
-send.add_argument('-p', '--project', default=project.DetectProject(),
+parser.add_option('-p', '--project', default=project.DetectProject(),
                   help="Project name; affects default option values and "
-                  "aliases [default: %(default)s]")
-send.add_argument('-r', '--in-reply-to', type=str, action='store',
+                  "aliases [default: %default]")
+parser.add_option('-r', '--in-reply-to', type='string', action='store',
                   help="Message ID that this series is in reply to")
-send.add_argument('-t', '--ignore-bad-tags', action='store_true',
+parser.add_option('-s', '--start', dest='start', type='int',
+       default=0, help='Commit to start creating patches from (0 = HEAD)')
+parser.add_option('-t', '--ignore-bad-tags', action='store_true',
                   default=False, help='Ignore bad tags / aliases')
-send.add_argument('-v', '--verbose', action='store_true', dest='verbose',
+parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
        default=False, help='Verbose output of errors and warnings')
-send.add_argument('-T', '--thread', action='store_true', dest='thread',
+parser.add_option('-T', '--thread', action='store_true', dest='thread',
                   default=False, help='Create patches as a single thread')
-send.add_argument('--cc-cmd', dest='cc_cmd', type=str, action='store',
+parser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store',
        default=None, help='Output cc list for patch file (used by git)')
-send.add_argument('--no-binary', action='store_true', dest='ignore_binary',
+parser.add_option('--no-binary', action='store_true', dest='ignore_binary',
                   default=False,
                   help="Do not output contents of changes in binary files")
-send.add_argument('--no-check', action='store_false', dest='check_patch',
+parser.add_option('--no-check', action='store_false', dest='check_patch',
                   default=True,
                   help="Don't check for patch compliance")
-send.add_argument('--no-tags', action='store_false', dest='process_tags',
+parser.add_option('--no-tags', action='store_false', dest='process_tags',
                   default=True, help="Don't process subject tags as aliases")
-send.add_argument('--smtp-server', type=str,
+parser.add_option('--smtp-server', type='str',
                   help="Specify the SMTP server to 'git send-email'")
-AddCommonArgs(send)
+parser.add_option('--test', action='store_true', dest='test',
+                  default=False, help='run tests')
 
-send.add_argument('patchfiles', nargs='*')
+parser.usage += """
 
-test_parser = subparsers.add_parser('test', help='Run tests')
-AddCommonArgs(test_parser)
+Create patches from commits in a branch, check them and email them as
+specified by tags you place in the commits. Use -n to do a dry run first."""
+
 
 # Parse options twice: first to get the project and second to handle
 # defaults properly (which depends on project).
-argv = sys.argv[1:]
-if len(argv) < 1 or argv[0].startswith('-'):
-    argv = ['send'] + argv
-args = parser.parse_args(argv)
-if hasattr(args, 'project'):
-    settings.Setup(gitutil, send, args.project, '')
-    args = parser.parse_args(argv)
+(options, args) = parser.parse_args()
+settings.Setup(gitutil, parser, options.project, '')
+(options, args) = parser.parse_args()
 
 if __name__ != "__main__":
     pass
 
-if not args.debug:
-    sys.tracebacklimit = 0
-
 # Run our meagre tests
-if args.cmd == 'test':
+elif options.test:
     import doctest
     from patman import func_test
 
@@ -119,31 +101,87 @@
         suite = doctest.DocTestSuite(module)
         suite.run(result)
 
-    sys.exit(test_util.ReportResult('patman', None, result))
+    # TODO: Surely we can just 'print' result?
+    print(result)
+    for test, err in result.errors:
+        print(err)
+    for test, err in result.failures:
+        print(err)
+
+# Called from git with a patch filename as argument
+# Printout a list of additional CC recipients for this patch
+elif options.cc_cmd:
+    fd = open(options.cc_cmd, 'r')
+    re_line = re.compile('(\S*) (.*)')
+    for line in fd.readlines():
+        match = re_line.match(line)
+        if match and match.group(1) == args[0]:
+            for cc in match.group(2).split('\0'):
+                cc = cc.strip()
+                if cc:
+                    print(cc)
+    fd.close()
+
+elif options.full_help:
+    pager = os.getenv('PAGER')
+    if not pager:
+        pager = 'more'
+    fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
+                         'README')
+    command.Run(pager, fname)
 
 # Process commits, produce patches files, check them, email them
-elif args.cmd == 'send':
-    # Called from git with a patch filename as argument
-    # Printout a list of additional CC recipients for this patch
-    if args.cc_cmd:
-        fd = open(args.cc_cmd, 'r')
-        re_line = re.compile('(\S*) (.*)')
-        for line in fd.readlines():
-            match = re_line.match(line)
-            if match and match.group(1) == args.patchfiles[0]:
-                for cc in match.group(2).split('\0'):
-                    cc = cc.strip()
-                    if cc:
-                        print(cc)
-        fd.close()
+else:
+    gitutil.Setup()
 
-    elif args.full_help:
-        pager = os.getenv('PAGER')
-        if not pager:
-            pager = 'more'
-        fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
-                             'README')
-        command.Run(pager, fname)
+    if options.count == -1:
+        # Work out how many patches to send if we can
+        options.count = gitutil.CountCommitsToBranch() - options.start
 
+    col = terminal.Color()
+    if not options.count:
+        str = 'No commits found to process - please use -c flag'
+        sys.exit(col.Color(col.RED, str))
+
+    # Read the metadata from the commits
+    if options.count:
+        series = patchstream.GetMetaData(options.start, options.count)
+        cover_fname, args = gitutil.CreatePatches(options.start, options.count,
+                options.ignore_binary, series)
+
+    # Fix up the patch files to our liking, and insert the cover letter
+    patchstream.FixPatches(series, args)
+    if cover_fname and series.get('cover'):
+        patchstream.InsertCoverLetter(cover_fname, series, options.count)
+
+    # Do a few checks on the series
+    series.DoChecks()
+
+    # Check the patches, and run them through 'git am' just to be sure
+    if options.check_patch:
+        ok = checkpatch.CheckPatches(options.verbose, args)
     else:
-        control.send(args)
+        ok = True
+
+    cc_file = series.MakeCcFile(options.process_tags, cover_fname,
+                                not options.ignore_bad_tags,
+                                options.add_maintainers, options.limit)
+
+    # Email the patches out (giving the user time to check / cancel)
+    cmd = ''
+    its_a_go = ok or options.ignore_errors
+    if its_a_go:
+        cmd = gitutil.EmailPatches(series, cover_fname, args,
+                options.dry_run, not options.ignore_bad_tags, cc_file,
+                in_reply_to=options.in_reply_to, thread=options.thread,
+                smtp_server=options.smtp_server)
+    else:
+        print(col.Color(col.RED, "Not sending emails due to errors/warnings"))
+
+    # For a dry run, just show our actions as a sanity check
+    if options.dry_run:
+        series.ShowActions(args, cmd, options.process_tags)
+        if not its_a_go:
+            print(col.Color(col.RED, "Email would not be sent"))
+
+    os.remove(cc_file)
diff --git a/tools/patman/patchstream.py b/tools/patman/patchstream.py
index ba0a13f..4fe465e 100644
--- a/tools/patman/patchstream.py
+++ b/tools/patman/patchstream.py
@@ -37,7 +37,7 @@
 re_commit_tag = re.compile('^Commit-([a-z-]*): *(.*)')
 
 # Commit tags that we want to collect and keep
-re_tag = re.compile('^(Tested-by|Acked-by|Reviewed-by|Patch-cc|Fixes): (.*)')
+re_tag = re.compile('^(Tested-by|Acked-by|Reviewed-by|Patch-cc): (.*)')
 
 # The start of a new commit in the git log
 re_commit = re.compile('^commit ([0-9a-f]*)$')
@@ -112,15 +112,6 @@
             self.in_section = 'commit-' + name
             self.skip_blank = False
 
-    def AddCommitRtag(self, rtag_type, who):
-        """Add a response tag to the current commit
-
-        Args:
-            key: rtag type (e.g. 'Reviewed-by')
-            who: Person who gave that rtag, e.g. 'Fred Bloggs <fred@bloggs.org>'
-        """
-        self.commit.AddRtag(rtag_type, who)
-
     def CloseCommit(self):
         """Save the current commit into our commit list, and reset our state"""
         if self.commit and self.is_log:
@@ -269,10 +260,6 @@
             else:
                 self.section.append(line)
 
-        # If we are not in a section, it is an unexpected END
-        elif line == 'END':
-                raise ValueError("'END' wihout section")
-
         # Detect the commit subject
         elif not is_blank and self.state == STATE_PATCH_SUBJECT:
             self.commit.subject = line
@@ -351,9 +338,6 @@
             elif name == 'changes':
                 self.in_change = 'Commit'
                 self.change_version = self.ParseVersion(value, line)
-            else:
-                self.warn.append('Line %d: Ignoring Commit-%s' %
-                    (self.linenum, name))
 
         # Detect the start of a new commit
         elif commit_match:
@@ -362,14 +346,12 @@
 
         # Detect tags in the commit message
         elif tag_match:
-            rtag_type, who = tag_match.groups()
-            self.AddCommitRtag(rtag_type, who)
             # Remove Tested-by self, since few will take much notice
-            if (rtag_type == 'Tested-by' and
-                    who.find(os.getenv('USER') + '@') != -1):
+            if (tag_match.group(1) == 'Tested-by' and
+                    tag_match.group(2).find(os.getenv('USER') + '@') != -1):
                 self.warn.append("Ignoring %s" % line)
-            elif rtag_type == 'Patch-cc':
-                self.commit.AddCc(who.split(','))
+            elif tag_match.group(1) == 'Patch-cc':
+                self.commit.AddCc(tag_match.group(2).split(','))
             else:
                 out = [line]
 
@@ -530,19 +512,17 @@
     ps.Finalize()
     return series
 
-def GetMetaData(branch, start, count):
+def GetMetaData(start, count):
     """Reads out patch series metadata from the commits
 
     This does a 'git log' on the relevant commits and pulls out the tags we
     are interested in.
 
     Args:
-        branch: Branch to use (None for current branch)
-        start: Commit to start from: 0=branch HEAD, 1=next one, etc.
+        start: Commit to start from: 0=HEAD, 1=next one, etc.
         count: Number of commits to list
     """
-    return GetMetaDataForList('%s~%d' % (branch if branch else 'HEAD', start),
-                              None, count)
+    return GetMetaDataForList('HEAD~%d' % start, None, count)
 
 def GetMetaDataForTest(text):
     """Process metadata from a file containing a git log. Used for tests
diff --git a/tools/patman/series.py b/tools/patman/series.py
index 9f885c8..b7eef37 100644
--- a/tools/patman/series.py
+++ b/tools/patman/series.py
@@ -244,7 +244,7 @@
             add_maintainers: Either:
                 True/False to call the get_maintainers to CC maintainers
                 List of maintainers to include (for testing)
-            limit: Limit the length of the Cc list (None if no limit)
+            limit: Limit the length of the Cc list
         Return:
             Filename of temp file created
         """
diff --git a/tools/patman/settings.py b/tools/patman/settings.py
index 732bd40..635561a 100644
--- a/tools/patman/settings.py
+++ b/tools/patman/settings.py
@@ -233,19 +233,17 @@
         config: An instance of _ProjectConfigParser that we will query
             for settings.
     """
-    defaults = parser.parse_known_args()[0]
-    defaults = vars(defaults)
+    defaults = parser.get_default_values()
     for name, val in config.items('settings'):
-        if name in defaults:
-            default_val = defaults[name]
+        if hasattr(defaults, name):
+            default_val = getattr(defaults, name)
             if isinstance(default_val, bool):
                 val = config.getboolean('settings', name)
             elif isinstance(default_val, int):
                 val = config.getint('settings', name)
-            defaults[name] = val
+            parser.set_default(name, val)
         else:
             print("WARNING: Unknown setting %s" % name)
-        parser.set_defaults(**defaults)
 
 def _ReadAliasFile(fname):
     """Read in the U-Boot git alias file if it exists.
diff --git a/tools/patman/terminal.py b/tools/patman/terminal.py
index 60dbce3..c709438 100644
--- a/tools/patman/terminal.py
+++ b/tools/patman/terminal.py
@@ -122,7 +122,7 @@
     return out
 
 
-def Print(text='', newline=True, colour=None, limit_to_line=False, bright=True):
+def Print(text='', newline=True, colour=None, limit_to_line=False):
     """Handle a line of output to the terminal.
 
     In test mode this is recorded in a list. Otherwise it is output to the
@@ -140,7 +140,7 @@
     else:
         if colour:
             col = Color()
-            text = col.Color(colour, text, bright=bright)
+            text = col.Color(colour, text)
         if newline:
             print(text)
             last_print_len = None
diff --git a/tools/patman/test_util.py b/tools/patman/test_util.py
index 4e26175..aac58fb 100644
--- a/tools/patman/test_util.py
+++ b/tools/patman/test_util.py
@@ -16,14 +16,12 @@
 
 use_concurrent = True
 try:
-    from concurrencytest.concurrencytest import ConcurrentTestSuite
-    from concurrencytest.concurrencytest import fork_for_tests
+    from concurrencytest import ConcurrentTestSuite, fork_for_tests
 except:
     use_concurrent = False
 
 
-def RunTestCoverage(prog, filter_fname, exclude_list, build_dir, required=None,
-                    extra_args=None):
+def RunTestCoverage(prog, filter_fname, exclude_list, build_dir, required=None):
     """Run tests and check that we get 100% coverage
 
     Args:
@@ -36,8 +34,6 @@
             calculation
         build_dir: Build directory, used to locate libfdt.py
         required: List of modules which must be in the coverage report
-        extra_args (str): Extra arguments to pass to the tool before the -t/test
-            arg
 
     Raises:
         ValueError if the code coverage is not 100%
@@ -51,14 +47,13 @@
         glob_list = []
     glob_list += exclude_list
     glob_list += ['*libfdt.py', '*site-packages*', '*dist-packages*']
-    glob_list += ['*concurrencytest*']
-    test_cmd = 'test' if 'binman' in prog or 'patman' in prog else '-t'
+    test_cmd = 'test' if 'binman' in prog else '-t'
     prefix = ''
     if build_dir:
         prefix = 'PYTHONPATH=$PYTHONPATH:%s/sandbox_spl/tools ' % build_dir
     cmd = ('%spython3-coverage run '
-           '--omit "%s" %s %s %s -P1' % (prefix, ','.join(glob_list),
-                                         prog, extra_args or '', test_cmd))
+           '--omit "%s" %s %s -P1' % (prefix, ','.join(glob_list),
+                                      prog, test_cmd))
     os.system(cmd)
     stdout = command.Output('python3-coverage', 'report')
     lines = stdout.splitlines()
@@ -128,12 +123,12 @@
     for test, err in result.failures:
         print(err, result.failures)
     if result.skipped:
-        print('%d %s test%s SKIPPED:' % (len(result.skipped), toolname,
-            's' if len(result.skipped) > 1 else ''))
+        print('%d binman test%s SKIPPED:' %
+              (len(result.skipped), 's' if len(result.skipped) > 1 else ''))
         for skip_info in result.skipped:
             print('%s: %s' % (skip_info[0], skip_info[1]))
     if result.errors or result.failures:
-        print('%s tests FAILED' % toolname)
+        print('binman tests FAILED')
         return 1
     return 0
 
diff --git a/tools/patman/tools.py b/tools/patman/tools.py
index d41115a..b50370d 100644
--- a/tools/patman/tools.py
+++ b/tools/patman/tools.py
@@ -114,16 +114,14 @@
     indir = dirname
     tout.Debug("Using input directories %s" % indir)
 
-def GetInputFilename(fname, allow_missing=False):
+def GetInputFilename(fname):
     """Return a filename for use as input.
 
     Args:
         fname: Filename to use for new file
-        allow_missing: True if the filename can be missing
 
     Returns:
-        The full path of the filename, within the input directory, or
-        None on error
+        The full path of the filename, within the input directory
     """
     if not indir or fname[:1] == '/':
         return fname
@@ -132,8 +130,6 @@
         if os.path.exists(pathname):
             return pathname
 
-    if allow_missing:
-        return None
     raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
                      (fname, ','.join(indir), os.getcwd()))
 
@@ -274,7 +270,7 @@
                    #(fname, len(data), len(data)))
     return data
 
-def WriteFile(fname, data, binary=True):
+def WriteFile(fname, data):
     """Write data into a file.
 
     Args:
@@ -283,7 +279,7 @@
     """
     #self._out.Info("Write file '%s' size %d (%#0x)" %
                    #(fname, len(data), len(data)))
-    with open(Filename(fname), binary and 'wb' or 'w') as fd:
+    with open(Filename(fname), 'wb') as fd:
         fd.write(data)
 
 def GetBytes(byte, size):
diff --git a/tools/patman/tout.py b/tools/patman/tout.py
index 3330526..c7e3272 100644
--- a/tools/patman/tout.py
+++ b/tools/patman/tout.py
@@ -83,10 +83,7 @@
         ClearProgress()
         if color:
             msg = _color.Color(color, msg)
-        if level < NOTICE:
-            print(msg, file=sys.stderr)
-        else:
-            print(msg)
+        print(msg)
 
 def DoOutput(level, msg):
     """Output a message to the terminal.
@@ -171,7 +168,6 @@
 
     # TODO(sjg): Move this into Chromite libraries when we have them
     stdout_is_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
-    stderr_is_tty = hasattr(sys.stderr, 'isatty') and sys.stderr.isatty()
 
 def Uninit():
     ClearProgress()