feat: Compression
All checks were successful
/ build (push) Successful in 37s

and refactoring

Signed-off-by: Minecon724 <git@m724.eu>
This commit is contained in:
Minecon724 2025-02-20 15:29:47 +01:00
parent 3d4597b198
commit 950645dcef
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
5 changed files with 102 additions and 25 deletions

14
pom.xml
View file

@ -41,11 +41,23 @@
<version>2.9</version> <version>2.9</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId> <!-- https://stackoverflow.com/questions/32184114 -->
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
<version>2.18.0</version> <version>2.18.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.27.1</version>
</dependency>
<dependency>
<groupId>com.github.luben</groupId>
<artifactId>zstd-jni</artifactId>
<version>1.5.6-10</version>
</dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>

View file

@ -1,9 +1,12 @@
package eu.m724.blog; package eu.m724.blog;
import eu.m724.blog.compress.FileCompressor;
import eu.m724.blog.data.Feed; import eu.m724.blog.data.Feed;
import eu.m724.blog.data.Post; import eu.m724.blog.data.Post;
import eu.m724.blog.data.Site; import eu.m724.blog.data.Site;
import eu.m724.blog.template.TemplateRenderer; import eu.m724.blog.template.TemplateRenderer;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.commons.io.file.PathUtils; import org.apache.commons.io.file.PathUtils;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.RepositoryBuilder; import org.eclipse.jgit.lib.RepositoryBuilder;
@ -14,6 +17,8 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -115,17 +120,35 @@ public class BlogBuilder {
* @throws IOException if an I/O error occurs * @throws IOException if an I/O error occurs
*/ */
public void build() throws IOException { public void build() throws IOException {
System.out.println("Loading site...");
if (site == null) if (site == null)
this.site = Site.fromConfig(workingDirectory.resolve("site-config.yml")); this.site = Site.fromConfig(workingDirectory.resolve("site-config.yml"));
if (template == null) if (template == null)
this.template = new TemplateRenderer(templateDirectory); this.template = new TemplateRenderer(templateDirectory);
copyIfExists(workingDirectory.resolve("assets"), outputDirectory.resolve("assets")); System.out.println("Copying assets...");
copyIfExists(templateDirectory.resolve("static"), outputDirectory.resolve("static")); copyTree(workingDirectory.resolve("assets"), outputDirectory.resolve("assets"));
copyTree(templateDirectory.resolve("static"), outputDirectory.resolve("static"));
System.out.println("Rendering posts...");
var posts = renderPosts();
System.out.println("Rendering meta...");
posts.sort(Comparator.comparing(Post::createdAt).reversed());
Files.writeString(outputDirectory.resolve("index.html"), template.renderIndex(site, posts));
Files.writeString(outputDirectory.resolve("posts.rss"), Feed.generateRss(site, posts));
System.out.println("Compressing...");
compressOutput();
}
private List<Post> renderPosts() throws IOException {
Files.createDirectory(outputDirectory.resolve("post")); Files.createDirectory(outputDirectory.resolve("post"));
var postDirectory = workingDirectory.resolve("posts"); var postDirectory = workingDirectory.resolve("posts");
var posts = new ArrayList<Post>(); var posts = new ArrayList<Post>();
try (var stream = Files.walk(postDirectory)) { try (var stream = Files.walk(postDirectory)) {
@ -158,20 +181,35 @@ public class BlogBuilder {
} }
} }
posts.sort(Comparator.comparing(Post::createdAt).reversed()); return posts;
Files.writeString(outputDirectory.resolve("index.html"), template.renderIndex(site, posts)); }
Files.writeString(outputDirectory.resolve("posts.rss"), Feed.generateRss(site, posts)); private void compressOutput() throws IOException {
var compressors = new FileCompressor[] {
new FileCompressor(CompressorStreamFactory.GZIP),
new FileCompressor(CompressorStreamFactory.ZSTANDARD)
};
Set<Path> tree;
try (var walk = Files.walk(outputDirectory)) {
tree = walk.filter(Files::isRegularFile).collect(Collectors.toSet());
}
for (var compressor : compressors) {
for (var path : tree) {
try {
compressor.compress(path);
} catch (CompressorException e) {
System.err.printf("Exception compressing %s to %s: %s%n", path, compressor.getAlgorithm(), e.getMessage());
}
}
}
} }
/* Internal functions */ /* Internal functions */
private boolean copyTree(Path srcDir, Path destDir) throws IOException { private void copyTree(Path srcDir, Path destDir) throws IOException {
if (!Files.isDirectory(srcDir)) {
return false;
}
try (var walk = Files.walk(srcDir)) { try (var walk = Files.walk(srcDir)) {
for (var src : walk.collect(Collectors.toSet())) { for (var src : walk.collect(Collectors.toSet())) {
var rel = srcDir.relativize(src); var rel = srcDir.relativize(src);
@ -188,17 +226,5 @@ public class BlogBuilder {
} }
} }
} }
return true;
}
private void copyIfExists(Path srcDir, Path destDir) throws IOException {
System.out.print(srcDir);
if (copyTree(srcDir, destDir)) {
System.out.println(" copied");
} else {
System.out.println(" doesn't exist, not copying");
}
} }
} }

View file

@ -36,7 +36,10 @@ public class Main {
.renderDrafts(renderDrafts); .renderDrafts(renderDrafts);
builder.mkdirs(force); builder.mkdirs(force);
System.out.println("---- START BUILD ----");
builder.build(); builder.build();
System.out.println("----- END BUILD -----");
var end = System.nanoTime(); var end = System.nanoTime();
System.out.printf("Exported to %s (%.2f ms)\n", outputDirectory, (end - start) / 1000000.0); System.out.printf("Exported to %s (%.2f ms)\n", outputDirectory, (end - start) / 1000000.0);

View file

@ -0,0 +1,36 @@
package eu.m724.blog.compress;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
import java.io.IOException;
import java.nio.file.*;
public class FileCompressor {
private final String algorithm;
public FileCompressor(String algorithm) {
this.algorithm = algorithm;
}
public void compress(Path source) throws IOException, CompressorException {
var destination = source.resolveSibling(source.getFileName() + "." + algorithm);
compress(source, destination);
}
public void compress(Path source, Path destination) throws IOException, CompressorException {
if (Files.exists(destination))
throw new FileAlreadyExistsException(destination.toString());
try (
var outputStream = new CompressorStreamFactory()
.createCompressorOutputStream(algorithm, Files.newOutputStream(destination))
) {
Files.copy(source, outputStream);
}
}
public String getAlgorithm() {
return algorithm;
}
}

View file

@ -9,7 +9,7 @@ import io.pebbletemplates.pebble.template.PebbleTemplate;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -46,7 +46,7 @@ public class TemplateRenderer {
* @return the rendered index HTML page as a string * @return the rendered index HTML page as a string
* @throws IOException if an error occurs during the template evaluation * @throws IOException if an error occurs during the template evaluation
*/ */
public String renderIndex(Site site, ArrayList<Post> posts) throws IOException { public String renderIndex(Site site, List<Post> posts) throws IOException {
Map<String, Object> context = Map.of( Map<String, Object> context = Map.of(
"site", site, "site", site,
"articles", posts "articles", posts