
wrm.CompilationMojo Maven / Gradle / Ivy
package wrm;
import io.bit3.jsass.CompilationException;
import io.bit3.jsass.Output;
import wrm.libsass.SassCompiler;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
/**
* Compilation of all scss files from inputpath to outputpath using includePaths
*
* @goal compile
* @phase generate-resources
*/
public class CompilationMojo extends AbstractMojo {
/**
* The directory in which the compiled CSS files will be placed. The default value is
* ${project.build.directory}
*
* @parameter property="project.build.directory"
* @required
*/
private File outputPath;
/**
* The directory from which the source .scss files will be read. This directory will be
* traversed recursively, and all .scss files found in this directory or subdirectories
* will be compiled. The default value is src/main/sass
*
* @parameter default-value="src/main/sass"
*/
private String inputPath;
/**
* Additional include path, ';'-separated. The default value is null
*
* @parameter
*/
private String includePath;
/**
* Output style for the generated css code. One of nested, expanded,
* compact, compressed. Note that as of libsass 3.1, expanded
* and compact are the same as nested. The default value is
* nested.
*
* @parameter default-value="nested"
*/
private SassCompiler.OutputStyle outputStyle;
/**
* Emit comments in the compiled CSS indicating the corresponding source line. The default
* value is false
*
* @parameter default-value="false"
*/
private boolean generateSourceComments;
/**
* Generate source map files. The generated source map files will be placed in the directory
* specified by sourceMapOutputPath. The default value is true.
*
* @parameter default-value="true"
*/
private boolean generateSourceMap;
/**
* The directory in which the source map files that correspond to the compiled CSS will be
* placed. The default value is ${project.build.directory}
*
* @parameter property="project.build.directory"
*/
private String sourceMapOutputPath;
/**
* Prevents the generation of the sourceMappingURL special comment as the last
* line of the compiled CSS. The default value is false.
*
* @parameter default-value="false"
*/
private boolean omitSourceMapingURL;
/**
* Embeds the whole source map data directly into the compiled CSS file by transforming
* sourceMappingURL into a data URI. The default value is false.
*
* @parameter default-value="false"
*/
private boolean embedSourceMapInCSS;
/**
* Embeds the contents of the source .scss files in the source map file instead of the
* paths to those files. The default value is false
*
* @parameter default-value="false"
*/
private boolean embedSourceContentsInSourceMap;
/**
* Switches the input syntax used by the files to either sass or scss.
* The default value is scss.
*
* @parameter default-value="scss"
*/
private SassCompiler.InputSyntax inputSyntax;
/**
* Precision for fractional numbers. The default value is 5.
*
* @parameter default-value="5"
*/
private int precision;
/**
* should fail the build in case of compilation errors.
*
* @parameter default-value="true"
*/
private boolean failOnError;
/**
* Copy source files to output directory.
*
* @parameter default-value="false"
*/
private boolean copySourceToOutput;
/**
* @parameter property="project"
* @required
* @readonly
*/
protected MavenProject project;
private SassCompiler compiler;
public void execute() throws MojoExecutionException, MojoFailureException {
validateConfig();
compiler = initCompiler();
inputPath = inputPath.replaceAll("\\\\", "/");
getLog().debug("Input Path=" + inputPath);
getLog().debug("Output Path=" + outputPath);
final Path root = project.getBasedir().toPath().resolve(Paths.get(inputPath));
String fileExt = getFileExtension();
String globPattern = "glob:{**/,}*."+fileExt;
getLog().debug("Glob = " + globPattern);
final PathMatcher matcher = FileSystems.getDefault().getPathMatcher(globPattern);
final AtomicInteger errorCount = new AtomicInteger(0);
final AtomicInteger fileCount = new AtomicInteger(0);
try {
Files.walkFileTree(root, new SimpleFileVisitor() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (matcher.matches(file) && !file.getFileName().toString().startsWith("_")) {
fileCount.incrementAndGet();
if(!processFile(root, file)){
errorCount.incrementAndGet();
}
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
});
}
catch (IOException e) {
throw new MojoExecutionException("Failed", e);
}
getLog().info("Compiled " + fileCount + " files");
if(errorCount.get() > 0){
if (failOnError){
throw new MojoExecutionException("Failed with " + errorCount.get() + " errors");
} else {
getLog().error("Failed with " + errorCount.get() + " errors. Continuing due to failOnError=false.");
}
}
}
private String getFileExtension() {
return inputSyntax.toString();
}
private void validateConfig() {
if (!generateSourceMap) {
if (embedSourceMapInCSS) {
getLog().warn("embedSourceMapInCSS=true is ignored. Cause: generateSourceMap=false");
}
if (embedSourceContentsInSourceMap) {
getLog().warn("embedSourceContentsInSourceMap=true is ignored. Cause: generateSourceMap=false");
}
}
if (outputStyle != SassCompiler.OutputStyle.compressed && outputStyle != SassCompiler.OutputStyle.nested) {
getLog().warn("outputStyle=" + outputStyle + " is replaced by nested. Cause: libsass 3.1 only supports compressed and nested");
}
}
private SassCompiler initCompiler() {
SassCompiler compiler = new SassCompiler();
compiler.setEmbedSourceMapInCSS(this.embedSourceMapInCSS);
compiler.setEmbedSourceContentsInSourceMap(this.embedSourceContentsInSourceMap);
compiler.setGenerateSourceComments(this.generateSourceComments);
compiler.setGenerateSourceMap(this.generateSourceMap);
compiler.setIncludePaths(this.includePath);
compiler.setInputSyntax(this.inputSyntax);
compiler.setOmitSourceMappingURL(this.omitSourceMapingURL);
compiler.setOutputStyle(this.outputStyle);
compiler.setPrecision(this.precision);
return compiler;
}
private boolean processFile(Path inputRootPath, Path inputFilePath) throws IOException {
getLog().debug("Processing File " + inputFilePath);
Path relativeInputPath = inputRootPath.relativize(inputFilePath);
Path outputRootPath = this.outputPath.toPath();
Path outputFilePath = outputRootPath.resolve(relativeInputPath);
String fileExtension = getFileExtension();
outputFilePath = Paths.get(outputFilePath.toAbsolutePath().toString().replaceFirst("\\."+fileExtension+"$", ".css"));
Path sourceMapRootPath = Paths.get(this.sourceMapOutputPath);
Path sourceMapOutputPath = sourceMapRootPath.resolve(relativeInputPath);
sourceMapOutputPath = Paths.get(sourceMapOutputPath.toAbsolutePath().toString().replaceFirst("\\.scss$", ".css.map"));
if (copySourceToOutput) {
Path inputOutputPath = outputRootPath.resolve(relativeInputPath);
inputOutputPath.toFile().mkdirs();
Files.copy(inputFilePath, inputOutputPath, REPLACE_EXISTING);
inputFilePath = inputOutputPath;
}
Output out;
try {
out = compiler.compileFile(
inputFilePath.toAbsolutePath().toString(),
outputFilePath.toAbsolutePath().toString(),
sourceMapOutputPath.toAbsolutePath().toString()
);
}
catch (CompilationException e) {
getLog().error(e.getMessage());
getLog().debug(e);
return false;
}
getLog().debug("Compilation finished.");
writeContentToFile(outputFilePath, out.getCss());
if (out.getSourceMap() != null) {
writeContentToFile(sourceMapOutputPath, out.getSourceMap());
}
return true;
}
private void writeContentToFile(Path outputFilePath, String content) throws IOException {
File f = outputFilePath.toFile();
f.getParentFile().mkdirs();
f.createNewFile();
OutputStreamWriter os = null;
try{
os = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
os.write(content);
os.flush();
} finally {
if (os != null)
os.close();
}
getLog().debug("Written to: " + f);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy