1 package org.apache.maven.plugins.shade.mojo;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6
7 import org.apache.maven.plugin.AbstractMojo;
8 import org.apache.maven.plugin.MojoExecutionException;
9
10
11
12
13
14
15
16
17
18
19 @SuppressWarnings( "all" )
20 public class HelpMojo
21 extends AbstractMojo
22 {
23
24
25
26
27
28 private boolean detail;
29
30
31
32
33
34
35 private java.lang.String goal;
36
37
38
39
40
41
42 private int lineLength;
43
44
45
46
47
48
49 private int indentSize;
50
51
52
53 public void execute()
54 throws MojoExecutionException
55 {
56 if ( lineLength <= 0 )
57 {
58 getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." );
59 lineLength = 80;
60 }
61 if ( indentSize <= 0 )
62 {
63 getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." );
64 indentSize = 2;
65 }
66
67 StringBuffer sb = new StringBuffer();
68
69 append( sb, "org.apache.maven.plugins:maven-shade-plugin:1.7.1", 0 );
70 append( sb, "", 0 );
71
72 append( sb, "Maven Shade Plugin", 0 );
73 append( sb, "Repackages the project classes together with their dependencies into a single uber-jar, optionally renaming classes or removing unused classes.", 1 );
74 append( sb, "", 0 );
75
76 if ( goal == null || goal.length() <= 0 )
77 {
78 append( sb, "This plugin has 2 goals:", 0 );
79 append( sb, "", 0 );
80 }
81
82 if ( goal == null || goal.length() <= 0 || "help".equals( goal ) )
83 {
84 append( sb, "shade:help", 0 );
85 append( sb, "Display help information on maven-shade-plugin.\nCall\n\u00a0\u00a0mvn\u00a0shade:help\u00a0-Ddetail=true\u00a0-Dgoal=<goal-name>\nto display parameter details.", 1 );
86 append( sb, "", 0 );
87 if ( detail )
88 {
89 append( sb, "Available parameters:", 1 );
90 append( sb, "", 0 );
91
92 append( sb, "detail (Default: false)", 2 );
93 append( sb, "If true, display all settable properties for each goal.", 3 );
94 append( sb, "Expression: ${detail}", 3 );
95 append( sb, "", 0 );
96
97 append( sb, "goal", 2 );
98 append( sb, "The name of the goal for which to show help. If unspecified, all goals will be displayed.", 3 );
99 append( sb, "Expression: ${goal}", 3 );
100 append( sb, "", 0 );
101
102 append( sb, "indentSize (Default: 2)", 2 );
103 append( sb, "The number of spaces per indentation level, should be positive.", 3 );
104 append( sb, "Expression: ${indentSize}", 3 );
105 append( sb, "", 0 );
106
107 append( sb, "lineLength (Default: 80)", 2 );
108 append( sb, "The maximum length of a display line, should be positive.", 3 );
109 append( sb, "Expression: ${lineLength}", 3 );
110 append( sb, "", 0 );
111 }
112 }
113
114 if ( goal == null || goal.length() <= 0 || "shade".equals( goal ) )
115 {
116 append( sb, "shade:shade", 0 );
117 append( sb, "Mojo that performs shading delegating to the Shader component.", 1 );
118 append( sb, "", 0 );
119 if ( detail )
120 {
121 append( sb, "Available parameters:", 1 );
122 append( sb, "", 0 );
123
124 append( sb, "artifactSet", 2 );
125 append( sb, "Artifacts to include/exclude from the final artifact. Artifacts are denoted by composite identifiers of the general form groupId:artifactId:type:classifier. Since version 1.3, the wildcard characters \'*\' and \'?\' can be used within the sub parts of those composite identifiers to do pattern matching. For convenience, the syntax groupId is equivalent to groupId:*:*:*, groupId:artifactId is equivalent to groupId:artifactId:*:* and groupId:artifactId:classifier is equivalent to groupId:artifactId:*:classifier. For example:\n<artifactSet>\n\u00a0\u00a0<includes>\n\u00a0\u00a0\u00a0\u00a0<include>org.apache.maven:*</include>\n\u00a0\u00a0</includes>\n\u00a0\u00a0<excludes>\n\u00a0\u00a0\u00a0\u00a0<exclude>*:maven-core</exclude>\n\u00a0\u00a0</excludes>\n</artifactSet>\n", 3 );
126 append( sb, "", 0 );
127
128 append( sb, "createDependencyReducedPom (Default: true)", 2 );
129 append( sb, "Flag whether to generate a simplified POM for the shaded artifact. If set to true, dependencies that have been included into the uber JAR will be removed from the <dependencies> section of the generated POM. The reduced POM will be named dependency-reduced-pom.xml and is stored into the same directory as the shaded artifact. Unless you also specify dependencyReducedPomLocation, the plugin will create a temporary file named dependency-reduced-pom.xml in the project basedir.", 3 );
130 append( sb, "Expression: ${createDependencyReducedPom}", 3 );
131 append( sb, "", 0 );
132
133 append( sb, "createSourcesJar (Default: false)", 2 );
134 append( sb, "When true, it will attempt to create a sources jar as well", 3 );
135 append( sb, "Expression: ${createSourcesJar}", 3 );
136 append( sb, "", 0 );
137
138 append( sb, "dependencyReducedPomLocation", 2 );
139 append( sb, "(no description available)", 3 );
140 append( sb, "Expression: ${dependencyReducedPomLocation}", 3 );
141 append( sb, "", 0 );
142
143 append( sb, "filters", 2 );
144 append( sb, "Archive Filters to be used. Allows you to specify an artifact in the form of a composite identifier as used by artifactSet and a set of include/exclude file patterns for filtering which contents of the archive are added to the shaded jar. From a logical perspective, includes are processed before excludes, thus it\'s possible to use an include to collect a set of files from the archive then use excludes to further reduce the set. By default, all files are included and no files are excluded. If multiple filters apply to an artifact, the intersection of the matched files will be included in the final JAR. For example:\n<filters>\n\u00a0\u00a0<filter>\n\u00a0\u00a0\u00a0\u00a0<artifact>junit:junit</artifact>\n\u00a0\u00a0\u00a0\u00a0<includes>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<include>org/junit/**</include>\n\u00a0\u00a0\u00a0\u00a0</includes>\n\u00a0\u00a0\u00a0\u00a0<excludes>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<exclude>org/junit/experimental/**</exclude>\n\u00a0\u00a0\u00a0\u00a0</excludes>\n\u00a0\u00a0</filter>\n</filters>\n", 3 );
145 append( sb, "", 0 );
146
147 append( sb, "finalName", 2 );
148 append( sb, "The name of the shaded artifactId. If you like to change the name of the native artifact, you may use the <build><finalName> setting. If this is set to something different than <build><finalName>, no file replacement will be performed, even if shadedArtifactAttached is being used.", 3 );
149 append( sb, "Expression: ${finalName}", 3 );
150 append( sb, "", 0 );
151
152 append( sb, "keepDependenciesWithProvidedScope (Default: false)", 2 );
153 append( sb, "When true, dependencies are kept in the pom but with scope \'provided\'; when false, the dependency is removed.", 3 );
154 append( sb, "Expression: ${keepDependenciesWithProvidedScope}", 3 );
155 append( sb, "", 0 );
156
157 append( sb, "minimizeJar (Default: false)", 2 );
158 append( sb, "When true, dependencies will be stripped down on the class level to only the transitive hull required for the artifact. Note: Usage of this feature requires Java 1.5 or higher.", 3 );
159 append( sb, "", 0 );
160
161 append( sb, "outputDirectory (Default: ${project.build.directory})", 2 );
162 append( sb, "The destination directory for the shaded artifact.", 3 );
163 append( sb, "", 0 );
164
165 append( sb, "outputFile", 2 );
166 append( sb, "The path to the output file for the shaded artifact. When this parameter is set, the created archive will neither replace the project\'s main artifact nor will it be attached. Hence, this parameter causes the parameters finalName, shadedArtifactAttached, shadedClassifierName and createDependencyReducedPom to be ignored when used.", 3 );
167 append( sb, "", 0 );
168
169 append( sb, "promoteTransitiveDependencies (Default: false)", 2 );
170 append( sb, "When true, transitive deps of removed dependencies are promoted to direct dependencies. This should allow the drop in replacement of the removed deps with the new shaded jar and everything should still work.", 3 );
171 append( sb, "Expression: ${promoteTransitiveDependencies}", 3 );
172 append( sb, "", 0 );
173
174 append( sb, "relocations", 2 );
175 append( sb, "Packages to be relocated. For example:\n<relocations>\n\u00a0\u00a0<relocation>\n\u00a0\u00a0\u00a0\u00a0<pattern>org.apache</pattern>\n\u00a0\u00a0\u00a0\u00a0<shadedPattern>hidden.org.apache</shadedPattern>\n\u00a0\u00a0\u00a0\u00a0<includes>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<include>org.apache.maven.*</include>\n\u00a0\u00a0\u00a0\u00a0</includes>\n\u00a0\u00a0\u00a0\u00a0<excludes>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<exclude>org.apache.maven.Public*</exclude>\n\u00a0\u00a0\u00a0\u00a0</excludes>\n\u00a0\u00a0</relocation>\n</relocations>\nNote: Support for includes exists only since version 1.4.", 3 );
176 append( sb, "", 0 );
177
178 append( sb, "shadedArtifactAttached (Default: false)", 2 );
179 append( sb, "Defines whether the shaded artifact should be attached as classifier to the original artifact. If false, the shaded jar will be the main artifact of the project", 3 );
180 append( sb, "Expression: ${shadedArtifactAttached}", 3 );
181 append( sb, "", 0 );
182
183 append( sb, "shadedArtifactId (Default: ${project.artifactId})", 2 );
184 append( sb, "The name of the shaded artifactId. So you may want to use a different artifactId and keep the standard version. If the original artifactId was \'foo\' then the final artifact would be something like foo-1.0.jar. So if you change the artifactId you might have something like foo-special-1.0.jar.", 3 );
185 append( sb, "Expression: ${shadedArtifactId}", 3 );
186 append( sb, "", 0 );
187
188 append( sb, "shadedClassifierName (Default: shaded)", 2 );
189 append( sb, "The name of the classifier used in case the shaded artifact is attached.", 3 );
190 append( sb, "Expression: ${shadedClassifierName}", 3 );
191 append( sb, "", 0 );
192
193 append( sb, "shadedGroupFilter", 2 );
194 append( sb, "If specified, this will include only artifacts which have groupIds which start with this.", 3 );
195 append( sb, "Expression: ${shadedGroupFilter}", 3 );
196 append( sb, "", 0 );
197
198 append( sb, "shaderHint", 2 );
199 append( sb, "You can pass here the roleHint about your own Shader implementation plexus component.", 3 );
200 append( sb, "", 0 );
201
202 append( sb, "transformers", 2 );
203 append( sb, "Resource transformers to be used. Please see the \'Examples\' section for more information on available transformers and their configuration.", 3 );
204 append( sb, "", 0 );
205 }
206 }
207
208 if ( getLog().isInfoEnabled() )
209 {
210 getLog().info( sb.toString() );
211 }
212 }
213
214
215
216
217
218
219
220
221
222
223 private static String repeat( String str, int repeat )
224 {
225 StringBuffer buffer = new StringBuffer( repeat * str.length() );
226
227 for ( int i = 0; i < repeat; i++ )
228 {
229 buffer.append( str );
230 }
231
232 return buffer.toString();
233 }
234
235
236
237
238
239
240
241
242
243 private void append( StringBuffer sb, String description, int indent )
244 {
245 for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); )
246 {
247 sb.append( it.next().toString() ).append( '\n' );
248 }
249 }
250
251
252
253
254
255
256
257
258
259
260
261 private static List toLines( String text, int indent, int indentSize, int lineLength )
262 {
263 List<String> lines = new ArrayList<String>();
264
265 String ind = repeat( "\t", indent );
266 String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
267 for ( int i = 0; i < plainLines.length; i++ )
268 {
269 toLines( lines, ind + plainLines[i], indentSize, lineLength );
270 }
271
272 return lines;
273 }
274
275
276
277
278
279
280
281
282
283 private static void toLines( List<String> lines, String line, int indentSize, int lineLength )
284 {
285 int lineIndent = getIndentLevel( line );
286 StringBuffer buf = new StringBuffer( 256 );
287 String[] tokens = line.split( " +" );
288 for ( int i = 0; i < tokens.length; i++ )
289 {
290 String token = tokens[i];
291 if ( i > 0 )
292 {
293 if ( buf.length() + token.length() >= lineLength )
294 {
295 lines.add( buf.toString() );
296 buf.setLength( 0 );
297 buf.append( repeat( " ", lineIndent * indentSize ) );
298 }
299 else
300 {
301 buf.append( ' ' );
302 }
303 }
304 for ( int j = 0; j < token.length(); j++ )
305 {
306 char c = token.charAt( j );
307 if ( c == '\t' )
308 {
309 buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
310 }
311 else if ( c == '\u00A0' )
312 {
313 buf.append( ' ' );
314 }
315 else
316 {
317 buf.append( c );
318 }
319 }
320 }
321 lines.add( buf.toString() );
322 }
323
324
325
326
327
328
329
330 private static int getIndentLevel( String line )
331 {
332 int level = 0;
333 for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
334 {
335 level++;
336 }
337 for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
338 {
339 if ( line.charAt( i ) == '\t' )
340 {
341 level++;
342 break;
343 }
344 }
345 return level;
346 }
347 }