123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- # See utils/checkpackagelib/readme.txt before editing this file.
- # Kconfig generates errors if someone introduces a typo like "boool" instead of
- # "bool", so below check functions don't need to check for things already
- # checked by running "make menuconfig".
- import re
- from checkpackagelib.base import _CheckFunction
- from checkpackagelib.lib import ConsecutiveEmptyLines # noqa: F401
- from checkpackagelib.lib import EmptyLastLine # noqa: F401
- from checkpackagelib.lib import NewlineAtEof # noqa: F401
- from checkpackagelib.lib import TrailingSpace # noqa: F401
- def _empty_or_comment(text):
- line = text.strip()
- # ignore empty lines and comment lines indented or not
- return line == "" or line.startswith("#")
- def _part_of_help_text(text):
- return text.startswith("\t ")
- # used in more than one check
- entries_that_should_not_be_indented = [
- "choice", "comment", "config", "endchoice", "endif", "endmenu", "if",
- "menu", "menuconfig", "source"]
- class AttributesOrder(_CheckFunction):
- attributes_order_convention = {
- "bool": 1, "prompt": 1, "string": 1, "default": 2, "depends": 3,
- "select": 4, "help": 5}
- def before(self):
- self.state = 0
- def check_line(self, lineno, text):
- if _empty_or_comment(text) or _part_of_help_text(text):
- return
- attribute = text.split()[0]
- if attribute in entries_that_should_not_be_indented:
- self.state = 0
- return
- if attribute not in self.attributes_order_convention.keys():
- return
- new_state = self.attributes_order_convention[attribute]
- wrong_order = self.state > new_state
- # save to process next line
- self.state = new_state
- if wrong_order:
- return ["{}:{}: attributes order: type, default, depends on,"
- " select, help ({}#_config_files)"
- .format(self.filename, lineno, self.url_to_manual),
- text]
- class CommentsMenusPackagesOrder(_CheckFunction):
- def before(self):
- self.level = 0
- self.menu_of_packages = ["The top level menu"]
- self.new_package = ""
- self.package = [""]
- self.print_package_warning = [True]
- self.state = ""
- def get_level(self):
- return len(self.state.split('-')) - 1
- def initialize_package_level_elements(self, text):
- try:
- self.menu_of_packages[self.level] = text[:-1]
- self.package[self.level] = ""
- self.print_package_warning[self.level] = True
- except IndexError:
- self.menu_of_packages.append(text[:-1])
- self.package.append("")
- self.print_package_warning.append(True)
- def initialize_level_elements(self, text):
- self.level = self.get_level()
- self.initialize_package_level_elements(text)
- def check_line(self, lineno, text):
- # We only want to force sorting for the top-level menus
- if self.filename not in ["fs/Config.in",
- "package/Config.in",
- "package/Config.in.host",
- "package/kodi/Config.in"]:
- return
- source_line = re.match(r'^\s*source ".*/([^/]*)/Config.in(.host)?"', text)
- if text.startswith("comment "):
- if not self.state.endswith("-comment"):
- self.state += "-comment"
- self.initialize_level_elements(text)
- elif text.startswith("if "):
- self.state += "-if"
- self.initialize_level_elements(text)
- elif text.startswith("menu "):
- if self.state.endswith("-comment"):
- self.state = self.state[:-8]
- self.state += "-menu"
- self.initialize_level_elements(text)
- elif text.startswith("endif") or text.startswith("endmenu"):
- if self.state.endswith("-comment"):
- self.state = self.state[:-8]
- if text.startswith("endif"):
- self.state = self.state[:-3]
- elif text.startswith("endmenu"):
- self.state = self.state[:-5]
- self.level = self.get_level()
- elif source_line:
- self.new_package = source_line.group(1)
- # We order _ before A, so replace it with .
- new_package_ord = self.new_package.replace('_', '.')
- if self.package[self.level] != "" and \
- self.print_package_warning[self.level] and \
- new_package_ord < self.package[self.level]:
- self.print_package_warning[self.level] = False
- prefix = "{}:{}: ".format(self.filename, lineno)
- spaces = " " * len(prefix)
- return ["{prefix}Packages in: {menu},\n"
- "{spaces}are not alphabetically ordered;\n"
- "{spaces}correct order: '-', '_', digits, capitals, lowercase;\n"
- "{spaces}first incorrect package: {package}"
- .format(prefix=prefix, spaces=spaces,
- menu=self.menu_of_packages[self.level],
- package=self.new_package),
- text]
- self.package[self.level] = new_package_ord
- class HelpText(_CheckFunction):
- HELP_TEXT_FORMAT = re.compile(r"^\t .{,62}$")
- URL_ONLY = re.compile(r"^(http|https|git)://\S*$")
- def before(self):
- self.help_text = False
- def check_line(self, lineno, text):
- if _empty_or_comment(text):
- return
- entry = text.split()[0]
- if entry in entries_that_should_not_be_indented:
- self.help_text = False
- return
- if text.strip() == "help":
- self.help_text = True
- return
- if not self.help_text:
- return
- if self.HELP_TEXT_FORMAT.match(text.rstrip()):
- return
- if self.URL_ONLY.match(text.strip()):
- return
- return ["{}:{}: help text: <tab><2 spaces><62 chars>"
- " ({}#writing-rules-config-in)"
- .format(self.filename, lineno, self.url_to_manual),
- text,
- "\t " + "123456789 " * 6 + "12"]
- class Indent(_CheckFunction):
- ENDS_WITH_BACKSLASH = re.compile(r"^[^#].*\\$")
- entries_that_should_be_indented = [
- "bool", "default", "depends", "help", "prompt", "select", "string"]
- def before(self):
- self.backslash = False
- def check_line(self, lineno, text):
- if _empty_or_comment(text) or _part_of_help_text(text):
- self.backslash = False
- return
- entry = text.split()[0]
- last_line_ends_in_backslash = self.backslash
- # calculate for next line
- if self.ENDS_WITH_BACKSLASH.search(text):
- self.backslash = True
- else:
- self.backslash = False
- if last_line_ends_in_backslash:
- if text.startswith("\t"):
- return
- return ["{}:{}: continuation line should be indented using tabs"
- .format(self.filename, lineno),
- text]
- if entry in self.entries_that_should_be_indented:
- if not text.startswith("\t{}".format(entry)):
- return ["{}:{}: should be indented with one tab"
- " ({}#_config_files)"
- .format(self.filename, lineno, self.url_to_manual),
- text]
- elif entry in entries_that_should_not_be_indented:
- if not text.startswith(entry):
- # four Config.in files have a special but legitimate indentation rule
- if self.filename in ["package/Config.in",
- "package/Config.in.host",
- "package/kodi/Config.in",
- "package/x11r7/Config.in"]:
- return
- return ["{}:{}: should not be indented"
- .format(self.filename, lineno),
- text]
|