|
|
@ -0,0 +1,187 @@ |
|
|
|
#!/usr/bin/env python3 |
|
|
|
''' ADI builder |
|
|
|
author: Steven Kuterna steven.kuterna@devoteam.com |
|
|
|
''' |
|
|
|
|
|
|
|
import sys |
|
|
|
import argparse |
|
|
|
import logging |
|
|
|
import os |
|
|
|
import shutil |
|
|
|
import yaml |
|
|
|
from lxml import etree as ET |
|
|
|
import hashlib |
|
|
|
from datetime import datetime |
|
|
|
|
|
|
|
loglevel= logging.WARNING |
|
|
|
|
|
|
|
logger = logging.getLogger() |
|
|
|
logger.setLevel(loglevel) |
|
|
|
ch = logging.StreamHandler() |
|
|
|
ch.setLevel(loglevel) |
|
|
|
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') |
|
|
|
ch.setFormatter(formatter) |
|
|
|
logger.addHandler(ch) |
|
|
|
|
|
|
|
def insertMetadata(tree, config): |
|
|
|
if config['Verb'] is None: config['Verb'] = '' |
|
|
|
if config['CreateDate'] is None: |
|
|
|
now = datetime.now() |
|
|
|
date = now.strftime("%Y-%m-%d") |
|
|
|
config['CreateDate'] = date |
|
|
|
try: |
|
|
|
attributes= { 'Asset_Class': 'package', |
|
|
|
'Asset_ID': str(config['AssetId']), |
|
|
|
'Asset_Name': str(config['AssetName']), |
|
|
|
'Provider': str(config['Provider']), |
|
|
|
'Provider_ID': str(config['ProviderId']), |
|
|
|
'Product': 'MOD', |
|
|
|
'Description': str(config['Description']), |
|
|
|
'Creation_Date': str(config['CreateDate']), |
|
|
|
'Verb': str(config['Verb']), |
|
|
|
'Version_Major': str(config['VersionMajor']), |
|
|
|
'Version_Minor': str(config['VersionMinor']) |
|
|
|
} |
|
|
|
except KeyError as e: |
|
|
|
logger.error('failed to add Metadata AMS attribute '+str(e)) |
|
|
|
sys.exit(0) |
|
|
|
ET.SubElement(tree, 'AMS', attributes) |
|
|
|
|
|
|
|
|
|
|
|
def createAMSattributes(asset_type, metadata): |
|
|
|
if metadata['Verb'] is None: metadata['Verb'] = '' |
|
|
|
try: |
|
|
|
ams_attributes= { 'Asset_Class': asset_type, |
|
|
|
'Asset_ID': asset_type.upper() + str(metadata['AssetId']), |
|
|
|
'Asset_Name': str(metadata['AssetName'] + ' ' + asset_type), |
|
|
|
'Provider': str(metadata['Provider']), |
|
|
|
'Provider_ID': str(metadata['ProviderId']), |
|
|
|
'Product': 'MOD', |
|
|
|
'Description': str(metadata['Description'] + ' ' + asset_type), |
|
|
|
'Creation_Date': str(metadata['CreateDate']), |
|
|
|
'Verb': str(metadata['Verb']), |
|
|
|
'Version_Major': str(metadata['VersionMajor']), |
|
|
|
'Version_Minor': str(metadata['VersionMinor']) |
|
|
|
} |
|
|
|
except KeyError as e: |
|
|
|
logger.error('failed to add Metadata AMS attribute '+str(e)) |
|
|
|
sys.exit(0) |
|
|
|
return ams_attributes |
|
|
|
|
|
|
|
|
|
|
|
def addAsset(tree, asset_type, asset, metadata, output): |
|
|
|
if not 'Content' in asset: |
|
|
|
for subasset in asset: |
|
|
|
addAsset(tree, asset_type, asset[subasset], metadata, output) |
|
|
|
return |
|
|
|
logger.info(f'insert asset: {asset}') |
|
|
|
|
|
|
|
ams_attributes = createAMSattributes(asset_type, metadata) |
|
|
|
assetTree = ET.SubElement(tree, 'Asset') |
|
|
|
assetMetadata = ET.SubElement(assetTree, 'Metadata') |
|
|
|
ET.SubElement(assetMetadata, 'AMS', ams_attributes) |
|
|
|
ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Type': asset_type}) |
|
|
|
|
|
|
|
for element in asset: |
|
|
|
if type(asset[element]) is dict: |
|
|
|
for subelement in asset[element]: |
|
|
|
if type(asset[element][subelement]) is dict: |
|
|
|
for subsubelemment in asset[element][subelement]: |
|
|
|
ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': subsubelemment, 'Value': str(asset[element][subelement][subsubelemment])}) |
|
|
|
else: |
|
|
|
if asset[element][subelement] is None: |
|
|
|
asset[element][subelement] = '' |
|
|
|
ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': element, 'Value': str(asset[element][subelement])}) |
|
|
|
else: |
|
|
|
# is it content? add it under the Asset level |
|
|
|
if str(element).upper() == 'CONTENT_CHECKSUM' or str(element).upper() == 'CONTENT_FILESIZE': |
|
|
|
continue |
|
|
|
if str(element).upper() == 'CONTENT': |
|
|
|
if not os.path.exists(args.input): |
|
|
|
logger.error(f"content file {asset[element]} is not found, exiting...") |
|
|
|
sys.exit(0) |
|
|
|
ET.SubElement(assetTree, 'Content', {'Value': asset[element]}) |
|
|
|
checksum = hashlib.md5(open(asset[element],'rb').read()).hexdigest() |
|
|
|
filesize = os.path.getsize(asset[element]) |
|
|
|
ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': 'Content_CheckSum', 'Value': str(checksum)}) |
|
|
|
ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': 'Content_Filesize', 'Value': str(filesize)}) |
|
|
|
shutil.copyfile(asset[element], f'{output}/{asset[element]}') |
|
|
|
continue |
|
|
|
# no content, add it under the Metadata level |
|
|
|
if asset[element] is None: |
|
|
|
asset[element] = '' |
|
|
|
ET.SubElement(assetMetadata, 'App_Data', {'App': 'MOD', 'Name': element, 'Value': str(asset[element])}) |
|
|
|
|
|
|
|
|
|
|
|
def addTitle(tree, title, metadata): |
|
|
|
logger.info(f'insert title: {title}') |
|
|
|
ams_attributes = createAMSattributes('title', metadata) |
|
|
|
titleTree = ET.SubElement(tree, 'Metadata') |
|
|
|
ET.SubElement(titleTree, 'AMS', ams_attributes) |
|
|
|
ET.SubElement(titleTree, 'App_Data', {'App': 'MOD', 'Type': 'title'}) |
|
|
|
|
|
|
|
for element in title: |
|
|
|
# check if there are multiple elements available |
|
|
|
if type(title[element]) == dict: |
|
|
|
for subelement in title[element]: |
|
|
|
# check if it contains multiple attributes like Language and a Value |
|
|
|
if type(title[element][subelement]) == dict: |
|
|
|
attributes = {'App': 'MOD', 'Name': element} |
|
|
|
# if the attribute is the same as the element change it to 'Value' |
|
|
|
for subsubelement in title[element][subelement]: |
|
|
|
if subsubelement == element: |
|
|
|
attributes.update({'Value': title[element][subelement][subsubelement]}) |
|
|
|
else: |
|
|
|
# just add it to the attributes list |
|
|
|
attributes.update({subsubelement: title[element][subelement][subsubelement]}) |
|
|
|
# add the multiattribute element to the tree |
|
|
|
ET.SubElement(titleTree, 'App_Data', attributes) |
|
|
|
continue |
|
|
|
# single attribute, add to the tree |
|
|
|
if title[element][subelement] is None: |
|
|
|
title[element][subelement] = '' |
|
|
|
ET.SubElement(titleTree, 'App_Data', {'App': 'MOD', 'Name': element, 'Value': title[element][subelement]}) |
|
|
|
else: |
|
|
|
# single element, add to the tree |
|
|
|
if title[element] is None: |
|
|
|
title[element] = '' |
|
|
|
ET.SubElement(titleTree, 'App_Data', {'App': 'MOD', 'Name': element, 'Value': str(title[element])}) |
|
|
|
|
|
|
|
|
|
|
|
def insertAssets(tree, metadata, assets, output): |
|
|
|
for asset in assets: |
|
|
|
if asset.upper() == 'TITLE': |
|
|
|
addTitle(tree, assets[asset], metadata) |
|
|
|
else: |
|
|
|
addAsset(tree, asset, assets[asset], metadata, output) |
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__" : |
|
|
|
argparser = argparse.ArgumentParser(description='Creates ADI from yaml...') |
|
|
|
argparser.add_argument('--input', required=False, default="adi.yaml", help="yaml input to build adi.xml") |
|
|
|
argparser.add_argument('--output', required=True, help="output directory for xml and content files") |
|
|
|
args = argparser.parse_args() |
|
|
|
|
|
|
|
logger.debug(f"generating adi based on {args.input}") |
|
|
|
if not os.path.exists(args.input): |
|
|
|
logger.error(f"file {args.input} is not found, exiting...") |
|
|
|
sys.exit(0) |
|
|
|
with open(args.input, 'r') as ymlfile: |
|
|
|
cfg = yaml.load(ymlfile, Loader=yaml.FullLoader) |
|
|
|
|
|
|
|
try: |
|
|
|
os.mkdir(args.output) |
|
|
|
except FileExistsError: |
|
|
|
logger.warning(f'directory {args.output} already exists!') |
|
|
|
root = ET.Element('ADI') |
|
|
|
metadataTree = ET.SubElement(root, 'Metadata') |
|
|
|
insertMetadata(metadataTree, cfg['metadata']) |
|
|
|
assetTree = ET.SubElement(root, 'Asset') |
|
|
|
insertAssets(assetTree, cfg['metadata'], cfg['asset'], args.output) |
|
|
|
tree = ET.ElementTree(root) |
|
|
|
|
|
|
|
try: |
|
|
|
tree.write(f'{args.output}/adi.xml', encoding='utf-8', xml_declaration=True, pretty_print=True, doctype='<!DOCTYPE ADI PUBLIC "ADI" "ADI.DTD">') |
|
|
|
except Exception as e: |
|
|
|
print(str(e)) |