generate.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #!/usr/bin/env python
  2. '''
  3. Generate the openshift-ansible/roles/lib_openshift_cli/library/ modules.
  4. '''
  5. import argparse
  6. import os
  7. import re
  8. import yaml
  9. import six
  10. OPENSHIFT_ANSIBLE_PATH = os.path.dirname(os.path.realpath(__file__))
  11. OPENSHIFT_ANSIBLE_SOURCES_PATH = os.path.join(OPENSHIFT_ANSIBLE_PATH, 'sources.yml') # noqa: E501
  12. LIBRARY = os.path.join(OPENSHIFT_ANSIBLE_PATH, '..', 'library/')
  13. SKIP_COVERAGE_PATTERN = [re.compile('class Yedit.*$'),
  14. re.compile('class Utils.*$')]
  15. PRAGMA_STRING = ' # pragma: no cover'
  16. class GenerateAnsibleException(Exception):
  17. '''General Exception for generate function'''
  18. pass
  19. def parse_args():
  20. '''parse arguments to generate'''
  21. parser = argparse.ArgumentParser(description="Generate ansible modules.")
  22. parser.add_argument('--verify', action='store_true', default=False,
  23. help='Verify library code matches the generated code.')
  24. return parser.parse_args()
  25. def fragment_banner(fragment_path, side, data):
  26. """Generate a banner to wrap around file fragments
  27. :param string fragment_path: A path to a module fragment
  28. :param string side: ONE OF: "header", "footer"
  29. :param StringIO data: A StringIO object to write the banner to
  30. """
  31. side_msg = {
  32. "header": "Begin included fragment: {}",
  33. "footer": "End included fragment: {}"
  34. }
  35. annotation = side_msg[side].format(fragment_path)
  36. banner = """
  37. # -*- -*- -*- {} -*- -*- -*-
  38. """.format(annotation)
  39. # Why skip?
  40. #
  41. # * 'generated' - This is the head of the script, we don't want to
  42. # put comments before the #!shebang
  43. #
  44. # * 'license' - Wrapping this just seemed like gratuitous extra
  45. if ("generated" not in fragment_path) and ("license" not in fragment_path):
  46. data.write(banner)
  47. # Make it self-contained testable
  48. return banner
  49. def generate(parts):
  50. '''generate the source code for the ansible modules
  51. :param Array parts: An array of paths (strings) to module fragments
  52. '''
  53. data = six.StringIO()
  54. for fpart in parts:
  55. # first line is pylint disable so skip it
  56. with open(os.path.join(OPENSHIFT_ANSIBLE_PATH, fpart)) as pfd:
  57. fragment_banner(fpart, "header", data)
  58. for idx, line in enumerate(pfd):
  59. if idx in [0, 1] and 'flake8: noqa' in line or 'pylint: skip-file' in line: # noqa: E501
  60. continue
  61. for skip in SKIP_COVERAGE_PATTERN:
  62. if re.match(skip, line):
  63. line = line.strip()
  64. line += PRAGMA_STRING + os.linesep
  65. data.write(line)
  66. fragment_banner(fpart, "footer", data)
  67. return data
  68. def get_sources():
  69. '''return the path to the generate sources'''
  70. return yaml.load(open(OPENSHIFT_ANSIBLE_SOURCES_PATH).read())
  71. def verify():
  72. '''verify if the generated code matches the library code'''
  73. for fname, parts in get_sources().items():
  74. data = generate(parts)
  75. fname = os.path.join(LIBRARY, fname)
  76. if not open(fname).read() == data.getvalue():
  77. raise GenerateAnsibleException('Generated content does not match for %s' % fname)
  78. def main():
  79. ''' combine the necessary files to create the ansible module '''
  80. args = parse_args()
  81. if args.verify:
  82. verify()
  83. for fname, parts in get_sources().items():
  84. data = generate(parts)
  85. fname = os.path.join(LIBRARY, fname)
  86. with open(fname, 'w') as afd:
  87. afd.seek(0)
  88. afd.write(data.getvalue())
  89. if __name__ == '__main__':
  90. main()