1 package net_alchim31_maven_yuicompressor;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.InputStreamReader;
8 import java.io.OutputStreamWriter;
9 import java.util.zip.GZIPOutputStream;
10
11 import org.apache.maven.plugin.MojoExecutionException;
12 import org.codehaus.plexus.util.FileUtils;
13 import org.codehaus.plexus.util.IOUtil;
14
15 import com.yahoo.platform.yui.compressor.CssCompressor;
16 import com.yahoo.platform.yui.compressor.JavaScriptCompressor;
17
18
19
20
21
22
23
24
25
26
27
28 public class YuiCompressorMojo extends MojoSupport {
29
30
31
32
33
34
35 private String encoding;
36
37
38
39
40
41
42 private String suffix;
43
44
45
46
47
48
49 private boolean nosuffix;
50
51
52
53
54
55
56 private int linebreakpos;
57
58
59
60
61
62
63 private boolean nocompress;
64
65
66
67
68
69
70 private boolean nomunge;
71
72
73
74
75
76
77 private boolean preserveAllSemiColons;
78
79
80
81
82
83
84 private boolean disableOptimizations;
85
86
87
88
89
90
91
92 private boolean force;
93
94
95
96
97
98
99
100
101 private Aggregation[] aggregations;
102
103
104
105
106
107
108 private boolean gzip;
109
110
111
112
113
114
115 private boolean statistics;
116
117
118
119
120
121 private boolean preProcessAggregates;
122
123 private long inSizeTotal_;
124 private long outSizeTotal_;
125
126 @Override
127 protected String[] getDefaultIncludes() throws Exception {
128 return new String[]{"**/*.css", "**/*.js"};
129 }
130
131 @Override
132 public void beforeProcess() throws Exception {
133 if (nosuffix) {
134 suffix = "";
135 }
136
137 if(preProcessAggregates) aggregate();
138 }
139
140 @Override
141 protected void afterProcess() throws Exception {
142 if (statistics && (inSizeTotal_ > 0)) {
143 getLog().info(String.format("total input (%db) -> output (%db)[%d%%]", inSizeTotal_, outSizeTotal_, ((outSizeTotal_ * 100)/inSizeTotal_)));
144 }
145
146 if(!preProcessAggregates) aggregate();
147 }
148
149 private void aggregate() throws Exception {
150 if (aggregations != null) {
151 for(Aggregation aggregation : aggregations) {
152 getLog().info("generate aggregation : " + aggregation.output);
153 aggregation.run();
154 File gzipped = gzipIfRequested(aggregation.output);
155 if (statistics) {
156 if (gzipped != null) {
157 getLog().info(String.format("%s (%db) -> %s (%db)[%d%%]", aggregation.output.getName(), aggregation.output.length(), gzipped.getName(), gzipped.length(), ratioOfSize(aggregation.output, gzipped)));
158 } else if (aggregation.output.exists()){
159 getLog().info(String.format("%s (%db)", aggregation.output.getName(), aggregation.output.length()));
160 } else {
161 getLog().warn(String.format("%s not created", aggregation.output.getName()));
162 }
163 }
164 }
165 }
166 }
167
168 @Override
169 protected void processFile(SourceFile src) throws Exception {
170 if (getLog().isDebugEnabled()) {
171 getLog().debug("compress file :" + src.toFile()+ " to " + src.toDestFile(suffix));
172 }
173 File inFile = src.toFile();
174 File outFile = src.toDestFile(suffix);
175
176 getLog().debug("only compress if input file is younger than existing output file");
177 if (!force && outFile.exists() && (outFile.lastModified() > inFile.lastModified())) {
178 if (getLog().isInfoEnabled()) {
179 getLog().info("nothing to do, " + outFile + " is younger than original, use 'force' option or clean your target");
180 }
181 return;
182 }
183
184 InputStreamReader in = null;
185 OutputStreamWriter out = null;
186 File outFileTmp = new File(outFile.getAbsolutePath() + ".tmp");
187 FileUtils.forceDelete(outFileTmp);
188 try {
189 in = new InputStreamReader(new FileInputStream(inFile), encoding);
190 if (!outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs()) {
191 throw new MojoExecutionException( "Cannot create resource output directory: " + outFile.getParentFile() );
192 }
193 getLog().debug("use a temporary outputfile (in case in == out)");
194
195 getLog().debug("start compression");
196 out = new OutputStreamWriter(new FileOutputStream(outFileTmp), encoding);
197 if (nocompress) {
198 getLog().info("No compression is enabled");
199 IOUtil.copy(in, out);
200 }
201 else if (".js".equalsIgnoreCase(src.getExtension())) {
202 JavaScriptCompressor compressor = new JavaScriptCompressor(in, jsErrorReporter_);
203 compressor.compress(out, linebreakpos, !nomunge, jswarn, preserveAllSemiColons, disableOptimizations);
204 } else if (".css".equalsIgnoreCase(src.getExtension())) {
205 compressCss(in, out);
206 }
207 getLog().debug("end compression");
208 } finally {
209 IOUtil.close(in);
210 IOUtil.close(out);
211 }
212 FileUtils.forceDelete(outFile);
213 FileUtils.rename(outFileTmp, outFile);
214 File gzipped = gzipIfRequested(outFile);
215 if (statistics) {
216 inSizeTotal_ += inFile.length();
217 outSizeTotal_ += outFile.length();
218 getLog().info(String.format("%s (%db) -> %s (%db)[%d%%]", inFile.getName(), inFile.length(), outFile.getName(), outFile.length(), ratioOfSize(inFile, outFile)));
219 if (gzipped != null) {
220 getLog().info(String.format("%s (%db) -> %s (%db)[%d%%]", inFile.getName(), inFile.length(), gzipped.getName(), gzipped.length(), ratioOfSize(inFile, gzipped)));
221 }
222 }
223 }
224
225 private void compressCss(InputStreamReader in, OutputStreamWriter out)
226 throws IOException {
227 try{
228 CssCompressor compressor = new CssCompressor(in);
229 compressor.compress(out, linebreakpos);
230 }catch(IllegalArgumentException e){
231 throw new IllegalArgumentException(
232 "Unexpected characters found in CSS file. Ensure that the CSS file does not contain '$', and try again",e);
233 }
234 }
235
236 protected File gzipIfRequested(File file) throws Exception {
237 if (!gzip || (file == null) || (!file.exists())) {
238 return null;
239 }
240 if (".gz".equalsIgnoreCase(FileUtils.getExtension(file.getName()))) {
241 return null;
242 }
243 File gzipped = new File(file.getAbsolutePath()+".gz");
244 getLog().debug(String.format("create gzip version : %s", gzipped.getName()));
245 GZIPOutputStream out = null;
246 FileInputStream in = null;
247 try {
248 out = new GZIPOutputStream(new FileOutputStream(gzipped));
249 in = new FileInputStream(file);
250 IOUtil.copy(in, out);
251 } finally {
252 IOUtil.close(in);
253 IOUtil.close(out);
254 }
255 return gzipped;
256 }
257
258 protected long ratioOfSize(File file100, File fileX) throws Exception {
259 long v100 = Math.max(file100.length(), 1);
260 long vX = Math.max(fileX.length(), 1);
261 return (vX * 100)/v100;
262 }
263 }