#!/usr/bin/env python # -*- coding: UTF-8 -*- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Copyright (C) 2015-2017 Simon Stuerz # # Copyright (C) 2014 Michael Zanetti # # # # 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 . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 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 ') writeToFile('#include ') 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 ') 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()