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.6", 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.", 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, "filters", 2 );
139 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 );
140 append( sb, "", 0 );
141
142 append( sb, "finalName", 2 );
143 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 );
144 append( sb, "Expression: ${finalName}", 3 );
145 append( sb, "", 0 );
146
147 append( sb, "keepDependenciesWithProvidedScope (Default: false)", 2 );
148 append( sb, "When true, dependencies are kept in the pom but with scope \'provided\'; when false, the dependency is removed.", 3 );
149 append( sb, "Expression: ${keepDependenciesWithProvidedScope}", 3 );
150 append( sb, "", 0 );
151
152 append( sb, "minimizeJar (Default: false)", 2 );
153 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 );
154 append( sb, "", 0 );
155
156 append( sb, "outputDirectory (Default: ${project.build.directory})", 2 );
157 append( sb, "The destination directory for the shaded artifact.", 3 );
158 append( sb, "", 0 );
159
160 append( sb, "outputFile", 2 );
161 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 );
162 append( sb, "", 0 );
163
164 append( sb, "promoteTransitiveDependencies (Default: false)", 2 );
165 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 );
166 append( sb, "Expression: ${promoteTransitiveDependencies}", 3 );
167 append( sb, "", 0 );
168
169 append( sb, "relocations", 2 );
170 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 );
171 append( sb, "", 0 );
172
173 append( sb, "shadedArtifactAttached (Default: false)", 2 );
174 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 );
175 append( sb, "Expression: ${shadedArtifactAttached}", 3 );
176 append( sb, "", 0 );
177
178 append( sb, "shadedArtifactId (Default: ${project.artifactId})", 2 );
179 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 );
180 append( sb, "Expression: ${shadedArtifactId}", 3 );
181 append( sb, "", 0 );
182
183 append( sb, "shadedClassifierName (Default: shaded)", 2 );
184 append( sb, "The name of the classifier used in case the shaded artifact is attached.", 3 );
185 append( sb, "Expression: ${shadedClassifierName}", 3 );
186 append( sb, "", 0 );
187
188 append( sb, "shadedGroupFilter", 2 );
189 append( sb, "If specified, this will include only artifacts which have groupIds which start with this.", 3 );
190 append( sb, "Expression: ${shadedGroupFilter}", 3 );
191 append( sb, "", 0 );
192
193 append( sb, "shaderHint", 2 );
194 append( sb, "You can pass here the roleHint about your own Shader implementation plexus component.", 3 );
195 append( sb, "", 0 );
196
197 append( sb, "transformers", 2 );
198 append( sb, "Resource transformers to be used. Please see the \'Examples\' section for more information on available transformers and their configuration.", 3 );
199 append( sb, "", 0 );
200 }
201 }
202
203 if ( getLog().isInfoEnabled() )
204 {
205 getLog().info( sb.toString() );
206 }
207 }
208
209
210
211
212
213
214
215
216
217
218 private static String repeat( String str, int repeat )
219 {
220 StringBuffer buffer = new StringBuffer( repeat * str.length() );
221
222 for ( int i = 0; i < repeat; i++ )
223 {
224 buffer.append( str );
225 }
226
227 return buffer.toString();
228 }
229
230
231
232
233
234
235
236
237
238 private void append( StringBuffer sb, String description, int indent )
239 {
240 for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); )
241 {
242 sb.append( it.next().toString() ).append( '\n' );
243 }
244 }
245
246
247
248
249
250
251
252
253
254
255
256 private static List toLines( String text, int indent, int indentSize, int lineLength )
257 {
258 List<String> lines = new ArrayList<String>();
259
260 String ind = repeat( "\t", indent );
261 String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
262 for ( int i = 0; i < plainLines.length; i++ )
263 {
264 toLines( lines, ind + plainLines[i], indentSize, lineLength );
265 }
266
267 return lines;
268 }
269
270
271
272
273
274
275
276
277
278 private static void toLines( List<String> lines, String line, int indentSize, int lineLength )
279 {
280 int lineIndent = getIndentLevel( line );
281 StringBuffer buf = new StringBuffer( 256 );
282 String[] tokens = line.split( " +" );
283 for ( int i = 0; i < tokens.length; i++ )
284 {
285 String token = tokens[i];
286 if ( i > 0 )
287 {
288 if ( buf.length() + token.length() >= lineLength )
289 {
290 lines.add( buf.toString() );
291 buf.setLength( 0 );
292 buf.append( repeat( " ", lineIndent * indentSize ) );
293 }
294 else
295 {
296 buf.append( ' ' );
297 }
298 }
299 for ( int j = 0; j < token.length(); j++ )
300 {
301 char c = token.charAt( j );
302 if ( c == '\t' )
303 {
304 buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
305 }
306 else if ( c == '\u00A0' )
307 {
308 buf.append( ' ' );
309 }
310 else
311 {
312 buf.append( c );
313 }
314 }
315 }
316 lines.add( buf.toString() );
317 }
318
319
320
321
322
323
324
325 private static int getIndentLevel( String line )
326 {
327 int level = 0;
328 for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
329 {
330 level++;
331 }
332 for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
333 {
334 if ( line.charAt( i ) == '\t' )
335 {
336 level++;
337 break;
338 }
339 }
340 return level;
341 }
342 }