Automatic compilation of LESS CSS files in the theme
git-svn-id: https://svn.libreccm.org/ccm/trunk@4994 8810af33-2d31-482b-a856-94f89814c4dfmaster
parent
06487845bb
commit
522ab912e5
Binary file not shown.
|
|
@ -11,15 +11,18 @@
|
||||||
* implied. See the License for the specific language governing
|
* implied. See the License for the specific language governing
|
||||||
* rights and limitations under the License.
|
* rights and limitations under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.arsdigita.themedirector.util;
|
package com.arsdigita.themedirector.util;
|
||||||
|
|
||||||
import com.arsdigita.themedirector.Theme;
|
import com.arsdigita.themedirector.Theme;
|
||||||
import com.arsdigita.themedirector.ThemeFile;
|
import com.arsdigita.themedirector.ThemeFile;
|
||||||
import com.arsdigita.themedirector.ThemeFileCollection;
|
import com.arsdigita.themedirector.ThemeFileCollection;
|
||||||
import com.arsdigita.util.Assert;
|
import com.arsdigita.util.Assert;
|
||||||
|
import com.arsdigita.util.UncheckedWrapperException;
|
||||||
|
|
||||||
|
import com.inet.lib.less.Less;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
@ -28,7 +31,16 @@ import java.io.IOException;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import javax.script.Invocable;
|
||||||
|
import javax.script.ScriptEngine;
|
||||||
|
import javax.script.ScriptEngineManager;
|
||||||
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a utility class that is able to take a theme and, when necessary,
|
* This is a utility class that is able to take a theme and, when necessary,
|
||||||
|
|
@ -40,39 +52,44 @@ import java.io.FileNotFoundException;
|
||||||
*/
|
*/
|
||||||
public class ThemeFileUtil {
|
public class ThemeFileUtil {
|
||||||
|
|
||||||
private static Logger s_log =
|
private static Logger s_log = Logger.getLogger(ThemeFileUtil.class);
|
||||||
Logger.getLogger(ThemeFileUtil.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this copies the files from the file system to the database.
|
* this copies the files from the file system to the database.
|
||||||
*
|
*
|
||||||
* @param currentFile The directory to search recursively for files
|
* @param currentFile The directory to search recursively for files
|
||||||
* to put in the database or the single file to add to the db.
|
* to put in the database or the single file to
|
||||||
|
* add to the db.
|
||||||
* @param currentTheme The current theme that is being operated on
|
* @param currentTheme The current theme that is being operated on
|
||||||
* @param serverSpecificPath The absolute path of the root
|
* @param serverSpecificPath The absolute path of the root file. This
|
||||||
* file. This string is removed from the absolute path of the current
|
* string is removed from the absolute path of
|
||||||
* file to get the filePath property of the ThemeFile
|
* the current file to get the filePath property
|
||||||
|
* of the ThemeFile
|
||||||
* @param themeFiles A Map of ThemeFiles with the key being the
|
* @param themeFiles A Map of ThemeFiles with the key being the
|
||||||
* filePath. This is used to look up files that have already been
|
* filePath. This is used to look up files that
|
||||||
* pulled from the database so that the code does not have to
|
* have already been pulled from the database so
|
||||||
* check the db once for every file.
|
* that the code does not have to check the db
|
||||||
* @param overwriteNewerFiles If this is true then it insert everything
|
* once for every file.
|
||||||
* in to the database. If this is false, it only writes the file to the
|
* @param overwriteNewerFiles If this is true then it insert everything in
|
||||||
* database if the file on the file system is newer than the one in
|
* to the database. If this is false, it only
|
||||||
* the database.
|
* writes the file to the database if the file on
|
||||||
* @param fileType The type of file this is.
|
* the file system is newer than the one in the
|
||||||
* ThemeFile.LIVE and ThemeFile.DRAFT are the two allowed values.
|
* database.
|
||||||
|
* @param fileType The type of file this is. ThemeFile.LIVE and
|
||||||
|
* ThemeFile.DRAFT are the two allowed values.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static void updateDatabaseFiles(File currentFile, Theme currentTheme,
|
public static void updateDatabaseFiles(File currentFile, Theme currentTheme,
|
||||||
String serverSpecificPath,
|
String serverSpecificPath,
|
||||||
boolean overwriteNewerFiles,
|
boolean overwriteNewerFiles,
|
||||||
String fileType) {
|
String fileType) {
|
||||||
Assert.isTrue(ThemeFile.LIVE.equals(fileType) ||
|
Assert.isTrue(ThemeFile.LIVE.equals(fileType) || ThemeFile.DRAFT.equals(
|
||||||
ThemeFile.DRAFT.equals(fileType));
|
fileType));
|
||||||
HashMap themeFiles = new HashMap();
|
|
||||||
ThemeFileCollection collection = null;
|
prepareThemeDirectory(serverSpecificPath);
|
||||||
|
|
||||||
|
Map<String, ThemeFile> themeFiles = new HashMap<>();
|
||||||
|
ThemeFileCollection collection;
|
||||||
if (ThemeFile.LIVE.equals(fileType)) {
|
if (ThemeFile.LIVE.equals(fileType)) {
|
||||||
collection = currentTheme.getPublishedThemeFiles();
|
collection = currentTheme.getPublishedThemeFiles();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -85,30 +102,123 @@ public class ThemeFileUtil {
|
||||||
themeFiles.put(file.getFilePath(), file);
|
themeFiles.put(file.getFilePath(), file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDatabaseFiles(currentFile, currentTheme, serverSpecificPath,
|
updateDatabaseFiles(currentFile, currentTheme, serverSpecificPath,
|
||||||
themeFiles, overwriteNewerFiles, fileType);
|
themeFiles, overwriteNewerFiles, fileType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the theme directory. At the moment only compiles LESS CSS files.
|
||||||
|
* All files which do not end with {@code *.less}. Also files ending with
|
||||||
|
* {@code *.inc.less}. are ignored. These files are interpreted as include
|
||||||
|
* files that are included into another LESS file.
|
||||||
|
*
|
||||||
|
* @param themePath
|
||||||
|
*/
|
||||||
|
private static void prepareThemeDirectory(final String themePath) {
|
||||||
|
|
||||||
|
final Path root = Paths.get(themePath);
|
||||||
|
|
||||||
|
if (!Files.isDirectory(root)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files
|
||||||
|
.newDirectoryStream(root)
|
||||||
|
.forEach(path -> prepareThemeFile(path));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void prepareThemeFile(final Path path) {
|
||||||
|
|
||||||
|
if (Files.isDirectory(path)) {
|
||||||
|
try {
|
||||||
|
Files
|
||||||
|
.newDirectoryStream(path)
|
||||||
|
.forEach(current -> prepareThemeFile(current));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String fileName = path.toString();
|
||||||
|
if (fileName.toLowerCase().endsWith(".less")
|
||||||
|
&& !fileName.toLowerCase().endsWith(".inc.less")) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String result = Less.compile(path.toFile(), false);
|
||||||
|
final String outputPath = String.format(
|
||||||
|
"%s.css",
|
||||||
|
fileName.substring(0, fileName.length() - ".less"
|
||||||
|
.length()));
|
||||||
|
final Path output = Paths.get(outputPath);
|
||||||
|
Files.write(output, result.getBytes());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
}
|
||||||
|
// s_log.debug(String.format("Compiling %s to CSS...", fileName));
|
||||||
|
// final ScriptEngine scriptEngine = new ScriptEngineManager()
|
||||||
|
// .getEngineByName("JavaScript");
|
||||||
|
// try {
|
||||||
|
// scriptEngine.eval("var global = this;\n"
|
||||||
|
// + "var window = this;\n"
|
||||||
|
// + "var process = {env:{}};\n" + "\n"
|
||||||
|
// + "var console = {};\n"
|
||||||
|
// + "console.debug = print;\n"
|
||||||
|
// + "console.log = print;\n"
|
||||||
|
// + "console.warn = print;\n"
|
||||||
|
// + "console.error = print;");
|
||||||
|
// scriptEngine
|
||||||
|
// .eval(new InputStreamReader(ThemeFileUtil.class
|
||||||
|
// .getResourceAsStream(
|
||||||
|
// "/com/arsdigita/themedirector/util/less.min.js")));
|
||||||
|
// } catch (ScriptException ex) {
|
||||||
|
// throw new UncheckedWrapperException(ex);
|
||||||
|
// }
|
||||||
|
// final Invocable invocable = (Invocable) scriptEngine;
|
||||||
|
// final String lesscss;
|
||||||
|
// try {
|
||||||
|
// lesscss = new String(Files.readAllBytes(path));
|
||||||
|
// } catch (IOException ex) {
|
||||||
|
// throw new UncheckedWrapperException(ex);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// final Object result = invocable.invokeFunction("render",
|
||||||
|
// lesscss);
|
||||||
|
// s_log.debug(result);
|
||||||
|
// } catch (NoSuchMethodException | ScriptException ex) {
|
||||||
|
// throw new UncheckedWrapperException(ex);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this copies the files to the database
|
* this copies the files to the database
|
||||||
*
|
*
|
||||||
* @param currentFile The directory to search recursively for files
|
* @param currentFile The directory to search recursively for files
|
||||||
* to put in the database or the single file to add to the db.
|
* to put in the database or the single file to
|
||||||
|
* add to the db.
|
||||||
* @param currentTheme The current theme that is being operated on
|
* @param currentTheme The current theme that is being operated on
|
||||||
* @param serverSpecificPath The absolute path of the root
|
* @param serverSpecificPath The absolute path of the root file. This
|
||||||
* file. This string is removed from the absolute path of the current
|
* string is removed from the absolute path of
|
||||||
* file to get the filePath property of the ThemeFile
|
* the current file to get the filePath property
|
||||||
|
* of the ThemeFile
|
||||||
* @param themeFiles A Map of ThemeFiles with the key being the
|
* @param themeFiles A Map of ThemeFiles with the key being the
|
||||||
* filePath. This is used to look up files that have already been
|
* filePath. This is used to look up files that
|
||||||
* pulled from the database so that the code does not have to
|
* have already been pulled from the database so
|
||||||
* check the db once for every file.
|
* that the code does not have to check the db
|
||||||
* @param overwriteNewerFiles If this is true then it insert everything
|
* once for every file.
|
||||||
* in to the database. If this is false, it only writes the file to the
|
* @param overwriteNewerFiles If this is true then it insert everything in
|
||||||
* database if the file on the file system is newer than the one in
|
* to the database. If this is false, it only
|
||||||
* the database.
|
* writes the file to the database if the file on
|
||||||
* @param fileType The type of file this is.
|
* the file system is newer than the one in the
|
||||||
* ThemeFile.LIVE and ThemeFile.DRAFT are the two allowed values.
|
* database.
|
||||||
|
* @param fileType The type of file this is. ThemeFile.LIVE and
|
||||||
|
* ThemeFile.DRAFT are the two allowed values.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static void updateDatabaseFiles(File currentFile,
|
private static void updateDatabaseFiles(File currentFile,
|
||||||
|
|
@ -131,15 +241,16 @@ public class ThemeFileUtil {
|
||||||
String fullFilePath = currentFile.getAbsolutePath();
|
String fullFilePath = currentFile.getAbsolutePath();
|
||||||
String filePath = null;
|
String filePath = null;
|
||||||
int beginIndex = fullFilePath.indexOf(serverSpecificPath);
|
int beginIndex = fullFilePath.indexOf(serverSpecificPath);
|
||||||
if (beginIndex > -1 &&
|
if (beginIndex > -1 && fullFilePath.length()
|
||||||
fullFilePath.length() > serverSpecificPath.length()) {
|
> serverSpecificPath.length()) {
|
||||||
filePath = fullFilePath.substring
|
filePath = fullFilePath.substring(beginIndex
|
||||||
(beginIndex + serverSpecificPath.length() + 1);
|
+ serverSpecificPath
|
||||||
|
.length() + 1);
|
||||||
} else {
|
} else {
|
||||||
filePath = fullFilePath;
|
filePath = fullFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeFile themeFile = (ThemeFile)themeFiles.get(filePath);
|
ThemeFile themeFile = (ThemeFile) themeFiles.get(filePath);
|
||||||
if (!overwriteNewerFiles && themeFile != null) {
|
if (!overwriteNewerFiles && themeFile != null) {
|
||||||
// make sure the currentFile is newer than the
|
// make sure the currentFile is newer than the
|
||||||
// file in the db.
|
// file in the db.
|
||||||
|
|
@ -176,8 +287,8 @@ public class ThemeFileUtil {
|
||||||
}
|
}
|
||||||
themeFile.setVersion(fileType);
|
themeFile.setVersion(fileType);
|
||||||
themeFile.setContent(content);
|
themeFile.setContent(content);
|
||||||
themeFile.setLastModifiedDate
|
themeFile.setLastModifiedDate(new Date(currentFile
|
||||||
(new Date(currentFile.lastModified()));
|
.lastModified()));
|
||||||
|
|
||||||
// we save to help with stack trace issues and so that
|
// we save to help with stack trace issues and so that
|
||||||
// we don't have too many build up.
|
// we don't have too many build up.
|
||||||
|
|
@ -185,14 +296,15 @@ public class ThemeFileUtil {
|
||||||
in.close();
|
in.close();
|
||||||
os.close();
|
os.close();
|
||||||
} catch (FileNotFoundException fnfe) {
|
} catch (FileNotFoundException fnfe) {
|
||||||
s_log.error("Error opening file reader for " +
|
s_log.error("Error opening file reader for " + currentFile
|
||||||
currentFile.getAbsolutePath(), fnfe);
|
.getAbsolutePath(), fnfe);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
s_log.error("Error working with either the input or " +
|
s_log.error("Error working with either the input or "
|
||||||
" output stream for " +
|
+ " output stream for " + currentFile
|
||||||
currentFile.getAbsolutePath(), ex);
|
.getAbsolutePath(), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue