tools/apidoc/gen_toc.py (350 lines of code) (raw):

#!/cygdrive/c/Python27 # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # 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 # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os.path import sys from xml.dom import minidom from xml.parsers.expat import ExpatError import difflib ROOT_ADMIN = 'r' user_to_func = { ROOT_ADMIN: 'populateForApi', } user_to_cns = { ROOT_ADMIN: 'allCommandNames', } dirname_to_user = { 'apis': ROOT_ADMIN, } dirname_to_dirname = { 'apis': 'apis', } known_categories = { 'Cisco' : 'External Device', 'SystemVm': 'System VM', 'VirtualMachine': 'Virtual Machine', 'VM': 'Virtual Machine', 'Vnf': 'Virtual Network Functions', 'VnfTemplate': 'Virtual Network Functions', 'GuestSubnet': 'Routing', 'HypervisorGuestOsNames': 'Guest OS', 'Domain': 'Domain', 'Template': 'Template', 'Iso': 'ISO', 'Volume': 'Volume', 'Vlan': 'VLAN', 'IpAddress': 'Address', 'PortForwarding': 'Firewall', 'Firewall': 'Firewall', 'StaticNat': 'NAT', 'IpForwarding': 'NAT', 'Host': 'Host', 'HostTags': 'Host', 'OutOfBandManagement': 'Out-of-band Management', 'Cluster': 'Cluster', 'Account': 'Account', 'Role': 'Role', 'Snapshot': 'Snapshot', 'User': 'User', 'UserData': 'User Data', 'Os': 'Guest OS', 'ServiceOffering': 'Service Offering', 'DiskOffering': 'Disk Offering', 'LoadBalancer': 'Load Balancer', 'SslCert': 'SSL Certificates', 'Router': 'Router', 'Configuration': 'Configuration', 'Capabilities': 'Configuration', 'Pod': 'Pod', 'ManagementNetworkIpRange': 'Pod', 'PublicIpRange': 'Network', 'Zone': 'Zone', 'Vmware' : 'Zone', 'NetworkOffering': 'Network Offering', 'NetworkACL': 'Network ACL', 'NetworkAclItem': 'Network ACL', 'Network': 'Network', 'CiscoNexus': 'Network', 'OpenDaylight': 'Network', 'createServiceInstance': 'Network', 'addGloboDnsHost': 'Network', 'TungstenFabric': 'Tungsten', 'listNsxControllers': 'NSX', 'addNsxController': 'NSX', 'deleteNsxController': 'NSX', 'Vpn': 'VPN', 'Limit': 'Resource Limit', 'Netscaler': 'Netscaler', 'NetscalerControlCenter': 'Netscaler', 'NetscalerLoadBalancer': 'Netscaler', 'SolidFire': 'SolidFire', 'PaloAlto': 'Palo Alto', 'ResourceCount': 'Limit', 'CloudIdentifier': 'Cloud Identifier', 'InstanceGroup': 'VM Group', 'StorageMaintenance': 'Storage Pool', 'StoragePool': 'Storage Pool', 'StorageProvider': 'Storage Pool', 'StorageScope' : 'Storage Pool', 'updateStorageCapabilities' : 'Storage Pool', 'SecurityGroup': 'Security Group', 'SSH': 'SSH', 'AsyncJob': 'Async job', 'Certificate': 'Certificate', 'Hypervisor': 'Configuration', 'Alert': 'Alert', 'Event': 'Event', 'login': 'Authentication', 'logout': 'Authentication', 'saml': 'Authentication', 'getSPMetadata': 'Authentication', 'listIdps': 'Authentication', 'authorizeSamlSso': 'Authentication', 'listSamlAuthorization': 'Authentication', 'oauthlogin': 'Authentication', 'deleteOauthProvider': 'Oauth', 'listOauthProvider': 'Oauth', 'registerOauthProvider': 'Oauth', 'updateOauthProvider': 'Oauth', 'quota': 'Quota', 'emailTemplate': 'Quota', 'Capacity': 'System Capacity', 'NetworkDevice': 'Network Device', 'ExternalLoadBalancer': 'Ext Load Balancer', 'ExternalFirewall': 'Ext Firewall', 'Usage': 'Usage', 'TrafficMonitor': 'Network', 'TrafficType': 'Network', 'Product': 'Product', 'LB': 'Load Balancer', 'ldap': 'LDAP', 'Ldap': 'LDAP', 'Swift': 'Image Store', 'S3' : 'S3', 'SecondaryStorage': 'Image Store', 'Project': 'Project', 'Lun': 'Storage', 'Pool': 'Pool', 'VPC': 'VPC', 'VPCOffering': 'VPC Offering', 'PrivateGateway': 'VPC', 'migrateVpc': 'VPC', 'Simulator': 'simulator', 'StaticRoute': 'VPC', 'Tags': 'Resource tags', 'Icon': 'Resource Icon', 'NiciraNvpDevice': 'Nicira NVP', 'BrocadeVcsDevice': 'Brocade VCS', 'BigSwitchBcfDevice': 'BigSwitch BCF', 'AutoScale': 'AutoScale', 'Counter': 'AutoScale', 'Condition': 'AutoScale', 'Api': 'API Discovery', 'ApiLimit': 'Configuration', 'Region': 'Region', 'Detail': 'Resource metadata', 'addIpToNic': 'Nic', 'removeIpFromNic': 'Nic', 'updateVmNicIp': 'Nic', 'listNics':'Nic', 'AffinityGroup': 'Affinity Group', 'ImageStore': 'Image Store', 'addImageStore': 'Image Store', 'listImageStore': 'Image Store', 'deleteImageStore': 'Image Store', 'createSecondaryStagingStore': 'Image Store', 'deleteSecondaryStagingStore': 'Image Store', 'listSecondaryStagingStores': 'Image Store', 'updateImageStore': 'Image Store', 'downloadImageStoreObject': 'Image Store', 'InternalLoadBalancer': 'Internal LB', 'DeploymentPlanners': 'Configuration', 'ObjectStore': 'Image Store', 'PortableIp': 'Portable IP', 'dedicateHost': 'Dedicate Resources', 'releaseDedicatedHost': 'Dedicate Resources', 'Baremetal' : 'Baremetal', 'UCS' : 'UCS', 'Ucs' : 'UCS', 'CacheStores' : 'Cache Stores', 'CacheStore' : 'Cache Store', 'OvsElement' : 'Ovs Element', 'StratosphereSsp' : 'Misc Network Service Providers', 'Metrics' : 'Metrics', 'listClustersMetrics': 'Cluster', 'VpnUser': 'VPN', 'listZonesMetrics': 'Metrics', 'Infrastructure' : 'Metrics', 'listRegisteredServicePackages': 'Load Balancer', 'listNsVpx' : 'Load Balancer', 'destroyNsVPx': 'Load Balancer', 'deployNetscalerVpx' : 'Load Balancer', 'stopNetScalerVpx' : 'Load Balancer', 'deleteServicePackageOffering' : 'Load Balancer', 'destroyNsVpx' : 'Load Balancer', 'startNsVpx' : 'Load Balancer', 'listAnnotations' : 'Annotations', 'addAnnotation' : 'Annotations', 'removeAnnotation' : 'Annotations', 'updateAnnotationVisibility' : 'Annotations', 'CA': 'Certificate', 'listElastistorInterface': 'Misc', 'cloudian': 'Cloudian', 'Sioc' : 'Sioc', 'Diagnostics': 'Diagnostics', 'Management': 'Management', 'Backup' : 'Backup and Recovery', 'Restore' : 'Backup and Recovery', 'UnmanagedInstance': 'Virtual Machine', 'KubernetesSupportedVersion': 'Kubernetes Service', 'KubernetesCluster': 'Kubernetes Service', 'Rolling': 'Rolling Maintenance', 'importVsphereStoragePolicies' : 'vSphere storage policies', 'listVsphereStoragePolicies' : 'vSphere storage policies', 'ConsoleEndpoint': 'Console Endpoint', 'importVm': 'Virtual Machine', 'revertToVMSnapshot': 'Virtual Machine', 'listQuarantinedIp': 'IP Quarantine', 'updateQuarantinedIp': 'IP Quarantine', 'removeQuarantinedIp': 'IP Quarantine', 'Shutdown': 'Maintenance', 'Maintenance': 'Maintenance', 'addObjectStoragePool': 'Object Store', 'listObjectStoragePools': 'Object Store', 'deleteObjectStoragePool': 'Object Store', 'updateObjectStoragePool': 'Object Store', 'createBucket': 'Object Store', 'updateBucket': 'Object Store', 'deleteBucket': 'Object Store', 'listBuckets': 'Object Store', 'listVmsForImport': 'Virtual Machine', 'SharedFS': 'Shared FileSystem', 'SharedFileSystem': 'Shared FileSystem', 'Webhook': 'Webhook', 'Webhooks': 'Webhook', 'purgeExpungedResources': 'Resource', 'forgotPassword': 'Authentication', 'resetPassword': 'Authentication', 'BgpPeer': 'BGP Peer', 'createASNRange': 'AS Number Range', 'listASNRange': 'AS Number Range', 'deleteASNRange': 'AS Number Range', 'listASNumbers': 'AS Number', 'releaseASNumber': 'AS Number', } categories = {} def choose_category(fn): possible_known_categories = [] for k, v in known_categories.items(): if k in fn: possible_known_categories.append(k) if len(possible_known_categories) > 0: close_matches = difflib.get_close_matches(fn, possible_known_categories, n=1, cutoff=0.1) if len(close_matches) > 0: return known_categories[close_matches[0]] else: return known_categories[possible_known_categories[0]] raise Exception('Need to add a category for %s to %s:known_categories' % (fn, __file__)) for f in sys.argv: dirname, fn = os.path.split(f) if not fn.endswith('.xml'): continue if fn.endswith('Summary.xml') and fn != 'quotaSummary.xml': continue if fn.endswith('SummarySorted.xml'): continue if fn == 'alert_types.xml': continue if dirname.startswith('./'): dirname = dirname[2:] try: with open(f) as data: dom = minidom.parse(data) name = dom.getElementsByTagName('name')[0].firstChild.data isAsync = dom.getElementsByTagName('isAsync')[0].firstChild.data isDeprecated = dom.getElementsByTagName('isDeprecated')[0].firstChild.data category = choose_category(fn) if category not in categories: categories[category] = [] categories[category].append({ 'name': name, 'dirname': dirname_to_dirname[dirname], 'async': isAsync == 'true', 'deprecated': isDeprecated == 'true', 'user': dirname_to_user[dirname], }) except ExpatError as e: pass except IndexError as e: print(fn) def xml_for(command): name = command['name'] isAsync = command['async'] and ' (A)' or '' isDeprecated = command['deprecated'] and ' (D)' or '' dirname = command['dirname'] return '''<xsl:if test="name=\'%(name)s\'"> <li><a href="%(dirname)s/%(name)s.html"><xsl:value-of select="name"/>%(isAsync)s %(isDeprecated)s</a></li> </xsl:if> ''' % locals() def write_xml(out, user): with open(out, 'w') as f: cat_strings = [] for category in categories.keys(): strings = [] for command in categories[category]: if command['user'] == user: strings.append(xml_for(command)) if strings: all_strings = ''.join(strings) cat_strings.append((len(strings), category, all_strings)) cat_strings.sort(reverse=True) i = 0 for _1, category, all_strings in cat_strings: if i == 0: f.write('<div class="apismallsections">\n') f.write('''<div class="apismallbullet_box"> <h5>%(category)s</h5> <ul> <xsl:for-each select="commands/command"> %(all_strings)s </xsl:for-each> </ul> </div> ''' % locals()) if i == 3: f.write('</div>\n') i = 0 else: i += 1 if i != 0: f.write('</div>\n') def java_for(command, user): name = command['name'] cns = user_to_cns[user] return '''%(cns)s.add("%(name)s"); ''' % locals() def java_for_user(user): strings = [] for category in categories.keys(): for command in categories[category]: if command['user'] == user: strings.append(java_for(command, user)) func = user_to_func[user] all_strings = ''.join(strings) return ''' public void %(func)s() { %(all_strings)s } ''' % locals() def write_java(out): with open(out, 'w') as f: f.write('''/* Generated using gen_toc.py. Do not edit. */ import java.util.HashSet; import java.util.Set; public class XmlToHtmlConverterData { Set<String> allCommandNames = new HashSet<String>(); ''') f.write(java_for_user(ROOT_ADMIN) + "\n") f.write(''' } ''') write_xml('generatetoc_include.xsl', ROOT_ADMIN) write_java('XmlToHtmlConverterData.java')