diff --git a/tools/marvin/marvin/cs_entity_generator.py b/tools/marvin/marvin/cs_entity_generator.py index f0c5fb8b866..3b3f85abb4c 100644 --- a/tools/marvin/marvin/cs_entity_generator.py +++ b/tools/marvin/marvin/cs_entity_generator.py @@ -83,35 +83,64 @@ def singularize(word, num=0): return inflector.singular_noun(word) -def transform_entity(entity): - if entity == 'DefaultZoneForAccount': - #markDefaultZoneForAccount -> Zone - return 'Zone' - elif entity in ['ToGlobalLoadBalancerRule', 'FromGlobalLoadBalancerRule']: - return 'GlobalLoadBalancerRule' - elif entity in ['AccountToProject', 'AccountFromProject']: - return 'Project' - elif entity in ['ToSnapshot']: - return 'Snapshot' - return entity +def transform_api(api): + """Brute-force transform for entities that don't match other transform rules + """ + + if api == 'markDefaultZoneForAccount': + #markDefaultZoneForAccount -> Account.markDefaultZone + return 'markDefaultZone', 'Account' + return api, None + + +def prepositon_transformer(preposition=None): + """Returns a transformer for the entity if it has a doXPrepositionY style API + + @param entity: The entity eg: resetPasswordForVirtualMachine, preposition=For + @return: transformed entity, Y is the entity and doX is the verb, eg: VirtualMachine, resetPassword + """ + def transform_api(api): + if api.find(preposition) > 0: + if api[api.find(preposition) + len(preposition)].isupper(): + return api[:api.find(preposition)], api[api.find(preposition) + len(preposition):] + return api, None + return transform_api def skip_list(): - """Entities and APIs that we will not auto-generate + """APIs that we will not auto-generate """ return ['ldapConfigCmd', 'ldapRemoveCmd'] +def get_transformers(): + """ List of transform rules as lambdas + """ + transformers = [prepositon_transformer('Of'), + prepositon_transformer('For'), + prepositon_transformer('To'), + prepositon_transformer('From'), + transform_api] + return transformers + + def get_verb_and_entity(cmd): """Break down the API cmd instance in to `verb` and `Entity` @return: verb, Entity tuple """ api = cmd.__class__.__name__ + #apply known list of transformations + for transformer in get_transformers(): + api = api.replace('Cmd', '') + if transformer(api)[0] != api: + print "Transforming using %s, %s -> %s" % (transformer.__name__, api, transformer(api)) + return transformer(api)[0], \ + singularize(transformer(api)[1]) if singularize(transformer(api)[1]) else transformer(api)[1] + matching_verbs = filter(lambda v: api.startswith(v), grammar) if len(matching_verbs) > 0: verb = matching_verbs[0] entity = api.replace(verb, '').replace('Cmd', '') - entity = transform_entity(entity) return verb, singularize(entity) if singularize(entity) else entity else: print "No matching verb, entity breakdown for api %s" % api @@ -168,7 +197,7 @@ def write_entity_classes(entities, module=None): if action not in ['create', 'deploy']: if len(details['args']) > 0: body.append(tabspace + 'def %s(self, apiclient, %s, **kwargs):' % ( - action, ', '.join(list(set(details['args']))))) + action, ', '.join(list(set(details['args']))))) else: body.append(tabspace + 'def %s(self, apiclient, **kwargs):' % (action)) body.append(tabspace * 2 + 'cmd = %(module)s.%(command)s()' % {"module": details["apimodule"], @@ -182,7 +211,7 @@ def write_entity_classes(entities, module=None): if action in ['list']: body.append( tabspace * 2 + 'return map(lambda e: %s(e.__dict__), %s) if %s and len(%s) > 0 else None' % ( - entity, entity.lower(), entity.lower(), entity.lower())) + entity, entity.lower(), entity.lower(), entity.lower())) else: body.append(tabspace * 2 + 'return %s if %s else None' % (entity.lower(), entity.lower())) else: @@ -191,7 +220,7 @@ def write_entity_classes(entities, module=None): action, ', '.join(map(lambda arg: arg + '=None', list(set(details['args'])))))) else: body.append(tabspace + 'def %s(cls, apiclient, factory=None, **kwargs):' % action) - #TODO: Add docs for actions + #TODO: Add docs for actions body.append(tabspace * 2 + 'cmd = %(module)s.%(command)s()' % {"module": details["apimodule"], "command": details["apicmd"]}) body.append(tabspace * 2 + 'if factory:') @@ -202,7 +231,8 @@ def write_entity_classes(entities, module=None): body.append(tabspace * 3 + "cmd.%s = %s" % (arg, arg)) body.append(tabspace * 2 + '[setattr(cmd, key, value) for key, value in kwargs.iteritems()]') body.append(tabspace * 2 + '%s = apiclient.%s(cmd)' % (entity.lower(), details['apimodule'])) - body.append(tabspace * 2 + 'return %s(%s.__dict__) if %s else None' % (entity, entity.lower(), entity.lower())) + body.append( + tabspace * 2 + 'return %s(%s.__dict__) if %s else None' % (entity, entity.lower(), entity.lower())) body.append('\n') imports = '\n'.join(imports) @@ -214,7 +244,7 @@ def write_entity_classes(entities, module=None): if module.find('.') > 0: module_path = '/'.join(module.split('.'))[1:] else: - module_path = '/'+module + module_path = '/' + module if not os.path.exists(".%s" % module_path): os.mkdir(".%s" % module_path) with open(".%s/%s.py" % (module_path, entity), "w") as writer: @@ -223,6 +253,9 @@ def write_entity_classes(entities, module=None): def write_entity_factory(entity, actions): + """Data factories for each entity + """ + tabspace = ' ' code = '' factory_defaults = []