| # Copyright 2012 Citrix Systems, Inc. Licensed under the |
| # Apache License, Version 2.0 (the "License"); you may not use this |
| # file except in compliance with the License. Citrix Systems, Inc. |
| # reserves all rights not expressly granted by the License. |
| # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| # Automatically generated by addcopyright.py at 04/03/2012 |
| import xml.dom.minidom |
| from optparse import OptionParser |
| import os |
| import sys |
| class cmdParameterProperty(object): |
| def __init__(self): |
| self.name = None |
| self.required = False |
| self.desc = "" |
| self.type = "planObject" |
| self.subProperties = [] |
| |
| class cloudStackCmd: |
| def __init__(self): |
| self.name = "" |
| self.desc = "" |
| self.async = "false" |
| self.request = [] |
| self.response = [] |
| |
| class codeGenerator: |
| space = " " |
| |
| cmdsName = [] |
| |
| def __init__(self, outputFolder, apiSpecFile): |
| self.cmd = None |
| self.code = "" |
| self.required = [] |
| self.subclass = [] |
| self.outputFolder = outputFolder |
| self.apiSpecFile = apiSpecFile |
| |
| def addAttribute(self, attr, pro): |
| value = pro.value |
| if pro.required: |
| self.required.append(attr) |
| desc = pro.desc |
| if desc is not None: |
| self.code += self.space |
| self.code += "''' " + pro.desc + " '''" |
| self.code += "\n" |
| |
| self.code += self.space |
| self.code += attr + " = " + str(value) |
| self.code += "\n" |
| |
| def generateSubClass(self, name, properties): |
| '''generate code for sub list''' |
| subclass = 'class %s:\n'%name |
| subclass += self.space + "def __init__(self):\n" |
| for pro in properties: |
| if pro.desc is not None: |
| subclass += self.space + self.space + '""""%s"""\n'%pro.desc |
| if len (pro.subProperties) > 0: |
| subclass += self.space + self.space + 'self.%s = []\n'%pro.name |
| self.generateSubClass(pro.name, pro.subProperties) |
| else: |
| subclass += self.space + self.space + 'self.%s = None\n'%pro.name |
| |
| self.subclass.append(subclass) |
| def generate(self, cmd): |
| |
| self.cmd = cmd |
| self.cmdsName.append(self.cmd.name) |
| self.code += "\n" |
| self.code += '"""%s"""\n'%self.cmd.desc |
| self.code += 'from baseCmd import *\n' |
| self.code += 'from baseResponse import *\n' |
| self.code += "class %sCmd (baseCmd):\n"%self.cmd.name |
| self.code += self.space + "def __init__(self):\n" |
| |
| self.code += self.space + self.space + 'self.isAsync = "%s"\n' %self.cmd.async |
| |
| for req in self.cmd.request: |
| if req.desc is not None: |
| self.code += self.space + self.space + '"""%s"""\n'%req.desc |
| if req.required == "true": |
| self.code += self.space + self.space + '"""Required"""\n' |
| |
| value = "None" |
| if req.type == "list" or req.type == "map": |
| value = "[]" |
| |
| self.code += self.space + self.space + 'self.%s = %s\n'%(req.name,value) |
| if req.required == "true": |
| self.required.append(req.name) |
| |
| self.code += self.space + self.space + "self.required = [" |
| for require in self.required: |
| self.code += '"' + require + '",' |
| self.code += "]\n" |
| self.required = [] |
| |
| |
| """generate response code""" |
| subItems = {} |
| self.code += "\n" |
| self.code += 'class %sResponse (baseResponse):\n'%self.cmd.name |
| self.code += self.space + "def __init__(self):\n" |
| if len(self.cmd.response) == 0: |
| self.code += self.space + self.space + "pass" |
| else: |
| for res in self.cmd.response: |
| if res.desc is not None: |
| self.code += self.space + self.space + '"""%s"""\n'%res.desc |
| |
| if len(res.subProperties) > 0: |
| self.code += self.space + self.space + 'self.%s = []\n'%res.name |
| self.generateSubClass(res.name, res.subProperties) |
| else: |
| self.code += self.space + self.space + 'self.%s = None\n'%res.name |
| self.code += '\n' |
| |
| for subclass in self.subclass: |
| self.code += subclass + "\n" |
| |
| fp = open(self.outputFolder + "/cloudstackAPI/%s.py"%self.cmd.name, "w") |
| fp.write(self.code) |
| fp.close() |
| self.code = "" |
| self.subclass = [] |
| |
| |
| def finalize(self): |
| '''generate an api call''' |
| |
| header = '"""Test Client for CloudStack API"""\n' |
| imports = "import copy\n" |
| initCmdsList = '__all__ = [' |
| body = '' |
| body += "class CloudStackAPIClient:\n" |
| body += self.space + 'def __init__(self, connection):\n' |
| body += self.space + self.space + 'self.connection = connection\n' |
| body += "\n" |
| |
| body += self.space + 'def __copy__(self):\n' |
| body += self.space + self.space + 'return CloudStackAPIClient(copy.copy(self.connection))\n' |
| body += "\n" |
| |
| for cmdName in self.cmdsName: |
| body += self.space + 'def %s(self,command):\n'%cmdName |
| body += self.space + self.space + 'response = %sResponse()\n'%cmdName |
| body += self.space + self.space + 'response = self.connection.make_request(command, response)\n' |
| body += self.space + self.space + 'return response\n' |
| body += '\n' |
| |
| imports += 'from %s import %sResponse\n'%(cmdName, cmdName) |
| initCmdsList += '"%s",'%cmdName |
| |
| fp = open(self.outputFolder + '/cloudstackAPI/cloudstackAPIClient.py', 'w') |
| for item in [header, imports, body]: |
| fp.write(item) |
| fp.close() |
| |
| '''generate __init__.py''' |
| initCmdsList += '"cloudstackAPIClient"]' |
| fp = open(self.outputFolder + '/cloudstackAPI/__init__.py', 'w') |
| fp.write(initCmdsList) |
| fp.close() |
| |
| fp = open(self.outputFolder + '/cloudstackAPI/baseCmd.py', 'w') |
| basecmd = '"""Base Command"""\n' |
| basecmd += 'class baseCmd:\n' |
| basecmd += self.space + 'pass\n' |
| fp.write(basecmd) |
| fp.close() |
| |
| fp = open(self.outputFolder + '/cloudstackAPI/baseResponse.py', 'w') |
| basecmd = '"""Base class for response"""\n' |
| basecmd += 'class baseResponse:\n' |
| basecmd += self.space + 'pass\n' |
| fp.write(basecmd) |
| fp.close() |
| |
| |
| def constructResponse(self, response): |
| paramProperty = cmdParameterProperty() |
| paramProperty.name = getText(response.getElementsByTagName('name')) |
| paramProperty.desc = getText(response.getElementsByTagName('description')) |
| if paramProperty.name.find('(*)') != -1: |
| '''This is a list''' |
| paramProperty.name = paramProperty.name.split('(*)')[0] |
| for subresponse in response.getElementsByTagName('arguments')[0].getElementsByTagName('arg'): |
| subProperty = self.constructResponse(subresponse) |
| paramProperty.subProperties.append(subProperty) |
| return paramProperty |
| |
| def loadCmdFromXML(self): |
| dom = xml.dom.minidom.parse(self.apiSpecFile) |
| cmds = [] |
| for cmd in dom.getElementsByTagName("command"): |
| csCmd = cloudStackCmd() |
| csCmd.name = getText(cmd.getElementsByTagName('name')) |
| assert csCmd.name |
| |
| desc = getText(cmd.getElementsByTagName('description')) |
| if desc: |
| csCmd.desc = desc |
| |
| async = getText(cmd.getElementsByTagName('isAsync')) |
| if async: |
| csCmd.async = async |
| |
| for param in cmd.getElementsByTagName("request")[0].getElementsByTagName("arg"): |
| paramProperty = cmdParameterProperty() |
| |
| paramProperty.name = getText(param.getElementsByTagName('name')) |
| assert paramProperty.name |
| |
| required = param.getElementsByTagName('required') |
| if required: |
| paramProperty.required = getText(required) |
| |
| requestDescription = param.getElementsByTagName('description') |
| if requestDescription: |
| paramProperty.desc = getText(requestDescription) |
| |
| type = param.getElementsByTagName("type") |
| if type: |
| paramProperty.type = getText(type) |
| |
| csCmd.request.append(paramProperty) |
| |
| responseEle = cmd.getElementsByTagName("response")[0] |
| for response in responseEle.getElementsByTagName("arg"): |
| if response.parentNode != responseEle: |
| continue |
| |
| paramProperty = self.constructResponse(response) |
| csCmd.response.append(paramProperty) |
| |
| cmds.append(csCmd) |
| return cmds |
| |
| def generateCode(self): |
| cmds = self.loadCmdFromXML() |
| for cmd in cmds: |
| self.generate(cmd) |
| self.finalize() |
| |
| def getText(elements): |
| return elements[0].childNodes[0].nodeValue.strip() |
| |
| if __name__ == "__main__": |
| parser = OptionParser() |
| |
| parser.add_option("-o", "--output", dest="output", help="the root path where code genereted, default is .") |
| parser.add_option("-s", "--specfile", dest="spec", help="the path and name of the api spec xml file, default is /etc/cloud/cli/commands.xml") |
| |
| (options, args) = parser.parse_args() |
| |
| apiSpecFile = "/etc/cloud/cli/commands.xml" |
| if options.spec is not None: |
| apiSpecFile = options.spec |
| |
| if not os.path.exists(apiSpecFile): |
| print "the spec file %s does not exists"%apiSpecFile |
| print parser.print_help() |
| exit(1) |
| |
| |
| folder = "." |
| if options.output is not None: |
| folder = options.output |
| apiModule=folder + "/cloudstackAPI" |
| if not os.path.exists(apiModule): |
| try: |
| os.mkdir(apiModule) |
| except: |
| print "Failed to create folder %s, due to %s"%(apiModule,sys.exc_info()) |
| print parser.print_help() |
| exit(2) |
| |
| cg = codeGenerator(folder, apiSpecFile) |
| cg.generateCode() |
| |