build_modules_xml.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. """
  2. @package tools.build_modules_xml
  3. @brief Builds XML metadata of GRASS modules. Runs only during compilation.
  4. (C) 2013 by the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. @author Vaclav Petras <wenzeslaus gmail.com>
  8. @author Anna Petrasova <kratochanna gmail.com>
  9. """
  10. from __future__ import print_function
  11. import sys
  12. import grass.script.core as gcore
  13. import grass.script.task as gtask
  14. def escapeXML(text):
  15. """This is a duplicate of function in core/toolboxes.
  16. >>> escapeXML('<>&')
  17. '&amp;lt;&gt;&amp;'
  18. """
  19. return text.replace("<", "&lt;").replace("&", "&amp;").replace(">", "&gt;")
  20. def do_doctest_gettext_workaround():
  21. """This is a duplicate of function in core/toolboxes."""
  22. def new_displayhook(string):
  23. """A replacement for default `sys.displayhook`"""
  24. if string is not None:
  25. sys.stdout.write("%r\n" % (string,))
  26. def new_translator(string):
  27. """A fake gettext underscore function."""
  28. return string
  29. sys.displayhook = new_displayhook
  30. sys.__displayhook__ = new_displayhook
  31. import __builtin__
  32. __builtin__._ = new_translator
  33. def parse_modules(fd):
  34. """Writes metadata to xml file."""
  35. # TODO: what about ms windows? does gtask handle this?
  36. mlist = list(gcore.get_commands()[0])
  37. indent = 4
  38. for m in sorted(mlist):
  39. # TODO: get rid of g.mapsets_picker.py
  40. if m == "g.mapsets_picker.py" or m == "g.parser":
  41. continue
  42. desc, keyw = get_module_metadata(m)
  43. fd.write('%s<module-item name="%s">\n' % (" " * indent, m))
  44. indent += 4
  45. fd.write("%s<module>%s</module>\n" % (" " * indent, m))
  46. fd.write("%s<description>%s</description>\n" % (" " * indent, escapeXML(desc)))
  47. fd.write(
  48. "%s<keywords>%s</keywords>\n" % (" " * indent, escapeXML(",".join(keyw)))
  49. )
  50. indent -= 4
  51. fd.write("%s</module-item>\n" % (" " * indent))
  52. def get_module_metadata(name):
  53. """
  54. >>> get_module_metadata('g.region')
  55. ('Manages the boundary definitions for the geographic region.', ['general', 'settings'])
  56. >>> get_module_metadata('m.proj')
  57. ('Converts coordinates from one projection to another (cs2cs frontend).', ['miscellaneous', 'projection'])
  58. """
  59. try:
  60. task = gtask.parse_interface(name)
  61. except:
  62. sys.stderr.write(
  63. "Cannot parse interface for module %s. Empty strings"
  64. " will be placed instead of description and keywords."
  65. "\n" % name
  66. )
  67. return "", ""
  68. return task.get_description(full=True), task.get_keywords()
  69. def header(fd):
  70. fd.write('<?xml version="1.0" encoding="UTF-8"?>\n')
  71. fd.write('<!DOCTYPE module-items SYSTEM "module_items.dtd">\n')
  72. fd.write("<!--This file is automatically generated using %s-->\n" % sys.argv[0])
  73. # g.version -r is crashing, commenting this block for now
  74. # vInfo = gcore.version()
  75. # fd.write('<!--version="%s" revision="%s" date="%s"-->\n' % \
  76. # (vInfo['version'].split('.')[0],
  77. # vInfo['revision'],
  78. # datetime.now()))
  79. fd.write("<module-items>\n")
  80. def footer(fd):
  81. fd.write("</module-items>\n")
  82. def doc_test():
  83. """Tests the module using doctest
  84. :return: a number of failed tests
  85. """
  86. import doctest
  87. do_doctest_gettext_workaround()
  88. return doctest.testmod().failed
  89. def module_test():
  90. grass_commands = gcore.get_commands()[0]
  91. if "g.region" not in grass_commands:
  92. print("No g.region")
  93. return 1
  94. if "m.proj" not in grass_commands:
  95. print("No m.proj")
  96. return 1
  97. if "t.rast.univar" not in grass_commands:
  98. print("No t.rast.univar")
  99. return 1
  100. print(get_module_metadata("g.region"))
  101. print(get_module_metadata("m.proj"))
  102. print(get_module_metadata("t.rast.univar"))
  103. def main():
  104. fh = sys.stdout
  105. header(fh)
  106. parse_modules(fh)
  107. footer(fh)
  108. return 0
  109. if __name__ == "__main__":
  110. if len(sys.argv) > 1:
  111. if sys.argv[1] == "doctest":
  112. sys.exit(doc_test())
  113. elif sys.argv[1] == "test":
  114. sys.exit(module_test())
  115. else:
  116. gcore.fatal("Unrecognized parameter.")
  117. sys.exit(main())