mirror of https://github.com/apache/cloudstack.git
CLOUDSTACK-3096: format codegenerator.py
This commit is contained in:
parent
f0ab05dc04
commit
1c50f1c756
|
|
@ -5,9 +5,9 @@
|
|||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with 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
|
||||
|
|
@ -23,6 +23,7 @@ import os
|
|||
import sys
|
||||
import urllib2
|
||||
|
||||
|
||||
class cmdParameterProperty(object):
|
||||
def __init__(self):
|
||||
self.name = None
|
||||
|
|
@ -30,7 +31,8 @@ class cmdParameterProperty(object):
|
|||
self.desc = ""
|
||||
self.type = "planObject"
|
||||
self.subProperties = []
|
||||
|
||||
|
||||
|
||||
class cloudStackCmd:
|
||||
def __init__(self):
|
||||
self.name = ""
|
||||
|
|
@ -42,8 +44,9 @@ class cloudStackCmd:
|
|||
|
||||
class codeGenerator:
|
||||
"""
|
||||
Apache CloudStack- marvin python classes can be generated from the json returned by API discovery or from the
|
||||
xml spec of commands generated by the ApiDocWriter. This class provides helper methods for these uses.
|
||||
Apache CloudStack- marvin python classes can be generated from the json
|
||||
returned by API discovery or from the xml spec of commands generated by
|
||||
the ApiDocWriter. This class provides helper methods for these uses.
|
||||
"""
|
||||
space = " "
|
||||
cmdsName = []
|
||||
|
|
@ -91,16 +94,18 @@ class codeGenerator:
|
|||
|
||||
def generateSubClass(self, name, properties):
|
||||
'''generate code for sub list'''
|
||||
subclass = 'class %s:\n'%name
|
||||
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
|
||||
subclass += self.space + self.space + '""""%s"""\n' % pro.desc
|
||||
if len(pro.subProperties) > 0:
|
||||
subclass += self.space + self.space
|
||||
subclass += 'self.%s = []\n' % pro.name
|
||||
self.generateSubClass(pro.name, pro.subProperties)
|
||||
else:
|
||||
subclass += self.space + self.space + 'self.%s = None\n'%pro.name
|
||||
subclass += self.space + self.space
|
||||
subclass += 'self.%s = None\n' % pro.name
|
||||
|
||||
self.subclass.append(subclass)
|
||||
|
||||
|
|
@ -110,17 +115,18 @@ class codeGenerator:
|
|||
self.cmdsName.append(self.cmd.name)
|
||||
self.code = self.license
|
||||
self.code += "\n"
|
||||
self.code += '"""%s"""\n'%self.cmd.desc
|
||||
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 += "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' %str(self.cmd.async).lower()
|
||||
self.code += self.space + self.space
|
||||
self.code += 'self.isAsync = "%s"\n' % str(self.cmd.async).lower()
|
||||
|
||||
for req in self.cmd.request:
|
||||
if req.desc is not None:
|
||||
self.code += self.space + self.space + '"""%s"""\n'%req.desc
|
||||
self.code += self.space + self.space + '"""%s"""\n' % req.desc
|
||||
if req.required == "true":
|
||||
self.code += self.space + self.space + '"""Required"""\n'
|
||||
|
||||
|
|
@ -128,7 +134,8 @@ class codeGenerator:
|
|||
if req.type == "list" or req.type == "map":
|
||||
value = "[]"
|
||||
|
||||
self.code += self.space + self.space + 'self.%s = %s\n'%(req.name,value)
|
||||
self.code += self.space + self.space
|
||||
self.code += 'self.%s = %s\n' % (req.name, value)
|
||||
if req.required == "true":
|
||||
self.required.append(req.name)
|
||||
|
||||
|
|
@ -138,30 +145,33 @@ class codeGenerator:
|
|||
self.code += "]\n"
|
||||
self.required = []
|
||||
|
||||
|
||||
"""generate response code"""
|
||||
subItems = {}
|
||||
self.code += "\n"
|
||||
self.code += 'class %sResponse (baseResponse):\n'%self.cmd.name
|
||||
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
|
||||
self.code += self.space + self.space
|
||||
self.code += '"""%s"""\n' % res.desc
|
||||
|
||||
if len(res.subProperties) > 0:
|
||||
self.code += self.space + self.space + 'self.%s = []\n'%res.name
|
||||
self.code += self.space + self.space
|
||||
self.code += '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 += self.space + self.space
|
||||
self.code += '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 = open(self.outputFolder + "/cloudstackAPI/%s.py" % self.cmd.name,
|
||||
"w")
|
||||
fp.write(self.code)
|
||||
fp.close()
|
||||
self.code = ""
|
||||
|
|
@ -180,20 +190,26 @@ class codeGenerator:
|
|||
body += "\n"
|
||||
|
||||
body += self.space + 'def __copy__(self):\n'
|
||||
body += self.space + self.space + 'return CloudStackAPIClient(copy.copy(self.connection))\n'
|
||||
body += self.space + self.space
|
||||
body += 'return CloudStackAPIClient(copy.copy(self.connection))\n'
|
||||
body += "\n"
|
||||
|
||||
for cmdName in self.cmdsName:
|
||||
body += self.space + 'def %s(self, command, method="GET"):\n'%cmdName
|
||||
body += self.space + self.space + 'response = %sResponse()\n'%cmdName
|
||||
body += self.space + self.space + 'response = self.connection.marvin_request(command, response_type=response, method=method)\n'
|
||||
body += self.space
|
||||
body += 'def %s(self, command, method="GET"):\n' % cmdName
|
||||
body += self.space + self.space
|
||||
body += 'response = %sResponse()\n' % cmdName
|
||||
body += self.space + self.space
|
||||
body += 'response = self.connection.marvin_request(command,'
|
||||
body += ' response_type=response, method=method)\n'
|
||||
body += self.space + self.space + 'return response\n'
|
||||
body += '\n'
|
||||
|
||||
imports += 'from %s import %sResponse\n'%(cmdName, cmdName)
|
||||
initCmdsList += '"%s",'%cmdName
|
||||
imports += 'from %s import %sResponse\n' % (cmdName, cmdName)
|
||||
initCmdsList += '"%s",' % cmdName
|
||||
|
||||
fp = open(self.outputFolder + '/cloudstackAPI/cloudstackAPIClient.py', 'w')
|
||||
fp = open(self.outputFolder + '/cloudstackAPI/cloudstackAPIClient.py',
|
||||
'w')
|
||||
fp.write(self.license)
|
||||
for item in [header, imports, body]:
|
||||
fp.write(item)
|
||||
|
|
@ -224,11 +240,14 @@ class codeGenerator:
|
|||
def constructResponseFromXML(self, response):
|
||||
paramProperty = cmdParameterProperty()
|
||||
paramProperty.name = getText(response.getElementsByTagName('name'))
|
||||
paramProperty.desc = getText(response.getElementsByTagName('description'))
|
||||
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'):
|
||||
argList = response.getElementsByTagName('arguments')[0].\
|
||||
getElementsByTagName('arg')
|
||||
for subresponse in argList:
|
||||
subProperty = self.constructResponseFromXML(subresponse)
|
||||
paramProperty.subProperties.append(subProperty)
|
||||
return paramProperty
|
||||
|
|
@ -248,10 +267,13 @@ class codeGenerator:
|
|||
if async:
|
||||
csCmd.async = async
|
||||
|
||||
for param in cmd.getElementsByTagName("request")[0].getElementsByTagName("arg"):
|
||||
argList = cmd.getElementsByTagName("request")[0].\
|
||||
getElementsByTagName("arg")
|
||||
for param in argList:
|
||||
paramProperty = cmdParameterProperty()
|
||||
|
||||
paramProperty.name = getText(param.getElementsByTagName('name'))
|
||||
paramProperty.name =\
|
||||
getText(param.getElementsByTagName('name'))
|
||||
assert paramProperty.name
|
||||
|
||||
required = param.getElementsByTagName('required')
|
||||
|
|
@ -288,18 +310,19 @@ class codeGenerator:
|
|||
|
||||
def constructResponseFromJSON(self, response):
|
||||
paramProperty = cmdParameterProperty()
|
||||
if response.has_key('name'):
|
||||
if 'name' in response:
|
||||
paramProperty.name = response['name']
|
||||
assert paramProperty.name, "%s has no property name"%response
|
||||
assert paramProperty.name, "%s has no property name" % response
|
||||
|
||||
if response.has_key('description'):
|
||||
if 'description' in response:
|
||||
paramProperty.desc = response['description']
|
||||
if response.has_key('type'):
|
||||
if 'type' in response:
|
||||
if response['type'] in ['list', 'map', 'set']:
|
||||
#Here list becomes a subproperty
|
||||
if response.has_key('response'):
|
||||
if 'response' in response:
|
||||
for innerResponse in response['response']:
|
||||
subProperty = self.constructResponseFromJSON(innerResponse)
|
||||
subProperty =\
|
||||
self.constructResponseFromJSON(innerResponse)
|
||||
paramProperty.subProperties.append(subProperty)
|
||||
paramProperty.type = response['type']
|
||||
return paramProperty
|
||||
|
|
@ -311,45 +334,45 @@ class codeGenerator:
|
|||
jsonOut = apiStream.readlines()
|
||||
assert len(jsonOut) > 0
|
||||
apiDict = json.loads(jsonOut[0])
|
||||
if not apiDict.has_key('listapisresponse'):
|
||||
if not 'listapisresponse' in apiDict:
|
||||
raise Exception("API discovery plugin response failed")
|
||||
if not apiDict['listapisresponse'].has_key('count'):
|
||||
if not 'count' in apiDict['listapisresponse']:
|
||||
raise Exception("Malformed api response")
|
||||
|
||||
apilist = apiDict['listapisresponse']['api']
|
||||
cmds = []
|
||||
for cmd in apilist:
|
||||
csCmd = cloudStackCmd()
|
||||
if cmd.has_key('name'):
|
||||
if 'name' in cmd:
|
||||
csCmd.name = cmd['name']
|
||||
assert csCmd.name
|
||||
|
||||
if cmd.has_key('description'):
|
||||
if 'description' in cmd:
|
||||
csCmd.desc = cmd['description']
|
||||
|
||||
if cmd.has_key('isasync'):
|
||||
if 'isasync' in cmd:
|
||||
csCmd.async = cmd['isasync']
|
||||
|
||||
for param in cmd['params']:
|
||||
paramProperty = cmdParameterProperty()
|
||||
|
||||
if param.has_key('name'):
|
||||
if 'name' in param:
|
||||
paramProperty.name = param['name']
|
||||
assert paramProperty.name
|
||||
|
||||
if param.has_key('required'):
|
||||
if 'required' in param:
|
||||
paramProperty.required = param['required']
|
||||
|
||||
if param.has_key('description'):
|
||||
if 'description' in param:
|
||||
paramProperty.desc = param['description']
|
||||
|
||||
if param.has_key('type'):
|
||||
if 'type' in param:
|
||||
paramProperty.type = param['type']
|
||||
|
||||
csCmd.request.append(paramProperty)
|
||||
|
||||
for response in cmd['response']:
|
||||
#FIXME: ExtractImage related APIs return empty dicts in response
|
||||
#FIXME: ExtractImage related APIs return empty dicts in response
|
||||
if len(response) > 0:
|
||||
paramProperty = self.constructResponseFromJSON(response)
|
||||
csCmd.response.append(paramProperty)
|
||||
|
|
@ -359,7 +382,8 @@ class codeGenerator:
|
|||
|
||||
def generateCodeFromJSON(self, endpointUrl):
|
||||
"""
|
||||
Api Discovery plugin returns the supported APIs of a CloudStack endpoint.
|
||||
Api Discovery plugin returns the supported APIs of a CloudStack
|
||||
endpoint.
|
||||
@return: The classes in cloudstackAPI/ formed from api discovery json
|
||||
"""
|
||||
if endpointUrl.find('response=json') >= 0:
|
||||
|
|
@ -369,30 +393,34 @@ class codeGenerator:
|
|||
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 path to the generated code entities, default is .")
|
||||
help="The path to the generated code entities, 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")
|
||||
help="The path and name of the api spec xml file,\
|
||||
default is /etc/cloud/cli/commands.xml")
|
||||
parser.add_option("-e", "--endpoint", dest="endpoint",
|
||||
help="The endpoint mgmt server (with open 8096) where apis are discovered, default is localhost")
|
||||
help="The endpoint mgmt server (with open 8096) where\
|
||||
apis are discovered, default is localhost")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
folder = "."
|
||||
if options.output is not None:
|
||||
folder = options.output
|
||||
apiModule=folder + "/cloudstackAPI"
|
||||
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 "Failed to create folder %s, due to %s" % (apiModule,
|
||||
sys.exc_info())
|
||||
print parser.print_help()
|
||||
exit(2)
|
||||
|
||||
|
|
@ -400,7 +428,7 @@ if __name__ == "__main__":
|
|||
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 "the spec file %s does not exists" % apiSpecFile
|
||||
print parser.print_help()
|
||||
exit(1)
|
||||
|
||||
|
|
@ -408,5 +436,6 @@ if __name__ == "__main__":
|
|||
if options.spec is not None:
|
||||
cg.generateCodeFromXML(apiSpecFile)
|
||||
elif options.endpoint is not None:
|
||||
endpointUrl='http://%s:8096/client/api?command=listApis&response=json'%options.endpoint
|
||||
endpointUrl = 'http://%s:8096/client/api?command=listApis&\
|
||||
response=json' % options.endpoint
|
||||
cg.generateCodeFromJSON(endpointUrl)
|
||||
|
|
|
|||
Loading…
Reference in New Issue