diff --git a/build.gradle b/build.gradle index 01222500..e415ab1a 100644 --- a/build.gradle +++ b/build.gradle @@ -26,23 +26,11 @@ buildscript { } } -plugins { - id "io.github.rwinch.antora" version "0.0.2" -} - - apply plugin: 'io.spring.convention.root' group = 'org.springframework.session' description = 'Spring Session' -antora { - playbookFile = file("local-antora-playbook.yml") - // default no version (current version) - antoraVersion = "3.0.0-alpha.9" - arguments = ["--fetch"] -} - subprojects { apply plugin: 'io.spring.javaformat' diff --git a/local-antora-playbook.yml b/local-antora-playbook.yml deleted file mode 100644 index 923e13ce..00000000 --- a/local-antora-playbook.yml +++ /dev/null @@ -1,14 +0,0 @@ -site: - title: Spring Session - start_page: session::index.adoc -content: - sources: - - url: https://github.com/spring-io/spring-generated-docs - branches: [spring-session/main] - - url: ./ - branches: HEAD - start_path: spring-session-docs -ui: - bundle: - url: https://github.com/spring-io/antora-ui-spring/releases/download/latest/ui-bundle.zip - snapshot: true diff --git a/spring-session-docs/antora-playbook.yml b/spring-session-docs/antora-playbook.yml new file mode 100644 index 00000000..f3ae42dc --- /dev/null +++ b/spring-session-docs/antora-playbook.yml @@ -0,0 +1,26 @@ +site: + title: Spring Session + url: https://docs.spring.io/spring-security/ +asciidoc: + attributes: + page-pagination: true +content: + sources: + - url: https://github.com/spring-io/spring-generated-docs + branches: [spring-projects/spring-session/*] + - url: https://github.com/spring-projects/spring-session + branches: [main] + start_path: spring-session-docs +urls: + latest_version_segment_strategy: redirect:to + latest_version_segment: '' + redirect_facility: httpd +ui: + bundle: + url: https://github.com/spring-io/antora-ui-spring/releases/download/latest/ui-bundle.zip + snapshot: true + +pipeline: + extensions: + - require: ./antora/extensions/major-minor-segment.js + - require: ./antora/extensions/root-component-name.js diff --git a/spring-session-docs/antora/extensions/major-minor-segment.js b/spring-session-docs/antora/extensions/major-minor-segment.js new file mode 100644 index 00000000..eec07645 --- /dev/null +++ b/spring-session-docs/antora/extensions/major-minor-segment.js @@ -0,0 +1,200 @@ +// https://gitlab.com/antora/antora/-/issues/132#note_712132072 +'use strict' + +const { posix: path } = require('path') + +module.exports.register = (pipeline, { config }) => { + pipeline.on('contentClassified', ({ contentCatalog }) => { + contentCatalog.getComponents().forEach(component => { + const componentName = component.name; + const generationToVersion = new Map(); + component.versions.forEach(version => { + const generation = getGeneration(version.version); + const original = generationToVersion.get(generation); + if (original === undefined || (original.prerelease && !version.prerelease)) { + generationToVersion.set(generation, version); + } + }); + + const versionToGeneration = Array.from(generationToVersion.entries()).reduce((acc, entry) => { + const [ generation, version ] = entry; + acc.set(version.version, generation); + return acc; + }, new Map()); + + contentCatalog.findBy({ component: componentName }).forEach((file) => { + const candidateVersion = file.src.version; + if (versionToGeneration.has(candidateVersion)) { + const generation = versionToGeneration.get(candidateVersion); + if (file.out) { + if (file.out) { + file.out.dirname = file.out.dirname.replace(candidateVersion, generation) + file.out.path = file.out.path.replace(candidateVersion, generation); + } + } + if (file.pub) { + file.pub.url = file.pub.url.replace(candidateVersion, generation) + } + } + }); + versionToGeneration.forEach((generation, mappedVersion) => { + contentCatalog.getComponent(componentName).versions.filter(version => version.version === mappedVersion).forEach((version) => { + version.url = version.url.replace(mappedVersion, generation); + }) + const symbolicVersionAlias = createSymbolicVersionAlias( + componentName, + mappedVersion, + generation, + 'redirect:to' + ) + symbolicVersionAlias.src.version = generation; + contentCatalog.addFile(symbolicVersionAlias); + }); + }) + }) +} + +function createSymbolicVersionAlias (component, version, symbolicVersionSegment, strategy) { + if (symbolicVersionSegment == null || symbolicVersionSegment === version) return + const family = 'alias' + const baseVersionAliasSrc = { component, module: 'ROOT', family, relative: '', basename: '', stem: '', extname: '' } + const symbolicVersionAliasSrc = Object.assign({}, baseVersionAliasSrc, { version: symbolicVersionSegment }) + const symbolicVersionAlias = { + src: symbolicVersionAliasSrc, + pub: computePub( + symbolicVersionAliasSrc, + computeOut(symbolicVersionAliasSrc, family, symbolicVersionSegment), + family + ), + } + const originalVersionAliasSrc = Object.assign({}, baseVersionAliasSrc, { version }) + const originalVersionSegment = computeVersionSegment(component, version, 'original') + const originalVersionAlias = { + src: originalVersionAliasSrc, + pub: computePub( + originalVersionAliasSrc, + computeOut(originalVersionAliasSrc, family, originalVersionSegment), + family + ), + } + if (strategy === 'redirect:to') { + originalVersionAlias.out = undefined + originalVersionAlias.rel = symbolicVersionAlias + return originalVersionAlias + } else { + symbolicVersionAlias.out = undefined + symbolicVersionAlias.rel = originalVersionAlias + return symbolicVersionAlias + } +} + + +function computeOut (src, family, version, htmlUrlExtensionStyle) { + let { component, module: module_, basename, extname, relative, stem } = src + if (module_ === 'ROOT') module_ = '' + let indexifyPathSegment = '' + let familyPathSegment = '' + + if (family === 'page') { + if (stem !== 'index' && htmlUrlExtensionStyle === 'indexify') { + basename = 'index.html' + indexifyPathSegment = stem + } else if (extname === '.adoc') { + basename = stem + '.html' + } + } else if (family === 'image') { + familyPathSegment = '_images' + } else if (family === 'attachment') { + familyPathSegment = '_attachments' + } + const modulePath = path.join(component, version, module_) + const dirname = path.join(modulePath, familyPathSegment, path.dirname(relative), indexifyPathSegment) + const path_ = path.join(dirname, basename) + const moduleRootPath = path.relative(dirname, modulePath) || '.' + const rootPath = path.relative(dirname, '') || '.' + + return { dirname, basename, path: path_, moduleRootPath, rootPath } +} + +function computePub (src, out, family, version, htmlUrlExtensionStyle) { + const pub = {} + let url + if (family === 'nav') { + const urlSegments = version ? [src.component, version] : [src.component] + if (src.module && src.module !== 'ROOT') urlSegments.push(src.module) + // an artificial URL used for resolving page references in navigation model + url = '/' + urlSegments.join('/') + '/' + pub.moduleRootPath = '.' + } else if (family === 'page') { + const urlSegments = out.path.split('/') + const lastUrlSegmentIdx = urlSegments.length - 1 + if (htmlUrlExtensionStyle === 'drop') { + // drop just the .html extension or, if the filename is index.html, the whole segment + const lastUrlSegment = urlSegments[lastUrlSegmentIdx] + urlSegments[lastUrlSegmentIdx] = + lastUrlSegment === 'index.html' ? '' : lastUrlSegment.substr(0, lastUrlSegment.length - 5) + } else if (htmlUrlExtensionStyle === 'indexify') { + urlSegments[lastUrlSegmentIdx] = '' + } + url = '/' + urlSegments.join('/') + } else { + url = '/' + out.path + if (family === 'alias' && !src.relative.length) pub.splat = true + } + + pub.url = ~url.indexOf(' ') ? url.replace(SPACE_RX, '%20') : url + + if (out) { + pub.moduleRootPath = out.moduleRootPath + pub.rootPath = out.rootPath + } + + return pub +} + +function computeVersionSegment (name, version, mode) { + if (mode === 'original') return !version || version === 'master' ? '' : version + const strategy = this.latestVersionUrlSegmentStrategy + // NOTE: special exception; revisit in Antora 3 + if (!version || version === 'master') { + if (mode !== 'alias') return '' + if (strategy === 'redirect:to') return + } + if (strategy === 'redirect:to' || strategy === (mode === 'alias' ? 'redirect:from' : 'replace')) { + const component = this.getComponent(name) + const componentVersion = component && this.getComponentVersion(component, version) + if (componentVersion) { + const segment = + componentVersion === component.latest + ? this.latestVersionUrlSegment + : componentVersion === component.latestPrerelease + ? this.latestPrereleaseVersionUrlSegment + : undefined + return segment == null ? version : segment + } + } + return version +} + +function getGeneration(version) { + if (!version) return version; + const firstIndex = version.indexOf('.') + if (firstIndex < 0) { + return version; + } + const secondIndex = version.indexOf('.', firstIndex + 1); + const result = version.substr(0, secondIndex); + return result; +} + +function out(args) { + console.log(JSON.stringify(args, no_data, 2)); +} + + +function no_data(key, value) { + if (key == "data" || key == "files") { + return value ? "__data__" : value; + } + return value; +} \ No newline at end of file diff --git a/spring-session-docs/antora/extensions/root-component-name.js b/spring-session-docs/antora/extensions/root-component-name.js new file mode 100644 index 00000000..dcc8dc48 --- /dev/null +++ b/spring-session-docs/antora/extensions/root-component-name.js @@ -0,0 +1,40 @@ +// https://gitlab.com/antora/antora/-/issues/132#note_712132072 +'use strict' + +const { posix: path } = require('path') + +module.exports.register = (pipeline, { config }) => { + pipeline.on('contentClassified', ({ contentCatalog }) => { + const rootComponentName = config.rootComponentName || 'ROOT' + const rootComponentNameLength = rootComponentName.length + contentCatalog.findBy({ component: rootComponentName }).forEach((file) => { + if (file.out) { + file.out.dirname = file.out.dirname.substr(rootComponentNameLength) + file.out.path = file.out.path.substr(rootComponentNameLength + 1) + file.out.rootPath = fixPath(file.out.rootPath) + } + if (file.pub) { + file.pub.url = file.pub.url.substr(rootComponentNameLength + 1) + if (file.pub.rootPath) { + file.pub.rootPath = fixPath(file.pub.rootPath) + } + } + if (file.rel) { + if (file.rel.pub) { + file.rel.pub.url = file.rel.pub.url.substr(rootComponentNameLength + 1) + file.rel.pub.rootPath = fixPath(file.rel.pub.rootPath); + } + } + }) + const rootComponent = contentCatalog.getComponent(rootComponentName) + rootComponent?.versions?.forEach((version) => { + version.url = version.url.substr(rootComponentName.length + 1) + }) + // const siteStartPage = contentCatalog.getById({ component: '', version: '', module: '', family: 'alias', relative: 'index.adoc' }) + // if (siteStartPage) delete siteStartPage.out + }) + + function fixPath(path) { + return path.split('/').slice(1).join('/') || '.' + } +} \ No newline at end of file diff --git a/spring-session-docs/local-antora-playbook.yml b/spring-session-docs/local-antora-playbook.yml new file mode 100644 index 00000000..be6a02b4 --- /dev/null +++ b/spring-session-docs/local-antora-playbook.yml @@ -0,0 +1,26 @@ +site: + title: Spring + url: https://docs.spring.io/spring-security/ +asciidoc: + attributes: + page-pagination: true +content: + sources: + - url: ../../spring-io/spring-generated-docs + branches: [spring-projects/spring-session/*] + - url: ../../spring-projects/spring-session + branches: [main] + start_path: spring-session-docs +urls: + latest_version_segment_strategy: redirect:to + latest_version_segment: '' + redirect_facility: httpd +ui: + bundle: + url: https://github.com/spring-io/antora-ui-spring/releases/download/latest/ui-bundle.zip + snapshot: true + +pipeline: + extensions: + - require: ./antora/extensions/major-minor-segment.js + - require: ./antora/extensions/root-component-name.js diff --git a/spring-session-docs/spring-session-docs.gradle b/spring-session-docs/spring-session-docs.gradle index cb735935..b0fb52d7 100644 --- a/spring-session-docs/spring-session-docs.gradle +++ b/spring-session-docs/spring-session-docs.gradle @@ -1,3 +1,7 @@ +plugins { + id "io.github.rwinch.antora" version "0.0.2" +} + apply plugin: 'io.spring.convention.docs' apply plugin: 'io.spring.convention.spring-test' @@ -23,6 +27,19 @@ dependencies { testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' } +antora { + antoraVersion = "3.0.0-alpha.8" + arguments = ["--fetch"] +} + +tasks.antora { + environment = [ + "ALGOLIA_API_KEY" : "82c7ead946afbac3cf98c32446154691", + "ALGOLIA_APP_ID" : "244V8V9FGG", + "ALGOLIA_INDEX_NAME" : "session-docs" + ] +} + sourceSets { test { java {