blob: 30b460e12a5026c8117df89700b15a717b829d02 [file] [log] [blame]
Patrick Williamsb48b7b42016-08-17 15:04:38 -05001#!/usr/bin/env python
2
3"""\
4Sanitize a bitbake file following the OpenEmbedded style guidelines,
Andrew Geisslere34f8962021-04-15 15:53:51 -05005see http://openembedded.org/wiki/StyleGuide
Patrick Williamsb48b7b42016-08-17 15:04:38 -05006
7(C) 2006 Cyril Romain <cyril.romain@gmail.com>
8MIT license
9
Andrew Geisslere34f8962021-04-15 15:53:51 -050010TODO:
Patrick Williamsb48b7b42016-08-17 15:04:38 -050011 - add the others OpenEmbedded variables commonly used:
12 - parse command arguments and print usage on misuse
13 . prevent giving more than one .bb file in arguments
14 - write result to a file
15 - backup the original .bb file
16 - make a diff and ask confirmation for patching ?
17 - do not use startswith only:
18 /!\ startswith('SOMETHING') is not taken into account due to the previous startswith('S').
19 - count rule breaks and displays them in the order frequence
20"""
21
Andrew Geisslere34f8962021-04-15 15:53:51 -050022from __future__ import print_function
Patrick Williamsb48b7b42016-08-17 15:04:38 -050023import fileinput
24import string
25import re
26
27__author__ = "Cyril Romain <cyril.romain@gmail.com>"
28__version__ = "$Revision: 0.5 $"
29
30# The standard set of variables often found in .bb files in the preferred order
31OE_vars = [
32 'SUMMARY',
33 'DESCRIPTION',
34 'AUTHOR',
35 'HOMEPAGE',
36 'SECTION',
37 'LICENSE',
38 'LIC_FILES_CHKSUM',
39 'DEPENDS',
40 'PROVIDES',
41 'SRCREV',
42 'SRCDATE',
43 'PE',
44 'PV',
45 'PR',
46 'INC_PR',
47 'SRC_URI',
48 'S',
49 'GPE_TARBALL_SUFFIX',
50 'inherit',
51 'EXTRA_',
52 'export',
53 'do_fetch',
54 'do_unpack',
55 'do_patch',
56 'WORKDIR',
57 'acpaths',
58 'do_configure',
59 'do_compile',
60 'do_install',
61 'PACKAGES',
62 'PACKAGE_ARCH',
63 'RDEPENDS',
64 'RRECOMMENDS',
65 'RSUGGESTS',
66 'RPROVIDES',
67 'RCONFLICTS',
Andrew Geisslere34f8962021-04-15 15:53:51 -050068 'FILES',
Patrick Williamsb48b7b42016-08-17 15:04:38 -050069 'do_package',
70 'do_stage',
71 'addhandler',
72 'addtask',
73 'bindir',
74 'headers',
75 'include',
76 'includedir',
77 'python',
78 'qtopiadir',
79 'pkg_preins',
80 'pkg_prerm',
81 'pkg_postins',
82 'pkg_postrm',
83 'require',
84 'sbindir',
85 'basesysconfdir',
86 'sysconfdir',
87 'ALLOW_EMPTY',
88 'ALTERNATIVE_NAME',
89 'ALTERNATIVE_PATH',
90 'ALTERNATIVE_LINK',
91 'ALTERNATIVE_PRIORITY',
92 'ALTNAME',
93 'AMD_DRIVER_LABEL',
94 'AMD_DRIVER_VERSION',
95 'ANGSTROM_EXTRA_INSTALL',
96 'APPDESKTOP',
97 'APPIMAGE',
98 'APPNAME',
99 'APPTYPE',
100 'APPWEB_BUILD',
101 'APPWEB_HOST',
102 'AR',
103 'ARCH',
104 'ARM_INSTRUCTION_SET',
Patrick Williamsddad1a12017-02-23 20:36:32 -0600105 'MIPS_INSTRUCTION_SET',
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500106 'ARM_MUTEX',
107 'ART_CONFIG',
108 'B',
109 'BJAM_OPTS',
110 'BJAM_TOOLS',
111 'BONOBO_HEADERS',
112 'BOOTSCRIPTS',
113 'BROKEN',
114 'BUILD_CPPFLAGS',
115 'CFLAGS',
116 'CCFLAGS',
117 'CMDLINE',
118 'COLLIE_MEMORY_SIZE',
119 'COMPATIBLE_HOST',
120 'COMPATIBLE_MACHINE',
121 'COMPILE_HERMES',
122 'CONFFILES',
123 'CONFLICTS',
124 'CORE_EXTRA_D',
125 'CORE_IMAGE_EXTRA_INSTALL',
126 'CORE_PACKAGES_D',
127 'CORE_PACKAGES_RD',
128 'CPPFLAGS',
129 'CVSDATE',
130 'CXXFLAGS',
131 'DEBIAN_NOAUTONAME',
132 'DEBUG_APPS',
133 'DEFAULT_PREFERENCE',
134 'DB4_CONFIG',
135 'EXCLUDE_FROM_SHLIBS',
136 'EXCLUDE_FROM_WORLD',
137 'FIXEDSRCDATE',
138 'GLIBC_ADDONS',
139 'GLIBC_EXTRA_OECONF',
140 'GNOME_VFS_HEADERS',
141 'HEADERS',
142 'INHIBIT_DEFAULT_DEPS',
143 'INITSCRIPT_PACKAGES',
144 'INITSCRIPT_NAME',
145 'INITSCRIPT_PARAMS',
146 'INSANE_SKIP',
147 'PACKAGE_INSTALL',
148 'KERNEL_IMAGETYPE',
149 'KERNEL_IMAGEDEST',
150 'KERNEL_OUTPUT',
151 'KERNEL_RELEASE',
152 'KERNEL_PRIORITY',
153 'KERNEL_SOURCE',
154 'KERNEL_SUFFIX',
155 'KERNEL_VERSION',
156 'K_MAJOR',
157 'K_MICRO',
158 'K_MINOR',
159 'HHV',
160 'KV',
161 'LDFLAGS',
162 'LD',
163 'LD_SO',
164 'LDLIBS',
165 'LEAD_SONAME',
166 'LIBTOOL',
167 'LIBBDB_EXTRA',
168 'LIBV',
169 'MACHINE_ESSENTIAL_EXTRA_RDEPENDS',
170 'MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS',
171 'MACHINE_EXTRA_RDEPENDS',
172 'MACHINE_EXTRA_RRECOMMENDS',
173 'MACHINE_FEATURES',
174 'MACHINE_TASKS',
175 'MACHINE',
176 'MACHTYPE',
177 'MAKE_TARGETS',
178 'MESSAGEUSER',
179 'MESSAGEHOME',
180 'MIRRORS',
181 'MUTEX',
182 'OE_QMAKE_INCDIR_QT',
183 'OE_QMAKE_CXXFLAGS',
184 'ORBIT_IDL_SRC',
185 'PARALLEL_MAKE',
186 'PAKCAGE_ARCH',
187 'PCMCIA_MANAGER',
188 'PKG_BASENAME',
189 'PKG',
190 'QEMU',
191 'QMAKE_PROFILES',
192 'QPEDIR',
193 'QPF_DESCRIPTION',
194 'QPF_PKGPATTERN',
195 'QT_CONFIG_FLAGS',
196 'QT_LIBRARY',
197 'ROOTFS_POSTPROCESS_COMMAND',
198 'RREPLACES',
199 'TARGET_CFLAGS',
200 'TARGET_CPPFLAGS',
201 'TARGET_LDFLAGS',
202 'UBOOT_MACHINE',
203 'UCLIBC_BASE',
204 'UCLIBC_PATCHES',
205 'USERADD_PACKAGES',
206 'USERADD_PARAM',
207 'VIRTUAL_NAME',
208 'XORG_PN',
209 'XSERVER',
210 'others'
211]
212
Andrew Geissler595f6302022-01-24 19:11:47 +0000213varRegexp = r'^([a-zA-Z_0-9${}:-]*)([ \t]*)([+.:]?=[+.]?)([ \t]*)([^\t]+)'
214routineRegexp = r'^([a-zA-Z0-9_ ${}:-]+?)\('
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500215
216# Variables seen in the processed .bb
217seen_vars = {}
Andrew Geisslere34f8962021-04-15 15:53:51 -0500218for v in OE_vars:
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500219 seen_vars[v] = []
220
Andrew Geisslere34f8962021-04-15 15:53:51 -0500221# _Format guideline #0_:
222# No spaces are allowed at the beginning of lines that define a variable or
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500223# a do_ routine
Andrew Geisslere34f8962021-04-15 15:53:51 -0500224
225
226def respect_rule0(line):
227 return line.lstrip() == line
228
229
230def conformTo_rule0(line):
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500231 return line.lstrip()
232
Andrew Geisslere34f8962021-04-15 15:53:51 -0500233# _Format guideline #1_:
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500234# No spaces are allowed behind the line continuation symbol '\'
Andrew Geisslere34f8962021-04-15 15:53:51 -0500235
236
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500237def respect_rule1(line):
238 if line.rstrip().endswith('\\'):
239 return line.endswith('\\')
Andrew Geisslere34f8962021-04-15 15:53:51 -0500240 else:
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500241 return True
Andrew Geisslere34f8962021-04-15 15:53:51 -0500242
243
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500244def conformTo_rule1(line):
245 return line.rstrip()
246
Andrew Geisslere34f8962021-04-15 15:53:51 -0500247# _Format guideline #2_:
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500248# Tabs should not be used (use spaces instead).
Andrew Geisslere34f8962021-04-15 15:53:51 -0500249
250
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500251def respect_rule2(line):
Andrew Geisslere34f8962021-04-15 15:53:51 -0500252 return line.count('\t') == 0
253
254
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500255def conformTo_rule2(line):
256 return line.expandtabs()
257
258# _Format guideline #3_:
Andrew Geisslere34f8962021-04-15 15:53:51 -0500259# Comments inside bb files are allowed using the '#' character at the
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500260# beginning of a line.
Andrew Geisslere34f8962021-04-15 15:53:51 -0500261
262
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500263def respect_rule3(line):
264 if line.lstrip().startswith('#'):
265 return line.startswith('#')
Andrew Geisslere34f8962021-04-15 15:53:51 -0500266 else:
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500267 return True
Andrew Geisslere34f8962021-04-15 15:53:51 -0500268
269
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500270def conformTo_rule3(line):
271 return line.lstrip()
272
273# _Format guideline #4_:
274# Use quotes on the right hand side of assignments FOO = "BAR"
Andrew Geisslere34f8962021-04-15 15:53:51 -0500275
276
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500277def respect_rule4(line):
278 r = re.search(varRegexp, line)
279 if r is not None:
280 r2 = re.search(r'("?)([^"\\]*)(["\\]?)', r.group(5))
281 # do not test for None it because always match
Andrew Geisslere34f8962021-04-15 15:53:51 -0500282 return r2.group(1) == '"' and r2.group(3) != ''
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500283 return False
Andrew Geisslere34f8962021-04-15 15:53:51 -0500284
285
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500286def conformTo_rule4(line):
287 r = re.search(varRegexp, line)
288 return ''.join([r.group(1), ' ', r.group(3), ' "', r.group(5), r.group(5).endswith('"') and '' or '"'])
289
290# _Format guideline #5_:
291# The correct spacing for a variable is FOO = "BAR".
Andrew Geisslere34f8962021-04-15 15:53:51 -0500292
293
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500294def respect_rule5(line):
295 r = re.search(varRegexp, line)
Andrew Geisslere34f8962021-04-15 15:53:51 -0500296 return r is not None and r.group(2) == " " and r.group(4) == " "
297
298
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500299def conformTo_rule5(line):
300 r = re.search(varRegexp, line)
301 return ''.join([r.group(1), ' ', r.group(3), ' ', r.group(5)])
302
303# _Format guideline #6_:
304# Don't use spaces or tabs on empty lines
Andrew Geisslere34f8962021-04-15 15:53:51 -0500305
306
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500307def respect_rule6(line):
Andrew Geisslere34f8962021-04-15 15:53:51 -0500308 return not line.isspace() or line == "\n"
309
310
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500311def conformTo_rule6(line):
312 return ""
313
314# _Format guideline #7_:
315# Indentation of multiline variables such as SRC_URI is desireable.
Andrew Geisslere34f8962021-04-15 15:53:51 -0500316
317
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500318def respect_rule7(line):
319 return True
Andrew Geisslere34f8962021-04-15 15:53:51 -0500320
321
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500322def conformTo_rule7(line):
323 return line
324
Andrew Geisslere34f8962021-04-15 15:53:51 -0500325
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500326rules = (
327 (respect_rule0, conformTo_rule0, "No spaces are allowed at the beginning of lines that define a variable or a do_ routine"),
328 (respect_rule1, conformTo_rule1, "No spaces are allowed behind the line continuation symbol '\\'"),
329 (respect_rule2, conformTo_rule2, "Tabs should not be used (use spaces instead)"),
330 (respect_rule3, conformTo_rule3, "Comments inside bb files are allowed using the '#' character at the beginning of a line"),
331 (respect_rule4, conformTo_rule4, "Use quotes on the right hand side of assignments FOO = \"BAR\""),
332 (respect_rule5, conformTo_rule5, "The correct spacing for a variable is FOO = \"BAR\""),
333 (respect_rule6, conformTo_rule6, "Don't use spaces or tabs on empty lines"),
334 (respect_rule7, conformTo_rule7, "Indentation of multiline variables such as SRC_URI is desireable"),
335)
336
337# Function to check that a line respects a rule. If not, it tries to conform
338# the line to the rule. Reminder or Disgression message are dump accordingly.
Andrew Geisslere34f8962021-04-15 15:53:51 -0500339
340
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500341def follow_rule(i, line):
342 oldline = line
343 # if the line does not respect the rule
344 if not rules[i][0](line):
345 # try to conform it to the rule
346 line = rules[i][1](line)
347 # if the line still does not respect the rule
348 if not rules[i][0](line):
349 # this is a rule disgression
Andrew Geisslere34f8962021-04-15 15:53:51 -0500350 print("## Disgression: ", rules[i][2], " in: '", oldline, "'")
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500351 else:
352 # just remind user about his/her errors
Andrew Geisslere34f8962021-04-15 15:53:51 -0500353 print("## Reminder: ", rules[i][2], " in : '", oldline, "'")
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500354 return line
355
356
357if __name__ == "__main__":
358
359 # -- retrieves the lines of the .bb file --
360 lines = []
361 for line in fileinput.input():
362 # use 'if True' to warn user about all the rule he/she breaks
363 # use 'if False' to conform to rules{2,1,6} without warnings
364 if True:
365 lines.append(line)
366 else:
Andrew Geisslere34f8962021-04-15 15:53:51 -0500367 # expandtabs on each line so that rule2 is always respected
368 # rstrip each line so that rule1 is always respected
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500369 line = line.expandtabs().rstrip()
370 # ignore empty lines (or line filled with spaces or tabs only)
371 # so that rule6 is always respected
Andrew Geissler595f6302022-01-24 19:11:47 +0000372 if line != '':
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500373 lines.append(line)
374
375 # -- parse the file --
376 var = ""
377 in_routine = False
378 commentBloc = []
379 olines = []
Andrew Geisslere34f8962021-04-15 15:53:51 -0500380 for line in lines:
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500381 originalLine = line
382 # rstrip line to remove line breaks characters
383 line = line.rstrip()
384 line = follow_rule(2, line)
385 line = follow_rule(1, line)
386 line = follow_rule(6, line)
387
388 # ignore empty lines
Andrew Geissler595f6302022-01-24 19:11:47 +0000389 if line.isspace() or line == '':
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500390 # flush comments into the olines
Andrew Geisslere34f8962021-04-15 15:53:51 -0500391 for c in commentBloc:
392 olines.append(c)
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500393 commentBloc = []
394 continue
395
Andrew Geisslere34f8962021-04-15 15:53:51 -0500396 if line.startswith('}'):
397 in_routine = False
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500398 keep = line.endswith('\\') or in_routine
399
400 # handles commented lines
401 if line.lstrip().startswith('#'):
402 # check and follow rule3 if not in a variables or routines
403 if not in_routine:
404 line = follow_rule(3, line)
405 commentBloc.append(line)
406 continue
407
408 if var in seen_vars:
Andrew Geisslere34f8962021-04-15 15:53:51 -0500409 for c in commentBloc:
410 seen_vars[var].append(c)
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500411 commentBloc = []
412 seen_vars[var].append(line)
413 else:
414 for k in OE_vars:
415 if line.startswith(k):
416 var = k
417 break
Andrew Geisslere34f8962021-04-15 15:53:51 -0500418 if re.match(routineRegexp, line) is not None:
419 in_routine = True
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500420 line = follow_rule(0, line)
421 elif re.match(varRegexp, line) is not None:
422 line = follow_rule(0, line)
423 line = follow_rule(4, line)
424 line = follow_rule(5, line)
425 if var == "":
426 if not in_routine:
Andrew Geisslere34f8962021-04-15 15:53:51 -0500427 print("## Warning: unknown variable/routine \"%s\"" % originalLine.rstrip('\n'))
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500428 var = 'others'
Andrew Geisslere34f8962021-04-15 15:53:51 -0500429 for c in commentBloc:
430 seen_vars[var].append(c)
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500431 commentBloc = []
432 seen_vars[var].append(line)
Andrew Geisslere34f8962021-04-15 15:53:51 -0500433 if not keep and not in_routine:
434 var = ""
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500435
436 # -- dump the sanitized .bb file --
437 addEmptyLine = False
438 # write comments that are not related to variables nor routines
Andrew Geisslere34f8962021-04-15 15:53:51 -0500439 for l in commentBloc:
440 olines.append(l)
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500441 # write variables and routines
442 previourVarPrefix = "unknown"
443 for k in OE_vars:
Andrew Geisslere34f8962021-04-15 15:53:51 -0500444 if k == 'SRC_URI':
445 addEmptyLine = True
446 if seen_vars[k] != []:
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500447 if addEmptyLine and not k.startswith(previourVarPrefix):
448 olines.append("")
Andrew Geisslere34f8962021-04-15 15:53:51 -0500449 for l in seen_vars[k]:
Patrick Williamsb48b7b42016-08-17 15:04:38 -0500450 olines.append(l)
Andrew Geisslere34f8962021-04-15 15:53:51 -0500451 previourVarPrefix = k.split('_')[0] == '' and "unknown" or k.split('_')[0]
452 for line in olines:
453 print(line)