2 * Copyright (c) 2017 Cisco and/or its affiliates.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package io.fd.hc2vpp.docs.scripts
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
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
38 import static java.util.stream.Collectors.toList
41 * Generates VPP api to Yang node index for hc2vpp guice modules listed in api.docs.modules maven property.
43 class ApiDocsIndexGenerator {
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
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 = "|"
53 * Generate coverage data for all configured coverage.modules and JVpp plugins
55 public static void generate(final project, final log) {
56 def loader = this.getClassLoader()
58 String moduleNames = project.properties.get("api.docs.modules")
59 String projectRoot = project.properties.get("project.root.folder")
61 if (moduleNames.trim().isEmpty()) {
62 log.info "No modules defined for ${project.name}. Skipping api-docs generation."
66 final List<String> moduleNamesList = moduleNames.split(",")
68 log.info "Reading module list for ${project.name}"
69 def modules = moduleNamesList.stream()
70 .map { moduleName -> moduleName.trim() }
72 log.info "Loading class $moduleName"
73 loader.loadClass(moduleName).newInstance()
77 String outPath = project.build.outputDirectory
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)
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)
92 //TODO operational coverage
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"
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()
108 log.debug "Docs result for ${pluginCoverage.getPluginName()}$NL$result"
110 Paths.get(outPath).toFile().mkdirs()
113 if (pluginCoverage.isConfig()) {
114 outFileName = "${normalizePluginName(pluginCoverage.getPluginName())}-yang-config-index.adoc"
116 outFileName = "${normalizePluginName(pluginCoverage.getPluginName())}-yang-operational-index.adoc"
119 def outFilePath = Paths.get(outPath, outFileName)
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()}"
125 private static String generateConfigTableContent(final Set<CoverageUnit> coverage) {
126 coverage.stream().sorted()
129 "${vppApiWithLink(unit.vppApi)}" +
130 "${javaApi(unit.javaApi)}" +
131 "${yangTypes(unit.yangTypes)}" +
132 "${supportedOperations(unit.supportedOperations)}"
134 .collect(Collectors.joining(NL))
137 private static String vppApiWithLink(final VppApiMessage vppApi) {
138 "$TABLE_PART_MARK${vppApi.link}[${vppApi.name}]$NL"
141 private static String javaApi(final JavaApiMessage javaApi) {
142 "$TABLE_PART_MARK${javaApi.name}$NL"
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))}"
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))}"
153 private static String normalizePluginName(final String name) {
154 name.toLowerCase().replace(" ", "-")