commit:     bad313667aa111639f9c5801d6f10420968ac2b9
Author:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
AuthorDate: Thu Nov  3 17:43:47 2022 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Tue Nov  8 18:59:00 2022 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=bad31366

NonPosixHeadTailUsage: new check

New warning for non-POSIX compliant head or tail without -n.

Closes: https://bugs.gentoo.org/558360
Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org>

 src/pkgcheck/checks/codingstyle.py                 | 46 ++++++++++++++++++++++
 .../NonPosixHeadTailUsage/expected.json            |  5 +++
 .../NonPosixCheck/NonPosixHeadTailUsage/fix.patch  | 26 ++++++++++++
 .../NonPosixHeadTailUsage-0.ebuild                 | 10 +++++
 .../NonPosixHeadTailUsage-1.ebuild                 | 11 ++++++
 5 files changed, 98 insertions(+)

diff --git a/src/pkgcheck/checks/codingstyle.py 
b/src/pkgcheck/checks/codingstyle.py
index 30e7f9f9..954ef09d 100644
--- a/src/pkgcheck/checks/codingstyle.py
+++ b/src/pkgcheck/checks/codingstyle.py
@@ -1170,3 +1170,49 @@ class DoCompressedFilesCheck(Check):
                 lineno, _ = arg.start_point
                 if arg_name.endswith(self.compresion_extentions):
                     yield self.functions[call_name](call_name, 
lineno=lineno+1, line=arg_name, pkg=pkg)
+
+
+class NonPosixHeadTailUsage(results.LineResult, results.Warning):
+    """Using of non-POSIX compliant ``head`` or ``tail``.
+
+    The numeric argument to ``head`` or ``tail`` without ``-n`` (for example
+    ``head -10``) is deprecated and not POSIX compliant. To fix, prepand ``-n``
+    before the number [#]_.
+
+    .. [#] 
https://devmanual.gentoo.org/tools-reference/head-and-tail/index.html
+    """
+    def __init__(self, command, **kwargs):
+        super().__init__(**kwargs)
+        self.command = command
+
+    @property
+    def desc(self):
+        return f'line {self.lineno}: non-posix usage of {self.command!r}: 
{self.line!r}'
+
+
+class NonPosixCheck(Check):
+    """Scan ebuild for non-posix usage, code which might be not portable."""
+
+    _source = sources.EbuildParseRepoSource
+    known_results = frozenset([NonPosixHeadTailUsage])
+
+    def __init__(self, options, **kwargs):
+        super().__init__(options, **kwargs)
+        self.re_head_tail = re.compile(r'[+-]\d+')
+
+    def check_head_tail(self, pkg, call_node, call_name):
+        prev_arg = ''
+        for arg in map(pkg.node_str, call_node.children[1:]):
+            if (self.re_head_tail.match(arg) and
+                not (prev_arg.startswith('-') and prev_arg.endswith(('n', 
'c')))):
+                lineno, _ = call_node.start_point
+                yield NonPosixHeadTailUsage(f'{call_name} {arg}',
+                    lineno=lineno+1, line=pkg.node_str(call_node), pkg=pkg)
+                break
+            prev_arg = arg
+
+    def feed(self, pkg):
+        for call_node, _ in bash.cmd_query.captures(pkg.tree.root_node):
+            call_name = pkg.node_str(call_node.child_by_field_name('name'))
+            if call_name in ('head', 'tail'):
+                yield from self.check_head_tail(pkg, call_node, call_name)

diff --git 
a/testdata/data/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/expected.json
 
b/testdata/data/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/expected.json
new file mode 100644
index 00000000..daed2c67
--- /dev/null
+++ 
b/testdata/data/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/expected.json
@@ -0,0 +1,5 @@
+{"__class__": "NonPosixHeadTailUsage", "category": "NonPosixCheck", "package": 
"NonPosixHeadTailUsage", "version": "0", "line": "head -1 file", "lineno": 7, 
"command": "head -1"}
+{"__class__": "NonPosixHeadTailUsage", "category": "NonPosixCheck", "package": 
"NonPosixHeadTailUsage", "version": "0", "line": "head -q file -1", "lineno": 
8, "command": "head -1"}
+{"__class__": "NonPosixHeadTailUsage", "category": "NonPosixCheck", "package": 
"NonPosixHeadTailUsage", "version": "1", "line": "tail -1 file", "lineno": 7, 
"command": "tail -1"}
+{"__class__": "NonPosixHeadTailUsage", "category": "NonPosixCheck", "package": 
"NonPosixHeadTailUsage", "version": "1", "line": "tail -q file -1", "lineno": 
8, "command": "tail -1"}
+{"__class__": "NonPosixHeadTailUsage", "category": "NonPosixCheck", "package": 
"NonPosixHeadTailUsage", "version": "1", "line": "tail -qn file +1", "lineno": 
9, "command": "tail +1"}

diff --git 
a/testdata/data/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/fix.patch 
b/testdata/data/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/fix.patch
new file mode 100644
index 00000000..c01e9028
--- /dev/null
+++ 
b/testdata/data/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/fix.patch
@@ -0,0 +1,26 @@
+--- 
standalone/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-0.ebuild
++++ fixed/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-0.ebuild
+@@ -4,7 +4,7 @@ SLOT="0"
+ LICENSE="BSD"
+
+ src_prepare() {
+-      head -1 file > another || die
+-      head -q file -1 > another || die
++      head -n -1 file > another || die
++      head -qn 1 file > another || die
+       default
+ }
+--- 
standalone/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-1.ebuild
++++ fixed/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-1.ebuild
+@@ -4,8 +4,8 @@ SLOT="0"
+ LICENSE="BSD"
+
+ src_prepare() {
+-      tail -1 file > another || die
+-      tail -q file -1 > another || die
+-      tail -qn file +1 > another || die
++      tail -n 1 file > another || die
++      tail -q file -c 1 > another || die
++      tail file -qn +1 > another || die
+       default
+ }

diff --git 
a/testdata/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-0.ebuild
 
b/testdata/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-0.ebuild
new file mode 100644
index 00000000..6ee3b8fc
--- /dev/null
+++ 
b/testdata/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-0.ebuild
@@ -0,0 +1,10 @@
+DESCRIPTION="Ebuild with non posix head usage"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+SLOT="0"
+LICENSE="BSD"
+
+src_prepare() {
+       head -1 file > another || die
+       head -q file -1 > another || die
+       default
+}

diff --git 
a/testdata/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-1.ebuild
 
b/testdata/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-1.ebuild
new file mode 100644
index 00000000..6e926ae8
--- /dev/null
+++ 
b/testdata/repos/standalone/NonPosixCheck/NonPosixHeadTailUsage/NonPosixHeadTailUsage-1.ebuild
@@ -0,0 +1,11 @@
+DESCRIPTION="Ebuild with non posix head usage"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+SLOT="0"
+LICENSE="BSD"
+
+src_prepare() {
+       tail -1 file > another || die
+       tail -q file -1 > another || die
+       tail -qn file +1 > another || die
+       default
+}

Reply via email to