From 0783f6fbe2104334195964bbc91cb584cbbab4e0 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 15 Jan 2015 14:59:50 +0100 Subject: Ant task for Dokka --- .idea/ant.xml | 6 ++ .idea/artifacts/dokka_jar.xml | 4 +- .idea/libraries/ant_1_9_4.xml | 9 ++ .idea/modules.xml | 4 +- ant/ant.iml | 14 +++ ant/src/dokka-antlib.xml | 3 + ant/src/dokka.kt | 85 ++++++++++++++++ build.xml | 9 ++ lib/ant-1.9.4.jar | Bin 0 -> 2019274 bytes src/Kotlin/DocumentationBuilder.kt | 4 +- src/main.kt | 203 +++++++++++++++++++++++-------------- test/src/TestAPI.kt | 2 +- 12 files changed, 259 insertions(+), 84 deletions(-) create mode 100644 .idea/ant.xml create mode 100644 .idea/libraries/ant_1_9_4.xml create mode 100644 ant/ant.iml create mode 100644 ant/src/dokka-antlib.xml create mode 100644 ant/src/dokka.kt create mode 100644 build.xml create mode 100644 lib/ant-1.9.4.jar diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 00000000..a2a47698 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/artifacts/dokka_jar.xml b/.idea/artifacts/dokka_jar.xml index 9aba0ca1..fd03fd07 100644 --- a/.idea/artifacts/dokka_jar.xml +++ b/.idea/artifacts/dokka_jar.xml @@ -5,8 +5,8 @@ - - + + \ No newline at end of file diff --git a/.idea/libraries/ant_1_9_4.xml b/.idea/libraries/ant_1_9_4.xml new file mode 100644 index 00000000..f68d9a6b --- /dev/null +++ b/.idea/libraries/ant_1_9_4.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 142d525a..bfcf8757 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,8 +2,8 @@ + - - + \ No newline at end of file diff --git a/ant/ant.iml b/ant/ant.iml new file mode 100644 index 00000000..0761035c --- /dev/null +++ b/ant/ant.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ant/src/dokka-antlib.xml b/ant/src/dokka-antlib.xml new file mode 100644 index 00000000..9c3373d5 --- /dev/null +++ b/ant/src/dokka-antlib.xml @@ -0,0 +1,3 @@ + + + diff --git a/ant/src/dokka.kt b/ant/src/dokka.kt new file mode 100644 index 00000000..9510f78b --- /dev/null +++ b/ant/src/dokka.kt @@ -0,0 +1,85 @@ +package org.jetbrains.dokka.ant + +import org.apache.tools.ant.Task +import org.apache.tools.ant.types.Path +import org.apache.tools.ant.types.Reference +import org.apache.tools.ant.BuildException +import org.apache.tools.ant.Project +import org.jetbrains.dokka.DokkaLogger +import org.jetbrains.dokka.DokkaGenerator + +class AntLogger(val task: Task): DokkaLogger { + override fun info(message: String) = task.log(message, Project.MSG_INFO) + override fun warn(message: String) = task.log(message, Project.MSG_WARN) + override fun error(message: String) = task.log(message, Project.MSG_ERR) +} + +class DokkaAntTask(): Task() { + public var moduleName: String? = null + public var outputDir: String? = null + public var outputFormat: String = "html" + + public val compileClasspath: Path = Path(getProject()) + public val sourcePath: Path = Path(getProject()) + public val samplesPath: Path = Path(getProject()) + public val includesPath: Path = Path(getProject()) + + public fun setClasspath(classpath: Path) { + compileClasspath.append(classpath) + } + + public fun setClasspathRef(ref: Reference) { + compileClasspath.createPath().setRefid(ref) + } + + public fun setSrc(src: Path) { + log("setSrc($src)") + sourcePath.append(src) + log("sourcePath=${sourcePath.list().join(",")}") + } + + public fun setSrcRef(ref: Reference) { + sourcePath.createPath().setRefid(ref) + } + + public fun setSamples(samples: Path) { + samplesPath.append(samples) + } + + public fun setSamplesRef(ref: Reference) { + samplesPath.createPath().setRefid(ref) + } + + public fun setInclude(include: Path) { + includesPath.append(include) + } + + override fun execute() { + if (sourcePath.list().size() == 0) { + throw BuildException("At least one source path needs to be specified") + } + if (moduleName == null) { + throw BuildException("Module name needs to be specified") + } + if (outputDir == null) { + throw BuildException("Output directory needs to be specified") + } + + val url = javaClass().getResource("/org/jetbrains/dokka/ant/DokkaAntTask.class") + val jarRoot = url.getPath().substringBefore("!/").trimLeading("file:") + log(jarRoot) + + val generator = DokkaGenerator( + AntLogger(this), + listOf(jarRoot) + compileClasspath.list().toList(), + sourcePath.list().toList(), + samplesPath.list().toList(), + includesPath.list().toList(), + moduleName!!, + outputDir!!, + outputFormat, + listOf() + ) + generator.generate() + } +} \ No newline at end of file diff --git a/build.xml b/build.xml new file mode 100644 index 00000000..81a4dea9 --- /dev/null +++ b/build.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/lib/ant-1.9.4.jar b/lib/ant-1.9.4.jar new file mode 100644 index 00000000..24641e74 Binary files /dev/null and b/lib/ant-1.9.4.jar differ diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt index c0533437..976626db 100644 --- a/src/Kotlin/DocumentationBuilder.kt +++ b/src/Kotlin/DocumentationBuilder.kt @@ -32,7 +32,7 @@ private fun isSamePackage(descriptor1: DeclarationDescriptor, descriptor2: Decla return package1 != null && package2 != null && package1.fqName == package2.fqName } -class DocumentationBuilder(val session: ResolveSession, val options: DocumentationOptions) { +class DocumentationBuilder(val session: ResolveSession, val options: DocumentationOptions, val logger: DokkaLogger) { val visibleToDocumentation = setOf(Visibilities.INTERNAL, Visibilities.PROTECTED, Visibilities.PUBLIC) val descriptorToNode = hashMapOf() val nodeToDescriptor = hashMapOf() @@ -246,7 +246,7 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati descriptors.put(name.asString(), parts.flatMap { it.getMemberScope().getAllDescriptors() }) } for ((packageName, declarations) in descriptors) { - println(" package $packageName: ${declarations.count()} declarations") + logger.info(" package $packageName: ${declarations.count()} declarations") val packageNode = DocumentationNode(packageName, Content.Empty, Kind.Package) val externalClassNodes = hashMapOf() declarations.forEach { descriptor -> diff --git a/src/main.kt b/src/main.kt index 9ebe0b1e..63725942 100644 --- a/src/main.kt +++ b/src/main.kt @@ -68,95 +68,144 @@ public fun main(args: Array) { listOf() } - val environment = AnalysisEnvironment(MessageCollectorPlainTextToStream.PLAIN_TEXT_TO_SYSTEM_ERR) { - addClasspath(PathUtil.getJdkClassesRoots()) - // addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath()) - for (element in arguments.classpath.split(File.pathSeparatorChar)) { - addClasspath(File(element)) - } - - addSources(sources) - addSources(samples) - } - - println("Module: ${arguments.moduleName}") - println("Output: ${arguments.outputDir}") - println("Sources: ${environment.sources.join()}") - println("Classpath: ${environment.classpath.joinToString()}") + val classPath = arguments.classpath.split(File.pathSeparatorChar).toList() + val generator = DokkaGenerator( + DokkaConsoleLogger, + classPath, + sources, + samples, + includes, + arguments.moduleName, + arguments.outputDir, + arguments.outputFormat, + sourceLinks) + + generator.generate() +} - println() +trait DokkaLogger { + fun info(message: String) + fun warn(message: String) + fun error(message: String) +} - println("Analysing sources and libraries... ") - val startAnalyse = System.currentTimeMillis() +object DokkaConsoleLogger: DokkaLogger { + override fun info(message: String) = println(message) + override fun warn(message: String) = println("WARN: $message") + override fun error(message: String) = println("ERROR: $message") +} +class DokkaMessageCollector(val logger: DokkaLogger): MessageCollector { + override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) { + logger.error(MessageRenderer.PLAIN_FULL_PATHS.render(severity, message, location)) + } +} - val documentation = environment.withContext { environment, session -> - val fragmentFiles = environment.getSourceFiles().filter { - val sourceFile = File(it.getVirtualFile()!!.getPath()) - samples.none { sample -> - val canonicalSample = File(sample).canonicalPath - val canonicalSource = sourceFile.canonicalPath - canonicalSource.startsWith(canonicalSample) +class DokkaGenerator(val logger: DokkaLogger, + val classpath: List, + val sources: List, + val samples: List, + val includes: List, + val moduleName: String, + val outputDir: String, + val outputFormat: String, + val sourceLinks: List) { + fun generate() { + val environment = createAnalysisEnvironment() + + logger.info("Module: ${moduleName}") + logger.info("Output: ${outputDir}") + logger.info("Sources: ${environment.sources.join()}") + logger.info("Classpath: ${environment.classpath.joinToString()}") + + logger.info("Analysing sources and libraries... ") + val startAnalyse = System.currentTimeMillis() + + val documentation = buildDocumentationModule(environment) + + val timeAnalyse = System.currentTimeMillis() - startAnalyse + logger.info("done in ${timeAnalyse / 1000} secs") + + val startBuild = System.currentTimeMillis() + val signatureGenerator = KotlinLanguageService() + val locationService = FoldersLocationService(outputDir) + val templateService = HtmlTemplateService.default("/dokka/styles/style.css") + + val (formatter, outlineFormatter) = when (outputFormat) { + "html" -> { + val htmlFormatService = HtmlFormatService(locationService, signatureGenerator, templateService) + htmlFormatService to htmlFormatService + } + "markdown" -> MarkdownFormatService(locationService, signatureGenerator) to null + "jekyll" -> JekyllFormatService(locationService, signatureGenerator) to null + "kotlin-website" -> KotlinWebsiteFormatService(locationService, signatureGenerator) to + YamlOutlineService(locationService, signatureGenerator) + else -> { + logger.error("Unrecognized output format ${outputFormat}") + null to null } } - val fragments = fragmentFiles.map { session.getPackageFragment(it.getPackageFqName()) }.filterNotNull().distinct() - val options = DocumentationOptions(false, sourceLinks) - val documentationBuilder = DocumentationBuilder(session, options) - - with(documentationBuilder) { - - val moduleContent = Content() - for (include in includes) { - val file = File(include) - if (file.exists()) { - val text = file.readText() - val tree = parseMarkdown(text) - val content = buildContent(tree) - moduleContent.children.addAll(content.children) - } else { - println("WARN: Include file $file was not found.") - } + if (formatter == null) return + + val generator = FileGenerator(signatureGenerator, locationService, formatter, outlineFormatter) + logger.info("Generating pages... ") + generator.buildPage(documentation) + generator.buildOutline(documentation) + val timeBuild = System.currentTimeMillis() - startBuild + logger.info("done in ${timeBuild / 1000} secs") + Disposer.dispose(environment) + } + + fun createAnalysisEnvironment(): AnalysisEnvironment { + val environment = AnalysisEnvironment(DokkaMessageCollector(logger)) { + addClasspath(PathUtil.getJdkClassesRoots()) + // addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath()) + for (element in this@DokkaGenerator.classpath) { + addClasspath(File(element)) } - val documentationModule = DocumentationModule(arguments.moduleName, moduleContent) - documentationModule.appendFragments(fragments) - documentationBuilder.resolveReferences(documentationModule) - documentationModule + addSources(this@DokkaGenerator.sources) + addSources(this@DokkaGenerator.samples) } + return environment } - val timeAnalyse = System.currentTimeMillis() - startAnalyse - println("done in ${timeAnalyse / 1000} secs") - - val startBuild = System.currentTimeMillis() - val signatureGenerator = KotlinLanguageService() - val locationService = FoldersLocationService(arguments.outputDir) - val templateService = HtmlTemplateService.default("/dokka/styles/style.css") + fun buildDocumentationModule(environment: AnalysisEnvironment): DocumentationModule { + val documentation = environment.withContext { environment, session -> + val fragmentFiles = environment.getSourceFiles().filter { + val sourceFile = File(it.getVirtualFile()!!.getPath()) + samples.none { sample -> + val canonicalSample = File(sample).canonicalPath + val canonicalSource = sourceFile.canonicalPath + canonicalSource.startsWith(canonicalSample) + } + } + val fragments = fragmentFiles.map { session.getPackageFragment(it.getPackageFqName()) }.filterNotNull().distinct() + val options = DocumentationOptions(false, sourceLinks) + val documentationBuilder = DocumentationBuilder(session, options, logger) + + with(documentationBuilder) { + + val moduleContent = Content() + for (include in includes) { + val file = File(include) + if (file.exists()) { + val text = file.readText() + val tree = parseMarkdown(text) + val content = buildContent(tree, session.getPackageFragment(FqName.ROOT)) + moduleContent.children.addAll(content.children) + } else { + logger.warn("Include file $file was not found.") + } + } - val (formatter, outlineFormatter) = when (arguments.outputFormat) { - "html" -> { - val htmlFormatService = HtmlFormatService(locationService, signatureGenerator, templateService) - htmlFormatService to htmlFormatService - } - "markdown" -> MarkdownFormatService(locationService, signatureGenerator) to null - "jekyll" -> JekyllFormatService(locationService, signatureGenerator) to null - "kotlin-website" -> KotlinWebsiteFormatService(locationService, signatureGenerator) to - YamlOutlineService(locationService, signatureGenerator) - else -> { - print("Unrecognized output format ${arguments.outputFormat}") - null to null + val documentationModule = DocumentationModule(moduleName, moduleContent) + documentationModule.appendFragments(fragments) + documentationBuilder.resolveReferences(documentationModule) + documentationModule + } } + + return documentation } - if (formatter == null) return - - val generator = FileGenerator(signatureGenerator, locationService, formatter, outlineFormatter) - print("Generating pages... ") - generator.buildPage(documentation) - generator.buildOutline(documentation) - val timeBuild = System.currentTimeMillis() - startBuild - println("done in ${timeBuild / 1000} secs") - println() - println("Done.") - Disposer.dispose(environment) } - diff --git a/test/src/TestAPI.kt b/test/src/TestAPI.kt index 2cdaad5d..b0e23e0f 100644 --- a/test/src/TestAPI.kt +++ b/test/src/TestAPI.kt @@ -38,7 +38,7 @@ public fun verifyModel(vararg files: String, verifier: (DocumentationModule) -> val fragments = environment.getSourceFiles().map { session.getPackageFragment(it.getPackageFqName()) }.filterNotNull().distinct() val documentationModule = DocumentationModule("test") - val documentationBuilder = DocumentationBuilder(session, options) + val documentationBuilder = DocumentationBuilder(session, options, DokkaConsoleLogger) with(documentationBuilder) { documentationModule.appendFragments(fragments) } -- cgit From f338bc0b6dfa603e369b0c727b6cb256dfc711be Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 15 Jan 2015 18:34:23 +0100 Subject: support source links in the Ant task --- ant/src/dokka.kt | 25 ++++++++++++++++++++++++- build.xml | 4 +++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ant/src/dokka.kt b/ant/src/dokka.kt index 9510f78b..464dadfe 100644 --- a/ant/src/dokka.kt +++ b/ant/src/dokka.kt @@ -7,6 +7,8 @@ import org.apache.tools.ant.BuildException import org.apache.tools.ant.Project import org.jetbrains.dokka.DokkaLogger import org.jetbrains.dokka.DokkaGenerator +import org.jetbrains.dokka.SourceLinkDefinition +import java.io.File class AntLogger(val task: Task): DokkaLogger { override fun info(message: String) = task.log(message, Project.MSG_INFO) @@ -14,6 +16,8 @@ class AntLogger(val task: Task): DokkaLogger { override fun error(message: String) = task.log(message, Project.MSG_ERR) } +class AntSourceLinkDefinition(var path: String? = null, var url: String? = null, var lineSuffix: String? = null) + class DokkaAntTask(): Task() { public var moduleName: String? = null public var outputDir: String? = null @@ -24,6 +28,8 @@ class DokkaAntTask(): Task() { public val samplesPath: Path = Path(getProject()) public val includesPath: Path = Path(getProject()) + public val antSourceLinks: MutableList = arrayListOf() + public fun setClasspath(classpath: Path) { compileClasspath.append(classpath) } @@ -54,6 +60,12 @@ class DokkaAntTask(): Task() { includesPath.append(include) } + public fun createSourceLink(): AntSourceLinkDefinition { + val def = AntSourceLinkDefinition() + antSourceLinks.add(def) + return def + } + override fun execute() { if (sourcePath.list().size() == 0) { throw BuildException("At least one source path needs to be specified") @@ -64,6 +76,17 @@ class DokkaAntTask(): Task() { if (outputDir == null) { throw BuildException("Output directory needs to be specified") } + val sourceLinks = antSourceLinks.map { + val path = it.path + if (path == null) { + throw BuildException("Path attribute of a element is required") + } + val url = it.url + if (url == null) { + throw BuildException("Path attribute of a element is required") + } + SourceLinkDefinition(File(path).getCanonicalFile().getAbsolutePath(), url, it.lineSuffix) + } val url = javaClass().getResource("/org/jetbrains/dokka/ant/DokkaAntTask.class") val jarRoot = url.getPath().substringBefore("!/").trimLeading("file:") @@ -78,7 +101,7 @@ class DokkaAntTask(): Task() { moduleName!!, outputDir!!, outputFormat, - listOf() + sourceLinks ) generator.generate() } diff --git a/build.xml b/build.xml index 81a4dea9..a11200f4 100644 --- a/build.xml +++ b/build.xml @@ -4,6 +4,8 @@ - + + + -- cgit From c12704ba2e1308a2df1068d75335d814b677d2ea Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 15 Jan 2015 18:43:22 +0100 Subject: remove some logging which is no longer needed --- ant/src/dokka.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/ant/src/dokka.kt b/ant/src/dokka.kt index 464dadfe..051b6fe7 100644 --- a/ant/src/dokka.kt +++ b/ant/src/dokka.kt @@ -39,9 +39,7 @@ class DokkaAntTask(): Task() { } public fun setSrc(src: Path) { - log("setSrc($src)") sourcePath.append(src) - log("sourcePath=${sourcePath.list().join(",")}") } public fun setSrcRef(ref: Reference) { @@ -90,7 +88,6 @@ class DokkaAntTask(): Task() { val url = javaClass().getResource("/org/jetbrains/dokka/ant/DokkaAntTask.class") val jarRoot = url.getPath().substringBefore("!/").trimLeading("file:") - log(jarRoot) val generator = DokkaGenerator( AntLogger(this), -- cgit From 1602b0f593cd0b9d0895177ce71827d934c8982b Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 30 Jan 2015 19:21:54 +0100 Subject: cleanup after rebase --- src/main.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.kt b/src/main.kt index 63725942..521adb61 100644 --- a/src/main.kt +++ b/src/main.kt @@ -192,7 +192,7 @@ class DokkaGenerator(val logger: DokkaLogger, if (file.exists()) { val text = file.readText() val tree = parseMarkdown(text) - val content = buildContent(tree, session.getPackageFragment(FqName.ROOT)) + val content = buildContent(tree) moduleContent.children.addAll(content.children) } else { logger.warn("Include file $file was not found.") -- cgit