From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 73E468226C for ; Tue, 20 Dec 2016 20:45:06 -0800 (PST) Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga103.jf.intel.com with ESMTP; 20 Dec 2016 20:45:05 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.33,381,1477983600"; d="scan'208";a="45212553" Received: from dbmeier-mobl.amr.corp.intel.com (HELO localhost) ([10.252.142.217]) by fmsmga005.fm.intel.com with ESMTP; 20 Dec 2016 20:45:05 -0800 MIME-Version: 1.0 To: "Gao, Liming" , "Daniil Egranov" , "edk2-devel@lists.01.org" Message-ID: <148229550515.13224.6796888079001609027@jljusten-ivb> From: Jordan Justen In-Reply-To: <4A89E2EF3DFEDB4C8BFDE51014F606A14D6B289C@shsmsx102.ccr.corp.intel.com> Cc: "leif.lindholm@linaro.org" References: <1481929878-30370-1-git-send-email-daniil.egranov@arm.com> <4A89E2EF3DFEDB4C8BFDE51014F606A14D6B289C@shsmsx102.ccr.corp.intel.com> User-Agent: alot/0.3.7 Date: Tue, 20 Dec 2016 20:45:05 -0800 Subject: Re: [PATCH v7] BaseTools/Scripts/PatchCheck.py: Extended patch style check for c code X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 21 Dec 2016 04:45:06 -0000 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable On 2016-12-19 00:31:13, Gao, Liming wrote: > Daniil: > This version has addressed my comments. I see Jordan also provides > some comments. Are they handled in this patch? > No, they were not addressed. Here are my replies: v5: https://lists.01.org/pipermail/edk2-devel/2016-December/005779.html v6: https://lists.01.org/pipermail/edk2-devel/2016-December/005866.html > > > -----Original Message----- > > From: Daniil Egranov [mailto:daniil.egranov@arm.com] > > Sent: Saturday, December 17, 2016 7:11 AM > > To: edk2-devel@lists.01.org > > Cc: leif.lindholm@linaro.org; Gao, Liming ; Daniil > > Egranov > > Subject: [PATCH v7] BaseTools/Scripts/PatchCheck.py: Extended patch sty= le > > check for c code > > = > > Changed output format to make it more comapct. > > Disabled colored output by default. For terminals which support ANSI > > escape codes, colored output can be enabled with the "--color" command > > line parameter. > > = > > Contributed-under: TianoCore Contribution Agreement 1.0 > > Signed-off-by: Daniil Egranov > > --- > > Changelog: > > = > > v6 > > Added reporting a source code line number in case of error when > > checking a patch file or using a git sha1 commit string. In case of > > a patch file, both patch and source code line numbers will be provided. > > Corrected handling the case with #define foo(..) macro. The absence of > > the space before open parenthesis is not reported as the error anymore. > > Added checking for lower case "void" and "static" words. > > Added colors for error messages (experimental?) > > = > > v5 > > Corrected code checking for multi-line and commented lines. Both > > multi-line and open comment flags will be reset when leaving > > diff "+" area of the patch. > > Changed version of the tool to 0.2. > > = > > v4 > > Corrected maximum code line size to 120 characters. > > = > > v3 > > Corrected space detection before parentheses. > > = > > v2: > > Fixed several indentation cases > > = > > v1: > > Fixed reporting signature error for a cover letter. > > Fixed reporting line size error for a file change information > > included in the commit message. > > Fixed line number reported in PatchCheck error messages. It > > points to the correct line in the diff file. > > The patch extends style checking for c code: > > Added check for code indentation. > > Added report line size greater than 80 characters. > > Added checking for space before '('. > > Added checking for space before '{'. > > Added checking for '}' to be on a new line and have spaces > > for "} else {" or "} while ()" cases. > > = > > BaseTools/Scripts/PatchCheck.py | 379 > > ++++++++++++++++++++++++++++++++++++---- > > 1 file changed, 341 insertions(+), 38 deletions(-) > > = > > diff --git a/BaseTools/Scripts/PatchCheck.py > > b/BaseTools/Scripts/PatchCheck.py > > index 7c30082..eae084c 100755 > > --- a/BaseTools/Scripts/PatchCheck.py > > +++ b/BaseTools/Scripts/PatchCheck.py > > @@ -15,7 +15,7 @@ > > = > > from __future__ import print_function > > = > > -VersionNumber =3D '0.1' > > +VersionNumber =3D '0.2' > > __copyright__ =3D "Copyright (c) 2015 - 2016, Intel Corporation All r= ights > > reserved." > > = > > import email > > @@ -25,6 +25,44 @@ import re > > import subprocess > > import sys > > = > > +class MsgFormat: > > + ERROR, WARNING, REPORT, LINK, NORMAL =3D range(5) > > + color_on =3D False > > + > > +class ColorTypes: > > + RED =3D '\033[91m' > > + GREEN =3D '\033[92m' > > + BLUE =3D '\033[94m' > > + CYAN =3D '\033[96m' > > + WHITE =3D '\033[97m' > > + YELLOW =3D '\033[93m' > > + MAGENTA =3D '\033[95m' > > + GREY =3D '\033[90m' > > + BLACK =3D '\033[90m' > > + DEFAULT =3D '\033[0m' > > + > > +class TextColor: > > + def __init__(self, color_on, msg_format): > > + self.color =3D '' > > + if color_on =3D=3D True: > > + if msg_format =3D=3D MsgFormat.ERROR: > > + self.color =3D ColorTypes.RED > > + elif msg_format =3D=3D MsgFormat.WARNING: > > + self.color =3D ColorTypes.YELLOW > > + elif msg_format =3D=3D MsgFormat.REPORT: > > + self.color =3D ColorTypes.CYAN > > + elif msg_format =3D=3D MsgFormat.LINK: > > + self.color =3D ColorTypes.BLUE > > + elif msg_format =3D=3D MsgFormat.NORMAL: > > + self.color =3D ColorTypes.DEFAULT > > + else: > > + self.color =3D ColorTypes.DEFAULT > > + else: > > + self.color =3D '' > > + > > + def __str__(self): > > + return self.color > > + > > class Verbose: > > SILENT, ONELINE, NORMAL =3D range(3) > > level =3D NORMAL > > @@ -32,7 +70,7 @@ class Verbose: > > class CommitMessageCheck: > > """Checks the contents of a git commit message.""" > > = > > - def __init__(self, subject, message): > > + def __init__(self, subject, message, message_offset, cover): > > self.ok =3D True > > = > > if subject is None and message is None: > > @@ -41,9 +79,15 @@ class CommitMessageCheck: > > = > > self.subject =3D subject > > self.msg =3D message > > + self.msg_offset =3D message_offset > > + self.cover =3D cover > > + > > + if not cover: > > + self.check_contributed_under() > > + self.check_signed_off_by() > > + else: > > + print('The commit message is cover letter.') > > = > > - self.check_contributed_under() > > - self.check_signed_off_by() > > self.check_misc_signatures() > > self.check_overall_format() > > self.report_message_result() > > @@ -60,9 +104,11 @@ class CommitMessageCheck: > > else: > > return_code =3D 1 > > if not self.ok: > > - print(self.url) > > + print('\n' + self.url) > > = > > def error(self, *err): > > + start =3D TextColor(MsgFormat.color_on, MsgFormat.ERROR) > > + end =3D TextColor(MsgFormat.color_on, MsgFormat.NORMAL) > > if self.ok and Verbose.level > Verbose.ONELINE: > > print('The commit message format is not valid:') > > self.ok =3D False > > @@ -71,7 +117,7 @@ class CommitMessageCheck: > > count =3D 0 > > for line in err: > > prefix =3D (' *', ' ')[count > 0] > > - print(prefix, line) > > + print(start, prefix, line, end) > > count +=3D 1 > > = > > def check_contributed_under(self): > > @@ -180,7 +226,12 @@ class CommitMessageCheck: > > for sig in self.sig_types: > > self.find_signatures(sig) > > = > > + diff_change_info_re =3D \ > > + re.compile(r'.*\|\s+(\d|Bin)*\s.*[\+\-]') > > + > > def check_overall_format(self): > > + start =3D TextColor(MsgFormat.color_on, MsgFormat.REPORT) > > + end =3D TextColor(MsgFormat.color_on, MsgFormat.NORMAL) > > lines =3D self.msg.splitlines() > > = > > if len(lines) >=3D 1 and lines[0].endswith('\r\n'): > > @@ -197,9 +248,10 @@ class CommitMessageCheck: > > self.error('Empty commit message!') > > return > > = > > - if count >=3D 1 and len(lines[0]) >=3D 72: > > + if count >=3D 1 and len(lines[0]) > 72: > > self.error('First line of commit message (subject line) ' + > > - 'is too long.') > > + 'is too long (%d) (max 72 characters): ' %(len(= lines[0])) + > > + str(start) + lines[0] + str(end)) > > = > > if count >=3D 1 and len(lines[0].strip()) =3D=3D 0: > > self.error('First line of commit message (subject line) ' + > > @@ -210,10 +262,13 @@ class CommitMessageCheck: > > 'empty.') > > = > > for i in range(2, count): > > - if (len(lines[i]) >=3D 76 and > > + if (len(lines[i]) > 76 and > > len(lines[i].split()) > 1 and > > - not lines[i].startswith('git-svn-id:')): > > - self.error('Line %d of commit message is too long.' % = (i + 1)) > > + not lines[i].startswith('git-svn-id:') and > > + self.diff_change_info_re.search(lines[i]) is None): > > + self.error('Line %d of commit message is too long (%d)= (max 76 > > characters): ' \ > > + % (i + self.msg_offset - 1, len(lines[i])) + > > + str(start) + lines[i] + str(end)) > > = > > last_sig_line =3D None > > for i in range(count - 1, 0, -1): > > @@ -236,13 +291,21 @@ class CommitMessageCheck: > > class GitDiffCheck: > > """Checks the contents of a git diff.""" > > = > > - def __init__(self, diff): > > + def __init__(self, diff, offset, patch_type): > > self.ok =3D True > > self.format_ok =3D True > > self.lines =3D diff.splitlines(True) > > self.count =3D len(self.lines) > > self.line_num =3D 0 > > self.state =3D START > > + self.comments_open =3D False > > + self.multiline_string =3D False > > + self.current_indent_size =3D 0 > > + self.parentheses_count =3D 0 > > + self.offset =3D offset > > + self.file_type =3D "other_type" > > + self.patch_type =3D patch_type > > + self.src_line_num =3D 0; > > while self.line_num < self.count and self.format_ok: > > line_num =3D self.line_num > > self.run() > > @@ -255,6 +318,14 @@ class GitDiffCheck: > > if self.ok: > > print('The code passed all checks.') > > = > > + def clean_counts(self): > > + self.current_indent_size =3D -1 > > + self.parentheses_count =3D 0 > > + self.comments_open =3D False > > + self.multiline_string =3D False > > + > > + diff_src_line_start_re =3D re.compile(r'(\+\d+)') > > + > > def run(self): > > line =3D self.lines[self.line_num] > > = > > @@ -281,9 +352,28 @@ class GitDiffCheck: > > self.format_error("didn't find diff command") > > self.line_num +=3D 1 > > elif self.state =3D=3D PRE_PATCH: > > - if line.startswith('+++ b/'): > > + if line.startswith('+++ '): > > self.set_filename(line[6:].rstrip()) > > + print("\nChecking patch for %s ..." %(self.hunk_filena= me)) > > + if self.hunk_filename.endswith(".c") or \ > > + self.hunk_filename.endswith(".h"): > > + self.file_type =3D "c_type" > > + elif self.hunk_filename.endswith(".dec") or \ > > + self.hunk_filename.endswith(".dsc") or \ > > + self.hunk_filename.endswith(".fdf"): > > + self.file_type =3D "edk2_type" > > + elif self.hunk_filename.endswith(".S"): > > + self.file_type =3D "asm_arm_type" > > + elif self.hunk_filename.endswith(".asm"): > > + self.file_type =3D "asm_type" > > + else: > > + self.file_type =3D "other_type" > > if line.startswith('@@ '): > > + sls =3D self.diff_src_line_start_re.search(line) > > + if sls is not None: > > + self.src_line_num =3D int(sls.group(0)) > > + else: > > + self.src_line_num =3D 0 > > self.state =3D PATCH > > self.binary =3D False > > elif line.startswith('GIT binary patch'): > > @@ -299,15 +389,25 @@ class GitDiffCheck: > > self.line_num +=3D 1 > > elif self.state =3D=3D PATCH: > > if self.binary: > > + self.clean_counts() > > pass > > if line.startswith('-'): > > + self.clean_counts() > > pass > > elif line.startswith('+'): > > - self.check_added_line(line[1:]) > > + # indentation resets every time we leave "+" diff area > > + self.check_added_line(line[1:], self.line_num + self.o= ffset, > > + self.src_line_num) > > + self.src_line_num +=3D1 > > elif line.startswith(r'\ No newline '): > > + self.clean_counts() > > pass > > elif not line.startswith(' '): > > + self.clean_counts() > > self.format_error("unexpected patch line") > > + else: > > + self.src_line_num +=3D1 > > + self.clean_counts() > > self.line_num +=3D 1 > > = > > pre_patch_prefixes =3D ( > > @@ -332,13 +432,19 @@ class GitDiffCheck: > > else: > > self.force_crlf =3D True > > = > > - def added_line_error(self, msg, line): > > + def added_line_error(self, msg, line, diff_line_num, src_line_num, > > patch_type): > > + start =3D TextColor(MsgFormat.color_on, MsgFormat.REPORT) > > + end =3D TextColor(MsgFormat.color_on, MsgFormat.NORMAL) > > lines =3D [ msg ] > > - if self.hunk_filename is not None: > > - lines.append('File: ' + self.hunk_filename) > > - lines.append('Line: ' + line) > > - > > self.error(*lines) > > + if self.hunk_filename is not None: > > + print('File: ' + self.hunk_filename) > > + line_info =3D 'Line ' > > + if patch_type =3D=3D 'patch_file_type': > > + line_info +=3D ('%d(patch) ' %(diff_line_num)) > > + line_info +=3D ('%d(source) ' %(src_line_num)) > > + line_info +=3D (': ' +str(start) + line.lstrip() + str(end)) > > + print(line_info) > > = > > old_debug_re =3D \ > > re.compile(r''' > > @@ -348,28 +454,195 @@ class GitDiffCheck: > > ''', > > re.VERBOSE) > > = > > - def check_added_line(self, line): > > + space_check_parentheses_re =3D re.compile(r'#define\s*[a-zA-Z0- > > 9_]\S*\(|[a-zA-Z0-9_]\S*\((? > + space_check_brace_open_re =3D re.compile(r'[a-zA-Z0-9_]\S*\{') > > + space_check_brace_close_re =3D re.compile(r'[\}]\S.*') > > + brace_open_check_re =3D re.compile(r'[a-zA-Z0-9_]*\{') > > + brace_close_check_re =3D re.compile(r'.*\}.*') > > + multiline_check_re =3D re.compile(r'[a-zA-Z0-9_]*(\\|\&|\,|\+|\- > > |\*|\||\=3D)\Z') > > + void_cap_check_re =3D re.compile(r'(\s|\b|\()void(\s+|\*|\,|\))') > > + static_cap_check_re =3D re.compile(r'(\s|\b)static\s+') > > + > > + def check_added_line(self, line, diff_line_num, src_line_num): > > eol =3D '' > > for an_eol in self.line_endings: > > if line.endswith(an_eol): > > eol =3D an_eol > > line =3D line[:-len(eol)] > > = > > - stripped =3D line.rstrip() > > + rstripped =3D line.rstrip() > > + lstripped =3D line.lstrip() > > = > > if self.force_crlf and eol !=3D '\r\n': > > self.added_line_error('Line ending (%s) is not CRLF' % rep= r(eol), > > - line) > > + line, diff_line_num, src_line_num, s= elf.patch_type) > > if ' ' in line: > > - self.added_line_error('Tab character used', line) > > - if len(stripped) < len(line): > > - self.added_line_error('Trailing whitespace found', line) > > + self.added_line_error('Tab character used', > > + line, diff_line_num, src_line_num, s= elf.patch_type) > > + if len(rstripped) < len(line): > > + self.added_line_error('Trailing whitespace found', > > + line, diff_line_num, src_line_num, s= elf.patch_type) > > + > > + # empty "+" line, skip it > > + if len(line) =3D=3D 0: > > + return > > = > > - mo =3D self.old_debug_re.search(line) > > - if mo is not None: > > - self.added_line_error('EFI_D_' + mo.group(1) + ' was used,= ' > > - 'but DEBUG_' + mo.group(1) + > > - ' is now recommended', line) > > + # the file type specific checks > > + if self.file_type =3D=3D "c_type": > > + > > + # set initial indentation as the number of spaces after th= e first "+" > > + # indentation does not apply on lines with 0 characters > > + # adjust the indentation if first "+" has "}" > > + if self.current_indent_size =3D=3D -1: > > + if len(lstripped) !=3D 0: > > + self.current_indent_size =3D len(line) - len(lstri= pped) > > + else: > > + self.clean_counts() > > + > > + if lstripped.startswith("}"): > > + self.current_indent_size =3D line.find("}") + 2 > > + > > + indent_size =3D len(line) - len(lstripped) > > + indent_size_adjust =3D 0 > > + force_brace_check =3D False > > + > > + if len(line) > 120: > > + self.added_line_error('Line is too long (%d) (max 120 = characters)', > > + line, diff_line_num, src_line_nu= m, self.patch_type) > > + > > + # skip comments for code checking > > + if lstripped.startswith("//"): > > + return > > + if lstripped.startswith("/*") and not self.comments_open: > > + self.comments_open =3D True > > + > > + if rstripped.endswith("*/") and self.comments_open: > > + self.comments_open =3D False > > + return > > + > > + if rstripped.endswith("*/") and not self.comments_open: > > + # found unknown close comment, reset the indentation as > > + # no idea where it started > > + self.current_indent_size =3D -1 > > + return > > + > > + if not self.comments_open: > > + mo =3D self.old_debug_re.search(line) > > + if mo is not None: > > + self.added_line_error('EFI_D_' + mo.group(1) + ' w= as used, ' > > + 'but DEBUG_' + mo.group(1) + > > + ' is now recommended', > > + line, diff_line_num, src_lin= e_num, self.patch_type) > > + > > + # track down multiple braces in the same line > > + braces_count =3D line.count('{') - line.count('}') > > + > > + # check if line has text in double quotes as we do not > > + # need to check text messages > > + text_str_start =3D line.find('\"') > > + > > + # track down a special case with "} else ..{" braces > > + if line.find("else") !=3D -1: > > + force_brace_check =3D True > > + > > + # check for closing brace which affects indentation > > + if braces_count < 0 and not force_brace_check: > > + self.current_indent_size -=3D 2 * abs(braces_count) > > + elif force_brace_check: > > + if line.find("}") !=3D -1: > > + self.current_indent_size -=3D 2 > > + braces_count =3D 1 > > + > > + # for the switch()/case:, adjust "case:" and "default:= " indentation > > + # as they aligned with the "switch()" indentation > > + if lstripped.startswith("case ") or \ > > + lstripped.startswith("default:"): > > + indent_size_adjust =3D -2 > > + > > + # indentation code check related to the diff structure > > + # do not check code indentation between parentheses > > + if indent_size !=3D self.current_indent_size + indent_= size_adjust \ > > + and len(line) !=3D 0 and self.parentheses_count = =3D=3D 0 \ > > + and not self.multiline_string: > > + self.added_line_error('Invalid indentation. Ex= pecting %d but > > found %d spaces' \ > > + %(self.current_indent_si= ze + indent_size_adjust, \ > > + indent_size), > > + line, diff_line_num, src= _line_num, self.patch_type) > > + > > + # check for missing space before open brace > > + if braces_count > 0 or force_brace_check: > > + if line.find("{") !=3D -1: > > + self.current_indent_size +=3D 2 * braces_count > > + if not line.startswith("{"): > > + spb_check =3D self.space_check_brace_open_re.s= earch(line) > > + if spb_check is not None: > > + self.added_line_error('Missing space befor= e \'{\'', > > + line, diff_line_num,= src_line_num, self.patch_type) > > + > > + # check for missing space before open parenthesis > > + spo =3D self.space_check_parentheses_re.finditer(line) > > + if spo is not None and not self.multiline_string: > > + # check if it's not inside of the double quoted st= ring or > > + # (aa)(bb)fff case or parenthesis belong to #defin= e macro > > + for parstr in spo: > > + if not (text_str_start !=3D -1 and text_str_st= art < parstr.start()) > > and \ > > + not parstr.group(0).startswith("#define"): > > + self.added_line_error('Missing space befor= e \'(\'', > > + line, diff_line_num,= src_line_num, self.patch_type) > > + break; > > + > > + # check for closing brace cases > > + if braces_count < 0 or \ > > + (force_brace_check and line.find("}") !=3D -1): > > + if not lstripped.startswith("}") and rstripped.end= swith("}"): > > + self.added_line_error('The \'}\' is not on its= own line', > > + line, diff_line_num, src= _line_num, self.patch_type) > > + if not lstripped.endswith("}"): > > + scb =3D self.space_check_brace_close_re.search= (lstripped) > > + if scb is not None \ > > + and lstripped[scb.start() + 1] !=3D ';' \ > > + and lstripped[scb.start() + 1] !=3D ',' \ > > + and lstripped[scb.start() + 1] !=3D '}': > > + self.added_line_error('Missing space after= \'}\'', > > + line, diff_line_num,= src_line_num, self.patch_type) > > + > > + # check for using "void" instead of "VOID" > > + vcc =3D self.void_cap_check_re.search(line) > > + if vcc is not None and \ > > + not (text_str_start !=3D -1 and text_str_start < v= cc.start()): > > + self.added_line_error('Using \"void\" instead of \= "VOID\"', > > + line, diff_line_num, src_lin= e_num, self.patch_type) > > + > > + #check for using "static" instead of "STATIC" > > + scc =3D self.static_cap_check_re.search(line) > > + if scc is not None and \ > > + not (text_str_start !=3D -1 and text_str_start < s= cc.start()): > > + self.added_line_error('Using \"static\" instead of= \"STATIC\"', > > + line, diff_line_num, src_lin= e_num, self.patch_type) > > + > > + # track down parentheses, no indentation check between= them > > + if not (self.parentheses_count =3D=3D 0 and lstripped.= startswith(')') \ > > + and not self.multiline_string and not self.com= ments_open): > > + self.parentheses_count +=3D line.count('(') - line= .count(')') > > + > > + # multiline strings indentation is unknown > > + if not self.comments_open: > > + mlc =3D self.multiline_check_re.search(line) > > + if mlc is not None: > > + self.multiline_string =3D True > > + else: > > + self.multiline_string =3D False > > + > > + elif self.file_type =3D=3D "edk2_type": > > + pass > > + elif self.file_type =3D=3D "asm_arm_type": > > + pass > > + elif self.file_type =3D=3D "asm_type": > > + pass > > + elif self.file_type =3D=3D "other_type": > > + pass > > + else: > > + pass > > = > > split_diff_re =3D re.compile(r''' > > (?P > > @@ -388,6 +661,8 @@ class GitDiffCheck: > > self.error(err, err2) > > = > > def error(self, *err): > > + start =3D TextColor(MsgFormat.color_on, MsgFormat.ERROR) > > + end =3D TextColor(MsgFormat.color_on, MsgFormat.NORMAL) > > if self.ok and Verbose.level > Verbose.ONELINE: > > print('Code format is not valid:') > > self.ok =3D False > > @@ -396,7 +671,7 @@ class GitDiffCheck: > > count =3D 0 > > for line in err: > > prefix =3D (' *', ' ')[count > 0] > > - print(prefix, line) > > + print(start, prefix, line, end) > > count +=3D 1 > > = > > class CheckOnePatch: > > @@ -406,16 +681,17 @@ class CheckOnePatch: > > patch content. > > """ > > = > > - def __init__(self, name, patch): > > + def __init__(self, name, patch, patch_type): > > self.patch =3D patch > > self.find_patch_pieces() > > = > > - msg_check =3D CommitMessageCheck(self.commit_subject, > > self.commit_msg) > > + msg_check =3D CommitMessageCheck(self.commit_subject, > > self.commit_msg, \ > > + self.commit_msg_offset, self.co= ver) > > msg_ok =3D msg_check.ok > > = > > diff_ok =3D True > > if self.diff is not None: > > - diff_check =3D GitDiffCheck(self.diff) > > + diff_check =3D GitDiffCheck(self.diff, self.diff_offset, p= atch_type) > > diff_ok =3D diff_check.ok > > = > > self.ok =3D msg_ok and diff_ok > > @@ -458,6 +734,16 @@ class CheckOnePatch: > > ''', > > re.VERBOSE) > > = > > + cover_letter_re =3D re.compile(r'Subject:\s*\[PATCH.*.0/.*', > > + re.IGNORECASE | re.MULTILINE) > > + > > + def is_cover_letter(self, patch): > > + cl =3D self.cover_letter_re.search(patch) > > + if cl is None: > > + return False > > + > > + return True > > + > > def find_patch_pieces(self): > > if sys.version_info < (3, 0): > > patch =3D self.patch.encode('ascii', 'ignore') > > @@ -465,10 +751,13 @@ class CheckOnePatch: > > patch =3D self.patch > > = > > self.commit_msg =3D None > > + self.commit_msg_offset =3D 0 > > self.stat =3D None > > self.commit_subject =3D None > > self.commit_prefix =3D None > > self.diff =3D None > > + self.diff_offset =3D 0 > > + self.cover =3D False > > = > > if patch.startswith('diff --git'): > > self.diff =3D patch > > @@ -480,6 +769,14 @@ class CheckOnePatch: > > assert(parts[0].get_content_type() =3D=3D 'text/plain') > > content =3D parts[0].get_payload(decode=3DTrue).decode('utf-8'= , 'ignore') > > = > > + # find offset of content > > + self.commit_msg_offset =3D len(patch.splitlines()) - > > len(content.splitlines()) > > + > > + # find offset of first diff section > > + mo =3D self.git_diff_re.search(patch) > > + if mo is not None: > > + self.diff_offset =3D len(patch[:mo.start()].splitlines()) = + 1 > > + > > mo =3D self.git_diff_re.search(content) > > if mo is not None: > > self.diff =3D content[mo.start():] > > @@ -492,6 +789,7 @@ class CheckOnePatch: > > self.stat =3D mo.group('stat') > > self.commit_msg =3D mo.group('commit_message') > > = > > + self.cover =3D self.is_cover_letter(patch) > > self.commit_subject =3D pmail['subject'].replace('\r\n', '') > > self.commit_subject =3D self.commit_subject.replace('\n', '') > > self.commit_subject =3D self.subject_prefix_re.sub('', > > self.commit_subject, 1) > > @@ -514,9 +812,9 @@ class CheckGitCommits: > > print() > > else: > > blank_line =3D True > > - print('Checking git commit:', commit) > > + print('Checking git commit:', commit, '\n') > > patch =3D self.read_patch_from_git(commit) > > - self.ok &=3D CheckOnePatch(commit, patch).ok > > + self.ok &=3D CheckOnePatch(commit, patch, "git_commit_type= ").ok > > = > > def read_commit_list_from_git(self, rev_spec, max_count): > > # Run git to get the commit patch > > @@ -554,8 +852,8 @@ class CheckOnePatchFile: > > patch =3D f.read().decode('utf-8', 'ignore') > > f.close() > > if Verbose.level > Verbose.ONELINE: > > - print('Checking patch file:', patch_filename) > > - self.ok =3D CheckOnePatch(patch_filename, patch).ok > > + print('Checking patch file:', patch_filename, '\n') > > + self.ok =3D CheckOnePatch(patch_filename, patch, "patch_file_t= ype").ok > > = > > class CheckOneArg: > > """Performs a patch check for a single command line argument. > > @@ -618,11 +916,16 @@ class PatchCheckApp: > > group.add_argument("--silent", > > action=3D"store_true", > > help=3D"Print nothing") > > + group.add_argument("--color", > > + action=3D"store_true", > > + help=3D"Enable color messages") > > self.args =3D parser.parse_args() > > if self.args.oneline: > > Verbose.level =3D Verbose.ONELINE > > if self.args.silent: > > Verbose.level =3D Verbose.SILENT > > + if self.args.color: > > + MsgFormat.color_on =3D True > > = > > if __name__ =3D=3D "__main__": > > sys.exit(PatchCheckApp().retval) > > -- > > 2.7.4 >=20