| Index: git_cl.py | 
| diff --git a/git_cl.py b/git_cl.py | 
| index 1dcb1fe8ca7bcc1bb0033997cd035a157f2b9e0c..60c41f4a87b3d38a94fb8b193477a076ef3a6bd2 100755 | 
| --- a/git_cl.py | 
| +++ b/git_cl.py | 
| @@ -1033,7 +1033,7 @@ def DownloadHooks(force): | 
|  | 
| @usage('[repo root containing codereview.settings]') | 
| def CMDconfig(parser, args): | 
| -  """Edits configuration for this tree.""" | 
| +  """edit configuration for this tree""" | 
|  | 
| _, args = parser.parse_args(args) | 
| if len(args) == 0: | 
| @@ -1052,7 +1052,7 @@ def CMDconfig(parser, args): | 
|  | 
|  | 
| def CMDbaseurl(parser, args): | 
| -  """Gets or sets base-url for this branch.""" | 
| +  """get or set base-url for this branch""" | 
| branchref = RunGit(['symbolic-ref', 'HEAD']).strip() | 
| branch = ShortBranchName(branchref) | 
| _, args = parser.parse_args(args) | 
| @@ -1067,17 +1067,7 @@ def CMDbaseurl(parser, args): | 
|  | 
|  | 
| def CMDstatus(parser, args): | 
| -  """Show status of changelists. | 
| - | 
| -  Colors are used to tell the state of the CL unless --fast is used: | 
| -    - Green   LGTM'ed | 
| -    - Blue    waiting for review | 
| -    - Yellow  waiting for you to reply to review | 
| -    - Red     not sent for review or broken | 
| -    - Cyan    was committed, branch can be deleted | 
| - | 
| -  Also see 'git cl comments'. | 
| -  """ | 
| +  """show status of changelists""" | 
| parser.add_option('--field', | 
| help='print only specific field (desc|id|patch|url)') | 
| parser.add_option('-f', '--fast', action='store_true', | 
| @@ -1119,37 +1109,18 @@ def CMDstatus(parser, args): | 
|  | 
| if not options.fast: | 
| def fetch(b): | 
| -      """Fetches information for an issue and returns (branch, issue, color).""" | 
| c = Changelist(branchref=b) | 
| i = c.GetIssueURL() | 
| -      props = {} | 
| -      r = None | 
| -      if i: | 
| -        try: | 
| -          props = c.GetIssueProperties() | 
| -          r = c.GetApprovingReviewers() if i else None | 
| -        except urllib2.HTTPError: | 
| -          # The issue probably doesn't exist anymore. | 
| -          i += ' (broken)' | 
| - | 
| -      msgs = props.get('messages') or [] | 
| - | 
| -      if not i: | 
| -        color = Fore.WHITE | 
| -      elif props.get('closed'): | 
| -        # Issue is closed. | 
| -        color = Fore.CYAN | 
| -      elif r: | 
| -        # Was LGTM'ed. | 
| -        color = Fore.GREEN | 
| -      elif not msgs: | 
| -        # No message was sent. | 
| -        color = Fore.RED | 
| -      elif msgs[-1]['sender'] != props.get('owner_email'): | 
| -        color = Fore.YELLOW | 
| -      else: | 
| -        color = Fore.BLUE | 
| -      output.put((b, i, color)) | 
| +      try: | 
| +        props = c.GetIssueProperties() | 
| +        r = c.GetApprovingReviewers() if i else None | 
| +        if not props.get('messages'): | 
| +          r = None | 
| +      except urllib2.HTTPError: | 
| +        # The issue probably doesn't exist anymore. | 
| +        i += ' (broken)' | 
| +        r = None | 
| +      output.put((b, i, r)) | 
|  | 
| threads = [threading.Thread(target=fetch, args=(b,)) for b in branches] | 
| for t in threads: | 
| @@ -1159,16 +1130,25 @@ def CMDstatus(parser, args): | 
| # Do not use GetApprovingReviewers(), since it requires an HTTP request. | 
| for b in branches: | 
| c = Changelist(branchref=b) | 
| -      url = c.GetIssueURL() | 
| -      output.put((b, url, Fore.BLUE if url else Fore.WHITE)) | 
| +      output.put((b, c.GetIssue(), None)) | 
|  | 
| tmp = {} | 
| alignment = max(5, max(len(ShortBranchName(b)) for b in branches)) | 
| for branch in sorted(branches): | 
| while branch not in tmp: | 
| -      b, i, color = output.get() | 
| -      tmp[b] = (i, color) | 
| -    issue, color = tmp.pop(branch) | 
| +      b, i, r = output.get() | 
| +      tmp[b] = (i, r) | 
| +    issue, reviewers = tmp.pop(branch) | 
| +    if not issue: | 
| +      color = Fore.WHITE | 
| +    elif reviewers: | 
| +      # Was approved. | 
| +      color = Fore.GREEN | 
| +    elif reviewers is None: | 
| +      # No message was sent. | 
| +      color = Fore.RED | 
| +    else: | 
| +      color = Fore.BLUE | 
| print '  %*s: %s%s%s' % ( | 
| alignment, ShortBranchName(branch), color, issue, Fore.RESET) | 
|  | 
| @@ -1187,10 +1167,10 @@ def CMDstatus(parser, args): | 
|  | 
| @usage('[issue_number]') | 
| def CMDissue(parser, args): | 
| -  """Sets or displays the current code review issue number. | 
| +  """Set or display the current code review issue number. | 
|  | 
| Pass issue number 0 to clear the current issue. | 
| -  """ | 
| +""" | 
| _, args = parser.parse_args(args) | 
|  | 
| cl = Changelist() | 
| @@ -1206,7 +1186,7 @@ def CMDissue(parser, args): | 
|  | 
|  | 
| def CMDcomments(parser, args): | 
| -  """Shows review comments of the current changelist.""" | 
| +  """show review comments of the current changelist""" | 
| (_, args) = parser.parse_args(args) | 
| if args: | 
| parser.error('Unsupported argument: %s' % args) | 
| @@ -1232,7 +1212,7 @@ def CMDcomments(parser, args): | 
|  | 
|  | 
| def CMDdescription(parser, args): | 
| -  """Brings up the editor for the current CL's description.""" | 
| +  """brings up the editor for the current CL's description.""" | 
| cl = Changelist() | 
| if not cl.GetIssue(): | 
| DieWithError('This branch has no associated changelist.') | 
| @@ -1257,7 +1237,7 @@ def CreateDescriptionFromLog(args): | 
|  | 
|  | 
| def CMDpresubmit(parser, args): | 
| -  """Runs presubmit tests on the current changelist.""" | 
| +  """run presubmit tests on the current changelist""" | 
| parser.add_option('-u', '--upload', action='store_true', | 
| help='Run upload hook instead of the push/dcommit hook') | 
| parser.add_option('-f', '--force', action='store_true', | 
| @@ -1444,7 +1424,7 @@ def cleanup_list(l): | 
|  | 
| @usage('[args to "git diff"]') | 
| def CMDupload(parser, args): | 
| -  """Uploads the current changelist to codereview.""" | 
| +  """upload the current changelist to codereview""" | 
| parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', | 
| help='bypass upload presubmit hook') | 
| parser.add_option('--bypass-watchlists', action='store_true', | 
| @@ -1767,7 +1747,7 @@ def SendUpstream(parser, args, cmd): | 
|  | 
| @usage('[upstream branch to apply against]') | 
| def CMDdcommit(parser, args): | 
| -  """Commits the current changelist via git-svn.""" | 
| +  """commit the current changelist via git-svn""" | 
| if not settings.GetIsGitSvn(): | 
| message = """This doesn't appear to be an SVN repository. | 
| If your project has a git mirror with an upstream SVN master, you probably need | 
| @@ -1783,7 +1763,7 @@ will instead be silently ignored.""" | 
|  | 
| @usage('[upstream branch to apply against]') | 
| def CMDpush(parser, args): | 
| -  """Commits the current changelist via git.""" | 
| +  """commit the current changelist via git""" | 
| if settings.GetIsGitSvn(): | 
| print('This appears to be an SVN repository.') | 
| print('Are you sure you didn\'t mean \'git cl dcommit\'?') | 
| @@ -1793,7 +1773,7 @@ def CMDpush(parser, args): | 
|  | 
| @usage('<patch url or issue id>') | 
| def CMDpatch(parser, args): | 
| -  """Patchs in a code review.""" | 
| +  """patch in a code review""" | 
| parser.add_option('-b', dest='newbranch', | 
| help='create a new branch off trunk for the patch') | 
| parser.add_option('-f', action='store_true', dest='force', | 
| @@ -1883,7 +1863,7 @@ def CMDpatch(parser, args): | 
|  | 
|  | 
| def CMDrebase(parser, args): | 
| -  """Rebases current branch on top of svn repo.""" | 
| +  """rebase current branch on top of svn repo""" | 
| # Provide a wrapper for git svn rebase to help avoid accidental | 
| # git svn dcommit. | 
| # It's the only command that doesn't use parser at all since we just defer | 
| @@ -1921,7 +1901,7 @@ def GetTreeStatusReason(): | 
|  | 
|  | 
| def CMDtree(parser, args): | 
| -  """Shows the status of the tree.""" | 
| +  """show the status of the tree""" | 
| _, args = parser.parse_args(args) | 
| status = GetTreeStatus() | 
| if 'unset' == status: | 
| @@ -2037,7 +2017,7 @@ def CMDtry(parser, args): | 
|  | 
| @usage('[new upstream branch]') | 
| def CMDupstream(parser, args): | 
| -  """Prints or sets the name of the upstream branch, if any.""" | 
| +  """prints or sets the name of the upstream branch, if any""" | 
| _, args = parser.parse_args(args) | 
| if len(args) > 1: | 
| parser.error('Unrecognized args: %s' % ' '.join(args)) | 
| @@ -2055,7 +2035,7 @@ def CMDupstream(parser, args): | 
|  | 
|  | 
| def CMDset_commit(parser, args): | 
| -  """Sets the commit bit to trigger the Commit Queue.""" | 
| +  """set the commit bit""" | 
| _, args = parser.parse_args(args) | 
| if args: | 
| parser.error('Unrecognized args: %s' % ' '.join(args)) | 
| @@ -2065,7 +2045,7 @@ def CMDset_commit(parser, args): | 
|  | 
|  | 
| def CMDset_close(parser, args): | 
| -  """Closes the issue.""" | 
| +  """close the issue""" | 
| _, args = parser.parse_args(args) | 
| if args: | 
| parser.error('Unrecognized args: %s' % ' '.join(args)) | 
| @@ -2077,7 +2057,7 @@ def CMDset_close(parser, args): | 
|  | 
|  | 
| def CMDformat(parser, args): | 
| -  """Runs clang-format on the diff.""" | 
| +  """run clang-format on the diff""" | 
| CLANG_EXTS = ['.cc', '.cpp', '.h'] | 
| parser.add_option('--full', action='store_true', default=False) | 
| opts, args = parser.parse_args(args) | 
| @@ -2174,7 +2154,7 @@ def Command(name): | 
|  | 
|  | 
| def CMDhelp(parser, args): | 
| -  """Prints list of commands or help for a specific command.""" | 
| +  """print list of commands or help for a specific command""" | 
| _, args = parser.parse_args(args) | 
| if len(args) == 1: | 
| return main(args + ['--help']) | 
| @@ -2192,32 +2172,11 @@ def GenUsage(parser, command): | 
| if command == 'help': | 
| command = '<command>' | 
| else: | 
| -    parser.description = obj.__doc__ | 
| +    # OptParser.description prefer nicely non-formatted strings. | 
| +    parser.description = re.sub('[\r\n ]{2,}', ' ', obj.__doc__) | 
| parser.set_usage('usage: %%prog %s [options] %s' % (command, more)) | 
|  | 
|  | 
| -class OptionParser(optparse.OptionParser): | 
| -  """Creates the option parse and add --verbose support.""" | 
| -  def __init__(self, *args, **kwargs): | 
| -    optparse.OptionParser.__init__(self, *args, **kwargs) | 
| -    self.add_option( | 
| -        '-v', '--verbose', action='count', default=0, | 
| -        help='Use 2 times for more debugging info') | 
| - | 
| -  def parse_args(self, args=None, values=None): | 
| -    options, args = optparse.OptionParser.parse_args(self, args, values) | 
| -    levels = [logging.WARNING, logging.INFO, logging.DEBUG] | 
| -    logging.basicConfig(level=levels[min(options.verbose, len(levels) - 1)]) | 
| -    return options, args | 
| - | 
| -  def format_description(self, _): | 
| -    """Disables automatic reformatting.""" | 
| -    lines = self.description.rstrip().splitlines() | 
| -    lines_fixed = [lines[0]] + [l[2:] if len(l) >= 2 else l for l in lines[1:]] | 
| -    description = ''.join(l + '\n' for l in lines_fixed) | 
| -    return description[0].upper() + description[1:] | 
| - | 
| - | 
| def main(argv): | 
| """Doesn't parse the arguments here, just find the right subcommand to | 
| execute.""" | 
| @@ -2234,19 +2193,29 @@ def main(argv): | 
| # Do it late so all commands are listed. | 
| commands = Commands() | 
| length = max(len(c) for c in commands) | 
| - | 
| -  def gen_summary(x): | 
| -    """Creates a oneline summary from the docstring.""" | 
| -    line = x.split('\n', 1)[0].rstrip('.') | 
| -    return line[0].lower() + line[1:] | 
| - | 
| docs = sorted( | 
| -      (name, gen_summary(handler.__doc__).strip()) | 
| +      (name, handler.__doc__.split('\n')[0].strip()) | 
| for name, handler in commands.iteritems()) | 
| CMDhelp.usage_more = ('\n\nCommands are:\n' + '\n'.join( | 
| '  %-*s %s' % (length, name, doc) for name, doc in docs)) | 
|  | 
| -  parser = OptionParser() | 
| +  # Create the option parse and add --verbose support. | 
| +  parser = optparse.OptionParser() | 
| +  parser.add_option( | 
| +      '-v', '--verbose', action='count', default=0, | 
| +      help='Use 2 times for more debugging info') | 
| +  old_parser_args = parser.parse_args | 
| +  def Parse(args): | 
| +    options, args = old_parser_args(args) | 
| +    if options.verbose >= 2: | 
| +      logging.basicConfig(level=logging.DEBUG) | 
| +    elif options.verbose: | 
| +      logging.basicConfig(level=logging.INFO) | 
| +    else: | 
| +      logging.basicConfig(level=logging.WARNING) | 
| +    return options, args | 
| +  parser.parse_args = Parse | 
| + | 
| if argv: | 
| command = Command(argv[0]) | 
| if command: | 
|  |