diff --git a/docs/guides/src/main/server/db.adoc b/docs/guides/src/main/server/db.adoc index 5f4aba3d281..af3bd4a7bbe 100644 --- a/docs/guides/src/main/server/db.adoc +++ b/docs/guides/src/main/server/db.adoc @@ -1,6 +1,7 @@ <#import "/templates/guide.adoc" as tmpl> <#import "/templates/kc.adoc" as kc> <#import "/templates/options.adoc" as opts> +<#import "/templates/links.adoc" as links> <@tmpl.guide title="Relational database setup" @@ -10,6 +11,8 @@ First step is to decide which database vendor you are going to use. Keycloak has support for a number of different vendors. +Take a look at <@links.server id="all-config"/> for more information. + Selecting the database vendor is done at build-time rather than at runtime. To select the database vendor run: <@kc.build parameters="--db "/> diff --git a/docs/guides/src/main/server/index.adoc b/docs/guides/src/main/server/index.adoc index cf8571a8615..61122c51957 100644 --- a/docs/guides/src/main/server/index.adoc +++ b/docs/guides/src/main/server/index.adoc @@ -1,5 +1,10 @@ +<#list ctx.guides as guide> +:links_server_${guide.id}_name: ${guide.title} +:links_server_${guide.id}_url: #${guide.id} + + = Keycloak server guide -<#list ctx.serverGuides as guide> -include::${guide}[leveloffset=+1] +<#list ctx.guides as guide> +include::${guide.template}[leveloffset=+1] diff --git a/docs/guides/src/main/templates/links.adoc b/docs/guides/src/main/templates/links.adoc new file mode 100644 index 00000000000..c1c3c80e960 --- /dev/null +++ b/docs/guides/src/main/templates/links.adoc @@ -0,0 +1,3 @@ +<#macro server id> +link:{links_server_${id}_url}[{links_server_${id}_name}] + \ No newline at end of file diff --git a/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Context.java b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Context.java index a8469447e11..34f1da7de4c 100644 --- a/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Context.java +++ b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Context.java @@ -1,25 +1,40 @@ package org.keycloak.guides.maven; import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; public class Context { private File srcDir; private Options options; - private String[] serverGuides; + private List guides; - public Context(File srcDir) { + public Context(File srcDir) throws IOException { this.srcDir = srcDir; this.options = new Options(); - this.serverGuides = new File(srcDir, "server").list((dir, f) -> f.endsWith(".adoc") && !f.equals("index.adoc")); + + this.guides = new LinkedList<>(); + + GuideParser parser = new GuideParser(); + for (File f : new File(srcDir, "server").listFiles((dir, f) -> f.endsWith(".adoc") && !f.equals("index.adoc"))) { + Guide guide = parser.parse(f); + if (guide != null) { + guides.add(guide); + } + } + + Collections.sort(guides, Comparator.comparingInt(Guide::getPriority)); } public Options getOptions() { return options; } - public String[] getServerGuides() { - return new File(srcDir, "server").list((dir, f) -> f.endsWith(".adoc") && !f.equals("index.adoc")); + public List getGuides() { + return guides; } - } diff --git a/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Guide.java b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Guide.java new file mode 100644 index 00000000000..15912b4e064 --- /dev/null +++ b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Guide.java @@ -0,0 +1,50 @@ +package org.keycloak.guides.maven; + +public class Guide { + + private String template; + private String id; + private String title; + private String summary; + private int priority; + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } +} diff --git a/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/GuideParser.java b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/GuideParser.java new file mode 100644 index 00000000000..062e070ae29 --- /dev/null +++ b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/GuideParser.java @@ -0,0 +1,86 @@ +package org.keycloak.guides.maven; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GuideParser { + + private Pattern TEMPLATE_IMPORT_PATTERN = Pattern.compile("<#import \"/templates/guide.adoc\" as (?[^ ]*)>"); + private Pattern GUIDE_ELEMENT_PATTERN = Pattern.compile("(?priority|title|summary)=(\\\"(?[^\\\"]*)\\\"|(?[\\d]*))"); + + /** + * Parses a FreeMarker template to retrieve Guide attributes + * @param file + * @return A Guide instance; or null if not a guide + * @throws IOException + */ + public Guide parse(File file) throws IOException { + try (BufferedReader br = new BufferedReader(new FileReader(file))) { + String importName = getImportName(br); + String importElement = getGuideElement(br, importName); + + if (importElement != null) { + Guide guide = new Guide(); + guide.setTemplate(file.getName()); + guide.setPriority(999); + + guide.setId(file.getName().replaceAll(".adoc", "")); + + setAttributes(importElement, guide); + + return guide; + } + + return null; + } + } + + private String getImportName(BufferedReader br) throws IOException { + for (String line = br.readLine(); line != null; line = br.readLine()) { + Matcher templateImportMatcher = TEMPLATE_IMPORT_PATTERN.matcher(line); + if (templateImportMatcher.matches()) { + return templateImportMatcher.group("importName"); + } + } + return null; + } + + private String getGuideElement(BufferedReader br, String importName) throws IOException { + if (importName != null) { + for (String line = br.readLine(); line != null; line = br.readLine()) { + if (line.contains("<@" + importName + ".guide")) { + StringBuilder sb = new StringBuilder(); + sb.append(line.trim()); + while (!line.contains(">")) { + line = br.readLine(); + sb.append(" " + line.trim()); + } + return sb.toString(); + } + } + } + return null; + } + + private void setAttributes(String importElement, Guide guide) { + Matcher attributeMatcher = GUIDE_ELEMENT_PATTERN.matcher(importElement); + while (attributeMatcher.find()) { + String key = attributeMatcher.group("key"); + switch (key) { + case "title": + guide.setTitle(attributeMatcher.group("valueString")); + break; + case "summary": + guide.setSummary(attributeMatcher.group("valueString")); + break; + case "priority": + guide.setPriority(Integer.parseInt(attributeMatcher.group("valueInt"))); + } + } + } + +}