blob: 111e14209400411cac13deb5b67065ffc02aa5c5 [file] [log] [blame]
package org.jetbrains.dokka
import com.sampullara.cli.Args
import com.sampullara.cli.Argument
import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink
import java.io.File
import java.net.MalformedURLException
import java.net.URL
import java.net.URLClassLoader
class DokkaArguments {
@set:Argument(value = "src", description = "Source file or directory (allows many paths separated by the system path separator)")
var src: String = ""
@set:Argument(value = "srcLink", description = "Mapping between a source directory and a Web site for browsing the code")
var srcLink: String = ""
@set:Argument(value = "include", description = "Markdown files to load (allows many paths separated by the system path separator)")
var include: String = ""
@set:Argument(value = "samples", description = "Source root for samples")
var samples: String = ""
@set:Argument(value = "output", description = "Output directory path")
var outputDir: String = "out/doc/"
@set:Argument(value = "format", description = "Output format (text, html, markdown, jekyll, kotlin-website)")
var outputFormat: String = "html"
@set:Argument(value = "module", description = "Name of the documentation module")
var moduleName: String = ""
@set:Argument(value = "classpath", description = "Classpath for symbol resolution")
var classpath: String = ""
@set:Argument(value = "nodeprecated", description = "Exclude deprecated members from documentation")
var nodeprecated: Boolean = false
@set:Argument(value = "jdkVersion", description = "Version of JDK to use for linking to JDK JavaDoc")
var jdkVersion: Int = 6
@set:Argument(value = "impliedPlatforms", description = "List of implied platforms (comma-separated)")
var impliedPlatforms: String = ""
@set:Argument(value = "packageOptions", description = "List of package options in format \"prefix,-deprecated,-privateApi,+warnUndocumented,+suppress;...\" ")
var packageOptions: String = ""
@set:Argument(value = "links", description = "External documentation links in format url^packageListUrl^^url2...")
var links: String = ""
@set:Argument(value = "noStdlibLink", description = "Disable documentation link to stdlib")
var noStdlibLink: Boolean = false
@set:Argument(value = "cacheRoot", description = "Path to cache folder, or 'default' to use ~/.cache/dokka, if not provided caching is disabled")
var cacheRoot: String? = null
@set:Argument(value = "languageVersion", description = "Language Version to pass to Kotlin Analysis")
var languageVersion: String? = null
@set:Argument(value = "apiVersion", description = "Kotlin Api Version to pass to Kotlin Analysis")
var apiVersion: String? = null
@set:Argument(value = "collectInheritedExtensionsFromLibraries", description = "Search for applicable extensions in libraries")
var collectInheritedExtensionsFromLibraries: Boolean = false
}
object MainKt {
fun parseLinks(links: String): List<ExternalDocumentationLink> {
val (parsedLinks, parsedOfflineLinks) = links.split("^^")
.map { it.split("^").map { it.trim() }.filter { it.isNotBlank() } }
.filter { it.isNotEmpty() }
.partition { it.size == 1 }
return parsedLinks.map { (root) -> ExternalDocumentationLink.Builder(root).build() } +
parsedOfflineLinks.map { (root, packageList) ->
val rootUrl = URL(root)
val packageListUrl =
try {
URL(packageList)
} catch (ex: MalformedURLException) {
File(packageList).toURI().toURL()
}
ExternalDocumentationLink.Builder(rootUrl, packageListUrl).build()
}
}
@JvmStatic
fun entry(args: Array<String>) {
val arguments = DokkaArguments()
val freeArgs: List<String> = Args.parse(arguments, args) ?: listOf()
val sources = if (arguments.src.isNotEmpty()) arguments.src.split(File.pathSeparatorChar).toList() + freeArgs else freeArgs
val samples = if (arguments.samples.isNotEmpty()) arguments.samples.split(File.pathSeparatorChar).toList() else listOf()
val includes = if (arguments.include.isNotEmpty()) arguments.include.split(File.pathSeparatorChar).toList() else listOf()
val sourceLinks = if (arguments.srcLink.isNotEmpty() && arguments.srcLink.contains("="))
listOf(SourceLinkDefinitionImpl.parseSourceLinkDefinition(arguments.srcLink))
else {
if (arguments.srcLink.isNotEmpty()) {
println("Warning: Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.")
}
listOf()
}
val classPath = arguments.classpath.split(File.pathSeparatorChar).toList()
val documentationOptions = DocumentationOptions(
arguments.outputDir.let { if (it.endsWith('/')) it else it + '/' },
arguments.outputFormat,
skipDeprecated = arguments.nodeprecated,
sourceLinks = sourceLinks,
impliedPlatforms = arguments.impliedPlatforms.split(','),
perPackageOptions = parsePerPackageOptions(arguments.packageOptions),
jdkVersion = arguments.jdkVersion,
externalDocumentationLinks = parseLinks(arguments.links),
noStdlibLink = arguments.noStdlibLink,
cacheRoot = arguments.cacheRoot,
languageVersion = arguments.languageVersion,
apiVersion = arguments.apiVersion,
collectInheritedExtensionsFromLibraries = arguments.collectInheritedExtensionsFromLibraries
)
val generator = DokkaGenerator(
DokkaConsoleLogger,
classPath,
sources.map(SourceRootImpl.Companion::parseSourceRoot),
samples,
includes,
arguments.moduleName,
documentationOptions)
generator.generate()
DokkaConsoleLogger.report()
}
fun findToolsJar(): File {
val javaHome = System.getProperty("java.home")
val default = File(javaHome, "../lib/tools.jar")
val mac = File(javaHome, "../Classes/classes.jar")
when {
default.exists() -> return default
mac.exists() -> return mac
else -> {
throw Exception("tools.jar not found, please check it, also you can provide it manually, using -cp")
}
}
}
fun createClassLoaderWithTools(): ClassLoader {
val toolsJar = findToolsJar().canonicalFile.toURI().toURL()
val originalUrls = (javaClass.classLoader as? URLClassLoader)?.urLs
val dokkaJar = javaClass.protectionDomain.codeSource.location
val urls = if (originalUrls != null) arrayOf(toolsJar, *originalUrls) else arrayOf(toolsJar, dokkaJar)
return URLClassLoader(urls, ClassLoader.getSystemClassLoader().parent)
}
fun startWithToolsJar(args: Array<String>) {
try {
javaClass.classLoader.loadClass("com.sun.tools.doclets.formats.html.HtmlDoclet")
entry(args)
} catch (e: ClassNotFoundException) {
val classLoader = createClassLoaderWithTools()
classLoader.loadClass("org.jetbrains.dokka.MainKt")
.methods.find { it.name == "entry" }!!
.invoke(null, args)
}
}
@JvmStatic
fun main(args: Array<String>) {
val arguments = DokkaArguments()
Args.parse(arguments, args)
if (arguments.outputFormat == "javadoc")
startWithToolsJar(args)
else
entry(args)
}
}