sanitize.py: add a script that does the heavy lifting for making recipes conform...
authorCyril Romain <cyril.romain@gmail.com>
Wed, 6 Sep 2006 17:35:43 +0000 (17:35 +0000)
committerKoen Kooi <koen@openembedded.org>
Wed, 6 Sep 2006 17:35:43 +0000 (17:35 +0000)
contrib/sanitize.py [new file with mode: 0644]

diff --git a/contrib/sanitize.py b/contrib/sanitize.py
new file mode 100644 (file)
index 0000000..6327653
--- /dev/null
@@ -0,0 +1,369 @@
+#!/usr/bin/env python\r
+\r
+# sanitize a bitbake file following the OpenEmbedded style guidelines \r
+# see http://openembedded.org/wiki/StyleGuide \r
+# (C) 2006 Cyril Romain <cyril.romain@gmail.com>\r
+# MIT license\r
+\r
+# TODO: \r
+#   -  add the others OpenEmbedded variables commonly used\r
+#   ./ handle comments in .bb files\r
+#   -  parse command arguments and print usage on misuse\r
+#       . prevent giving more than one .bb file in arguments\r
+#   -  write result to a file\r
+#   -  backup the original .bb file\r
+#   -  make a diff and ask confirmation for patching ?\r
+#   -  /!\ startswith('SOMETHING') is not taken into account due to the previous startswith('S').\r
+#   -  count rule breaks and displays them in the order frequence\r
+\r
+from odict import OrderedDict\r
+import fileinput\r
+import string\r
+import re\r
+\r
+__author__ = "Cyril Romain <cyril.romain@gmail.com>"\r
+__version__ = "$Revision: 0.3 $"\r
+\r
+# The ordered list of OpenEmbedded variables\r
+OE_vars = OrderedDict([\r
+    ('DESCRIPTION', []),\r
+    ('AUTHOR', []),\r
+    ('HOMEPAGE', []),\r
+    ('SECTION', []),\r
+    ('PRIORITY', []),\r
+    ('MAINTAINER', []),\r
+    ('LICENSE', []),\r
+    ('DEPENDS', []),\r
+    ('RDEPENDS', []),\r
+    ('RRECOMMENDS', []),\r
+    ('RSUGGESTS', []),\r
+    ('PROVIDES', []),\r
+    ('RPROVIDES', []),\r
+    ('RCONFLICTS', []),\r
+    ('SRCDATE', []),\r
+    ('PV', []),\r
+    ('PR', []),\r
+    ('SRC_URI', []),\r
+    ('S', []),\r
+    ('inherit', []),\r
+    ('EXTRA_', []),\r
+    ('do_fetch', []),\r
+    ('do_unpack', []),\r
+    ('do_patch', []),\r
+    ('do_configure', []),\r
+    ('do_compile', []),\r
+    ('do_install', []),\r
+    ('do_package', []),\r
+    ('do_stage', []),\r
+    ('PACKAGE_ARCH', []),\r
+    ('PACKAGES', []),\r
+    ('FILES', []),\r
+    ('WORKDIR', []),\r
+    ('acpaths', []),\r
+    ('addhandler', []),\r
+    ('addtask', []),\r
+    ('bindir', []),\r
+    ('export', []),\r
+    ('headers', []),\r
+    ('include', []),\r
+    ('includedir', []),\r
+    ('python', []),\r
+    ('qtopiadir', []),\r
+    ('pkg_postins', []),\r
+    ('pkg_postrm', []),\r
+    ('require', []),\r
+    ('sbindir', []),\r
+    ('basesysconfdir', []),\r
+    ('sysconfdir', []),\r
+    ('ALLOW_EMPTY', []),\r
+    ('ALTERNATIVE_LINK', []),\r
+    ('ALTERNATIVE_NAME', []),\r
+    ('ALTERNATIVE_PATH', []),\r
+    ('ALTERNATIVE_PRIORITY', []),\r
+    ('ALTNAME', []),\r
+    ('AMD_DRIVER_LABEL', []),\r
+    ('AMD_DRIVER_VERSION', []),\r
+    ('ANGSTROM_EXTRA_INSTALL', []),\r
+    ('APPDESKTOP', []),\r
+    ('APPIMAGE', []),\r
+    ('APPNAME', []),\r
+    ('APPTYPE', []),\r
+    ('APPWEB_BUILD', []),\r
+    ('APPWEB_HOST', []),\r
+    ('AR', []),\r
+    ('ARCH', []),\r
+    ('ARM_INSTRUCTION_SET', []),\r
+    ('ARM_MUTEX', []),\r
+    ('ART_CONFIG', []),\r
+    ('B', []),\r
+    ('BJAM_OPTS', []),\r
+    ('BJAM_TOOLS', []),\r
+    ('BONOBO_HEADERS', []),\r
+    ('BOOTSCRIPTS', []),\r
+    ('BROKEN', []),\r
+    ('BUILD_ALL_DEPS', []),\r
+    ('BUILD_CPPFLAGS', []),\r
+    ('CFLAGS', []),\r
+    ('CCFLAGS', []),\r
+    ('CMDLINE', []),\r
+    ('COLLIE_MEMORY_SIZE', []),\r
+    ('COMPATIBLE_HOST', []),\r
+    ('COMPATIBLE_MACHINE', []),\r
+    ('COMPILE_HERMES', []),\r
+    ('CONFFILES', []),\r
+    ('CONFLICTS', []),\r
+    ('CORE_EXTRA_D', []),\r
+    ('CORE_PACKAGES_D', []),\r
+    ('CORE_PACKAGES_RD', []),\r
+    ('CPPFLAGS', []),\r
+    ('CVSDATE', []),\r
+    ('CXXFLAGS', []),\r
+    ('DEBIAN_NOAUTONAME', []),\r
+    ('DEBUG_APPS', []),\r
+    ('DEFAULT_PREFERENCE', []),\r
+    ('DB4_CONFIG', []),\r
+    ('EXCLUDE_FROM_SHLIBS', []),\r
+    ('EXCLUDE_FROM_WORLD', []),\r
+    ('FIXEDSRCDATE', []),\r
+    ('GLIBC_ADDONS', []),\r
+    ('GLIBC_EXTRA_OECONF', []),\r
+    ('GNOME_VFS_HEADERS', []),\r
+    ('GPE_TARBALL_SUFFIX', []),\r
+    ('HEADERS', []),\r
+    ('INHIBIT_DEFAULT_DEPS', []),\r
+    ('INITSCRIPT_NAME', []),\r
+    ('INITSCRIPT_PACKAGES', []),\r
+    ('INITSCRIPT_PARAMS', []),\r
+    ('IPKG_INSTALL', []),\r
+    ('KERNEL_IMAGETYPE', []),\r
+    ('KERNEL_IMAGEDEST', []),\r
+    ('KERNEL_OUTPUT', []),\r
+    ('KERNEL_RELEASE', []),\r
+    ('KERNEL_PRIORITY', []),\r
+    ('KERNEL_SOURCE', []),\r
+    ('KERNEL_SUFFIX', []),\r
+    ('KERNEL_VERSION', []),\r
+    ('K_MAJOR', []),\r
+    ('K_MICRO', []),\r
+    ('K_MINOR', []),\r
+    ('HHV', []),\r
+    ('KV', []),\r
+    ('LDFLAGS', []),\r
+    ('LD', []),\r
+    ('LD_SO', []),\r
+    ('LDLIBS', []),\r
+    ('LEAD_SONAME', []),\r
+    ('LIBTOOL', []),\r
+    ('LIBBDB_EXTRA', []),\r
+    ('LIBV', []),\r
+    ('MACHINE', []),\r
+    ('MACHINE_ESSENTIAL_EXTRA_RDEPENDS', []),\r
+    ('MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS', []),\r
+    ('MACHINE_EXTRA_RDEPENDS', []),\r
+    ('MACHINE_EXTRA_RRECOMMENDS', []),\r
+    ('MACHINE_FEATURES', []),\r
+    ('MACHINE_TASKS', []),\r
+    ('MACHTYPE', []),\r
+    ('MAKE_TARGETS', []),\r
+    ('MESSAGEUSER', []),\r
+    ('MESSAGEHOME', []),\r
+    ('MIRRORS', []),\r
+    ('MUTEX', []),\r
+    ('OE_QMAKE_INCDIR_QT', []),\r
+    ('OE_QMAKE_CXXFLAGS', []),\r
+    ('ORBIT_IDL_SRC', []),\r
+    ('PARALLEL_MAKE', []),\r
+    ('PAKCAGE_ARCH', []),\r
+    ('PCMCIA_MANAGER', []),\r
+    ('PKG_BASENAME', []),\r
+    ('QEMU', []),\r
+    ('QMAKE_PROFILES', []),\r
+    ('QPEDIR', []),\r
+    ('QPF_DESCRIPTION', []),\r
+    ('QPF_PKGPATTERN', []),\r
+    ('QT_CONFIG_FLAGS', []),\r
+    ('QT_LIBRARY', []),\r
+    ('ROOTFS_POSTPROCESS_COMMAND', []),\r
+    ('RREPLACES', []),\r
+    ('TARGET_CFLAGS', []),\r
+    ('TARGET_CPPFLAGS', []),\r
+    ('TARGET_LDFLAGS', []),\r
+    ('UBOOT_MACHINE', []),\r
+    ('UCLIBC_BASE', []),\r
+    ('UCLIBC_PATCHES', []),\r
+    ('UNSLUNG_PACKAGES', []),\r
+    ('VIRTUAL_NAME', []),\r
+    ('XORG_PN', []),\r
+    ('XSERVER', []),\r
+    ('others', [])\r
+])\r
+\r
+varRegexp = r'^([A-Z_0-9]*)([ \t]*?)([+.:]?=[+.]?)([ \t]*?)("[^"]*["\\]?)'\r
+routineRegexp = r'^([a-zA-Z0-9_ -]+?)\('\r
+\r
+# Style guideline #0: No spaces are allowed at the beginning of lines that define a variable or a do_ routine\r
+def check_rule0(line): \r
+    return line.lstrip()==line\r
+def follow_rule0(line): \r
+    return line.lstrip()\r
+\r
+# Style guideline #1: No spaces are allowed behind the line continuation symbol '\'\r
+def check_rule1(line):\r
+    if line.rstrip().endswith('\\'):\r
+        return line.endswith('\\')\r
+    else: \r
+        return True\r
+def follow_rule1(line):\r
+    return line.rstrip()\r
+\r
+# Style guideline #2: Tabs should not be used (use spaces instead).\r
+def check_rule2(line):\r
+    return line.count('\t')==0\r
+def follow_rule2(line):\r
+    return line.expandtabs()\r
+\r
+# Style guideline #3: Comments inside bb files are allowed using the '#' character at the beginning of a line.\r
+def check_rule3(line):\r
+    if line.lstrip().startswith('#'):\r
+        return line.startswith('#')\r
+    else: \r
+        return True\r
+def follow_rule3(line):\r
+    return line.lstrip()\r
+\r
+# Style guideline #4: Use quotes on the right hand side of assignments: FOO = "BAR"\r
+def check_rule4(line):\r
+    return re.match(varRegexp, line) is not None\r
+def follow_rule4(line):\r
+    return follow_rule5(line)\r
+\r
+# Style guideline #5: The correct spacing for a variable is FOO = "BAR".\r
+def check_rule5(line):\r
+    r = re.search(varRegexp, line)\r
+    return r is not None and r.group(2)==" " and r.group(4)==" "\r
+def follow_rule5(line):\r
+    r = re.search(varRegexp, line)\r
+    return ''.join([r.group(1), ' ', r.group(3), ' ', r.group(5)])\r
+\r
+# Style guideline #6: Don't use spaces or tabs on empty lines\r
+def check_rule6(line):\r
+    return not line.isspace() or line=="\n"\r
+def follow_rule6(line):\r
+    return ""\r
+\r
+# Style guideline #7: Indentation of multiline variables such as SRC_URI is desireable.\r
+def check_rule7(line):\r
+    return True\r
+def follow_rule7(line):\r
+    return line\r
+\r
+rules = (\r
+    (check_rule0, follow_rule0, "No spaces are allowed at the beginning of lines that define a variable or a do_ routine"),\r
+    (check_rule1, follow_rule1, "No spaces are allowed behind the line continuation symbol '\\'"),\r
+    (check_rule2, follow_rule2, "Tabs should not be used (use spaces instead)"),\r
+    (check_rule3, follow_rule3, "Comments inside bb files are allowed using the '#' character at the beginning of a line"),\r
+    (check_rule4, follow_rule4, "Use quotes on the right hand side of assignments: FOO = \"BAR\""),\r
+    (check_rule5, follow_rule5, "The correct spacing for a variable is FOO = \"BAR\""),\r
+    (check_rule6, follow_rule6, "Don't use spaces or tabs on empty lines"),\r
+    (check_rule7, follow_rule7, "Indentation of multiline variables such as SRC_URI is desireable"),\r
+)\r
+\r
+def follow_rule(i, line):\r
+    oldline = line\r
+    if not rules[i][0](line):\r
+        line = rules[i][1](line)\r
+        if not rules[i][0](line):\r
+            print "## Rule %d disgression: on this line: " % i, line\r
+            print "## Warning: ", rules[i][2]\r
+        else:\r
+            print "## Reminder: ", rules[i][2], " in :", oldline\r
+    return line\r
+\r
+\r
+if __name__ == "__main__":\r
+\r
+    # -- retrieves lines of the .bb file --\r
+    lines = []\r
+    for line in fileinput.input():\r
+        if True:\r
+            lines.append(line)\r
+        else:\r
+            # expandtabs on each line so that rule2 is always respected \r
+            # rstrip each line so that rule1 is always respected \r
+            line = line.expandtabs().rstrip()\r
+            # ignore empty lines (or line filled with spaces or tabs only)\r
+            # so that rule6 is always respected\r
+            if line is not '':\r
+                lines.append(line)\r
+\r
+    # -- parse the file --\r
+    var = ""\r
+    in_routine = False\r
+    commentBloc = []\r
+    olines = []\r
+    unknownVar = set()\r
+    for line in lines: \r
+        line = line.rstrip()\r
+        line = follow_rule(2, line)\r
+        line = follow_rule(1, line)\r
+        line = follow_rule(6, line)\r
+        # ignore empty lines\r
+        if line.isspace() or line is '':\r
+            # flush comments into the olines\r
+            for c in commentBloc: olines.append(c)\r
+            commentBloc = []\r
+            continue\r
+\r
+        if line.startswith('}'): in_routine=False\r
+        keep = line.endswith('\\') or in_routine\r
+\r
+        # handles commented lines\r
+        if line.lstrip().startswith('#'):\r
+            # check and follow rule3 if not in a variables or routines\r
+            if not in_routine:\r
+                line = follow_rule(3, line)\r
+            commentBloc.append(line)\r
+            continue\r
+\r
+        if OE_vars.has_key(var):\r
+            for c in commentBloc: \r
+                OE_vars[var].append(c)\r
+                commentBloc = []\r
+            OE_vars[var].append(line)\r
+        else:\r
+            varexist = False\r
+            for k in OE_vars:\r
+                if line.startswith(k):\r
+                    line = follow_rule(0, line)\r
+                    varexist = True\r
+                    if re.match(routineRegexp, line) is not None: \r
+                        in_routine=True\r
+                    elif re.match(varRegexp, line) is not None:\r
+                        line = follow_rule(4, line)\r
+                        line = follow_rule(5, line)\r
+                    for c in commentBloc: \r
+                        OE_vars[k].append(c)\r
+                        commentBloc = []\r
+                    OE_vars[k].append(line)\r
+                    var = (keep==True or in_routine==True) and k or ""\r
+                    break\r
+            if not varexist:\r
+                s = string.split(line)[0].rstrip().lstrip()\r
+                if s not in unknownVar: \r
+                    unknownVar.add(s)\r
+                if not in_routine:\r
+                    print "## Warning: unknown variable/routine \"%s\"" % line\r
+                    OE_vars['others'].append(line)\r
+        if not keep and not in_routine: var = ""\r
+\r
+    # -- prepare the sanitized .bb file --\r
+    #for k in OE_vars: print k, OE_vars[k]\r
+    addEmptyLine = False\r
+    for k in OE_vars:\r
+        if k=='SRC_URI': addEmptyLine = True\r
+        if OE_vars[k] != []: \r
+            if addEmptyLine: olines.append("")\r
+            for l in OE_vars[k]: \r
+                olines.append(l)\r
+    for line in olines: print line\r
+    #for i in unknownVar: print i, '\n'
\ No newline at end of file