[libvirt] [PATCH v5 03/23] build-aux: rewrite mock inline checker in Python

Daniel P. Berrangé posted 23 patches 5 years ago
There is a newer version of this series
[libvirt] [PATCH v5 03/23] build-aux: rewrite mock inline checker in Python
Posted by Daniel P. Berrangé 5 years ago
As part of an goal to eliminate Perl from libvirt build tools,
rewrite the mock-noinline.pl tool in Python.

This was a straight conversion, manually going line-by-line to
change the syntax from Perl to Python. Thus the overall structure
of the file and approach is the same.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 Makefile.am                |  2 +-
 build-aux/mock-noinline.pl | 75 ---------------------------------
 build-aux/syntax-check.mk  |  4 +-
 scripts/mock-noinline.py   | 85 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 88 insertions(+), 78 deletions(-)
 delete mode 100644 build-aux/mock-noinline.pl
 create mode 100644 scripts/mock-noinline.py

diff --git a/Makefile.am b/Makefile.am
index 5187ca6cc2..d9369c9197 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,7 +49,7 @@ EXTRA_DIST = \
   scripts/check-spacing.py \
   build-aux/header-ifdef.pl \
   scripts/minimize-po.py \
-  build-aux/mock-noinline.pl \
+  scripts/mock-noinline.py \
   scripts/prohibit-duplicate-header.py \
   build-aux/syntax-check.mk \
   build-aux/useless-if-before-free \
diff --git a/build-aux/mock-noinline.pl b/build-aux/mock-noinline.pl
deleted file mode 100644
index b005b8d95e..0000000000
--- a/build-aux/mock-noinline.pl
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/env perl
-
-my %noninlined;
-my %mocked;
-
-# Functions in public header don't get the noinline annotation
-# so whitelist them here
-$noninlined{"virEventAddTimeout"} = 1;
-# This one confuses the script as its defined in the mock file
-# but is actually just a local helper
-$noninlined{"virMockStatRedirect"} = 1;
-
-foreach my $arg (@ARGV) {
-    if ($arg =~ /\.h$/) {
-        #print "Scan header $arg\n";
-        &scan_annotations($arg);
-    } elsif ($arg =~ /mock\.c$/) {
-        #print "Scan mock $arg\n";
-        &scan_overrides($arg);
-    }
-}
-
-my $warned = 0;
-foreach my $func (keys %mocked) {
-    next if exists $noninlined{$func};
-
-    $warned++;
-    print STDERR "$func is mocked at $mocked{$func} but missing noinline annotation\n";
-}
-
-exit $warned ? 1 : 0;
-
-
-sub scan_annotations {
-    my $file = shift;
-
-    open FH, $file or die "cannot read $file: $!";
-
-    my $func;
-    while (<FH>) {
-        if (/^\s*(\w+)\(/ || /^(?:\w+\*?\s+)+(?:\*\s*)?(\w+)\(/) {
-            my $name = $1;
-            if ($name !~ /(?:G_GNUC|ATTRIBUTE)/) {
-                $func = $name;
-            }
-        } elsif (/^\s*$/) {
-            $func = undef;
-        }
-        if (/G_GNUC_NO_INLINE/) {
-            if (defined $func) {
-                $noninlined{$func} = 1;
-            }
-        }
-    }
-
-    close FH
-}
-
-sub scan_overrides {
-    my $file = shift;
-
-    open FH, $file or die "cannot read $file: $!";
-
-    my $func;
-    while (<FH>) {
-        if (/^(\w+)\(/ || /^\w+\s*(?:\*\s*)?(\w+)\(/) {
-            my $name = $1;
-            if ($name =~ /^vir/) {
-                $mocked{$name} = "$file:$.";
-            }
-        }
-    }
-
-    close FH
-}
diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk
index d308896b26..0cfd181224 100644
--- a/build-aux/syntax-check.mk
+++ b/build-aux/syntax-check.mk
@@ -2162,8 +2162,8 @@ spacing-check:
 	  { echo '$(ME): incorrect formatting' 1>&2; exit 1; }
 
 mock-noinline:
-	$(AM_V_GEN)$(VC_LIST) | $(GREP) '\.[ch]$$' | xargs \
-	$(PERL) $(top_srcdir)/build-aux/mock-noinline.pl
+	$(AM_V_GEN)$(VC_LIST) | $(GREP) '\.[ch]$$' | $(RUNUTF8) xargs \
+	$(PYTHON) $(top_srcdir)/scripts/mock-noinline.py
 
 header-ifdef:
 	$(AM_V_GEN)$(VC_LIST) | $(GREP) '\.[h]$$' | xargs \
diff --git a/scripts/mock-noinline.py b/scripts/mock-noinline.py
new file mode 100644
index 0000000000..2770ea1238
--- /dev/null
+++ b/scripts/mock-noinline.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017-2019 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library.  If not, see
+# <http://www.gnu.org/licenses/>.
+
+from __future__ import print_function
+
+import re
+import sys
+
+noninlined = {}
+mocked = {}
+
+# Functions in public header don't get the noinline annotation
+# so whitelist them here
+noninlined["virEventAddTimeout"] = True
+# This one confuses the script as its defined in the mock file
+# but is actually just a local helper
+noninlined["virMockStatRedirect"] = True
+
+
+def scan_annotations(filename):
+    with open(filename, "r") as fh:
+        func = None
+        for line in fh:
+            line = line.strip()
+            m = re.search(r'''^\s*(\w+)\(''', line)
+            if m is None:
+                m = re.search(r'''^(?:\w+\*?\s+)+(?:\*\s*)?(\w+)\(''', line)
+            if m is not None:
+                name = m.group(1)
+                if name.find("ATTRIBUTE") == -1 and name.find("G_GNUC_") == -1:
+                    func = name
+            elif line == "":
+                func = None
+
+            if line.find("G_GNUC_NO_INLINE") != -1:
+                if func is not None:
+                    noninlined[func] = True
+
+
+def scan_overrides(filename):
+    with open(filename, "r") as fh:
+        lineno = 0
+        for line in fh:
+            lineno = lineno + 1
+
+            m = re.search(r'''^(\w+)\(''', line)
+            if m is None:
+                m = re.search(r'''^\w+\s*(?:\*\s*)?(\w+)\(''', line)
+            if m is not None:
+                name = m.group(1)
+                if name.startswith("vir"):
+                    mocked[name] = "%s:%d" % (filename, lineno)
+
+
+for filename in sys.argv[1:]:
+    if filename.endswith(".h"):
+        scan_annotations(filename)
+    elif filename.endswith("mock.c"):
+        scan_overrides(filename)
+
+warned = False
+for func in mocked.keys():
+    if func not in noninlined:
+        warned = True
+        print("%s is mocked at %s but missing noinline annotation" %
+              (func, mocked[func]), file=sys.stderr)
+
+if warned:
+    sys.exit(1)
+sys.exit(0)
-- 
2.21.0

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v5 03/23] build-aux: rewrite mock inline checker in Python
Posted by Cole Robinson 5 years ago
On 11/11/19 9:38 AM, Daniel P. Berrangé wrote:
> As part of an goal to eliminate Perl from libvirt build tools,
> rewrite the mock-noinline.pl tool in Python.
> 
> This was a straight conversion, manually going line-by-line to
> change the syntax from Perl to Python. Thus the overall structure
> of the file and approach is the same.
> 
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>

Verified it catches a single failure case

Tested-by: Cole Robinson <crobinso@redhat.com>

- Cole

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v5 03/23] build-aux: rewrite mock inline checker in Python
Posted by Ján Tomko 5 years ago
On Mon, Nov 11, 2019 at 02:38:06PM +0000, Daniel P. Berrangé wrote:
>As part of an goal to eliminate Perl from libvirt build tools,
>rewrite the mock-noinline.pl tool in Python.
>
>This was a straight conversion, manually going line-by-line to
>change the syntax from Perl to Python. Thus the overall structure
>of the file and approach is the same.
>
>Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
>---
> Makefile.am                |  2 +-
> build-aux/mock-noinline.pl | 75 ---------------------------------
> build-aux/syntax-check.mk  |  4 +-
> scripts/mock-noinline.py   | 85 ++++++++++++++++++++++++++++++++++++++
> 4 files changed, 88 insertions(+), 78 deletions(-)
> delete mode 100644 build-aux/mock-noinline.pl
> create mode 100644 scripts/mock-noinline.py
>
>diff --git a/scripts/mock-noinline.py b/scripts/mock-noinline.py
>new file mode 100644
>index 0000000000..2770ea1238
>--- /dev/null
>+++ b/scripts/mock-noinline.py
>@@ -0,0 +1,85 @@

>+# Functions in public header don't get the noinline annotation
>+# so whitelist them here
>+noninlined["virEventAddTimeout"] = True
>+# This one confuses the script as its defined in the mock file
>+# but is actually just a local helper
>+noninlined["virMockStatRedirect"] = True
>+
>+
>+def scan_annotations(filename):
>+    with open(filename, "r") as fh:
>+        func = None
>+        for line in fh:
>+            line = line.strip()
>+            m = re.search(r'''^\s*(\w+)\(''', line)
>+            if m is None:
>+                m = re.search(r'''^(?:\w+\*?\s+)+(?:\*\s*)?(\w+)\(''', line)
>+            if m is not None:
>+                name = m.group(1)
>+                if name.find("ATTRIBUTE") == -1 and name.find("G_GNUC_") == -1:
>+                    func = name

More readable as:
if "ATTRIBUTE" not in name and "G_GNUC_" not in name:

>+            elif line == "":

If you use line.isspace() here, you don't need to strip the whitespace above.

>+                func = None
>+
>+            if line.find("G_GNUC_NO_INLINE") != -1:

if "G_GNUC_NO_INLINE" in line:

>+                if func is not None:
>+                    noninlined[func] = True
>+
>+

Reviewed-by: Ján Tomko <jtomko@redhat.com>

Jano
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list