1 | |
package org.apache.maven.plugin.patch; |
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 | 0 | public class HelpMojo |
19 | |
extends AbstractMojo |
20 | |
{ |
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | |
private boolean detail; |
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
private java.lang.String goal; |
34 | |
|
35 | |
|
36 | |
|
37 | |
|
38 | |
|
39 | |
|
40 | |
private int lineLength; |
41 | |
|
42 | |
|
43 | |
|
44 | |
|
45 | |
|
46 | |
|
47 | |
private int indentSize; |
48 | |
|
49 | |
|
50 | |
|
51 | |
public void execute() |
52 | |
throws MojoExecutionException |
53 | |
{ |
54 | 0 | if ( lineLength <= 0 ) |
55 | |
{ |
56 | 0 | getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." ); |
57 | 0 | lineLength = 80; |
58 | |
} |
59 | 0 | if ( indentSize <= 0 ) |
60 | |
{ |
61 | 0 | getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." ); |
62 | 0 | indentSize = 2; |
63 | |
} |
64 | |
|
65 | 0 | StringBuffer sb = new StringBuffer(); |
66 | |
|
67 | 0 | append( sb, "org.apache.maven.plugins:maven-patch-plugin:1.1.1", 0 ); |
68 | 0 | append( sb, "", 0 ); |
69 | |
|
70 | 0 | append( sb, "Maven Patch Plugin", 0 ); |
71 | 0 | append( sb, "The Patch Plugin is used to apply patches to source files.", 1 ); |
72 | 0 | append( sb, "", 0 ); |
73 | |
|
74 | 0 | if ( goal == null || goal.length() <= 0 ) |
75 | |
{ |
76 | 0 | append( sb, "This plugin has 2 goals:", 0 ); |
77 | 0 | append( sb, "", 0 ); |
78 | |
} |
79 | |
|
80 | 0 | if ( goal == null || goal.length() <= 0 || "apply".equals( goal ) ) |
81 | |
{ |
82 | 0 | append( sb, "patch:apply", 0 ); |
83 | 0 | append( sb, "Apply one or more patches to project sources.", 1 ); |
84 | 0 | append( sb, "", 0 ); |
85 | 0 | if ( detail ) |
86 | |
{ |
87 | 0 | append( sb, "Available parameters:", 1 ); |
88 | 0 | append( sb, "", 0 ); |
89 | |
|
90 | 0 | append( sb, "backups (Default: false)", 2 ); |
91 | 0 | append( sb, "Whether to make backups of the original files before modding them.", 3 ); |
92 | 0 | append( sb, "", 0 ); |
93 | |
|
94 | 0 | append( sb, "destFile", 2 ); |
95 | 0 | append( sb, "The output file which is the original file, plus modifications from the patch. By default, the file(s) will be patched inplace.", 3 ); |
96 | 0 | append( sb, "", 0 ); |
97 | |
|
98 | 0 | append( sb, "failFast (Default: true)", 2 ); |
99 | 0 | append( sb, "Flag being true if the desired behavior is to fail the build on the first failed patch detected.", 3 ); |
100 | 0 | append( sb, "", 0 ); |
101 | |
|
102 | 0 | append( sb, "failurePhrases", 2 ); |
103 | 0 | append( sb, "List of phrases to watch for in the command output from the patch tool. If one is found, it will cause the build to fail. All phrases should be lower-case only. By default, the phrases fail, skip and reject are used.", 3 ); |
104 | 0 | append( sb, "", 0 ); |
105 | |
|
106 | 0 | append( sb, "ignoredPatches", 2 ); |
107 | 0 | append( sb, "When the strictPatching flag is set, this parameter is useful to mark certain contents of the patch-source directory that should be ignored without causing the build to fail.", 3 ); |
108 | 0 | append( sb, "", 0 ); |
109 | |
|
110 | 0 | append( sb, "ignoreWhitespace (Default: true)", 2 ); |
111 | 0 | append( sb, "Whether to ignore whitespaces when applying the patches.", 3 ); |
112 | 0 | append( sb, "", 0 ); |
113 | |
|
114 | 0 | append( sb, "naturalOrderProcessing (Default: false)", 2 ); |
115 | 0 | append( sb, "Setting natural order processing to true will cause all patches in a directory to be processed in a natural order alleviating the need to declare patches directly in the project file.", 3 ); |
116 | 0 | append( sb, "", 0 ); |
117 | |
|
118 | 0 | append( sb, "optimizations (Default: true)", 2 ); |
119 | 0 | append( sb, "Flag to enable/disable optimization file from being written. This file tracks the patches that were applied the last time this goal actually executed. It is required for cases where project-sources optimizations are enabled, since project-sources will not be re-unpacked if they are at least as fresh as the source archive. If we avoid re-unpacking project sources, we need to make sure we don\'t reapply patches.\nNote: If the list of patches changes and this flag is enabled, a \'mvn clean\' must be executed before the next build, to remove the tracking file.", 3 ); |
120 | 0 | append( sb, "", 0 ); |
121 | |
|
122 | 0 | append( sb, "originalFile", 2 ); |
123 | 0 | append( sb, "The original file which will be modified by the patch. By default, the patch tool will automatically derive the original file from the header of the patch file.", 3 ); |
124 | 0 | append( sb, "", 0 ); |
125 | |
|
126 | 0 | append( sb, "patchDirectory (Default: src/main/patches)", 2 ); |
127 | 0 | append( sb, "The base directory for the file names specified by the parameter patches.", 3 ); |
128 | 0 | append( sb, "", 0 ); |
129 | |
|
130 | 0 | append( sb, "patches", 2 ); |
131 | 0 | append( sb, "The list of patch file names, supplying the order in which patches should be applied. The path names in this list must be relative to the base directory specified by the parameter patchDirectory. This parameter is mutually exclusive with the patchfile parameter.", 3 ); |
132 | 0 | append( sb, "", 0 ); |
133 | |
|
134 | 0 | append( sb, "patchFile", 2 ); |
135 | 0 | append( sb, "The single patch file to apply. This parameter is mutually exclusive with the patches parameter.", 3 ); |
136 | 0 | append( sb, "", 0 ); |
137 | |
|
138 | 0 | append( sb, "patchTrackingFile (Default: ${project.build.directory}/optimization-files/patches-applied.txt)", 2 ); |
139 | 0 | append( sb, "This is the tracking file used to maintain a list of the patches applied to the unpacked project sources which are currently in the target directory. If this file is present, and project-source unpacking is optimized (meaning it won\'t re-unpack unless the project-sources archive is newer), this goal will not execute and no patches will be applied in the current build.", 3 ); |
140 | 0 | append( sb, "", 0 ); |
141 | |
|
142 | 0 | append( sb, "removeEmptyFiles (Default: false)", 2 ); |
143 | 0 | append( sb, "When set to true, the empty files resulting from the patching process are removed. Empty ancestor directories are removed as well.", 3 ); |
144 | 0 | append( sb, "", 0 ); |
145 | |
|
146 | 0 | append( sb, "reverse (Default: false)", 2 ); |
147 | 0 | append( sb, "Whether to treat these patches as having reversed source and dest in the patch syntax.", 3 ); |
148 | 0 | append( sb, "", 0 ); |
149 | |
|
150 | 0 | append( sb, "skipApplication (Default: false)", 2 ); |
151 | 0 | append( sb, "Whether to skip this goal\'s execution.", 3 ); |
152 | 0 | append( sb, "", 0 ); |
153 | |
|
154 | 0 | append( sb, "strictPatching (Default: false)", 2 ); |
155 | 0 | append( sb, "Flag that, when set to true, will make sure that all patches included in the patches list must be present and describe the full contents of the patch directory. If strictPatching is set to true, and the patches list has a value that does not correspond to a file in the patch directory, the build will fail. If strictPatching is set to true, and the patch directory contains files not listed in the patches parameter, the build will fail. If set to false, only the patches listed in the patches parameter that have corresponding files will be applied; the rest will be ignored.", 3 ); |
156 | 0 | append( sb, "", 0 ); |
157 | |
|
158 | 0 | append( sb, "strip (Default: 0)", 2 ); |
159 | 0 | append( sb, "The number of directories to be stripped from patch file paths, before applying, starting from the leftmost, or root-est.", 3 ); |
160 | 0 | append( sb, "", 0 ); |
161 | |
|
162 | 0 | append( sb, "targetDirectory (Default: ${project.build.sourceDirectory})", 2 ); |
163 | 0 | append( sb, "The target directory for applying patches. Files in this directory will be modified.", 3 ); |
164 | 0 | append( sb, "", 0 ); |
165 | |
|
166 | 0 | append( sb, "useDefaultIgnores (Default: true)", 2 ); |
167 | 0 | append( sb, "Whether to exclude default ignored patch items, such as .svn or CVS directories.", 3 ); |
168 | 0 | append( sb, "", 0 ); |
169 | |
} |
170 | |
} |
171 | |
|
172 | 0 | if ( goal == null || goal.length() <= 0 || "help".equals( goal ) ) |
173 | |
{ |
174 | 0 | append( sb, "patch:help", 0 ); |
175 | 0 | append( sb, "Display help information on maven-patch-plugin.\nCall\n\u00a0\u00a0mvn\u00a0patch:help\u00a0-Ddetail=true\u00a0-Dgoal=<goal-name>\nto display parameter details.", 1 ); |
176 | 0 | append( sb, "", 0 ); |
177 | 0 | if ( detail ) |
178 | |
{ |
179 | 0 | append( sb, "Available parameters:", 1 ); |
180 | 0 | append( sb, "", 0 ); |
181 | |
|
182 | 0 | append( sb, "detail (Default: false)", 2 ); |
183 | 0 | append( sb, "If true, display all settable properties for each goal.", 3 ); |
184 | 0 | append( sb, "", 0 ); |
185 | |
|
186 | 0 | append( sb, "goal", 2 ); |
187 | 0 | append( sb, "The name of the goal for which to show help. If unspecified, all goals will be displayed.", 3 ); |
188 | 0 | append( sb, "", 0 ); |
189 | |
|
190 | 0 | append( sb, "indentSize (Default: 2)", 2 ); |
191 | 0 | append( sb, "The number of spaces per indentation level, should be positive.", 3 ); |
192 | 0 | append( sb, "", 0 ); |
193 | |
|
194 | 0 | append( sb, "lineLength (Default: 80)", 2 ); |
195 | 0 | append( sb, "The maximum length of a display line, should be positive.", 3 ); |
196 | 0 | append( sb, "", 0 ); |
197 | |
} |
198 | |
} |
199 | |
|
200 | 0 | if ( getLog().isInfoEnabled() ) |
201 | |
{ |
202 | 0 | getLog().info( sb.toString() ); |
203 | |
} |
204 | 0 | } |
205 | |
|
206 | |
|
207 | |
|
208 | |
|
209 | |
|
210 | |
|
211 | |
|
212 | |
|
213 | |
|
214 | |
|
215 | |
private static String repeat( String str, int repeat ) |
216 | |
{ |
217 | 0 | StringBuffer buffer = new StringBuffer( repeat * str.length() ); |
218 | |
|
219 | 0 | for ( int i = 0; i < repeat; i++ ) |
220 | |
{ |
221 | 0 | buffer.append( str ); |
222 | |
} |
223 | |
|
224 | 0 | return buffer.toString(); |
225 | |
} |
226 | |
|
227 | |
|
228 | |
|
229 | |
|
230 | |
|
231 | |
|
232 | |
|
233 | |
|
234 | |
|
235 | |
private void append( StringBuffer sb, String description, int indent ) |
236 | |
{ |
237 | 0 | for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); ) |
238 | |
{ |
239 | 0 | sb.append( it.next().toString() ).append( '\n' ); |
240 | |
} |
241 | 0 | } |
242 | |
|
243 | |
|
244 | |
|
245 | |
|
246 | |
|
247 | |
|
248 | |
|
249 | |
|
250 | |
|
251 | |
|
252 | |
|
253 | |
private static List toLines( String text, int indent, int indentSize, int lineLength ) |
254 | |
{ |
255 | 0 | List lines = new ArrayList(); |
256 | |
|
257 | 0 | String ind = repeat( "\t", indent ); |
258 | 0 | String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" ); |
259 | 0 | for ( int i = 0; i < plainLines.length; i++ ) |
260 | |
{ |
261 | 0 | toLines( lines, ind + plainLines[i], indentSize, lineLength ); |
262 | |
} |
263 | |
|
264 | 0 | return lines; |
265 | |
} |
266 | |
|
267 | |
|
268 | |
|
269 | |
|
270 | |
|
271 | |
|
272 | |
|
273 | |
|
274 | |
|
275 | |
private static void toLines( List lines, String line, int indentSize, int lineLength ) |
276 | |
{ |
277 | 0 | int lineIndent = getIndentLevel( line ); |
278 | 0 | StringBuffer buf = new StringBuffer( 256 ); |
279 | 0 | String[] tokens = line.split( " +" ); |
280 | 0 | for ( int i = 0; i < tokens.length; i++ ) |
281 | |
{ |
282 | 0 | String token = tokens[i]; |
283 | 0 | if ( i > 0 ) |
284 | |
{ |
285 | 0 | if ( buf.length() + token.length() >= lineLength ) |
286 | |
{ |
287 | 0 | lines.add( buf.toString() ); |
288 | 0 | buf.setLength( 0 ); |
289 | 0 | buf.append( repeat( " ", lineIndent * indentSize ) ); |
290 | |
} |
291 | |
else |
292 | |
{ |
293 | 0 | buf.append( ' ' ); |
294 | |
} |
295 | |
} |
296 | 0 | for ( int j = 0; j < token.length(); j++ ) |
297 | |
{ |
298 | 0 | char c = token.charAt( j ); |
299 | 0 | if ( c == '\t' ) |
300 | |
{ |
301 | 0 | buf.append( repeat( " ", indentSize - buf.length() % indentSize ) ); |
302 | |
} |
303 | 0 | else if ( c == '\u00A0' ) |
304 | |
{ |
305 | 0 | buf.append( ' ' ); |
306 | |
} |
307 | |
else |
308 | |
{ |
309 | 0 | buf.append( c ); |
310 | |
} |
311 | |
} |
312 | |
} |
313 | 0 | lines.add( buf.toString() ); |
314 | 0 | } |
315 | |
|
316 | |
|
317 | |
|
318 | |
|
319 | |
|
320 | |
|
321 | |
|
322 | |
private static int getIndentLevel( String line ) |
323 | |
{ |
324 | 0 | int level = 0; |
325 | 0 | for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ ) |
326 | |
{ |
327 | 0 | level++; |
328 | |
} |
329 | 0 | for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ ) |
330 | |
{ |
331 | 0 | if ( line.charAt( i ) == '\t' ) |
332 | |
{ |
333 | 0 | level++; |
334 | 0 | break; |
335 | |
} |
336 | |
} |
337 | 0 | return level; |
338 | |
} |
339 | |
} |