65ee2ed1e16d20845332bc114d82b02c675d0631
[hc2vpp.git] /
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package io.fd.hc2vpp.docs.scripts
18
19 import groovy.text.SimpleTemplateEngine
20 import io.fd.hc2vpp.docs.api.*
21 import io.fd.hc2vpp.docs.core.ClassPathTypeIndex
22 import io.fd.hc2vpp.docs.core.CoverageGenerator
23 import io.fd.hc2vpp.docs.core.YangTypeLinkIndex
24 import io.fd.vpp.jvpp.acl.future.FutureJVppAcl
25 import io.fd.vpp.jvpp.core.future.FutureJVppCore
26 import io.fd.vpp.jvpp.ioamexport.future.FutureJVppIoamexport
27 import io.fd.vpp.jvpp.ioampot.future.FutureJVppIoampot
28 import io.fd.vpp.jvpp.ioamtrace.future.FutureJVppIoamtrace
29 import io.fd.vpp.jvpp.nsh.future.FutureJVppNsh
30 import io.fd.vpp.jvpp.nat.future.FutureJVppNat
31
32 import java.nio.charset.StandardCharsets
33 import java.nio.file.Files
34 import java.nio.file.Paths
35 import java.nio.file.StandardOpenOption
36 import java.util.stream.Collectors
37
38 import static java.util.stream.Collectors.toList
39
40 /**
41  * Generates VPP api to Yang node index for hc2vpp guice modules listed in api.docs.modules maven property.
42  */
43 class ApiDocsIndexGenerator {
44
45     private static def NL = System.lineSeparator()
46     // TODO - check if list of plugin classes can be generated based on list of modules enabled for doc generation
47     private static
48     def PLUGIN_CLASSES = [FutureJVppCore.class, FutureJVppAcl.class, FutureJVppNat.class, FutureJVppNsh.class,
49                           FutureJVppIoamexport.class, FutureJVppIoampot.class, FutureJVppIoamtrace.class]
50     private static def TABLE_PART_MARK = "|"
51
52     /**
53      * Generate coverage data for all configured coverage.modules and JVpp plugins
54      * */
55     public static void generate(final project, final log) {
56         def loader = this.getClassLoader()
57
58         String moduleNames = project.properties.get("api.docs.modules")
59         String projectRoot = project.properties.get("project.root.folder")
60
61         if (moduleNames.trim().isEmpty()) {
62             log.info "No modules defined for ${project.name}. Skipping api-docs generation."
63             return
64         }
65
66         final List<String> moduleNamesList = moduleNames.split(",")
67
68         log.info "Reading module list for ${project.name}"
69         def modules = moduleNamesList.stream()
70                 .map { moduleName -> moduleName.trim() }
71                 .map { moduleName ->
72             log.info "Loading class $moduleName"
73             loader.loadClass(moduleName).newInstance()
74         }
75         .collect(toList())
76
77         String outPath = project.build.outputDirectory
78
79         log.info "Generating yang type generateLink index"
80         YangTypeLinkIndex yangTypeIndex = new YangTypeLinkIndex(projectRoot)
81         log.info "Classpath type generateLink index"
82         ClassPathTypeIndex classPathIndex = new ClassPathTypeIndex(projectRoot)
83
84         log.info "Generating VPP API to YANG mapping"
85         PLUGIN_CLASSES.stream()
86                 .forEach { pluginClass ->
87             log.info "Generating mapping for ${pluginClass}"
88             final PluginCoverage configCoverage = new CoverageGenerator()
89                     .generateConfigCoverage(pluginClass, modules, yangTypeIndex, classPathIndex)
90             generateJvppCoverageDoc(configCoverage, outPath, log)
91
92             //TODO operational coverage
93         }
94     }
95
96     static void generateJvppCoverageDoc(
97             final PluginCoverage pluginCoverage, final String outPath, final log) {
98         if (!pluginCoverage.hasCoverage()) {
99             log.info "Plugin ${pluginCoverage.getPluginName()} does not have coverage data, skipping config docs generation"
100             return
101         }
102         log.info "Generating config api docs for plugin ${pluginCoverage.getPluginName()}"
103         def template = this.getClassLoader().getResource("yang_to_jvpp_template")
104         def result = new SimpleTemplateEngine()
105                 .createTemplate(template)
106                 .make(["pluginName": pluginCoverage.getPluginName(), "tableContent": generateConfigTableContent(pluginCoverage.getCoverage())]).toString()
107
108         log.debug "Docs result for ${pluginCoverage.getPluginName()}$NL$result"
109
110         Paths.get(outPath).toFile().mkdirs()
111
112         def outFileName
113         if (pluginCoverage.isConfig()) {
114             outFileName = "${normalizePluginName(pluginCoverage.getPluginName())}-yang-config-index.adoc"
115         } else {
116             outFileName = "${normalizePluginName(pluginCoverage.getPluginName())}-yang-operational-index.adoc"
117         }
118
119         def outFilePath = Paths.get(outPath, outFileName)
120
121         Files.write(outFilePath, result.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE)
122         log.info "Plugin ${pluginCoverage.getPluginName()} config api docs sucessfully writen to ${outFilePath.toString()}"
123     }
124
125     private static String generateConfigTableContent(final Set<CoverageUnit> coverage) {
126         coverage.stream().sorted()
127                 .map { unit ->
128             "$NL" +
129                     "${vppApiWithLink(unit.vppApi)}" +
130                     "${javaApi(unit.javaApi)}" +
131                     "${yangTypes(unit.yangTypes)}" +
132                     "${supportedOperations(unit.supportedOperations)}"
133         }
134         .collect(Collectors.joining(NL))
135     }
136
137     private static String vppApiWithLink(final VppApiMessage vppApi) {
138         "$TABLE_PART_MARK${vppApi.link}[${vppApi.name}]$NL"
139     }
140
141     private static String javaApi(final JavaApiMessage javaApi) {
142         "$TABLE_PART_MARK${javaApi.name}$NL"
143     }
144
145     private static String yangTypes(final List<YangType> yangTypes) {
146         "$NL$TABLE_PART_MARK$NL ${yangTypes.stream().map { yangType -> " ${yangType.link}[${yangType.type}]" }.collect(Collectors.joining(NL))}"
147     }
148
149     private static String supportedOperations(final Collection<Operation> operations) {
150         "$NL$TABLE_PART_MARK${operations.stream().map { reference -> " ${reference.link}[${reference.operation}]" }.collect(Collectors.joining(NL))}"
151     }
152
153     private static String normalizePluginName(final String name) {
154         name.toLowerCase().replace(" ", "-")
155     }
156 }