You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
8.3 KiB

4 years ago
4 years ago
4 years ago
4 years ago
  1. #!/usr/bin/env python3
  2. ''' ADI builder
  3. author: Steven Kuterna steven.kuterna@devoteam.com
  4. '''
  5. import sys
  6. import argparse
  7. import logging
  8. import os
  9. import shutil
  10. import yaml
  11. from lxml import etree as ET
  12. import hashlib
  13. from datetime import datetime
  14. loglevel= logging.WARNING
  15. logger = logging.getLogger()
  16. logger.setLevel(loglevel)
  17. ch = logging.StreamHandler()
  18. ch.setLevel(loglevel)
  19. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  20. ch.setFormatter(formatter)
  21. logger.addHandler(ch)
  22. def insertMetadata(tree, config):
  23. if config['Verb'] is None: config['Verb'] = ''
  24. if config['CreateDate'] is None:
  25. now = datetime.now()
  26. date = now.strftime("%Y-%m-%d")
  27. config['CreateDate'] = date
  28. try:
  29. attributes= { 'Asset_Class': 'package',
  30. 'Asset_ID': str(config['AssetId']),
  31. 'Asset_Name': str(config['AssetName']),
  32. 'Provider': str(config['Provider']),
  33. 'Provider_ID': str(config['ProviderId']),
  34. 'Product': 'MOD',
  35. 'Description': str(config['Description']),
  36. 'Creation_Date': str(config['CreateDate']),
  37. 'Verb': str(config['Verb']),
  38. 'Version_Major': str(config['VersionMajor']),
  39. 'Version_Minor': str(config['VersionMinor'])
  40. }
  41. except KeyError as e:
  42. logger.error('failed to add Metadata AMS attribute '+str(e))
  43. sys.exit(0)
  44. ET.SubElement(tree, 'AMS', attributes)
  45. def createAMSattributes(asset_type, metadata):
  46. if metadata['Verb'] is None: metadata['Verb'] = ''
  47. try:
  48. ams_attributes= { 'Asset_Class': asset_type,
  49. 'Asset_ID': asset_type.upper() + str(metadata['AssetId']),
  50. 'Asset_Name': str(metadata['AssetName'] + ' ' + asset_type),
  51. 'Provider': str(metadata['Provider']),
  52. 'Provider_ID': str(metadata['ProviderId']),
  53. 'Product': 'MOD',
  54. 'Description': str(metadata['Description'] + ' ' + asset_type),
  55. 'Creation_Date': str(metadata['CreateDate']),
  56. 'Verb': str(metadata['Verb']),
  57. 'Version_Major': str(metadata['VersionMajor']),
  58. 'Version_Minor': str(metadata['VersionMinor'])
  59. }
  60. except KeyError as e:
  61. logger.error('failed to add Metadata AMS attribute '+str(e))
  62. sys.exit(0)
  63. return ams_attributes
  64. def addAsset(tree, asset_type, asset, metadata, output):
  65. if not 'Content' in asset:
  66. for subasset in asset:
  67. addAsset(tree, asset_type, asset[subasset], metadata, output)
  68. return
  69. logger.info(f'insert asset: {asset}')
  70. ams_attributes = createAMSattributes(asset_type, metadata)
  71. assetTree = ET.SubElement(tree, 'Asset')
  72. assetMetadata = ET.SubElement(assetTree, 'Metadata')
  73. ET.SubElement(assetMetadata, 'AMS', ams_attributes)
  74. ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': 'Type', 'Value': asset_type})
  75. for element in asset:
  76. if type(asset[element]) is dict:
  77. for subelement in asset[element]:
  78. if type(asset[element][subelement]) is dict:
  79. for subsubelemment in asset[element][subelement]:
  80. ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': subsubelemment, 'Value': str(asset[element][subelement][subsubelemment])})
  81. else:
  82. if asset[element][subelement] is None:
  83. asset[element][subelement] = ''
  84. ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': element, 'Value': str(asset[element][subelement])})
  85. else:
  86. # is it content? add it under the Asset level
  87. if str(element).upper() == 'CONTENT_CHECKSUM' or str(element).upper() == 'CONTENT_FILESIZE':
  88. continue
  89. if str(element).upper() == 'CONTENT':
  90. if not os.path.exists(args.input):
  91. logger.error(f"content file {asset[element]} is not found, exiting...")
  92. sys.exit(0)
  93. ET.SubElement(assetTree, 'Content', {'Value': asset[element]})
  94. checksum = hashlib.md5(open(asset[element],'rb').read()).hexdigest()
  95. filesize = os.path.getsize(asset[element])
  96. ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': 'Content_CheckSum', 'Value': str(checksum)})
  97. ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': 'Content_Filesize', 'Value': str(filesize)})
  98. shutil.copyfile(asset[element], f'{output}/{asset[element]}')
  99. continue
  100. # no content, add it under the Metadata level
  101. if asset[element] is None:
  102. asset[element] = ''
  103. ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': element, 'Value': str(asset[element])})
  104. def addTitle(tree, title, metadata):
  105. logger.info(f'insert title: {title}')
  106. ams_attributes = createAMSattributes('title', metadata)
  107. titleTree = ET.SubElement(tree, 'Metadata')
  108. ET.SubElement(titleTree, 'AMS', ams_attributes)
  109. ET.SubElement(titleTree, 'App_Data', {'App': 'MOD', 'Type': 'title'})
  110. for element in title:
  111. # check if there are multiple elements available
  112. if type(title[element]) == dict:
  113. for subelement in title[element]:
  114. # check if it contains multiple attributes like Language and a Value
  115. if type(title[element][subelement]) == dict:
  116. attributes = {'App': 'MOD', 'Name': element}
  117. # if the attribute is the same as the element change it to 'Value'
  118. for subsubelement in title[element][subelement]:
  119. if subsubelement == element:
  120. attributes.update({'Value': title[element][subelement][subsubelement]})
  121. else:
  122. # just add it to the attributes list
  123. attributes.update({subsubelement: title[element][subelement][subsubelement]})
  124. # add the multiattribute element to the tree
  125. ET.SubElement(titleTree, 'App_Data', attributes)
  126. continue
  127. # single attribute, add to the tree
  128. if title[element][subelement] is None:
  129. title[element][subelement] = ''
  130. ET.SubElement(titleTree, 'App_Data', {'App': 'MOD', 'Name': element, 'Value': title[element][subelement]})
  131. else:
  132. # single element, add to the tree
  133. if title[element] is None:
  134. title[element] = ''
  135. ET.SubElement(titleTree, 'App_Data', {'App': 'MOD', 'Name': element, 'Value': str(title[element])})
  136. def insertAssets(tree, metadata, assets, output):
  137. for asset in assets:
  138. if asset.upper() == 'TITLE':
  139. addTitle(tree, assets[asset], metadata)
  140. else:
  141. addAsset(tree, asset, assets[asset], metadata, output)
  142. return
  143. if __name__ == "__main__" :
  144. argparser = argparse.ArgumentParser(description='Creates ADI from yaml...')
  145. argparser.add_argument('--input', required=False, default="adi.yaml", help="yaml input to build adi.xml")
  146. argparser.add_argument('--output', required=True, help="output directory for xml and content files")
  147. args = argparser.parse_args()
  148. logger.debug(f"generating adi based on {args.input}")
  149. if not os.path.exists(args.input):
  150. logger.error(f"file {args.input} is not found, exiting...")
  151. sys.exit(0)
  152. with open(args.input, 'r') as ymlfile:
  153. cfg = yaml.load(ymlfile, Loader=yaml.FullLoader)
  154. try:
  155. os.mkdir(args.output)
  156. except FileExistsError:
  157. logger.warning(f'directory {args.output} already exists!')
  158. root = ET.Element('ADI')
  159. metadataTree = ET.SubElement(root, 'Metadata')
  160. insertMetadata(metadataTree, cfg['metadata'])
  161. assetTree = ET.SubElement(root, 'Asset')
  162. insertAssets(assetTree, cfg['metadata'], cfg['asset'], args.output)
  163. tree = ET.ElementTree(root)
  164. try:
  165. tree.write(f'{args.output}/adi.xml', encoding='utf-8', xml_declaration=True, pretty_print=True, doctype='<!DOCTYPE ADI SYSTEM "ADI.DTD">')
  166. except Exception as e:
  167. print(str(e))