configreader.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #!/usr/bin/python3
  2. import configparser
  3. class SectionValidator(object):
  4. def __init__(self, name, subsections, identification_func=None):
  5. """
  6. name
  7. a descriptive name of the section
  8. subsections
  9. list of tuples containing the names and whether the
  10. subsection is mandatory
  11. identy_func
  12. returns True if this is the correct Validator for the
  13. section name. If it is left out the descriptive name will be
  14. used to identify the section
  15. """
  16. self.name = name
  17. self.identification_func = identification_func
  18. self.subsections = subsections
  19. def check(self, config, section_name):
  20. """
  21. validates the section, if this is the correct validator for it
  22. returns True if this is the correct validator for this section
  23. raises InvalidConfig if something inside the section is wrong
  24. """
  25. was_identified = False
  26. if self._identify(section_name):
  27. was_identified = True
  28. self._check_mandatory_fields(section_name, config[section_name])
  29. self._check_invalid_subsections(section_name, config[section_name])
  30. return was_identified
  31. def _identify(self, section_name):
  32. # if no identification function is set, just compare the section
  33. # name with the name of the validator
  34. if self.identification_func is None:
  35. return section_name == self.name
  36. else:
  37. return self.identification_func(section_name)
  38. def _check_mandatory_fields(self, section_name, subsection):
  39. for subsection_name, mandatory in self.subsections:
  40. if mandatory:
  41. try:
  42. subsection[subsection_name]
  43. except KeyError:
  44. err_msg = ("The section '{0}' must contain a "
  45. "subsection '{1}'!").format(
  46. section_name,
  47. subsection_name)
  48. raise InvalidConfig(err_msg)
  49. def _check_invalid_subsections(self, section_name, section):
  50. # check subsection names
  51. for subsection in section:
  52. subsection_name = str(subsection)
  53. valid_subsection_names = [s[0] for s in self.subsections]
  54. is_valid_subsection = subsection_name in valid_subsection_names
  55. if not is_valid_subsection:
  56. err_msg = ("'{0}' is not a valid subsection name for '{1}'. Must "
  57. "be one of these: {2}").format(
  58. subsection_name,
  59. section_name,
  60. ', '.join(valid_subsection_names))
  61. raise InvalidConfig(err_msg)
  62. # contains all configuration sections and subsections
  63. # the subsections are a tuple with their name and a boolean, which
  64. # tells us whether the option is mandatory
  65. CONFIG_VALIDATORS = [
  66. SectionValidator('Application',
  67. [
  68. ('name', True),
  69. ('version', True),
  70. ('entry_point', True),
  71. ('script', False),
  72. ('icon', False),
  73. ('console', False),
  74. ],
  75. ),
  76. SectionValidator('Build',
  77. [
  78. ('directory', False),
  79. ('installer_name', False),
  80. ('nsi_template', False),
  81. ]
  82. ),
  83. SectionValidator('Include',
  84. [
  85. ('packages', False),
  86. ('files', False),
  87. ]
  88. ),
  89. SectionValidator('Python',
  90. [
  91. ('version', True),
  92. ('bitness', False),
  93. ]
  94. ),
  95. ]
  96. class InvalidConfig(ValueError):
  97. pass
  98. def read_and_validate(config_file):
  99. config = configparser.ConfigParser()
  100. config.read(config_file)
  101. for section in config.sections():
  102. # each section *must* be identified by at least one validator
  103. # otherwise it is an invalid section (e.g. has an invalid name)
  104. was_identified = False
  105. for validator in CONFIG_VALIDATORS:
  106. was_identified = validator.check(config, section)
  107. # if we already found the correct validator and it did not
  108. # raise InvalidConfig, we can skip the other validators
  109. if was_identified:
  110. break
  111. if not was_identified:
  112. valid_section_names = [v.name for v in CONFIG_VALIDATORS]
  113. err_msg = ("{0} is not a valid section header. Must "
  114. "be one of these: {1}").format(
  115. section,
  116. ', '.join(['"%s"' % n for n in valid_section_names]))
  117. raise InvalidConfig(err_msg)
  118. return config