1 /* <lambda>null2 * Copyright (C) 2017 The Android Open Source Project 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 writer.files 18 19 import parser.LOG_NAME 20 import parser.config 21 import parser.files.AbstractFileParser 22 import parser.files.InterfaceFileParser 23 import writer.getDescSummaryText 24 import writer.getOutPath 25 import java.io.File 26 import java.nio.file.Path 27 import java.nio.file.Paths 28 29 data class EntryData(val fullName: String, //package.BaseName 30 val baseName: String, 31 val packageName: String, 32 val packageVersion: Float, 33 val summary: String, 34 val relPath: Path) 35 36 class IndexFileWriter : AbstractFileWriter() { 37 38 override val baseName = "index" 39 override val templateResource = "/resources/template/${this.baseName}.html" 40 override val path: Path by lazy { Paths.get("${config.outDir}${File.separator}${this.baseName}.html") } 41 42 private val entries = mutableListOf<EntryData>() 43 44 fun addEntry(parser: AbstractFileParser) { 45 val summaryStr = when (parser) { 46 is InterfaceFileParser -> getDescSummaryText(parser.description) 47 else -> "" 48 } 49 entries.add(EntryData( 50 fullName = "${parser.packageName}.${parser.name}", 51 baseName = parser.name, 52 packageName = parser.packageName, 53 packageVersion = parser.packageVersion, 54 summary = summaryStr, 55 relPath = config.outDir.relativize(getOutPath(parser, config.outDir)) 56 )) 57 } 58 59 override fun printInfo() { 60 super.printInfo() 61 println( "IndexFileWriter:") 62 println(" entries: ${this.entries.size}") 63 } 64 65 /* 66 * HTML index file 67 */ 68 69 override fun replaceVars() { 70 replaceVar("title", "Index") 71 72 replaceVar("entries") { 73 val sb = StringBuilder() 74 if (entries.isNotEmpty()) { 75 entries.sortWith(EntryNameComparator()) 76 sb.append(buildEntryTable()) 77 } 78 sb.toString() 79 } 80 } 81 82 private fun buildEntryTable(): String { 83 return """ 84 <table> 85 <tr> 86 <th>Entry</th> 87 <th>Version</th> 88 <th>Summary</th> 89 </tr> 90 ${entries.map { buildClassEntry(it) }.joinToString("\n")} 91 </table> 92 """.trim() 93 } 94 95 private fun buildClassEntry(entry: EntryData): String { 96 return """ 97 <tr> 98 <td> 99 <a href="${entry.relPath}">${entry.fullName}</a> 100 </td> 101 <td> 102 ${entry.packageVersion} 103 </td> 104 <td> 105 ${entry.summary} 106 </td> 107 </tr> 108 """.trim() 109 } 110 111 private class EntryNameComparator : Comparator<EntryData> { 112 override fun compare(entry1: EntryData, entry2: EntryData): Int { 113 return if (entry1.fullName != entry2.fullName) { 114 //sort on name first, alphabetic 115 when { 116 entry1.fullName < entry2.fullName -> -1 117 entry1.fullName > entry2.fullName -> 1 118 else -> 0 119 } 120 } else { 121 //if same name, reverse sort on pkg version (highest first) 122 when { 123 entry1.packageVersion < entry2.packageVersion -> 1 124 entry1.packageVersion > entry2.packageVersion -> -1 125 else -> 0 126 } 127 } 128 } 129 } 130 131 /* 132 * YAML toc file 133 */ 134 135 private val tocFileName = "_book.yaml" 136 private val tocFileRelPath = "/reference/hidl" 137 private val tocOutPath: Path by lazy { Paths.get("${config.outDir}${File.separator}${this.tocFileName}") } 138 139 //write toc yaml file after html index 140 override fun onWrite() { 141 super.onWrite() 142 if (!config.lintMode) { 143 val fp = tocOutPath.toFile() 144 fp.bufferedWriter().use { 145 it.write(buildTocHeader()) 146 it.write(buildTocEntries(collectPackages())) 147 } 148 if (!fp.isFile) throw FileSystemException(fp, reason = "Error writing file") 149 println("$LOG_NAME Wrote toc: $tocOutPath") 150 } 151 } 152 153 private fun buildTocHeader(): String { 154 return """ 155 # Generated by hidl-doc 156 toc: 157 - title: Index 158 path: $tocFileRelPath 159 """.trimStart() 160 } 161 162 private fun buildTocEntries(pkgEntries: Map<String, List<EntryData>>): String { 163 val sb = StringBuilder() 164 165 for ((pkgName, entryList) in pkgEntries) { 166 sb.append("- title: $pkgName\n section:\n") 167 168 entryList.forEach { entry -> 169 sb.append(" - title: ${entry.baseName} @${entry.packageVersion}\n") 170 sb.append(" path: ${tocFileRelPath}/${entry.relPath}\n") 171 } 172 } 173 return sb.toString() 174 } 175 176 private fun collectPackages(): Map<String, List<EntryData>> { 177 val pkgEntries = mutableMapOf<String, MutableList<EntryData>>() 178 179 this.entries.forEach { entry -> 180 if (pkgEntries.containsKey(entry.packageName)) { 181 pkgEntries[entry.packageName]!!.add(entry) 182 } else { 183 pkgEntries[entry.packageName] = mutableListOf(entry) 184 } 185 } 186 //sort on package name. entries *should* already be sorted 187 return pkgEntries.toSortedMap() 188 } 189 }