From patchwork Mon Jul 6 03:42:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240795 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Sun, 5 Jul 2020 21:42:00 -0600 Subject: [RFC PATCH 13/16] patchstream: Support parsing of review snippets In-Reply-To: <20200706034203.2171077-1-sjg@chromium.org> References: <20200706034203.2171077-1-sjg@chromium.org> Message-ID: <20200706034203.2171077-14-sjg@chromium.org> Add support for parsing the contents of a patchwork 'patch' web page containing comments received from reviewers. This allows patman to show these comments in a simple 'snippets' format. A snippet is some quoted code plus some unquoted comments below it. Each review is from a unique person/email and can produce multiple snippets, one for each part of the code that attracts a comment. Signed-off-by: Simon Glass --- tools/patman/patchstream.py | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tools/patman/patchstream.py b/tools/patman/patchstream.py index 0c68c86156..5e2b8e3986 100644 --- a/tools/patman/patchstream.py +++ b/tools/patman/patchstream.py @@ -2,10 +2,12 @@ # Copyright (c) 2011 The Chromium OS Authors. # +import collections import datetime import math import os import re +import queue import shutil import tempfile @@ -80,6 +82,10 @@ class PatchStream: self.state = STATE_MSG_HEADER # What state are we in? self.signoff = [] # Contents of signoff line self.commit = None # Current commit + self.snippets = [] # List of unquoted test blocks + self.recent_quoted = collections.deque([], 5) + self.recent_unquoted = queue.Queue() + self.was_quoted = None def AddToSeries(self, line, name, value): """Add a new Series-xxx tag. @@ -165,6 +171,40 @@ class PatchStream: self.commit.AddChange(self.change_version, change) self.change_lines = [] + def FinaliseSnippet(self): + """Finish off a snippet and add it to the list + + This is called when we get to the end of a snippet, i.e. the we enter + the next block of quoted text: + + This is a comment from someone. + + Something else + + > Now we have some code <----- end of snippet + > more code + + Now a comment about the above code + + This adds the snippet to our list + """ + quoted_lines = [] + while len(self.recent_quoted): + quoted_lines.append(self.recent_quoted.popleft()) + unquoted_lines = [] + valid = False + while not self.recent_unquoted.empty(): + text = self.recent_unquoted.get() + unquoted_lines.append(text) + if text: + valid = True + if valid: + lines = quoted_lines + unquoted_lines + if lines[0].startswith('On ') and lines[0].endswith('wrote:'): + lines = lines[1:] + if lines: + self.snippets.append(lines) + def ProcessLine(self, line): """Process a single line of a patch file or commit log @@ -384,6 +424,18 @@ class PatchStream: out = [line] self.linenum += 1 self.skip_blank = False + + # If this is quoted, keep recent lines + if self.linenum > 1 and line: + if line.startswith('>'): + if not self.was_quoted: + self.FinaliseSnippet() + self.recent_quoted.append(line) + self.was_quoted = True + else: + self.recent_unquoted.put(line) + self.was_quoted = False + if self.state == STATE_DIFFS: pass @@ -407,6 +459,7 @@ class PatchStream: def Finalize(self): """Close out processing of this patch stream""" + self.FinaliseSnippet() self.FinalizeChange() self.CloseCommit() if self.lines_after_test: