in grails-gradle/docs-core/src/main/groovy/grails/doc/DocPublisher.groovy [153:428]
private void catPublish() {
initialize()
if (!src?.exists()) {
return
}
// unpack documentation resources
String docResources = "${workDir}/doc-resources"
ant.mkdir(dir: docResources)
unpack(dest: docResources, src: "grails-doc-files.jar")
def refDocsDir = calculateLanguageDir(target?.absolutePath ?: "./docs")
def refGuideDir = new File(refDocsDir, "guide")
def refPagesDir = "$refGuideDir/pages"
ant.mkdir(dir: refDocsDir)
ant.mkdir(dir: refGuideDir)
ant.mkdir(dir: refPagesDir)
ant.mkdir(dir: "$refDocsDir/ref")
String imgsDir = new File(refDocsDir, calculatePathToResources("img")).path
File fontsDir = new File(refDocsDir, calculatePathToResources("fonts"))
ant.mkdir(dir: imgsDir)
ant.mkdir(dir: fontsDir )
String cssDir = new File(refDocsDir, calculatePathToResources("css")).path
ant.mkdir(dir: cssDir)
String jsDir = new File(refDocsDir, calculatePathToResources("js")).path
ant.mkdir(dir: jsDir)
ant.mkdir(dir: "${refDocsDir}/ref")
ant.copy(todir: imgsDir, overwrite: true) {
fileset(dir: "${docResources}/img")
}
if (images && images.exists()) {
ant.copy(todir: imgsDir, overwrite: true, failonerror:false) {
fileset(dir: images)
}
}
ant.copy(todir: cssDir, overwrite: true) {
fileset(dir: "${docResources}/css")
}
ant.copy(todir: fontsDir, overwrite: true) {
fileset(dir: "${docResources}/fonts")
}
if (css && css.exists()) {
ant.copy(todir: cssDir, overwrite: true, failonerror:false) {
fileset(dir: css)
}
}
if (fonts && fonts.exists()) {
ant.copy(todir: fontsDir, overwrite: true, failonerror:false) {
fileset(dir: fonts)
}
}
ant.copy(todir: jsDir, overwrite: true) {
fileset(dir: "${docResources}/js")
}
if (js && js.exists()) {
ant.copy(todir: jsDir, overwrite: true, failonerror:false) {
fileset(dir: js)
}
}
if (style && style.exists()) {
ant.copy(todir: "${docResources}/style", overwrite: true, failonerror:false) {
fileset(dir: style)
}
}
// Build the table of contents as a tree of nodes. We currently support
// two strategies for this:
//
// 1. From a toc.yml file
// 2. From the gdoc filenames
//
// The first strategy is used if the TOC file exists, otherwise we call
// back to the old way of doing it, which means putting the section
// numbers in the gdoc filenames.
def guideSrcDir = new File(src, "guide")
def yamlTocFile = new File(guideSrcDir, TOC_FILENAME)
def guide
def ext = asciidoc ? ".adoc" : ".gdoc"
if (yamlTocFile.exists()) {
def tocStrategy = new YamlTocStrategy(new FileResourceChecker(guideSrcDir), ext)
guide = tocStrategy.generateToc(yamlTocFile)
// A set of all gdoc files.
def files = []
def pattern = asciidoc ? ~/^.+\.adoc$/ : ~/^.+\.gdoc$/
guideSrcDir.traverse(type: FileType.FILES, nameFilter: pattern) {
// We need relative file paths with '/' separators, since those
// are what are stored in the UserGuideNodes.
files << (it.absolutePath - guideSrcDir.absolutePath)[1..-1].
replace(File.separator as char, '/' as char)
}
def errors = verifyToc(guideSrcDir, files, guide)
if (errors) {
throw new RuntimeException("Encountered the following errors while building table of contents. Aborting.\n${errors.join("\n")}")
}
for (ch in guide.children) {
overrideAliasesFromToc(ch)
}
}
else {
throw new RuntimeException("Legacy TOC is no longer supported. Please add a ${TOC_FILENAME}")
}
// When migrating from the old style docs to the new style, existing
// external links that use URL fragment identifiers will break. To
// mitigate against this problem, the user can provide a list of mappings
// from the new fragment identifiers to the old ones. The docs will then
// include both.
def legacyLinksFile = new File(guideSrcDir, "links.yml")
def legacyLinks = [:]
if (legacyLinksFile.exists()) {
legacyLinksFile.withInputStream { input ->
legacyLinks = new Yaml(new SafeConstructor(new LoaderOptions())).load(input)
}
}
def templateEngine = new groovy.text.SimpleTemplateEngine()
// Reference menu items.
def sectionFilter = { it.directory && !it.name.startsWith('.') } as FileFilter
def files = new File(src, "ref").listFiles(sectionFilter)?.toList()?.sort() ?: []
def refCategories = files.collect { f ->
new Expando(
name: f.name,
usage: new File("${src}/ref/${f.name}$ext"),
sections: f.listFiles().findAll { it.name.endsWith(ext) }.sort())
}
def fullToc = new StringBuilder()
def pathToRoot = ".."
Map vars = new LinkedHashMap(engineProperties)
vars.putAll(
encoding: encoding,
title: title,
docTitle: title,
subtitle: subtitle,
footer: footer, // TODO - add a way to specify footer
authors: authors,
translators: translators,
version: version,
refMenu: refCategories,
toc: guide,
copyright: copyright,
logo: injectPath(logo, pathToRoot),
sponsorLogo: injectPath(sponsorLogo, pathToRoot),
single: false,
path: pathToRoot,
resourcesPath: calculatePathToResources(pathToRoot),
prev: null,
next: null,
legacyLinks: legacyLinks,
sourceRepo: sourceRepo,
)
if(engine instanceof AsciiDocEngine) {
// pass attributes to asciidoc
((AsciiDocEngine)engine).attributes.putAll(
version: version,
apiDocs: "https://docs.grails.org/${version}/api/",
sourceRepo: sourceRepo
)
((AsciiDocEngine)engine).attributes.putAll(
engineProperties
)
}
// Build the user guide sections first.
def template = templateEngine.createTemplate(new File("${docResources}/style/guideItem.html").newReader(encoding))
def sectionTemplate = templateEngine.createTemplate(new File("${docResources}/style/section.html").newReader(encoding))
def fullContents = new StringBuilder()
def chapterVars
def chapters = guide.children
chapters.eachWithIndex{ chapter, i ->
chapterVars = [*:vars, chapterNumber: i + 1]
if (i != 0) {
chapterVars['prev'] = chapters[i - 1]
}
if (i != (chapters.size() - 1)) {
chapterVars['next'] = chapters[i + 1]
}
chapterVars.sectionNumber = (i + 1).toString()
writeChapter(chapter, template, sectionTemplate, guideSrcDir, refGuideDir.path, fullContents, chapterVars)
}
files = new File("${src}/ref").listFiles()?.toList()?.sort() ?: []
def reference = [:]
template = templateEngine.createTemplate(new File("${docResources}/style/referenceItem.html").newReader(encoding))
pathToRoot = "../.."
vars.logo = injectPath(logo, pathToRoot)
vars.sponsorLogo = injectPath(sponsorLogo, pathToRoot)
vars.path = pathToRoot
vars.resourcesPath = calculatePathToResources(pathToRoot)
// Generate the reference section of the guide.
for (f in files) {
if (f.directory && !f.name.startsWith(".")) {
def section = f.name
vars.section = section
new File("${refDocsDir}/ref/${section}").mkdirs()
def textiles = f.listFiles().findAll { it.name.endsWith(ext)}.sort()
def usageFile = new File("${src}/ref/${section}${ext}")
if (usageFile.exists()) {
def data = usageFile.getText("UTF-8")
context.set(DocEngine.SOURCE_FILE, usageFile)
context.set(DocEngine.CONTEXT_PATH, pathToRoot)
context.set(DocEngine.API_CONTEXT_PATH, vars.resourcesPath)
output.warn "Rendering document file $usageFile.name"
vars.content = engine.render(data, context)
vars.sourcePath = "ref/$usageFile.name"
new File("${refDocsDir}/ref/${section}/Usage.html").withWriter(encoding) {out ->
template.make(vars).writeTo(out)
}
}
for (txt in textiles) {
def name = txt.name[0..-6]
def data = txt.getText("UTF-8")
context.set(DocEngine.SOURCE_FILE, txt.name)
context.set(DocEngine.CONTEXT_PATH, pathToRoot)
context.set(DocEngine.API_CONTEXT_PATH, vars.resourcesPath)
output.warn "Rendering document file $txt.name"
vars.content = engine.render(data, context)
vars.sourcePath = "ref/${section}/$txt.name"
new File("${refDocsDir}/ref/${section}/${name}.html").withWriter(encoding) {out ->
template.make(vars).writeTo(out)
}
}
}
}
vars.remove("section")
vars.content = fullContents.toString()
vars.single = true
pathToRoot = ".."
vars.logo = injectPath(logo, pathToRoot)
vars.sponsorLogo = injectPath(sponsorLogo, pathToRoot)
vars.path = pathToRoot
vars.resourcesPath = calculatePathToResources(pathToRoot)
template = templateEngine.createTemplate(new File("${docResources}/style/layout.html").newReader(encoding))
new File("${refGuideDir}/single.html").withWriter(encoding) {out ->
template.make(vars).writeTo(out)
}
vars.content = ""
vars.single = false
new File("${refGuideDir}/index.html").withWriter(encoding) {out ->
template.make(vars).writeTo(out)
}
pathToRoot = "."
vars.logo = injectPath(logo, pathToRoot)
vars.sponsorLogo = injectPath(sponsorLogo, pathToRoot)
vars.path = pathToRoot
vars.resourcesPath = calculatePathToResources(pathToRoot)
new File("${refDocsDir}/index.html").withWriter(encoding) {out ->
template.make(vars).writeTo(out)
}
ant.echo "Built user manual at ${refDocsDir}/index.html"
}