-
Notifications
You must be signed in to change notification settings - Fork 2
/
SiteGenerator.java
134 lines (115 loc) · 6.04 KB
/
SiteGenerator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package io.marioslab.basis.site;
import java.io.File;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import io.marioslab.basis.template.Error.TemplateException;
/** Takes an input directory, transforms the files via a list of {@link SiteFileProcessor} instances, and writes the results to an
* output directory. The site file processors may modify the content, metadata and output file name of files. Site file processors
* can be added via the */
public class SiteGenerator {
/** Optional callback to be invoked for each file that is successfully processed by this generator. See
* {@link SiteGenerator#generate(SiteGeneratorCallback)}. **/
public interface SiteGeneratorCallback {
public void generated (SiteFile file);
}
/** Exception used for all error reporting. **/
@SuppressWarnings("serial")
public static class SiteGeneratorException extends RuntimeException {
public SiteGeneratorException (String message, Throwable cause) {
super(message, cause);
}
public SiteGeneratorException (String message) {
super(message);
}
}
private final File inputDirectory;
private final File outputDirectory;
private final List<SiteFileProcessor> processors = new ArrayList<>();
/** Constructs a new site generator that processes the files in the input directory via the list of {@link SiteFileProcessor}
* instances (as returned by {@link #getProcessors()}) and writes the results to the output directory. **/
public SiteGenerator (File inputDirectory, File outputDirectory) {
this.inputDirectory = inputDirectory;
this.outputDirectory = outputDirectory;
}
/** Returns the input directory from which files will be read and processed. **/
public File getInputDirectory () {
return inputDirectory;
}
/** Returns the output directory to which files will be written. **/
public File getOutputDirectory () {
return outputDirectory;
}
/** Adds a {@link SiteFileProcessor} to this generator. The processors will be applied to input files in the order they have
* been added. **/
public void addProcessor (SiteFileProcessor processor) {
this.processors.add(processor);
}
/** Replaces the {@link SiteFileProcessor} of the same class with the provided processor, or appends it at the end of the
* procesor list. */
public void replaceProcessor (SiteFileProcessor processor) {
for (int i = 0; i < processors.size(); i++) {
if (processors.get(i).getClass().equals(processor.getClass())) {
processors.set(i, processor);
return;
}
}
processors.add(processor);
}
/** Transforms the files in the input directory via a list of {@link SiteFileProcessor} instances added via
* {@link #addProcessor(SiteFileProcessor)}, and writes the results to an output directory. Files and directories starting with
* "_" will be ignored. Throws a {@link SiteGeneratorException} in case anything went wrong. When an error occurs, files
* written until that point will not be cleaned up. */
public void generate () {
generate(inputDirectory, inputDirectory, outputDirectory, processors, null);
}
/** Transforms the files in the input directory via a list of {@link SiteFileProcessor} instances added via
* {@link #addProcessor(SiteFileProcessor)}, and writes the results to an output directory. Files and directories starting with
* "_" will be ignored. Throws a {@link SiteGeneratorException} in case anything went wrong. When an error occurs, files
* written until that point will not be cleaned up. For each successfully processed file, the {@link SiteGeneratorCallback}
* will be called. */
public void generate (SiteGeneratorCallback callback) {
generate(inputDirectory, inputDirectory, outputDirectory, processors, callback);
}
/** Processes a single file or directory via the list of {@link SiteFileProcessor} instances. **/
private void generate (File inputFile, File inputDirectory, File outputDirectory, List<SiteFileProcessor> processors, SiteGeneratorCallback callback) {
// Ignore files starting with "_" or non-existing files
if (inputFile.getName().startsWith("_") || !inputFile.exists()) return;
// If this is a directory, generate the output directory and recurse
if (inputFile.isDirectory()) {
File outputFile = new File(outputDirectory, inputFile.getAbsolutePath().replace(inputDirectory.getAbsolutePath(), ""));
if (!outputFile.exists() && !outputFile.mkdirs()) throw new SiteGeneratorException("Couldn't create output directory " + outputFile.getPath() + ".");
File[] children = inputFile.listFiles();
if (children == null) throw new SiteGeneratorException("Couldn't read directory " + inputFile.getPath() + ".");
for (File child : children)
generate(child, inputDirectory, outputDirectory, processors, callback);
return;
}
// Otherwise, load the file content and run it through the processors
try {
File outputFile = generateOutputFile(inputFile);
SiteFile file = new SiteFile(inputFile, outputFile, Files.readAllBytes(inputFile.toPath()));
for (SiteFileProcessor processor : processors)
processor.process(file);
Files.write(outputFile.toPath(), file.getContent());
if (callback != null) callback.generated(file);
} catch (Throwable t) {
if (t instanceof TemplateException) {
throw (TemplateException)t;
} else {
throw new SiteGeneratorException("Couldn't generate output for file " + inputFile.getPath() + ".", t);
}
}
}
/** Generates the output file by passing the input file through the list of {@link SiteFileProcessor} instances of this
* generator, calling each processor's {@link SiteFileProcessor#processOutputFileName(SiteFile) method, and calculating the end
* result relative to the output directory. **/
public File generateOutputFile (File inputFile) {
File outputFile = new File(outputDirectory, inputFile.getAbsolutePath().replace(inputDirectory.getAbsolutePath(), ""));
String outputFileName = outputFile.getName();
for (SiteFileProcessor processor : processors) {
outputFileName = processor.processOutputFileName(outputFileName);
}
return new File(outputFile.getParent() == null ? "" : outputFile.getParent(), outputFileName);
}
}