SerializeContextAnalyzer.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. ########################################################################################
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. ########################################################################################
  9. import argparse
  10. import getopt
  11. import jinja2
  12. import json
  13. import string
  14. import os
  15. # Creates the folder at the given path is it doesn't already exist.
  16. def CreateOutputFolder(path):
  17. folderPath = os.path.dirname(path)
  18. if not os.path.exists(folderPath):
  19. try:
  20. os.mkdir(folderPath)
  21. except OSError:
  22. print("Failed to create path '{0}'".format(folderPath))
  23. return False
  24. return True
  25. # Function to check if a type is derived from one of the provided classes.
  26. def IsDerivedFrom(context, classInfo, derivedType):
  27. bases = classInfo.get('Bases', [])
  28. for base in bases:
  29. baseUuid = base.get('Uuid')
  30. if baseUuid is not None:
  31. if baseUuid == derivedType:
  32. return True
  33. else:
  34. baseClassInfo = context.get(baseUuid)
  35. if baseClassInfo is not None:
  36. if IsDerivedFrom(context, baseClassInfo, derivedType):
  37. return True
  38. return False
  39. # A Jinja2 filter function that filters any type that's not one of the provided types.
  40. def FilterByBase(context, type):
  41. result = {}
  42. for uuid, classInfo in context.items():
  43. if uuid == type or IsDerivedFrom(context, classInfo, type):
  44. result[uuid] = classInfo
  45. return result
  46. def ParseAdditionalArguments(dict, arguments):
  47. currentArg = None
  48. for arg in arguments:
  49. if arg[:2] == '--' or arg[:1] == '-':
  50. if currentArg is not None:
  51. dict[currentArg] = True
  52. if arg[:2] == '--':
  53. currentArg = arg[2:]
  54. elif arg[:1] == '-':
  55. currentArg = arg[1:]
  56. else:
  57. if currentArg is not None:
  58. dict[currentArg] = arg
  59. currentArg = None
  60. if currentArg is not None:
  61. dict[currentArg] = True
  62. # Convert the json formatted Serialize Context through the provided Jinja2 template.
  63. def Convert(source, output, template, split, additionalArgs):
  64. with open(source) as jsonFile:
  65. data = json.load(jsonFile)
  66. jinjaEnvironment = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(template)), trim_blocks=True, lstrip_blocks=True)
  67. jinjaEnvironment.filters['FilterByBase'] = FilterByBase
  68. renderer = jinjaEnvironment.get_template(os.path.basename(template))
  69. path, extension = os.path.splitext(output);
  70. file = os.path.basename(path)
  71. data['Config'] = {}
  72. data['Config']['Document'] = file
  73. ParseAdditionalArguments(data['Config'], additionalArgs)
  74. print("Template arguments: {}".format(data['Config']))
  75. if split:
  76. for c in string.ascii_lowercase:
  77. data['Config']['Filter'] = c
  78. outputFilePath = "{0} {1}{2}".format(path, c, extension)
  79. rendering = renderer.render(data)
  80. with open(outputFilePath, 'w') as outputFile:
  81. outputFile.write(rendering)
  82. else:
  83. rendering = renderer.render(data)
  84. with open(output, 'w') as outputFile:
  85. outputFile.write(rendering)
  86. if __name__ == "__main__":
  87. parser = argparse.ArgumentParser(
  88. description='Takes a json-formatted dump of the Serialize Context and runs it through the provided Jinja2 templates.')
  89. parser.add_argument('--source', help='Path to the json file containing the output of the SerializeContext.', required=True)
  90. parser.add_argument('--output', help='Path to the file to write the converted result to.', required=True)
  91. parser.add_argument('--template', help='Path to the Jinja2 template to use for the conversion.', required=True)
  92. parser.add_argument('--split', help='Only include entries that start with this letter.', action='store_true')
  93. args, remainingArgs = parser.parse_known_args()
  94. sourcePath = args.source
  95. if not os.path.isabs(sourcePath):
  96. sourcePath = os.path.abspath(sourcePath)
  97. outputPath = args.output
  98. if not os.path.isabs(outputPath):
  99. outputPath = os.path.abspath(outputPath)
  100. templatePath = args.template
  101. if not os.path.isabs(templatePath):
  102. templatePath = os.path.abspath(templatePath)
  103. if CreateOutputFolder(outputPath):
  104. print('Converting from "{0}" to "{1}" using template "{2}".'.format(sourcePath, outputPath, templatePath))
  105. Convert(sourcePath, outputPath, templatePath, args.split, remainingArgs)