nymea/plugins/guh-generateplugininfo

447 lines
21 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# #
# Copyright (C) 2015-2017 Simon Stuerz <simon.stuerz@guh.io> #
# Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> #
# #
# This file is part of guh. #
# #
# guh is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, version 2 of the License. #
# #
# guh is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with guh. If not, see <http://www.gnu.org/licenses/>. #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
import argparse
import traceback
import json
import os
import subprocess
__version__='1.0.1'
##################################################################################################################
# Methods
#-----------------------------------------------------------------------------------------------------------------
def printInfo(info):
if args.filetype is 'i':
print(info)
#-----------------------------------------------------------------------------------------------------------------
def printWarning(warning):
if args.filetype is 'i':
print("Warning:" + warning)
#-----------------------------------------------------------------------------------------------------------------
def printError(error):
if args.filetype is 'i':
print('Error:' + error)
#-----------------------------------------------------------------------------------------------------------------
def writeToFile(line):
outputFile.write('%s\n' % line)
#-----------------------------------------------------------------------------------------------------------------
def extractPlugin(pluginMap):
variableName = 'pluginId'
if not variableName in variableNames:
variableNames.append(variableName)
printInfo('Define PluginId pluginId = %s' % (pluginMap['id']))
if args.filetype is 'i':
writeToFile('PluginId pluginId = PluginId(\"%s\");' % (pluginMap['id']))
addTranslationString(pluginMap['name'], 'The name of the plugin %s (%s)' % (pluginMap['name'], pluginMap['id']))
createExternDefinition('PluginId', variableName)
if 'paramTypes' in pluginMap:
extractParamTypes(pluginMap['paramTypes'], pluginMap['name'])
if 'vendors' in pluginMap:
extractVendors(pluginMap['vendors'])
#-----------------------------------------------------------------------------------------------------------------
def extractParamTypes(paramTypes, contextName):
for paramType in paramTypes:
try:
variableName = '%sParamTypeId' % (paramType['idName'])
if not variableName in variableNames:
variableNames.append(variableName)
printInfo('Define ParamTypeId %s = %s' % (variableName, paramType['id']))
if args.filetype is 'i':
writeToFile('ParamTypeId %s = ParamTypeId(\"%s\");' % (variableName, paramType['id']))
addTranslationString(paramType['name'], 'The name of the paramType (%s) of %s' % (paramType['id'], contextName))
createExternDefinition('ParamTypeId', variableName)
else:
printWarning('Duplicated variable name \"%s\" for ParamTypeId %s -> skipping') % (variableName, paramType['id'])
except:
pass
#-----------------------------------------------------------------------------------------------------------------
def extractVendors(vendors):
for vendor in vendors:
try:
variableName = '%sVendorId' % (vendor['idName'])
if not variableName in variableNames:
variableNames.append(variableName)
printInfo('Define VendorId %s = %s' % (variableName, vendor['id']))
if args.filetype is 'i':
writeToFile('VendorId %s = VendorId(\"%s\");' % (variableName, vendor['id']))
addTranslationString(vendor['name'], 'The name of the vendor (%s)' % vendor['id'])
createExternDefinition('VendorId', variableName)
else:
printWarning('Duplicated variable name \"%s\" for VendorId %s -> skipping') % (variableName, param['id'])
except:
pass
if 'deviceClasses' in vendor:
extractDeviceClasses(vendor['deviceClasses'])
#-----------------------------------------------------------------------------------------------------------------
def extractDeviceClasses(deviceClasses):
for deviceClass in deviceClasses:
try:
variableName = '%sDeviceClassId' % (deviceClass['idName'])
if 'pairingInfo' in deviceClass:
addTranslationString(deviceClass['pairingInfo'], 'The pairing info of deviceClass %s' % deviceClass['name'])
if not variableName in variableNames:
variableNames.append(variableName)
printInfo('Define DeviceClassId %s = %s' % (variableName, deviceClass['id']))
if args.filetype is 'i':
writeToFile('DeviceClassId %s = DeviceClassId(\"%s\");' % (variableName, deviceClass['id']))
addTranslationString(deviceClass['name'], 'The name of the DeviceClass (%s)' %(deviceClass['id']))
createExternDefinition('DeviceClassId', variableName)
else:
printWarning('Duplicated variable name \"%s\" for DeviceClassId %s -> skipping') % (variableName, deviceClass['deviceClassId'])
except:
pass
if 'paramTypes' in deviceClass:
extractParamTypes(deviceClass['paramTypes'], deviceClass['name'])
if 'discoveryParamTypes' in deviceClass:
extractParamTypes(deviceClass['discoveryParamTypes'], deviceClass['name'])
if 'stateTypes' in deviceClass:
extractStateTypes(deviceClass['stateTypes'], deviceClass['name'])
if 'actionTypes' in deviceClass:
extractActionTypes(deviceClass['actionTypes'], deviceClass['name'])
if 'eventTypes' in deviceClass:
extractEventTypes(deviceClass['eventTypes'], deviceClass['name'])
#-----------------------------------------------------------------------------------------------------------------
def extractStateTypes(stateTypes, deviceClassName):
for stateType in stateTypes:
try:
# Define StateType
variableName = '%sStateTypeId' % (stateType['idName'])
#addTranslationString(stateType['name'], 'The name of the stateType (%s) of DeviceClass %s' % (stateType['id'], deviceClassName))
if not variableName in variableNames:
variableNames.append(variableName)
printInfo('Define StateTypeId %s = %s' % (variableName, stateType['id']))
if args.filetype is 'i':
writeToFile('StateTypeId %s = StateTypeId(\"%s\");' % (variableName, stateType['id']))
createExternDefinition('StateTypeId', variableName)
else:
printWarning('Duplicated variable name \"%s\" for StateTypeId %s -> skipping') % (variableName, stateType['id'])
# Create EventTypeId for this state
variableName = '%sEventTypeId' % (stateType['idName'])
if not variableName in variableNames:
addTranslationString(stateType['eventTypeName'], 'The name of the autocreated EventType (%s)' % stateType['id'])
variableNames.append(variableName)
printInfo('Define EventTypeId %s = %s' % (variableName, stateType['id']))
if args.filetype is 'i':
writeToFile('EventTypeId %s = EventTypeId(\"%s\");' % (variableName, stateType['id']))
createExternDefinition('EventTypeId', variableName)
else:
printWarning('Duplicated variable name \"%s\" for autocreated EventTypeId %s -> skipping') % (variableName, stateType['id'])
#ParamType for EventType/ActionType
variableName = '%sStateParamTypeId' % (stateType['idName'])
if not variableName in variableNames:
variableNames.append(variableName)
printInfo('Define ParamTypeId %s for StateType %s = %s' % (variableName, variableName, stateType['id']))
if args.filetype is 'i':
writeToFile('ParamTypeId %s = ParamTypeId(\"%s\");' % (variableName, stateType['id']))
createExternDefinition('ParamTypeId', variableName)
addTranslationString(stateType['name'], 'The name of the ParamType of StateType (%s) of DeviceClass %s' % (stateType['id'], deviceClassName))
else:
printWarning('duplicated variable name \"%s\" for ParamTypeId %s -> skipping') % (variableName, stateType['id'])
# Create ActionTypeId if the state is writable
if 'writable' in stateType and stateType['writable']:
variableName = '%sActionTypeId' % (stateType['idName'])
if not variableName in variableNames:
variableNames.append(variableName)
printInfo('Define ActionTypeId for writable StateType %s = %s' % (variableName, stateType['id']))
addTranslationString(stateType['actionTypeName'], 'The name of the autocreated ActionType (%s)' % stateType['id'])
if args.filetype is 'i':
writeToFile('ActionTypeId %s = ActionTypeId(\"%s\");' % (variableName, stateType['id']))
createExternDefinition('ActionTypeId', variableName)
else:
printWarning('Duplicated variable name \"%s\" for autocreated ActionTypeId %s -> skipping') % (variableName, stateType['id'])
except:
pass
#-----------------------------------------------------------------------------------------------------------------
def extractActionTypes(actionTypes, deviceClassName):
for actionType in actionTypes:
try:
# Define ActionTypeId
variableName = '%sActionTypeId' % (actionType['idName'])
if not variableName in variableNames:
variableNames.append(variableName)
addTranslationString(actionType['name'], 'The name of the ActionType %s of deviceClass %s' % (actionType['id'], deviceClassName))
if args.filetype is 'i':
writeToFile('ActionTypeId %s = ActionTypeId(\"%s\");' % (variableName, actionType['id']))
createExternDefinition('ActionTypeId', variableName)
else:
printWarning('Duplicated variable name \"%s\" for ActionTypeId %s -> skipping') % (variableName, actionType['id'])
except:
pass
# Define paramTypes of this ActionType
if 'paramTypes' in actionType:
extractParamTypes(actionType['paramTypes'], deviceClassName)
#-----------------------------------------------------------------------------------------------------------------
def extractEventTypes(eventTypes, deviceClassName):
for eventType in eventTypes:
try:
# Define EventTypeId
variableName = '%sEventTypeId' % (eventType['idName'])
if not variableName in variableNames:
variableNames.append(variableName)
addTranslationString(eventType['name'], 'The name of the EventType %s of deviceClass %s' % (eventType['id'], deviceClassName))
if args.filetype is 'i':
writeToFile('EventTypeId %s = EventTypeId(\"%s\");' % (variableName, eventType['id']))
createExternDefinition('EventTypeId', variableName)
else:
printWarning('Duplicated variable name \"%s\" for EventTypeId %s -> skipping') % (variableName, eventType['id'])
except:
pass
# Define paramTypes of this EventType
if 'paramTypes' in eventType:
extractParamTypes(eventType['paramTypes'], deviceClassName)
#-----------------------------------------------------------------------------------------------------------------
def createExternDefinition(type, name):
definition = {}
definition['type'] = type
definition['variable'] = name
externDefinitions.append(definition)
#-----------------------------------------------------------------------------------------------------------------
def addTranslationString(string, comment):
translationStrings.append([string, comment])
#-----------------------------------------------------------------------------------------------------------------
def writeTranslationStrings():
if len(args.translations) is 0:
return
if len(translationStrings) is not 0:
writeToFile('// Translation strings')
writeToFile('const QString translations[] {')
for index, value in enumerate(translationStrings):
writeToFile(' //: %s' % value[1])
if index != len(translationStrings) - 1:
writeToFile(' QT_TRANSLATE_NOOP(\"%s\", \"%s\"), \n' % (pluginMap['idName'], value[0]))
else:
writeToFile(' QT_TRANSLATE_NOOP(\"%s\", \"%s\")' % (pluginMap['idName'], value[0]))
writeToFile('};')
#-----------------------------------------------------------------------------------------------------------------
def createTranslationFiles():
for translation in args.translations:
translationFile = (sourceDir + '/' + translation)
path, fileName = os.path.split(translationFile)
translationOutput = (path + '/' + pluginMap['id'] + '-' + os.path.splitext(fileName)[0] + '.qm')
printInfo(' --> Translation update %s' % translationFile)
printInfo(subprocess.check_output(['mkdir', '-p', path]))
printInfo(subprocess.check_output(['lupdate', '-recursive', '-no-obsolete', sourceDir, (args.builddir + '/' + args.output), '-ts', translationFile]))
printInfo(' --> Translation release %s' % translationOutput)
printInfo(subprocess.check_output(['lrelease', translationFile, '-qm', translationOutput]))
printInfo(' --> Copy translation files to build dir %s' % args.builddir + '/translations/')
subprocess.check_output(['rsync', '-a', translationOutput, args.builddir + '/translations/'])
#-----------------------------------------------------------------------------------------------------------------
def writePluginInfoFile():
printInfo(' --> generate plugininfo.h for plugin \"%s\" = %s' % (pluginMap['name'], pluginMap['id']))
writeToFile('/* This file is generated by the guh build system. Any changes to this file will')
writeToFile(' * be lost.')
writeToFile(' *')
writeToFile(' * If you want to change this file, edit the plugin\'s json file.')
writeToFile(' */')
writeToFile('')
writeToFile('#ifndef PLUGININFO_H')
writeToFile('#define PLUGININFO_H')
writeToFile('')
writeToFile('#include <QLoggingCategory>')
writeToFile('#include <QObject>')
writeToFile('')
writeToFile('#include \"typeutils.h\"')
writeToFile('')
writeToFile('// Id definitions')
extractPlugin(pluginMap)
writeToFile('')
writeToFile('// Logging category')
if 'idName' in pluginMap:
writeToFile('Q_DECLARE_LOGGING_CATEGORY(dc%s)' % pluginMap['idName'])
writeToFile('Q_LOGGING_CATEGORY(dc%s, \"%s\")' % (pluginMap['idName'], pluginMap['idName']))
printInfo('Define logging category: \'dc%s\'' % pluginMap['idName'])
writeToFile('')
# Write translation strings
writeTranslationStrings()
writeToFile('')
writeToFile('#endif // PLUGININFO_H')
outputFile.close()
printInfo(' --> generated successfully \"%s\"' % (args.output))
# Translate
if len(translationStrings) is not 0:
createTranslationFiles()
#-----------------------------------------------------------------------------------------------------------------
def writeExternPluginInfoFile():
printInfo(' --> generate extern-plugininfo.h for plugin \"%s\" = %s' % (pluginMap['name'], pluginMap['id']))
extractPlugin(pluginMap)
writeToFile('/* This file is generated by the guh build system. Any changes to this file will')
writeToFile(' * be lost.')
writeToFile(' *')
writeToFile(' * If you want to change this file, edit the plugin\'s json file and add')
writeToFile(' * idName tags where appropriate.')
writeToFile(' */')
writeToFile('')
writeToFile('#ifndef EXTERNPLUGININFO_H')
writeToFile('#define EXTERNPLUGININFO_H')
writeToFile('#include \"typeutils.h\"')
writeToFile('#include <QLoggingCategory>')
writeToFile('')
writeToFile('// Id definitions')
for externDefinition in externDefinitions:
writeToFile('extern %s %s;' % (externDefinition['type'], externDefinition['variable']))
writeToFile('')
writeToFile('// Logging category definition')
if 'idName' in pluginMap:
writeToFile('Q_DECLARE_LOGGING_CATEGORY(dc%s)' % pluginMap['idName'])
writeToFile('')
writeToFile('#endif // EXTERNPLUGININFO_H')
outputFile.close()
printInfo(' --> generated successfully \'%s\'' % (args.output))
##################################################################################################################
# Main
##################################################################################################################
if __name__ == '__main__':
# Argument parser
parser = argparse.ArgumentParser(description='The guh-generateplugininfo is a precompiler for building plugins. This precompiler will create a plugininfo.h containing the uuid definitions from the plugin json file and creates the translations for the plugin.')
parser.add_argument('-j', '--jsonfile', help='The JSON input file name with the plugin description', metavar='jsonfile', required=True)
parser.add_argument('-b', '--builddir', help='The path to the build directory of the plugin where the plugininfo.h file can be found.', metavar='buildpath', required=True)
parser.add_argument('-f', '--filetype', help='The file type to generate: e = extern infofile, i = infofile', action='store', choices=['e', 'i'], default='i')
parser.add_argument('-o', '--output', help='The plugininfo.h outputFile with the uuid declarations', metavar='output')
parser.add_argument('-t', '--translations', help='The translation files for the plugin.', nargs='*', type=str, metavar='*.ts')
parser.add_argument('-v', '--version', action='version', version=__version__)
args = parser.parse_args()
# Get the source directors
sourceDir = os.path.dirname(os.path.abspath(args.jsonfile))
# Print build information for debugging
printInfo('Json file: %s' % args.jsonfile)
printInfo('Output: %s/%s' % (args.builddir, args.output))
printInfo('Build directory: %s' % args.builddir)
printInfo('Source directory: %s' % sourceDir)
printInfo('Translations: %s' % args.translations)
printInfo('FileType: %s' % args.filetype)
# Tuple ('string to translate', 'comment for translater')
translationStrings = []
variableNames = []
externDefinitions = []
# Open files
try:
inputFile = open(args.jsonfile, 'r')
except:
printError('Could not open file \"%s\"' % (args.jsonfile))
exit -1
try:
outputFile = open(args.builddir + '/' + args.output, 'w')
except:
printError('Could not open file \"%s\"' % (args.jsonfile))
exit -1
# Read json file
try:
pluginMap = json.loads(inputFile.read())
inputFile.close()
except ValueError as error:
printError(' --> Could not load json input file \"%s\"' % (args.input))
printError(' %s' % (error))
inputFile.close()
exit -1
# Write files
if args.filetype is 'i':
writePluginInfoFile()
else:
writeExternPluginInfoFile()