Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion code/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<version>3.14.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
Expand Down
1 change: 0 additions & 1 deletion code/src/main/java/org/nocturne/main/PageLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*/
package org.nocturne.main;

import com.google.common.base.Throwables;
import org.apache.log4j.Logger;
import org.nocturne.exception.ConfigurationException;
import org.nocturne.pool.PagePool;
Expand Down
77 changes: 64 additions & 13 deletions code/src/main/java/org/nocturne/template/impl/Less.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,66 @@
import com.github.sommeri.less4j.Less4jException;
import com.github.sommeri.less4j.LessCompiler;
import com.github.sommeri.less4j.core.DefaultLessCompiler;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.log4j.Logger;
import org.nocturne.util.StringUtil;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* @author MikeMirzayanov (mirzayanovmr@gmail.com)
*/
public class Less {
private static final Logger logger = Logger.getLogger(Less.class);

// Matches var(--variable-name) where variable name uses valid identifier symbols
private static final Pattern BEFORE_REPL_CSS_VAR_PATTERN = Pattern.compile("var\\(--([\\w-]+)\\)");
private static final Pattern AFTER_REPL_CSS_VAR_PATTERN = Pattern.compile("nocturne-rpl-var--([\\w-]+)");

private static final String CACHE_OPEN_TAG = "<cache>";
private static final String CACHE_CLOSE_TAG = "</cache>";
private static File tmpDir;
private static final File tmpDir;

// Replaces all var(--id) with nocturne-rpl-var--id
@SuppressWarnings("StringBufferMayBeStringBuilder")
private static String preprocessCssVars(String lessCode) {
Matcher m = BEFORE_REPL_CSS_VAR_PATTERN.matcher(lessCode);
StringBuffer result = new StringBuffer();
while (m.find()) {
m.appendReplacement(result, "nocturne-rpl-var--" + m.group(1));
}
m.appendTail(result);
return result.toString();
}

// Replaces all nocturne-rpl-var--id with var(--id)
@SuppressWarnings("StringBufferMayBeStringBuilder")
private static String postprocessCssVars(String cssCode) {
Matcher m = AFTER_REPL_CSS_VAR_PATTERN.matcher(cssCode);
StringBuffer result = new StringBuffer();
while (m.find()) {
m.appendReplacement(result, "var(--" + m.group(1) + ")");
}
m.appendTail(result);
return result.toString();
}

@SuppressWarnings("ResultOfMethodCallIgnored")
public static synchronized String compile(@Nonnull Object source, @Nonnull String lessCode, @Nullable File commonsFile) throws IOException {
public static synchronized String compile(@Nonnull Object source,
@Nonnull String lessCode,
@Nullable File commonsFile) throws IOException {
long commonsFileLastModified = commonsFile == null ? 0 : commonsFile.lastModified();
long commonsFileLength = commonsFile == null ? 0 : commonsFile.length();
String cacheKey = getName(source).trim() + "_" + commonsFileLastModified + "_" + commonsFileLength + "_" + hash(lessCode);
String cacheKey = getName(source).trim()
+ "_" + commonsFileLastModified
+ "_" + commonsFileLength
+ "_" + hash(lessCode);

File cacheDir = new File(tmpDir, "cache");
if (!cacheDir.isDirectory()) {
Expand All @@ -46,6 +83,7 @@ public static synchronized String compile(@Nonnull Object source, @Nonnull Strin
return css;
}
}

if (cacheFile.exists()) {
cacheFile.delete();
}
Expand All @@ -59,10 +97,11 @@ public static synchronized String compile(@Nonnull Object source, @Nonnull Strin
File workCommonsFile;
if (commonsFile != null) {
workCommonsFile = new File(workDir, commonsFile.getName());
writeFile(workCommonsFile, readFile(commonsFile));
lessCode = "@import \"" + commonsFile.getName() + "\";\n" + lessCode;
writeFile(workCommonsFile, preprocessCssVars(readFile(commonsFile)));
lessCode = "@import \"" + commonsFile.getName() + "\";\n" + preprocessCssVars(lessCode);
} else {
workCommonsFile = null;
lessCode = preprocessCssVars(lessCode);
}

File workMainFile = new File(workDir, "main.less");
Expand All @@ -73,8 +112,12 @@ public static synchronized String compile(@Nonnull Object source, @Nonnull Strin
try {
LessCompiler.CompilationResult compilationResult = compiler.compile(workMainFile);
String cachedResult = CACHE_OPEN_TAG + compilationResult.getCss() + CACHE_CLOSE_TAG;
writeFile(cacheFile, cachedResult);
return compilationResult.getCss();

File tmpCacheFile = new File(cacheDir, RandomStringUtils.randomAlphabetic(32));
writeFile(tmpCacheFile, cachedResult);
tmpCacheFile.renameTo(cacheFile);

return postprocessCssVars(compilationResult.getCss());
} catch (Less4jException e) {
throw new IOException("Can't compile less code in \"" + source + "\": " + e.getMessage(), e);
}
Expand Down Expand Up @@ -113,14 +156,14 @@ private static long hash(String css) {
return a ^ b;
}

private static void writeFile(File file, String content) throws FileNotFoundException {
try (PrintWriter writer = new PrintWriter(file)) {
writer.print(content);
private static void writeFile(File file, String content) throws IOException {
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
writer.write(content);
}
}

private static String readFile(File file) throws IOException {
try (FileReader reader = new FileReader(file)) {
try (Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
StringBuilder result = new StringBuilder((int) file.length());
char[] buffer = new char[65536];
int len;
Expand All @@ -140,11 +183,19 @@ private static String readFile(File file) throws IOException {
tmpDir = new File(tmpFile.getParentFile(), "nocturne-less-tmp");
if (!tmpDir.isDirectory()) {
if (!tmpDir.mkdirs()) {
throw new IOException("Can't create " + tmpFile + ".");
throw new IOException("Can't create " + tmpDir + ".");
}
}
} catch (IOException e) {
e.printStackTrace();
String message = "Unable to validate temp directory before using Less engine: " + e.getMessage();

System.out.println(message);
e.printStackTrace(System.out);

System.err.println(message);
e.printStackTrace(System.err);

throw new RuntimeException(message, e);
}
}
}