--- /dev/null
+#!/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