Skip to content
Permalink
Browse files

i17,i19,i22 Copy dependent resources, fix ToC external links

  • Loading branch information...
Pingvin235 committed Oct 9, 2019
1 parent 7aaaee5 commit cb1bc70aa4887335eef6215bae432b59d73a1522
@@ -6,10 +6,10 @@ Java binding of the excellent software documentation framework link:https://asci
Additionally to the information below you may have a look on the link:https://docs.google.com/presentation/d/1MEIMT9SEnepZdLMVFv2Koev3TILRGn_cNgdT25eS-Zg/edit?usp=sharing[Presentation]

== About
PzdcDoc is the complex ready-to-use solution, providing clear way and workflow for organizing software documentation.
PzdcDoc is the complete ready-to-use solution, providing clear way and workflow for organizing software documentation.
On top of AsciiDoctor there are added the following features:
[square]
* Delivered as a single Java artifact in Maven repository for simple integration in existing build processes.
* Delivered as a single Java link:https://mvnrepository.com/artifact/org.pzdcdoc/pzdcdoc[artifact] in Maven repository for simple integration in existing build processes.
* Building documentation out of many files structured in original way with ToC.
* Preserving structure, preview of documentation is <<src/doc/demo.adoc#, available>> in GitLab and GitHub.
* Internal references checking, no more broken links.
@@ -66,5 +66,6 @@ In the input directory may be placed:
* The generator goes through all the files in input dir and converting all with extension `.adoc` them to `.html`.
** Directory starting from `.` are skipped.
** Includes have to be named `.adocf` to avoid converting.
** Resources (files, images) must be placed in `_res` subdirectory near of referencing `.adoc` file, they are automatically copied.
** Resources (files, images) are recommended be placed in `_res` subdirectory near of referencing `.adoc` file,
but you may reference as well any project file, it will be copied to the target directory.
* All the used references between `.adoc` are relative and automatically converted to HTML.
@@ -104,7 +104,7 @@ class My {
----

== References
Image, must be always places in directory *_res* near of the file.
Image, recommended to be places in directory `_res` near of the file.

image::_res/image.png[]

@@ -134,12 +134,21 @@ For any selection except of links use bold font:

[[diagrams]]
== Diagrams
=== Embedded
Supported Ditaa and PlantUML diagrams.
[square]
* https://asciidoctor.org/docs/asciidoctor-diagram/
* https://asciidoctor.org/news/2014/02/18/plain-text-diagrams-in-asciidoctor/

=== Ditaa
Advantages:
[square]
* lightness;
* quick preview;
* simplicity and uniformity;
* storage and editing in the text of the document;
* no need to export.

==== Ditaa
http://ditaa.sourceforge.net/

Use http://asciiflow.com/ for editing.
@@ -153,6 +162,12 @@ Use http://asciiflow.com/ for editing.
+------------------+ +---------------+
----

=== With 3rd party editors
Schemas can also be produced using third-party editors, for example: link:https://www.yworks.com/downloads#yEd[yEd]
Source files are stored in `_res` directories under names ending in `_schema.graphml`.
Files have to be exported as images in PNG format, preferably with the same name.
After any change source files have to be re-exported.

== Tools
AsciiDoctor may be edited in any text editor, but as more comfortable way I use an Eclipse plugin.

@@ -1,7 +1,8 @@
= Demo Local ToC
:nofooter:

* <<changes.adoc#, Last changes>>
* <<demo.adoc#, Demo AsciiDoctor>>
* Modules
** <<module/index.adoc#, Module>>
* <<changes.adoc#, Last changes>>
* External link:http://pzdcdoc.org[link]
@@ -34,8 +34,10 @@

public class DocGenerator {
private static final Logger log = LogManager.getLogger();

private static final String RES = "_res";

private static final String DIR_RES = "_res";
private static final String EXT_ADOC = ".adoc";
private static final String EXT_HTML = ".html";

private final Asciidoctor asciidoctor = Factory.create();

@@ -70,18 +72,18 @@ public DocGenerator(String configDir, String sourceDir, String targetDir) throws
}

public void process() throws Exception {
process(sourceDir, targetDir, -1, false, new HashMap<>());
process(sourceDir, targetDir, -1, new HashMap<>());
copyScriptsAndStyles();
}

public int check() throws Exception {
int errors = new LinksChecker(targetDir).check();
int errors = new Links().checkDir(targetDir);
if (errors > 0)
log.error("ERROR COUNT => " + errors);
return errors;
}

public void process(File source, File target, int depth, boolean resource, Map<String, Object> attributes) throws Exception {
public void process(File source, File target, int depth, Map<String, Object> attributes) throws Exception {
final String sourceName = source.getName();

// hidden resources, names started by .
@@ -97,8 +99,6 @@ public void process(File source, File target, int depth, boolean resource, Map<S
}

if (source.isDirectory()) {
final boolean resourceDir = resource || RES.equals(sourceName);

File[] files = source.listFiles();

// index.adoc in the root folder must be processed first to be included in all files after
@@ -113,15 +113,14 @@ public void process(File source, File target, int depth, boolean resource, Map<S
attributes = loadAttributes(source, attributes);

for (File file : files)
process(file, new File(target.getPath() + "/" + file.getName()), depth + 1, resourceDir, attributes);
process(file, new File(target.getPath() + "/" + file.getName()), depth + 1, attributes);
} else {
if (sourceName.endsWith(".adoc")) {
if (sourceName.endsWith(EXT_ADOC)) {
log.info("Processing: " + source);

Attributes attrs = AttributesBuilder.attributes()
.stylesDir(StringUtils.repeat("../", depth) + RES)
.stylesDir(StringUtils.repeat("../", depth) + DIR_RES)
.linkCss(true)
.attribute("imagesoutdir", RES)
.sourceHighlighter("coderay")
.icons(Attributes.FONT_ICONS)
.tableOfContents(true)
@@ -141,21 +140,18 @@ public void process(File source, File target, int depth, boolean resource, Map<S

String html = asciidoctor.convertFile(source, options);

String targetPath = target.getPath().replace(".adoc", ".html").replace('\\','/');
Path targetPath = Paths.get(target.getPath().replace(EXT_ADOC, EXT_HTML));

html = correctHtml(html, targetPath, depth);
html = correctHtmlAndCopyResources(source.toPath(), html, targetPath, depth);

FileUtils.forceMkdirParent(target);

FileWriterWithEncoding fos = new FileWriterWithEncoding(targetPath, StandardCharsets.UTF_8);
FileWriterWithEncoding fos = new FileWriterWithEncoding(targetPath.toFile(), StandardCharsets.UTF_8);
fos.write(html);
fos.close();

return;
}
// copy resource
else if (resource)
FileUtils.copyFile(source, target);
}
}
}

@@ -178,7 +174,7 @@ else if (resource)
public void copyScriptsAndStyles() throws IOException {
log.info("Copy scripts and styles.");

File rootRes = new File(targetDir + "/" + RES);
File rootRes = new File(targetDir + "/" + DIR_RES);
if (!rootRes.exists()) rootRes.mkdirs();

for (String script : SCRIPTS)
@@ -196,12 +192,12 @@ private boolean containsIndex(String name) {
return name.contains("index");
}

private String correctHtml(String html, String targetPath, int depth) throws Exception {
log.debug("correctHtml targetPath: {}, deep: {}", targetPath, depth);
private String correctHtmlAndCopyResources(Path source, String html, Path target, int depth) throws Exception {
log.debug("correctHtml targetPath: {}, deep: {}", target, depth);

if (toc == null) {
// the index file must be placed on the top the root directory
if (containsIndex(targetPath)) {
if (containsIndex(target.toString())) {
toc = Jsoup.parse(html, StandardCharsets.UTF_8.name());
toc = toc.select("body").tagName("div").get(0);
// add search field
@@ -215,20 +211,15 @@ private String correctHtml(String html, String targetPath, int depth) throws Exc

// add content to search index
if (search != null) {
final String relativePath = targetDir.toPath().relativize(Paths.get(targetPath)).toString().replace('\\', '/');
final String relativePath = targetDir.toPath().relativize(target).toString().replace('\\', '/');
search.addArticle(new Search.Article(relativePath, head.select("title").text(), jsoup.text()));
}

// patch diagram images links
for (Element diag : jsoup.select("img[src^=diag]")) {
String src = RES + "/" + diag.attr("src");
log.info("Corrected diagram path to: {}", src);
diag.attr("src", src);
}
copyResources(jsoup, source, target);

// inject JS files
for (String script : SCRIPTS_INJECT)
head.append("<script src='" + StringUtils.repeat("../", depth) + RES + "/" + script + "'/>");
head.append("<script src='" + StringUtils.repeat("../", depth) + DIR_RES + "/" + script + "'/>");

// find of the top ToC
Element pageToC = jsoup.selectFirst("#toc.toc");
@@ -245,8 +236,10 @@ private String correctHtml(String html, String targetPath, int depth) throws Exc

for (Element a : jsoup.select("#toc.toc2 a")) {
String href = a.attr("href");
if (Links.isExternalReference(href))
continue;

if (targetPath.endsWith(href)) {
if (target.endsWith(href)) {
a.addClass("current");
if (pageToC != null)
a.after(pageToC);
@@ -259,6 +252,31 @@ private String correctHtml(String html, String targetPath, int depth) throws Exc

return html;
}

private void copyResources(Document jsoup, Path source, Path target) throws IOException {
for (String href : new Links().getLinks(jsoup)) {
href = StringUtils.substringBefore(href, "#");
if (href.endsWith(EXT_HTML))
continue;

File resSrc = source.getParent().resolve(href).toFile();
if (!resSrc.exists() || resSrc.isDirectory()) {
log.debug("Skip: {}", resSrc);
continue;
}
File resTarget = target.getParent().resolve(href).toFile();

FileUtils.forceMkdirParent(resTarget);

if (href.startsWith("diag")) {
log.info("Move {} to {}", resSrc, resTarget);
FileUtils.moveFile(resSrc, resTarget);
} else {
log.info("Copy {} to {}", resSrc, resTarget);
FileUtils.copyFile(resSrc, resTarget);
}
}
}

public static void main(String[] args) throws Exception {
String configDir = args[0], sourceDir = args[1], targetDir = args[2];
@@ -3,34 +3,33 @@
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

public class LinksChecker {
public class Links {
private static final Logger log = LogManager.getLogger();

private final File outputDir;
private int errors;

LinksChecker(File outputDir) {
this.outputDir = outputDir;
}

int check() throws Exception {
int checkDir(File outputDir) throws Exception {
log.info("Start checking");
check(outputDir);
errors = 0;
checkFile(outputDir);
return errors;
}

private void check(File file) throws Exception {
private void checkFile(File file) throws Exception {
if (file.isDirectory()) {
for (File child : file.listFiles())
check(child);
checkFile(child);
return;
}

@@ -40,22 +39,13 @@ private void check(File file) throws Exception {
log.info("Checking file: " + file);

org.jsoup.nodes.Document doc = Jsoup.parse(file, StandardCharsets.UTF_8.name());
for (Element ref : doc.select("a")) {
String href = ref.attr("href");
String anchor = null;

if (href.startsWith("#_") || href.startsWith("mailto:"))
continue;

// TODO: Check also.
if (href.contains("://"))
continue;

for (String href : getLinks(doc)) {
log.debug("Checking: {}", href);

String fragment = null;
int pos = href.indexOf('#');
if (pos >= 0) {
anchor = href.substring(pos + 1);
fragment = href.substring(pos + 1);
href = href.substring(0, pos);
}

@@ -69,26 +59,37 @@ private void check(File file) throws Exception {
}
}

if (!StringUtils.isBlank(anchor) &&
!IOUtils.toString(new FileInputStream(refFile), StandardCharsets.UTF_8.name()).contains("id=\"" + anchor + "\"")) {
log.error("Not found referenced anchor: " + anchor);
if (!StringUtils.isBlank(fragment) &&
!IOUtils.toString(new FileInputStream(refFile), StandardCharsets.UTF_8.name()).contains("id=\"" + fragment + "\"")) {
log.error("Not found referenced fragment: " + fragment);
errors++;
}
}

}

public Iterable<String> getLinks(Document doc) {
List<String> result = new ArrayList<>();

for (Element ref : doc.select("a")) {
String href = ref.attr("href");
if (!isExternalReference(href))
result.add(href);
}

for (Element img : doc.select("img")) {
String src = img.attr("src");
// TODO: Check also.
if (src.contains("://"))
continue;

File refFile = file.toPath().getParent().resolve(src).toFile();
if (!refFile.exists()) {
log.error("Not found referenced image: " + src);
errors++;
continue;
}
if (!isExternalReference(src))
result.add(src);
}

return result;
}

public static boolean isExternalReference(String href) {
return
href.startsWith("#_") ||
href.startsWith("mailto:") ||
// TODO: Check also.
href.contains("://");
}

}

0 comments on commit cb1bc70

Please sign in to comment.
You can’t perform that action at this time.