001package org.jszip.maven; 002 003import org.apache.maven.plugin.MojoExecutionException; 004import org.apache.maven.plugin.MojoFailureException; 005import org.apache.maven.plugin.logging.Log; 006import org.apache.maven.plugins.annotations.LifecyclePhase; 007import org.apache.maven.plugins.annotations.Mojo; 008import org.apache.maven.plugins.annotations.Parameter; 009import org.apache.maven.plugins.annotations.ResolutionScope; 010import org.codehaus.plexus.util.IOUtil; 011import org.jszip.css.CssCompilationError; 012import org.jszip.css.CssEngine; 013import org.jszip.less.LessEngine; 014import org.jszip.pseudo.io.PseudoDirectoryScanner; 015import org.jszip.pseudo.io.PseudoFile; 016import org.jszip.pseudo.io.PseudoFileOutputStream; 017import org.jszip.pseudo.io.PseudoFileSystem; 018import org.jszip.rhino.GlobalFunctions; 019import org.jszip.rhino.JavaScriptTerminationException; 020import org.jszip.rhino.MavenLogErrorReporter; 021import org.mozilla.javascript.Context; 022import org.mozilla.javascript.ContextFactory; 023import org.mozilla.javascript.Script; 024import org.mozilla.javascript.Scriptable; 025import org.mozilla.javascript.ScriptableObject; 026import org.mozilla.javascript.tools.shell.Global; 027import org.mozilla.javascript.tools.shell.QuitAction; 028import org.mozilla.javascript.tools.shell.ShellContextFactory; 029 030import java.io.File; 031import java.io.FileInputStream; 032import java.io.IOException; 033import java.io.InputStream; 034import java.io.InputStreamReader; 035import java.util.ArrayList; 036import java.util.Arrays; 037import java.util.List; 038 039@Mojo(name = "compile-less", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, 040 requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) 041public class CompileLESSMojo extends AbstractPseudoFileSystemProcessorMojo { 042 043 /** 044 * Directory containing the less processor. 045 */ 046 @Parameter(defaultValue = "src/build/js/less-rhino.js") 047 private File customLessScript; 048 049 /** 050 * Skip compilation. 051 */ 052 @Parameter(property = "jszip.less.skip", defaultValue = "false") 053 private boolean lessSkip; 054 055 /** 056 * Force compilation even if the source LESS file is older than the destination CSS file. 057 */ 058 @Parameter(property = "jszip.less.forceIfOlder", defaultValue = "false") 059 private boolean lessForceIfOlder; 060 061 /** 062 * Compress CSS. 063 */ 064 @Parameter(property = "jszip.less.compress", defaultValue = "true") 065 private boolean lessCompress; 066 067 /** 068 * Indicates whether the build will continue even if there are compilation errors. 069 */ 070 @Parameter(property = "jszip.less.failOnError", defaultValue = "true") 071 private boolean lessFailOnError; 072 073 /** 074 * Indicates whether to show extracts of the code where errors occur. 075 */ 076 @Parameter(property = "jszip.less.showErrorExtracts", defaultValue = "false") 077 private boolean showErrorExtracts; 078 079 /** 080 * A list of <include> elements specifying the less files (by pattern) that should be included in 081 * processing. 082 */ 083 @Parameter 084 private List<String> lessIncludes; 085 086 /** 087 * A list of <exclude> elements specifying the less files (by pattern) that should be excluded from 088 * processing. 089 */ 090 @Parameter 091 private List<String> lessExcludes; 092 093 /** 094 * The character encoding scheme to be applied when reading LESS files. 095 */ 096 @Parameter( defaultValue = "${project.build.sourceEncoding}" ) 097 private String encoding; 098 099 /** 100 * @see org.apache.maven.plugin.Mojo#execute() 101 */ 102 public void execute() throws MojoExecutionException, MojoFailureException { 103 if (lessSkip) { 104 getLog().info("LESS compilation skipped."); 105 return; 106 } 107 if (webappDirectory.isFile()) { 108 throw new MojoExecutionException("Webapp directory '" + webappDirectory + "' is not a directory"); 109 } 110 if (!webappDirectory.isDirectory()) { 111 getLog().info("Webapp directory '" + webappDirectory + " does not exist. Nothing to do."); 112 return; 113 } 114 final List<PseudoFileSystem.Layer> layers = buildVirtualFileSystemLayers(); 115 final PseudoFileSystem fs = new PseudoFileSystem(layers); 116 try { 117 CssEngine engine = new LessEngine(fs, encoding == null ? "utf-8" : encoding, getLog(), lessCompress, customLessScript, showErrorExtracts); 118 119 // look for files to compile 120 121 PseudoDirectoryScanner scanner = new PseudoDirectoryScanner(); 122 123 scanner.setFileSystem(fs); 124 125 scanner.setBasedir(fs.getPseudoFile("/virtual")); 126 127 if (lessIncludes != null && !lessIncludes.isEmpty()) { 128 scanner.setIncludes(processIncludesExcludes(lessIncludes)); 129 } else { 130 scanner.setIncludes(new String[]{"**/*.less"}); 131 } 132 133 if (lessExcludes != null && !lessExcludes.isEmpty()) { 134 scanner.setExcludes(processIncludesExcludes(lessExcludes)); 135 } else { 136 scanner.setExcludes(new String[0]); 137 } 138 139 scanner.scan(); 140 141 final List<String> includedFiles = new ArrayList<String>(Arrays.asList(scanner.getIncludedFiles())); 142 getLog().debug("Files to compile: " + includedFiles); 143 144 for (String fileName : includedFiles) { 145 final PseudoFile dest = fs.getPseudoFile("/target/" + engine.mapName(fileName)); 146 if (!lessForceIfOlder) { 147 if (dest.isFile()) { 148 final PseudoFile src = fs.getPseudoFile("/virtual/" + fileName); 149 if (src.lastModified() < dest.lastModified()) { 150 continue; 151 } 152 } 153 } 154 if (!dest.getParentFile().isDirectory()) { 155 dest.getParentFile().mkdirs(); 156 } 157 158 final String css = engine.toCSS("/virtual/" + fileName); 159 PseudoFileOutputStream fos = null; 160 try { 161 fos = new PseudoFileOutputStream(dest); 162 IOUtil.copy(css, fos); 163 } catch (IOException e) { 164 throw new MojoFailureException("Could not write CSS file produced from " + fileName, e); 165 } finally { 166 IOUtil.close(fos); 167 } 168 } 169 } catch (CssCompilationError e) { 170 throw new MojoFailureException("Compilation failure: " + e.getMessage(), e); 171 } catch (IOException e) { 172 throw new MojoExecutionException("Could not instantiate compiler: " + e.getMessage(), e); 173 } 174 } 175}