From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 0AC41158020 for ; Fri, 28 Oct 2022 13:34:25 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 421A5E0729; Fri, 28 Oct 2022 13:34:24 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 21243E0729 for ; Fri, 28 Oct 2022 13:34:24 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 12E8A3410DE for ; Fri, 28 Oct 2022 13:34:23 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 7EA34523 for ; Fri, 28 Oct 2022 13:34:21 +0000 (UTC) From: "Arthur Zamarin" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Arthur Zamarin" Message-ID: <1666962903.c415e94f833acc4b824cf2b6db332244e97313e9.arthurzam@gentoo> Subject: [gentoo-commits] proj/pkgcore/pkgcheck:master commit in: src/pkgcheck/checks/, tests/checks/ X-VCS-Repository: proj/pkgcore/pkgcheck X-VCS-Files: src/pkgcheck/checks/codingstyle.py tests/checks/test_codingstyle.py X-VCS-Directories: src/pkgcheck/checks/ tests/checks/ X-VCS-Committer: arthurzam X-VCS-Committer-Name: Arthur Zamarin X-VCS-Revision: c415e94f833acc4b824cf2b6db332244e97313e9 X-VCS-Branch: master Date: Fri, 28 Oct 2022 13:34:21 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 22951e7f-1bec-4e25-8e0b-ab600fef1547 X-Archives-Hash: b9bab748408aeeb4a548c25791bbc28a commit: c415e94f833acc4b824cf2b6db332244e97313e9 Author: Arthur Zamarin gentoo org> AuthorDate: Sat Oct 22 08:21:13 2022 +0000 Commit: Arthur Zamarin gentoo org> CommitDate: Fri Oct 28 13:15:03 2022 +0000 URL: https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=c415e94f ExcessiveLineCheck: check for too long lines Closes: https://bugs.gentoo.org/440686 Signed-off-by: Arthur Zamarin gentoo.org> src/pkgcheck/checks/codingstyle.py | 39 +++++++++++++++++++++++++ tests/checks/test_codingstyle.py | 59 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/pkgcheck/checks/codingstyle.py b/src/pkgcheck/checks/codingstyle.py index e8a2f45a..0933c492 100644 --- a/src/pkgcheck/checks/codingstyle.py +++ b/src/pkgcheck/checks/codingstyle.py @@ -1079,3 +1079,42 @@ class EclassUnquotedVariablesCheck(_UnquotedVariablesCheck): def feed(self, eclass): for var_name, lines in self._feed(eclass): yield EclassUnquotedVariable(var_name, lines=lines, eclass=eclass.name) + + +class ExcessiveLineLength(results.LinesResult, results.Style): + """Line is longer than 120 characters.""" + + line_length = 120 + word_length = 110 + + @property + def desc(self): + return f'excessive line length (over {self.line_length} characters) {self.lines_str}' + + +class LineLengthCheck(Check): + """Scan ebuild for lines with excessive length.""" + + _source = sources.EbuildFileRepoSource + known_results = frozenset([ExcessiveLineLength]) + + def __init__(self, options, **kwargs): + super().__init__(options, **kwargs) + self.exception = re.compile(r'\s*(?:DESCRIPTION|KEYWORDS|IUSE)=') + str_length = f'[^\'\"]{{{ExcessiveLineLength.word_length},}}' + self.long_string = re.compile(rf'"{str_length}"|\'{str_length}\'') + + def feed(self, pkg): + lines = [] + for lineno, line in enumerate(pkg.lines, 1): + if len(line) <= ExcessiveLineLength.line_length: + continue + if self.exception.match(line): + continue # exception variables which are fine to be long + if max(map(len, line.split())) > ExcessiveLineLength.word_length: + continue # if one part of the line is very long word + if self.long_string.search(line): + continue # skip lines with long quoted string + lines.append(lineno) + if lines: + yield ExcessiveLineLength(lines=lines, pkg=pkg) diff --git a/tests/checks/test_codingstyle.py b/tests/checks/test_codingstyle.py index 3becc919..1c6a0075 100644 --- a/tests/checks/test_codingstyle.py +++ b/tests/checks/test_codingstyle.py @@ -433,3 +433,62 @@ class TestStaticSrcUri(misc.ReportTestCase): r = self.assertReport(self.check, self._prepare_pkg('Diffball-0.1.2.3', pkgver='Diffball-0.1.2.3')) assert r.static_str == 'Diffball-0.1.2.3' assert r.replacement == '${P}' + + +class TestExcessiveLineLength(misc.ReportTestCase): + + check_kls = codingstyle.LineLengthCheck + check = check_kls(None) + word_length = codingstyle.ExcessiveLineLength.word_length + + + @staticmethod + def _prepare_pkg(*lines: str): + fake_pkg = misc.FakePkg("dev-util/diffball-0", ebuild=''.join(lines), lines=lines) + data = ''.join(lines).encode() + return _ParsedPkg(data, pkg=fake_pkg) + + def test_normal_length(self): + self.assertNoReport(self.check, self._prepare_pkg('echo "short line"')) + + def test_long_line(self): + r = self.assertReport(self.check, self._prepare_pkg(f'echo {"a " * codingstyle.ExcessiveLineLength.line_length}')) + assert r.lines == (1, ) + + def test_multiple_lines(self): + r = self.assertReport(self.check, self._prepare_pkg( + f'echo {"a " * codingstyle.ExcessiveLineLength.line_length}', + 'echo "short line"', + f'echo {"Hello " * codingstyle.ExcessiveLineLength.line_length}', + )) + assert r.lines == (1, 3) + + @pytest.mark.parametrize('variable', ('DESCRIPTION', 'KEYWORDS', 'IUSE')) + def test_special_variables(self, variable): + self.assertNoReport(self.check, self._prepare_pkg( + f'{variable}="{"a " * codingstyle.ExcessiveLineLength.line_length}"', + f' {variable}="{"a " * codingstyle.ExcessiveLineLength.line_length}"', + f'\t\t{variable}="{"a " * codingstyle.ExcessiveLineLength.line_length}"', + )) + + def test_long_words(self): + long_word = 'a' * self.word_length + 'b' + medium_word = 'a' * (self.word_length // 2) + r = self.assertReport(self.check, self._prepare_pkg( + f'echo {"a" * codingstyle.ExcessiveLineLength.line_length}', + f'echo {medium_word} {long_word}', + f'echo {medium_word} {long_word[:-5]}', + )) + assert r.lines == (3, ) + + def test_long_quotes(self): + # The exception is for any quoted string with length >= word_length. + # Each quoted string is computed by itself. + long_word = 'a ' * (self.word_length // 2) + 'b' # long quoted string, skipped + medium_word = 'a ' * (self.word_length // 4) # not long enough string, not skipped + r = self.assertReport(self.check, self._prepare_pkg( + f'echo "{"a" * codingstyle.ExcessiveLineLength.line_length}"', + f'echo "{medium_word}" "{long_word}"', + 'echo' + f' "{medium_word}"' * 3, + )) + assert r.lines == (3, )