oe-stylize.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. #!/usr/bin/env python
  2. """\
  3. Sanitize a bitbake file following the OpenEmbedded style guidelines,
  4. see http://openembedded.org/wiki/StyleGuide
  5. (C) 2006 Cyril Romain <cyril.romain@gmail.com>
  6. MIT license
  7. TODO:
  8. - add the others OpenEmbedded variables commonly used:
  9. - parse command arguments and print usage on misuse
  10. . prevent giving more than one .bb file in arguments
  11. - write result to a file
  12. - backup the original .bb file
  13. - make a diff and ask confirmation for patching ?
  14. - do not use startswith only:
  15. /!\ startswith('SOMETHING') is not taken into account due to the previous startswith('S').
  16. - count rule breaks and displays them in the order frequence
  17. """
  18. import fileinput
  19. import string
  20. import re
  21. __author__ = "Cyril Romain <cyril.romain@gmail.com>"
  22. __version__ = "$Revision: 0.5 $"
  23. # The standard set of variables often found in .bb files in the preferred order
  24. OE_vars = [
  25. 'SUMMARY',
  26. 'DESCRIPTION',
  27. 'AUTHOR',
  28. 'HOMEPAGE',
  29. 'SECTION',
  30. 'LICENSE',
  31. 'LIC_FILES_CHKSUM',
  32. 'DEPENDS',
  33. 'PROVIDES',
  34. 'SRCREV',
  35. 'SRCDATE',
  36. 'PE',
  37. 'PV',
  38. 'PR',
  39. 'INC_PR',
  40. 'SRC_URI',
  41. 'S',
  42. 'GPE_TARBALL_SUFFIX',
  43. 'inherit',
  44. 'EXTRA_',
  45. 'export',
  46. 'do_fetch',
  47. 'do_unpack',
  48. 'do_patch',
  49. 'WORKDIR',
  50. 'acpaths',
  51. 'do_configure',
  52. 'do_compile',
  53. 'do_install',
  54. 'PACKAGES',
  55. 'PACKAGE_ARCH',
  56. 'RDEPENDS',
  57. 'RRECOMMENDS',
  58. 'RSUGGESTS',
  59. 'RPROVIDES',
  60. 'RCONFLICTS',
  61. 'FILES',
  62. 'do_package',
  63. 'do_stage',
  64. 'addhandler',
  65. 'addtask',
  66. 'bindir',
  67. 'headers',
  68. 'include',
  69. 'includedir',
  70. 'python',
  71. 'qtopiadir',
  72. 'pkg_preins',
  73. 'pkg_prerm',
  74. 'pkg_postins',
  75. 'pkg_postrm',
  76. 'require',
  77. 'sbindir',
  78. 'basesysconfdir',
  79. 'sysconfdir',
  80. 'ALLOW_EMPTY',
  81. 'ALTERNATIVE_NAME',
  82. 'ALTERNATIVE_PATH',
  83. 'ALTERNATIVE_LINK',
  84. 'ALTERNATIVE_PRIORITY',
  85. 'ALTNAME',
  86. 'AMD_DRIVER_LABEL',
  87. 'AMD_DRIVER_VERSION',
  88. 'ANGSTROM_EXTRA_INSTALL',
  89. 'APPDESKTOP',
  90. 'APPIMAGE',
  91. 'APPNAME',
  92. 'APPTYPE',
  93. 'APPWEB_BUILD',
  94. 'APPWEB_HOST',
  95. 'AR',
  96. 'ARCH',
  97. 'ARM_INSTRUCTION_SET',
  98. 'ARM_MUTEX',
  99. 'ART_CONFIG',
  100. 'B',
  101. 'BJAM_OPTS',
  102. 'BJAM_TOOLS',
  103. 'BONOBO_HEADERS',
  104. 'BOOTSCRIPTS',
  105. 'BROKEN',
  106. 'BUILD_CPPFLAGS',
  107. 'CFLAGS',
  108. 'CCFLAGS',
  109. 'CMDLINE',
  110. 'COLLIE_MEMORY_SIZE',
  111. 'COMPATIBLE_HOST',
  112. 'COMPATIBLE_MACHINE',
  113. 'COMPILE_HERMES',
  114. 'CONFFILES',
  115. 'CONFLICTS',
  116. 'CORE_EXTRA_D',
  117. 'CORE_PACKAGES_D',
  118. 'CORE_PACKAGES_RD',
  119. 'CPPFLAGS',
  120. 'CVSDATE',
  121. 'CXXFLAGS',
  122. 'DEBIAN_NOAUTONAME',
  123. 'DEBUG_APPS',
  124. 'DEFAULT_PREFERENCE',
  125. 'DB4_CONFIG',
  126. 'EXCLUDE_FROM_SHLIBS',
  127. 'EXCLUDE_FROM_WORLD',
  128. 'FIXEDSRCDATE',
  129. 'GLIBC_ADDONS',
  130. 'GLIBC_EXTRA_OECONF',
  131. 'GNOME_VFS_HEADERS',
  132. 'HEADERS',
  133. 'INHIBIT_DEFAULT_DEPS',
  134. 'INITSCRIPT_PACKAGES',
  135. 'INITSCRIPT_NAME',
  136. 'INITSCRIPT_PARAMS',
  137. 'PACKAGE_INSTALL',
  138. 'KERNEL_IMAGETYPE',
  139. 'KERNEL_IMAGEDEST',
  140. 'KERNEL_OUTPUT',
  141. 'KERNEL_RELEASE',
  142. 'KERNEL_PRIORITY',
  143. 'KERNEL_SOURCE',
  144. 'KERNEL_SUFFIX',
  145. 'KERNEL_VERSION',
  146. 'K_MAJOR',
  147. 'K_MICRO',
  148. 'K_MINOR',
  149. 'HHV',
  150. 'KV',
  151. 'LDFLAGS',
  152. 'LD',
  153. 'LD_SO',
  154. 'LDLIBS',
  155. 'LEAD_SONAME',
  156. 'LIBTOOL',
  157. 'LIBBDB_EXTRA',
  158. 'LIBV',
  159. 'MACHINE_ESSENTIAL_EXTRA_RDEPENDS',
  160. 'MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS',
  161. 'MACHINE_EXTRA_RDEPENDS',
  162. 'MACHINE_EXTRA_RRECOMMENDS',
  163. 'MACHINE_FEATURES',
  164. 'MACHINE_TASKS',
  165. 'MACHINE',
  166. 'MACHTYPE',
  167. 'MAKE_TARGETS',
  168. 'MESSAGEUSER',
  169. 'MESSAGEHOME',
  170. 'MIRRORS',
  171. 'MUTEX',
  172. 'OE_QMAKE_INCDIR_QT',
  173. 'OE_QMAKE_CXXFLAGS',
  174. 'ORBIT_IDL_SRC',
  175. 'PARALLEL_MAKE',
  176. 'PAKCAGE_ARCH',
  177. 'PCMCIA_MANAGER',
  178. 'PKG_BASENAME',
  179. 'PKG',
  180. 'QEMU',
  181. 'QMAKE_PROFILES',
  182. 'QPEDIR',
  183. 'QPF_DESCRIPTION',
  184. 'QPF_PKGPATTERN',
  185. 'QT_CONFIG_FLAGS',
  186. 'QT_LIBRARY',
  187. 'ROOTFS_POSTPROCESS_COMMAND',
  188. 'RREPLACES',
  189. 'TARGET_CFLAGS',
  190. 'TARGET_CPPFLAGS',
  191. 'TARGET_LDFLAGS',
  192. 'UBOOT_MACHINE',
  193. 'UCLIBC_BASE',
  194. 'UCLIBC_PATCHES',
  195. 'VIRTUAL_NAME',
  196. 'XORG_PN',
  197. 'XSERVER',
  198. 'others'
  199. ]
  200. varRegexp = r'^([a-zA-Z_0-9${}-]*)([ \t]*)([+.:]?=[+.]?)([ \t]*)([^\t]+)'
  201. routineRegexp = r'^([a-zA-Z0-9_ ${}-]+?)\('
  202. # Variables seen in the processed .bb
  203. seen_vars = {}
  204. for v in OE_vars:
  205. seen_vars[v] = []
  206. # _Format guideline #0_:
  207. # No spaces are allowed at the beginning of lines that define a variable or
  208. # a do_ routine
  209. def respect_rule0(line):
  210. return line.lstrip()==line
  211. def conformTo_rule0(line):
  212. return line.lstrip()
  213. # _Format guideline #1_:
  214. # No spaces are allowed behind the line continuation symbol '\'
  215. def respect_rule1(line):
  216. if line.rstrip().endswith('\\'):
  217. return line.endswith('\\')
  218. else:
  219. return True
  220. def conformTo_rule1(line):
  221. return line.rstrip()
  222. # _Format guideline #2_:
  223. # Tabs should not be used (use spaces instead).
  224. def respect_rule2(line):
  225. return line.count('\t')==0
  226. def conformTo_rule2(line):
  227. return line.expandtabs()
  228. # _Format guideline #3_:
  229. # Comments inside bb files are allowed using the '#' character at the
  230. # beginning of a line.
  231. def respect_rule3(line):
  232. if line.lstrip().startswith('#'):
  233. return line.startswith('#')
  234. else:
  235. return True
  236. def conformTo_rule3(line):
  237. return line.lstrip()
  238. # _Format guideline #4_:
  239. # Use quotes on the right hand side of assignments FOO = "BAR"
  240. def respect_rule4(line):
  241. r = re.search(varRegexp, line)
  242. if r is not None:
  243. r2 = re.search(r'("?)([^"\\]*)(["\\]?)', r.group(5))
  244. # do not test for None it because always match
  245. return r2.group(1)=='"' and r2.group(3)!=''
  246. return False
  247. def conformTo_rule4(line):
  248. r = re.search(varRegexp, line)
  249. return ''.join([r.group(1), ' ', r.group(3), ' "', r.group(5), r.group(5).endswith('"') and '' or '"'])
  250. # _Format guideline #5_:
  251. # The correct spacing for a variable is FOO = "BAR".
  252. def respect_rule5(line):
  253. r = re.search(varRegexp, line)
  254. return r is not None and r.group(2)==" " and r.group(4)==" "
  255. def conformTo_rule5(line):
  256. r = re.search(varRegexp, line)
  257. return ''.join([r.group(1), ' ', r.group(3), ' ', r.group(5)])
  258. # _Format guideline #6_:
  259. # Don't use spaces or tabs on empty lines
  260. def respect_rule6(line):
  261. return not line.isspace() or line=="\n"
  262. def conformTo_rule6(line):
  263. return ""
  264. # _Format guideline #7_:
  265. # Indentation of multiline variables such as SRC_URI is desireable.
  266. def respect_rule7(line):
  267. return True
  268. def conformTo_rule7(line):
  269. return line
  270. rules = (
  271. (respect_rule0, conformTo_rule0, "No spaces are allowed at the beginning of lines that define a variable or a do_ routine"),
  272. (respect_rule1, conformTo_rule1, "No spaces are allowed behind the line continuation symbol '\\'"),
  273. (respect_rule2, conformTo_rule2, "Tabs should not be used (use spaces instead)"),
  274. (respect_rule3, conformTo_rule3, "Comments inside bb files are allowed using the '#' character at the beginning of a line"),
  275. (respect_rule4, conformTo_rule4, "Use quotes on the right hand side of assignments FOO = \"BAR\""),
  276. (respect_rule5, conformTo_rule5, "The correct spacing for a variable is FOO = \"BAR\""),
  277. (respect_rule6, conformTo_rule6, "Don't use spaces or tabs on empty lines"),
  278. (respect_rule7, conformTo_rule7, "Indentation of multiline variables such as SRC_URI is desireable"),
  279. )
  280. # Function to check that a line respects a rule. If not, it tries to conform
  281. # the line to the rule. Reminder or Disgression message are dump accordingly.
  282. def follow_rule(i, line):
  283. oldline = line
  284. # if the line does not respect the rule
  285. if not rules[i][0](line):
  286. # try to conform it to the rule
  287. line = rules[i][1](line)
  288. # if the line still does not respect the rule
  289. if not rules[i][0](line):
  290. # this is a rule disgression
  291. print "## Disgression: ", rules[i][2], " in:", oldline
  292. else:
  293. # just remind user about his/her errors
  294. print "## Reminder: ", rules[i][2], " in :", oldline
  295. return line
  296. if __name__ == "__main__":
  297. # -- retrieves the lines of the .bb file --
  298. lines = []
  299. for line in fileinput.input():
  300. # use 'if True' to warn user about all the rule he/she breaks
  301. # use 'if False' to conform to rules{2,1,6} without warnings
  302. if True:
  303. lines.append(line)
  304. else:
  305. # expandtabs on each line so that rule2 is always respected
  306. # rstrip each line so that rule1 is always respected
  307. line = line.expandtabs().rstrip()
  308. # ignore empty lines (or line filled with spaces or tabs only)
  309. # so that rule6 is always respected
  310. if line is not '':
  311. lines.append(line)
  312. # -- parse the file --
  313. var = ""
  314. in_routine = False
  315. commentBloc = []
  316. olines = []
  317. for line in lines:
  318. originalLine = line
  319. # rstrip line to remove line breaks characters
  320. line = line.rstrip()
  321. line = follow_rule(2, line)
  322. line = follow_rule(1, line)
  323. line = follow_rule(6, line)
  324. # ignore empty lines
  325. if line.isspace() or line is '':
  326. # flush comments into the olines
  327. for c in commentBloc: olines.append(c)
  328. commentBloc = []
  329. continue
  330. if line.startswith('}'):
  331. in_routine=False
  332. keep = line.endswith('\\') or in_routine
  333. # handles commented lines
  334. if line.lstrip().startswith('#'):
  335. # check and follow rule3 if not in a variables or routines
  336. if not in_routine:
  337. line = follow_rule(3, line)
  338. commentBloc.append(line)
  339. continue
  340. if seen_vars.has_key(var):
  341. for c in commentBloc: seen_vars[var].append(c)
  342. commentBloc = []
  343. seen_vars[var].append(line)
  344. else:
  345. for k in OE_vars:
  346. if line.startswith(k):
  347. var = k
  348. break
  349. if re.match(routineRegexp, line) is not None:
  350. in_routine=True
  351. line = follow_rule(0, line)
  352. elif re.match(varRegexp, line) is not None:
  353. line = follow_rule(0, line)
  354. line = follow_rule(4, line)
  355. line = follow_rule(5, line)
  356. if var == "":
  357. if not in_routine:
  358. print "## Warning: unknown variable/routine \"%s\"" % originalLine.rstrip('\n')
  359. var = 'others'
  360. for c in commentBloc: seen_vars[var].append(c)
  361. commentBloc = []
  362. seen_vars[var].append(line)
  363. if not keep and not in_routine: var = ""
  364. # -- dump the sanitized .bb file --
  365. addEmptyLine = False
  366. # write comments that are not related to variables nor routines
  367. for l in commentBloc: olines.append(l)
  368. # write variables and routines
  369. previourVarPrefix = "unknown"
  370. for k in OE_vars:
  371. if k=='SRC_URI': addEmptyLine = True
  372. if seen_vars[k] != []:
  373. if addEmptyLine and not k.startswith(previourVarPrefix):
  374. olines.append("")
  375. for l in seen_vars[k]:
  376. olines.append(l)
  377. previourVarPrefix = k.split('_')[0]=='' and "unknown" or k.split('_')[0]
  378. for line in olines: print line