1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package de.smartics.maven.bugzilla;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.lang.reflect.Field;
21 import java.util.List;
22 import java.util.Properties;
23
24 import org.apache.commons.io.IOUtils;
25 import org.apache.commons.lang.reflect.FieldUtils;
26 import org.apache.maven.artifact.factory.ArtifactFactory;
27 import org.apache.maven.artifact.repository.ArtifactRepository;
28 import org.apache.maven.execution.MavenSession;
29 import org.apache.maven.plugin.AbstractMojo;
30 import org.apache.maven.plugin.MojoExecutionException;
31 import org.apache.maven.plugin.MojoFailureException;
32 import org.apache.maven.plugin.PluginManager;
33 import org.apache.maven.plugin.logging.Log;
34 import org.apache.maven.plugins.help.DescribeMojo;
35 import org.apache.maven.project.MavenProject;
36 import org.apache.maven.project.MavenProjectBuilder;
37 import org.apache.maven.settings.Settings;
38
39
40
41
42
43
44
45
46
47
48
49 public final class HelpMojo extends AbstractMojo
50 {
51
52
53
54
55
56
57
58
59
60
61
62
63
64 private ArtifactFactory artifactFactory;
65
66
67
68
69
70
71 private PluginManager pluginManager;
72
73
74
75
76
77
78
79
80 private MavenProjectBuilder projectBuilder;
81
82
83
84
85
86
87
88
89
90
91 private MavenProject project;
92
93
94
95
96
97
98
99
100
101
102 private Settings settings;
103
104
105
106
107
108
109
110
111
112
113 private MavenSession session;
114
115
116
117
118
119
120
121
122
123
124 private ArtifactRepository localRepository;
125
126
127
128
129
130
131
132
133
134 private List<?> remoteRepositories;
135
136
137
138
139
140
141
142
143
144
145 private String goal;
146
147
148
149
150
151
152
153
154
155
156
157
158 private boolean detail;
159
160
161
162
163
164
165
166
167 private boolean medium;
168
169
170
171
172
173
174
175
176 private boolean minimal;
177
178
179
180
181
182
183 private String pluginId;
184
185
186
187
188 private String version;
189
190
191
192
193
194 private String pluginShortId;
195
196
197
198
199
200
201
202
203 private final class LogCatcher implements Log
204 {
205
206
207
208
209
210
211
212
213
214 private final Log delegate;
215
216
217
218
219
220 private LogCatcher(final Log delegate)
221 {
222 this.delegate = delegate;
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242 @Override
243 public boolean isDebugEnabled()
244 {
245 return delegate.isDebugEnabled();
246 }
247
248
249
250
251
252
253 @Override
254 public void debug(final CharSequence content)
255 {
256 delegate.debug(content);
257 }
258
259
260
261
262
263
264
265 @Override
266 public void debug(final CharSequence content, final Throwable error)
267 {
268 delegate.debug(content, error);
269 }
270
271
272
273
274
275
276 @Override
277 public void debug(final Throwable error)
278 {
279 delegate.debug(error);
280 }
281
282
283
284
285
286
287 @Override
288 public boolean isInfoEnabled()
289 {
290 return delegate.isInfoEnabled();
291 }
292
293
294
295
296
297
298 @Override
299 public void info(final CharSequence content)
300 {
301 final String string = content.toString();
302
303 if (string.startsWith(pluginId))
304 {
305 final String strippedContent = stripAllGoals(string);
306
307 final String fullContent =
308 strippedContent + ".\nFor detailed information on a goal, run"
309 + " 'mvn bugzilla:help -Dgoal=GOAL'.";
310 delegate.info(fullContent);
311 }
312 else if (string.startsWith("Mojo: '" + pluginShortId))
313 {
314 final String strippedContent = stripSingleGoal(string);
315 delegate.info(strippedContent);
316 }
317 else
318 {
319 delegate.info(content);
320 }
321 }
322
323 private String stripAllGoals(final String string)
324 {
325 final String tag = "Goal Prefix: " + pluginShortId;
326 final int startIndex = string.indexOf(tag) + tag.length();
327 final String fragment = string.substring(startIndex).trim();
328 final String replaced = replaceHelpIds(fragment);
329 return replaced;
330 }
331
332 private String replaceHelpIds(final String fragment)
333 {
334 final String replaced =
335 fragment.replaceAll("help:describe", pluginShortId + ":help")
336 .replace(" [...]", "");
337 return replaced;
338 }
339
340 private String stripSingleGoal(final String string)
341 {
342 final String replaced = replaceHelpIds(string);
343 return replaced;
344 }
345
346
347
348
349
350
351
352 @Override
353 public void info(final CharSequence content, final Throwable error)
354 {
355 delegate.info(content, error);
356 }
357
358
359
360
361
362
363 @Override
364 public void info(final Throwable error)
365 {
366 delegate.info(error);
367 }
368
369
370
371
372
373
374 @Override
375 public boolean isWarnEnabled()
376 {
377 return delegate.isWarnEnabled();
378 }
379
380
381
382
383
384
385 @Override
386 public void warn(final CharSequence content)
387 {
388 delegate.warn(content);
389 }
390
391
392
393
394
395
396
397 @Override
398 public void warn(final CharSequence content, final Throwable error)
399 {
400 delegate.warn(content, error);
401 }
402
403
404
405
406
407
408 @Override
409 public void warn(final Throwable error)
410 {
411 delegate.warn(error);
412 }
413
414
415
416
417
418
419 @Override
420 public boolean isErrorEnabled()
421 {
422 return delegate.isErrorEnabled();
423 }
424
425
426
427
428
429
430 @Override
431 public void error(final CharSequence content)
432 {
433 delegate.error(content);
434 }
435
436
437
438
439
440
441
442 @Override
443 public void error(final CharSequence content, final Throwable error)
444 {
445 delegate.error(content, error);
446 }
447
448
449
450
451
452
453 @Override
454 public void error(final Throwable error)
455 {
456 delegate.error(error);
457 }
458 }
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475 @Override
476 public void execute() throws MojoExecutionException, MojoFailureException
477 {
478 initPluginInfo();
479
480 if (goal != null)
481 {
482 this.detail = true;
483 }
484
485 final DescribeMojo describeMojo = createHelpMojo();
486
487 try
488 {
489 describeMojo.execute();
490
491 if (!this.detail)
492 {
493 provideBestPracticesInformation();
494 }
495 }
496 catch (final MojoExecutionException e)
497 {
498 throw new MojoExecutionException(createErrorMessage(), e);
499 }
500 catch (final MojoFailureException e)
501 {
502 throw new MojoExecutionException(createErrorMessage(), e);
503 }
504 }
505
506 private DescribeMojo createHelpMojo() throws MojoFailureException
507 {
508 final DescribeMojo describeMojo = new DescribeMojo()
509 {
510 @Override
511 public Log getLog()
512 {
513 return new LogCatcher(super.getLog());
514 }
515 };
516
517 setHelpMojoValues(describeMojo);
518
519 return describeMojo;
520 }
521
522 private void setHelpMojoValues(final DescribeMojo describeMojo)
523 throws MojoFailureException
524 {
525 setValue(describeMojo, "artifactFactory", artifactFactory);
526 setValue(describeMojo, "pluginManager", pluginManager);
527 setValue(describeMojo, "projectBuilder", projectBuilder);
528
529 setValue(describeMojo, "project", project);
530 setValue(describeMojo, "settings", settings);
531 setValue(describeMojo, "session", session);
532
533 setValue(describeMojo, "localRepository", localRepository);
534 setValue(describeMojo, "remoteRepositories", remoteRepositories);
535
536 setValue(describeMojo, "plugin", pluginId);
537 setValue(describeMojo, "goal", goal);
538
539 setValue(describeMojo, "detail", detail);
540 setValue(describeMojo, "medium", medium);
541 setValue(describeMojo, "minimal", minimal);
542 }
543
544 private void provideBestPracticesInformation()
545 {
546 final String server = "https://www.smartics.eu";
547 final String product = server + "/bugzilla-maven-plugin";
548 final String versionedProduct = product + '/' + version;
549 getLog()
550 .info(
551 "== Best Practices ==\n"
552 + " > Project Setup: mvn bugzilla:init\n"
553 + " See "
554 + versionedProduct
555 + "/best-practices.html#Project_Set_Up\n"
556 + "\n"
557 + " > After a Release: mvn bugzilla:sync -DreleasedVersion=VERSION\n"
558 + " See " + versionedProduct
559 + "/best-practices.html#Release\n\n"
560 + "For more and detailed information please visit:\n" + " "
561 + versionedProduct + "/index.html\n\n"
562 + "Or consult the latest version at :\n " + product
563 + "/index.html\n");
564 }
565
566 private void initPluginInfo() throws MojoExecutionException
567 {
568 final Properties properties = new Properties();
569 final InputStream inStream =
570 getClass().getResourceAsStream("/META-INF/build.properties");
571 try
572 {
573 properties.load(inStream);
574
575 final String groupId = properties.getProperty("build.groupId");
576 final String artifactId = properties.getProperty("build.artifactId");
577 this.version = properties.getProperty("build.version");
578
579 this.pluginId = groupId + ':' + artifactId + ':' + version;
580
581 final int endIndexShortId = artifactId.indexOf('-');
582 this.pluginShortId = artifactId.substring(0, endIndexShortId);
583 }
584 catch (final IOException e)
585 {
586 throw new MojoExecutionException("Cannot determine plugin properties.", e);
587 }
588 finally
589 {
590 IOUtils.closeQuietly(inStream);
591 }
592 }
593
594 private String createErrorMessage()
595 {
596 return "Cannot provide help information"
597 + (goal != null ? " on " + goal : "") + '.';
598 }
599
600 private static void setValue(final Object object, final String fieldName,
601 final Object value) throws MojoFailureException
602 {
603 final Class<?> type = object.getClass();
604
605 try
606 {
607 final Field field = FieldUtils.getField(type, fieldName, true);
608 field.setAccessible(true);
609 field.set(object, value);
610 }
611 catch (final Exception e)
612 {
613 throw new MojoFailureException("Cannot change describe mojo's field '"
614 + fieldName + "'.", e);
615 }
616 }
617
618
619
620 }