2c6b24f42b2e0718a3ccc14b248b34e07c543e50
[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.jvpp.acl.future.FutureJVppAcl
25 import io.fd.jvpp.core.future.FutureJVppCore
26 import io.fd.jvpp.ioamexport.future.FutureJVppIoamexport
27 import io.fd.jvpp.ioampot.future.FutureJVppIoampot
28 import io.fd.jvpp.ioamtrace.future.FutureJVppIoamtrace
29 import io.fd.jvpp.nat.future.FutureJVppNat
30 import io.fd.jvpp.nsh.future.FutureJVppNsh
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 }