View Javadoc

1   /**
2    *     Licensed under the Apache License, Version 2.0 (the "License");
3    *     you may not use this file except in compliance with the License.
4    *     You may obtain a copy of the License at
5    *
6    *         http://www.apache.org/licenses/LICENSE-2.0
7    *
8    *     Unless required by applicable law or agreed to in writing, software
9    *     distributed under the License is distributed on an "AS IS" BASIS,
10   *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   *     See the License for the specific language governing permissions and
12   *     limitations under the License.
13   */
14  package ch.ledcom.maven.sitespeed;
15  
16  import java.io.BufferedReader;
17  import java.io.File;
18  import java.io.IOException;
19  import java.io.InputStreamReader;
20  import java.net.URL;
21  import java.util.List;
22  
23  import org.apache.maven.plugin.AbstractMojo;
24  import org.apache.maven.plugin.MojoExecutionException;
25  import org.apache.maven.plugin.MojoFailureException;
26  import org.apache.maven.plugins.annotations.Mojo;
27  import org.apache.maven.plugins.annotations.Parameter;
28  
29  import com.google.common.base.Strings;
30  import com.google.common.collect.ImmutableList;
31  import com.google.common.io.Closeables;
32  
33  /**
34   * Generate a SiteSpeed.io report.
35   * 
36   * At the moment this Mojo is a simple wrapper around the sitespeed.io bash
37   * script.
38   * 
39   * @author gehel
40   */
41  @Mojo(name = "sitespeed")
42  public class SiteSpeedMojo extends AbstractMojo {
43  
44      private static final String PROPERTY_PREFIX = "siteSpeed";
45  
46      /** Path to the SiteSpeed.io directory. */
47      @Parameter(property = PROPERTY_PREFIX + ".siteSpeedPath", required = true)
48      private File siteSpeedPath;
49  
50      /** Path to the PhantomJS directory. */
51      @Parameter(property = PROPERTY_PREFIX + ".phantomJSPath", required = true)
52      private File phantomJSPath;
53  
54      /** The start url for the test. */
55      @Parameter(property = PROPERTY_PREFIX + ".url", required = true)
56      private URL url;
57  
58      /** Crawl depth, default is 1. */
59      @Parameter(property = PROPERTY_PREFIX + ".crawlDepth", required = false, defaultValue = "1")
60      private int crawlDepth;
61  
62      /** Skip urls that contains this in the path. */
63      @Parameter(property = PROPERTY_PREFIX + ".skipUrls", required = false)
64      private String skipUrls;
65  
66      /** The number of processes that will analyze pages. */
67      @Parameter(property = PROPERTY_PREFIX + ".nbProcesses", required = false, defaultValue = "5")
68      private int nbProcesses;
69  
70      /** The memory heap size for the java applications. */
71      @Parameter(property = PROPERTY_PREFIX + ".maxHeap", required = false, defaultValue = "1024")
72      private int maxHeap;
73  
74      /** The output format, always output as html but you can add images (img). */
75      @Parameter(property = PROPERTY_PREFIX + ".outputFormat", required = false)
76      private String outputFormat;
77  
78      /** The result base directory. */
79      @Parameter(property = PROPERTY_PREFIX + ".outputDir", required = false, defaultValue = "${project.build.directory}/sitespeed-result")
80      private File outputDir;
81  
82      /** Create a tar zip file of the result files. */
83      @Parameter(property = PROPERTY_PREFIX + ".zip", required = false, defaultValue = "false")
84      private boolean zip;
85  
86      /** The proxy host & protocol: proxy.soulgalore.com:80. */
87      @Parameter(property = PROPERTY_PREFIX + ".proxy", required = false)
88      private String proxy;
89  
90      /** The proxy type. */
91      @Parameter(property = PROPERTY_PREFIX + ".proxyType", required = false, defaultValue = "http")
92      private String proxyType;
93  
94      /** The user agent. */
95      @Parameter(property = PROPERTY_PREFIX + ".userAgent", required = false, defaultValue = "Mozilla/6.0")
96      private String userAgent;
97  
98      /** The view port, the page viewport size WidthxHeight, like 400x300. */
99      @Parameter(property = PROPERTY_PREFIX + ".viewPort", required = false, defaultValue = "1280x800")
100     private String viewport;
101 
102     /** The compiled yslow file. */
103     @Parameter(property = PROPERTY_PREFIX + ".yslowFile", required = false, defaultValue = "dependencies/yslow-3.1.4-sitespeed.js")
104     private String yslowFile;
105 
106     /** Which ruleset to use, default is the latest sitespeed.io version. */
107     @Parameter(property = PROPERTY_PREFIX + ".rulesetVersion", required = false)
108     private String rulesetVersion;
109 
110     /**
111      * Main Mojo method.
112      * 
113      * @throws MojoExecutionException
114      *             in case of execution error
115      * @throws MojoFailureException
116      *             in case of execution failure
117      */
118     @Override
119     public final void execute() throws MojoExecutionException,
120             MojoFailureException {
121         logParameters();
122         BufferedReader reader = null;
123         boolean threw = true;
124         try {
125             ProcessBuilder pb = new ProcessBuilder(constructCmdarray());
126             pb.directory(siteSpeedPath);
127             enrichEnvironment(pb);
128             pb.redirectErrorStream(true);
129             Process p = pb.start();
130             reader = new BufferedReader(new InputStreamReader(
131                     p.getInputStream()));
132             String line;
133             while ((line = reader.readLine()) != null) {
134                 getLog().info(line);
135             }
136             int status = p.waitFor();
137             if (status != 0) {
138                 throw new MojoExecutionException(
139                         "sitespeed.io exited with status [" + status + "]");
140             }
141             threw = false;
142         } catch (IOException ioe) {
143             throw new MojoExecutionException(
144                     "IOException when generating report", ioe);
145         } catch (InterruptedException ie) {
146             throw new MojoExecutionException(
147                     "InterruptedException when generating report", ie);
148         } finally {
149             try {
150                 Closeables.close(reader, threw);
151             } catch (IOException ioe) {
152                 throw new MojoExecutionException(
153                         "IOException when closing process input stream", ioe);
154             }
155         }
156     }
157 
158     private void logParameters() {
159         getLog().info("siteSpeedPath=[" + siteSpeedPath + "]");
160         getLog().info("phantomJSPath=[" + phantomJSPath + "]");
161         getLog().info("url=[" + url.toExternalForm() + "]");
162         getLog().info("crawlDepth=[" + crawlDepth + "]");
163         getLog().info("skipUrls=[" + skipUrls + "]");
164         getLog().info("nbProcesses=[" + nbProcesses + "]");
165         getLog().info("maxHeap=[" + maxHeap + "]");
166         getLog().info("outputFormat=[" + outputFormat + "]");
167         getLog().info("outputDir=[" + outputDir + "]");
168         getLog().info("zip=[" + zip + "]");
169         getLog().info("proxy=[" + proxy + "]");
170         getLog().info("proxyType=[" + proxyType + "]");
171         getLog().info("userAgent=[" + userAgent + "]");
172         getLog().info("viewport=[" + viewport + "]");
173         getLog().info("yslowFile=[" + yslowFile + "]");
174         getLog().info("rulesetVersion=[" + rulesetVersion + "]");
175     }
176 
177     private void enrichEnvironment(ProcessBuilder pb) {
178         final String currentPath = pb.environment().get("PATH");
179         pb.environment().put("PATH", getPhantomJSBinDir() + ":" + currentPath);
180     }
181 
182     /**
183      * Construct the sitespeed.io command.
184      * 
185      * @return the command to run (including arguments)
186      */
187     private List<String> constructCmdarray() {
188         ImmutableList.Builder<String> builder = ImmutableList
189                 .<String> builder();
190         builder.add(getSiteSpeedBin().toString());
191         builder.add("-u").add(url.toExternalForm());
192         builder.add("-d").add(Integer.toString(crawlDepth));
193         if (!Strings.isNullOrEmpty(skipUrls)) {
194             builder.add("-f").add(skipUrls);
195         }
196         builder.add("-p").add(Integer.toString(nbProcesses));
197         builder.add("-m").add(Integer.toString(maxHeap));
198         if (!Strings.isNullOrEmpty(outputFormat)) {
199             builder.add("-o").add(outputFormat);
200         }
201         builder.add("-r").add(outputDir.toString());
202         if (zip) {
203             builder.add("-z");
204         }
205         if (!Strings.isNullOrEmpty(proxy)) {
206             builder.add("-x").add(proxy);
207         }
208         if (!Strings.isNullOrEmpty(proxyType)) {
209             builder.add("-t").add(proxyType);
210         }
211         builder.add("-a").add(userAgent);
212         builder.add("-v").add(viewport);
213         builder.add("-y").add(yslowFile);
214         if (!Strings.isNullOrEmpty(rulesetVersion)) {
215             builder.add("-l").add(rulesetVersion);
216         }
217         return builder.build();
218     }
219 
220     /**
221      * Get the <code>bin</code> directory of the PhantomJS distribution.
222      * 
223      * @return the PhantomJS <code>bin</code> directory
224      */
225     private File getPhantomJSBinDir() {
226         return new File(phantomJSPath, "bin");
227     }
228 
229     /**
230      * Get the <code>sitespeed.io</code> script.
231      * 
232      * @return the <code>sitespeed.io</code> script
233      */
234     private File getSiteSpeedBin() {
235         return new File(siteSpeedPath, "sitespeed.io");
236     }
237 }