1 package eu.simuline.m2latex.core;
2
3 //import org.apache.maven.project.io.xpp3.MavenXpp3Reader;
4 //import org.apache.maven.project.Model;
5
6 import java.io.InputStream;
7
8 import java.io.IOException;
9 import java.io.File;
10
11 import java.util.Properties;
12 import java.util.Map;
13 import java.util.ArrayList;
14 import java.util.Enumeration;
15 import java.util.List;
16 import java.util.jar.Manifest;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19 import java.util.jar.Attributes;
20 import java.net.URISyntaxException;
21 import java.net.URL;
22
23 // TBD: extract this class into a separate git repository
24 // and use it as a submodule.
25 /**
26 * Gives access to meta info on this piece of software stored in the jar-file
27 * which provides this class.
28 * Start with version information.
29 */
30 public class MetaInfo {
31
32
33 /**
34 * Name of the folder <code>META-INF</code> in the jar file which provides this class.
35 * This contains
36 * <ul>
37 * <li>the folder <code>maven</code> created by maven and containing information
38 * like pom properties and pom itself which we currently do not consider</li>
39 * <li>the manifest file named {@link MetaInfo.ManifestInfo#MANIFEST_FILE}.</li>
40 * </ul>
41 */
42 private final static String META_FOLDER = "META-INF/";
43
44
45 /**
46 * Creates the stream for the file given by <code>fileName</code>.
47 * @param fileName
48 * a filename
49 * @return
50 * an input stream to read from <code>fileName</code>.
51 * @throws BuildFailureException
52 * TMI01: if the stream to <code>fileName</code> could not be created.
53 */
54 static InputStream getStream(String fileName)
55 throws BuildFailureException {
56 InputStream res = MetaInfo.class.getClassLoader().getResourceAsStream(fileName);
57 if (res == null) {
58 throw new BuildFailureException("TMI01: Cannot get stream to file '"
59 + fileName + "'. ");
60 }
61 return res;
62 }
63
64 /**
65 * @param fileName
66 * an input stream to read from <code>fileName</code>.
67 * @return
68 * Properties read from <code>fileName</code>.
69 * @throws BuildFailureException
70 * <ul>
71 * <li>TMI01: if the stream to <code>fileName</code> could not be created. </li>
72 * <li>TMI02: if the properties could not be read from <code>fileName</code>. </li>
73 * </ul>
74 */
75 static Properties getProperties(String fileName)
76 throws BuildFailureException {
77 try {
78 Properties properties = new Properties();
79 // may throw TFU01
80 properties.load(MetaInfo.getStream(fileName));
81 return properties;
82 } catch(IOException e) {
83 // TBD: assign exception identifier
84 throw new BuildFailureException("TMI02: Cannot load properties from file '"
85 + fileName + "'. ");
86 }
87 }
88
89
90
91 /**
92 * Reflects the pieces of information given by the manifest file
93 * with manifest version {@link #MANIFEST_VERSION} augmented
94 * by {@link #getCreatedBy()} and by {@link #getBuildJdkSpec()}
95 * which are both due to to the maven jar plugin and specific version
96 * given by {@link #MVN_JAR_PLUGIN}.
97 *
98 * TBD: change user and see whether author changes then also
99 * @author ernst
100 */
101 static class ManifestInfo {
102
103 /**
104 * The manifest version this class is designed for.
105 * When creating an instance, that version is checked
106 * and if the version found differs from that one, an exception is thrown.
107 */
108 private final static String MANIFEST_VERSION = "1.0";
109
110 /**
111 * An indicator that the jar file
112 * containing the manifest represented by this object
113 * was created by maven jar plugin with proper version.
114 */
115 private final static String MVN_JAR_PLUGIN = "Maven Jar Plugin 3.2.0";
116
117 /**
118 * The name of the manifest file which is in the folder {@link #META_FOLDER}
119 * of the jar file which provides this class.
120 */
121 private final static String MANIFEST_FILE = "MANIFEST.MF";
122
123 /**
124 * These attributes are added by the maven jar plugin in version 3.2.0 and is specific for that.
125 * Thus the according value is exactly the specification of that plugin with version info.
126 */
127 private final static Attributes.Name CREATED_BY = new Attributes.Name("Created-By");
128
129 /**
130 * The version of the jdk used to build the jar containing the manifest
131 * represented by this object.
132 * These attributes are added by the maven jar plugin version 3.2.0 and is specific for that.
133 */
134 private final static Attributes.Name BUILD_JDK_SPEC = new Attributes.Name("Build-Jdk-Spec");
135
136 // TBD: decide whether this is sensible
137 private final Manifest manifest;
138
139 /**
140 * The main attributes of the manifest.
141 */
142 private final Attributes mAtts;
143
144 /**
145 * Creates Manifest info instance
146 * @throws BuildFailureException
147 * TFU01: if the stream to the manifest file is not readable
148 * TFU03: the manifest file is not readable although the stream is ok.
149 */
150 ManifestInfo() throws BuildFailureException {
151
152 //System.out.println("MANIFEST: ");
153 try {
154 // getStream may throw TFU01
155 this.manifest = new Manifest(getStream(META_FOLDER + MANIFEST_FILE));
156 } catch (IOException e) {
157 throw new BuildFailureException
158 ("TMI03: IOException reading manifest. ");
159 }
160 this.mAtts = this.manifest.getMainAttributes();
161 // check the manifest version
162 if (!MANIFEST_VERSION.equals(getManifestVersion())) {
163 throw new IllegalStateException("Found manifest with version '"
164 + getManifestVersion() + " where expected version "
165 + MANIFEST_VERSION + ". ");
166 }
167 // CAUTION: don't use getCreatedBy() as this throws an exception
168 // if this jar is not created with the correct maven plugin
169 // (or even without maven at all)
170 if (!MVN_JAR_PLUGIN.equals(this.mAtts.get(CREATED_BY))) {
171 // MVN_JAR_PLUGIN includes the version also
172 throw new IllegalStateException("Found manifest not created by '"
173 + MVN_JAR_PLUGIN + "'. ");
174 }
175
176 // Map<String, Attributes> entriesMf = mf.getEntries();
177
178
179 // seems to correspond with Attributes.Name
180 // MANIFEST_VERSION,
181 // IMPLEMENTATION_TITLE, IMPLEMENTATION_VERSION, IMPLEMENTATION_VENDOR,
182 // SPECIFICATION_TITLE, SPECIFICATION_VERSION, SPECIFICATION_VENDOR,
183 //
184 // defined but not occurring:
185 // SIGNATURE_VERSION, CONTENT_TYPE, CLASS_PATH, MAIN_CLASS, SEALED,
186 // EXTENSION_LIST, EXTENSION_NAME, EXTENSION_INSTALLATION,
187 // IMPLEMENTATION_VENDOR_ID
188 // IMPLEMENTATION_URL,
189 //
190 // occurring but not defined in Attributes.Name:
191 // Created-By: Maven Jar Plugin 3.2.0, Build-Jdk-Spec: 11
192
193 //this.implVersion = this.mAtts.get(Attributes.Name.IMPLEMENTATION_VERSION).toString();
194
195 // TBC: seems to be empty in this case.
196 // in maven-jar-plugin set by manifestSections
197 // System.out.println("Manifest entries"+entriesMf);
198
199 // Enumeration entriesJar = mf.entries();
200 // System.out.println("jar entries"+entriesJar);
201 }
202
203 private String getAttrValue(Object name) {
204 // is in fact a string always but this is to detect null pointer exceptions
205 return this.mAtts.get(name).toString();
206 }
207
208 /**
209 * Returns the version of the implementation.
210 * This is the version given by the maven coordinates.
211 *
212 * @return
213 */
214 protected String getImplVersion() {
215 return getAttrValue(Attributes.Name.IMPLEMENTATION_VERSION);
216 }
217
218 /**
219 * Returns the vendor of the implementation.
220 * This is the vendor given by the maven <code>project.organization.name</code>.
221 *
222 * @return
223 */
224 protected String getImplVendor() {
225 return getAttrValue(Attributes.Name.IMPLEMENTATION_VENDOR);
226 }
227
228 protected String getManifestVersion() {
229 return getAttrValue(Attributes.Name.MANIFEST_VERSION);
230 }
231
232 protected String getSpecVersion() {
233 return getAttrValue(Attributes.Name.SPECIFICATION_VERSION);
234 }
235
236 // specific for Maven Jar Plugin 3.2.0 which is also the string returned.
237 protected String getCreatedBy() {
238 return getAttrValue(CREATED_BY);
239 }
240
241 // specific for Maven Jar Plugin 3.2.0
242 protected String getBuildJdkSpec() {
243 return getAttrValue(BUILD_JDK_SPEC);
244 }
245
246
247 protected String getPackageImplVersion() {
248 return this.getClass().getPackage().getImplementationVersion();
249 }
250
251 // TBD: tie names to values.
252 @Override
253 public String toString() {
254 StringBuilder stb = new StringBuilder();
255 for (String line : toStringArr()) {
256 stb.append(line);
257 stb.append('\n');
258 }
259 return stb.toString();
260 }
261
262 public String[] toStringArr() {
263 // List<String> lines = new ArrayList<String>();
264 // Object key, value;
265 // for (Map.Entry<Object,Object> entry : mAtts.entrySet()) {
266 // key = entry.getKey();
267 // value = entry.getValue();
268 // lines.add(" '" + key + "' cls: " + key.getClass() +
269 // "'->'" + value + "' cls: " + value.getClass());
270 // }
271 // return lines.toArray(new String[lines.size()]);
272
273 return new String[] {
274 "MANIFEST: ("+ getManifestVersion() + ")",
275 " Implementation-Version: '" + getImplVersion() + "'",
276 "PackageImplementation-Version: '" + getPackageImplVersion() + "'"
277 //"creator: '" + getCreatedBy() + "'",
278 //"version jdk: '" + getBuildJdkSpec() + "'"
279 };
280 }
281
282 } // class ManifestInfo
283
284
285 /**
286 * Reflects the pieces of information
287 * given by the <code>git-commit-id-plugin</code> in the current(?) version.
288 *
289 *
290 * @author ernst
291 */
292 class GitProperties {
293 private final static String GIT_PROPS_FILE = "git.properties";
294
295 private final static String GIT_BUILD_VERSION = "git.build.version";
296 private final static String GIT_COMMIT_ID_DESCRIBE = "git.commit.id.describe";
297 private final static String GIT_CLOSEST_TAG_NAME = "git.closest.tag.name";
298 private final static String GIT_CLOSEST_TAG_COMMIT_COUNT = "git.closest.tag.commit.count";
299 private final static String GIT_COMMIT_ID_ABBREV = "git.commit.id.abbrev";
300 private final static String GIT_DIRTY = "git.dirty";
301 private final static String GIT_BUILD_TIME = "git.build.time";
302
303
304 private final Properties properties;
305
306 /**
307 * @throws BuildFailureException
308 * <ul>
309 * <li>TMI01: if the stream to {@link #GIT_PROPS_FILE} could not be created. </li>
310 * <li>TMI02: if the properties could not be read from @link #GIT_PROPS_FILE}. </li>
311 * </ul>
312 */
313 GitProperties() throws BuildFailureException {
314 // TBD: extract properties
315 this.properties = getProperties(GIT_PROPS_FILE);
316
317 //String gitBuildVersion = getBuildVersion();
318 // latex-maven-plugin-1.4-44-g555bde8-dirty
319 // is constructed from
320 //String gitCommitIdDescribe = getCommitIdDescribe();
321 // also interesting:
322 }
323
324 private String getAttrValue(String key) {
325 // is in fact a string always but this is to detect null pointer exceptions
326 return this.properties.get(key).toString();
327 }
328
329 /**
330 * Returns the build version which is the same as the version in the coordinate
331 * provided the <code>maven-release-plugin</code> is used correctly.
332 * @return
333 * the build version.
334 */
335 String getBuildVersion() {
336 return getAttrValue(GIT_BUILD_VERSION);
337 }
338
339 // latex-maven-plugin-1.4-44-g555bde8-dirty
340 /**
341 * Returns the commit identifiers description TBC which consists of
342 * <ul>
343 * <li> the closest tag name as given by {@link #getClosestTagName()} </li>
344 * <li> the number of commits since the last tag
345 * given by {@link #getClosestTagCommitCount()}</li>
346 * <li> something unknown which leads to the 'g'</li>
347 * <li> git.commit.id.abbrev=555bde8</li>
348 * <li> 'dirty' if {@link #getDirty()} returns true. </li>
349 * </ul>
350 * each segment separated by a dash
351 *
352 * @return
353 * the commit identifiers description
354 */
355 String getCommitIdDescribe() {
356 return getAttrValue(GIT_COMMIT_ID_DESCRIBE);
357 }
358
359 // latex-maven-plugin-1.4
360 /**
361 * This is the artifact id and, separated by a dash,
362 * by the current version tag, if there is one,
363 * else, i.e. for snapshots, by the next lowest.
364 * The tag given is current, iff {@link #getClosestTagCommitCount()} returns 0.
365 *
366 * @return
367 * the closest tag name for the last commit.
368 */
369 String getClosestTagName() {
370 return getAttrValue(GIT_CLOSEST_TAG_NAME);
371 }
372
373 // TBD: shall be a number, not a string
374 /**
375 * Returns the number of commits since the last tag
376 * which is given by {@link #getClosestTagName()}.
377 *
378 * @return
379 * the number of commits since the last tag.
380 */
381 String getClosestTagCommitCount() {
382 return getAttrValue(GIT_CLOSEST_TAG_COMMIT_COUNT);
383 }
384
385 // TBC: maybe a string maybe an int or what.
386 /**
387 * Returns the abbreviated hash of the last commit.
388 *
389 * @return
390 * the abbreviated hash of the last commit.
391 */
392 String getCommitIdAbbrev() {
393 return getAttrValue(GIT_COMMIT_ID_ABBREV);
394 }
395
396 // TBD: this shall not be a string but a boolean
397 /**
398 * Returns whether the current working environment is dirty,
399 * i.e. there is something not committed inside.
400 *
401 * @return
402 * whether the current working environment is dirty.
403 */
404 String getDirty() {
405 return getAttrValue(GIT_DIRTY);
406 }
407
408 /**
409 * Returns the build time TBD: not just a string
410 * @return
411 * the build time as a string.
412 */
413 String getBuildTime() {
414 return getAttrValue(GIT_BUILD_TIME);
415 }
416
417 @Override
418 public String toString() {
419 StringBuilder stb = new StringBuilder();
420 stb.append("build version: '" + getBuildVersion() + "'\n");
421 stb.append("commit id desc: '" + getCommitIdDescribe() + "'\n");
422 stb.append("buildTime: '" + getBuildTime() + "'\n");
423 return stb.toString();
424 }
425
426 void log() {
427 MetaInfo.this.log.info("build version: '" + getBuildVersion() + "'");
428 MetaInfo.this.log.info("commit id desc: '" + getCommitIdDescribe() + "'");
429 MetaInfo.this.log.info("buildTime: '" + getBuildTime() + "'");
430 }
431
432 } // class GitProperties
433
434 static class Version implements Comparable<Version> {
435
436 private final static String VERSION_UNKNOWN = "version";
437
438 private final String text;
439 private final Matcher matcher;
440 private final String versionStr;
441 private final List<Number> segments;
442
443 /**
444 * Create a version for a converter <code>conv</code>
445 * invoking it with the proper option using <code>executor</code>
446 *
447 * @param conv
448 * a converter.
449 * @param executor
450 * an executor to execute the command of the converter
451 * to obtain a feedback containing the version.
452 * @throws BuildFailureException
453 * TEX01 if invocation of <code>command</code> fails very basically.
454 */
455 Version(Converter conv, CommandExecutor executor)
456 throws BuildFailureException {
457 this(conv.getVersionEnvironment(),
458 conv.getVersionPattern(),
459 // may throw BuildFailureException
460 executor.execute(null, null,
461 conv.getCommand(), new String[] {
462 conv.getVersionOption()}));
463 }
464
465 /**
466 * Create a version from given pattern
467 * @param patternEnv
468 * the regex pattern <code>text</code> shall match.
469 * The literal <code>%s</code> of this format string
470 * indicates the location of the version pattern <code>patternVrs</code>.
471 * @param patternVrs
472 * the regex pattern expected for this version.
473 * This is in a form
474 * as returned by {@link Converter#getVersionPattern()}.
475 * @param text
476 * some text containing (among other things)
477 * version information described by <code>patternVrs</code>
478 * and conforming to <code>patternEnv</code>.
479 * The origin of that text may be output of invocation of a converter
480 * or a property file with allowed versions (as version intervals)
481 */
482 Version(String patternEnv, String patternVrs, String text) {
483 this.text = text;
484 this.matcher = Pattern.compile(String.format(patternEnv, patternVrs))
485 .matcher(text);
486 if (!this.matcher.find()) {
487 this.versionStr = VERSION_UNKNOWN;
488 this.segments = null;
489 return;
490 }
491 this.versionStr = this.matcher.group(1);
492 this.segments = new ArrayList<Number>(this.matcher.groupCount());
493 String segment;
494 Number num;
495 for (int idx = 2; idx <= this.matcher.groupCount(); idx++) {
496 segment = this.matcher.group(idx);
497 if (segment == null) {
498 break;
499 }
500 if (Pattern.matches("[a-z]", segment)) {
501 num = Byte.valueOf((byte)segment.codePointAt(0));
502 } else {
503 // TBC: why works the 2nd version, but the 1st does not?
504 // num = segment.indexOf('.') == -1
505 // ? Integer.valueOf(segment)
506 // : Double .valueOf(segment);
507 if (segment.indexOf('.') == -1) {
508 num = Integer.valueOf(segment);
509 } else {
510 num = Double.valueOf(segment);
511 }
512 }
513 this.segments.add(num);
514 }
515 }
516
517 boolean isMatching() {
518 return this.segments != null;
519 }
520
521 String getText() {
522 return this.text;
523 }
524
525 String getString() {
526 return this.versionStr;
527 }
528
529 private List<Number> getSegments() {
530 return this.segments;
531 }
532
533 public int compareTo(Version other) {
534 int idxMax = Math.max(getSegments().size(), other.getSegments().size());
535 int sign;
536 for (int idx = 0; idx < idxMax; idx++) {
537 // TBD: eliminate hack
538 sign = (int)Math.signum(getSegments().get(idx).doubleValue()
539 - other.getSegments().get(idx).doubleValue());
540 switch (sign) {
541 case 0:
542 continue;
543 case -1:
544 // fall through
545 case +1:
546 return sign;
547 default:
548 throw new IllegalStateException
549 ("Found unexpected signum. ");
550 }
551 }
552 // TBD: unoconv is an example where 0.9 and 0.9.0 occur,
553 // in different distributions but both versions identical
554 // This must be taken into account
555 return getSegments().size() - other.getSegments().size();
556 }
557
558 } // class Version
559
560 /**
561 * An interval of versions, representing intervals
562 * between the boundaries {@link #min} and {@link #min}
563 * which offers a containment predicate {@link #contains(Version)}.
564 * <p>
565 * Tied to this is a string representation given by {@link #toString()}
566 * and also used by the constructor {@link #VersionInterval(Converter, String)}.
567 */
568 static class VersionInterval {
569
570 /**
571 * Separator between minimum version and maximum version in string representation.
572 * This must be a character not occurring within a version string.
573 * We have a piece of software, see {@link Converter#Latex2rtf}
574 * which has a blank in the version string and as a consequence,
575 * we cannot use a blank here.
576 */
577 private final static char SEP = ';';
578
579 /**
580 * The pattern for a one point interval, essentially the version within brackets.
581 * Note that the version string is represented as the formatter <code>%s</code>.
582 *
583 * @see #ENV_PATTERN2LOW
584 * @see #ENV_PATTERN2HIG
585 */
586 private final static String ENV_PATTERN1 = "^\\[%s\\]$";
587
588 /**
589 * The pattern for a non-degenerate interval,
590 * minimum and maximum version separated by {@link #SEP}
591 * and enclosed within brackets.
592 * The minimum version string is represented as the formatter <code>%s</code>
593 * whereas the maximum version string is represented by the general pattern.
594 *
595 * @see #ENV_PATTERN1
596 * @see #ENV_PATTERN2HIG
597 */
598 private final static String ENV_PATTERN2LOW = "^\\[%s"+SEP+".*\\]$";
599
600 /**
601 * The pattern for a non-degenerate interval,
602 * minimum and maximum version separated by {@link #SEP}
603 * and enclosed within brackets.
604 * The maximum version string is represented as the formatter <code>%s</code>
605 * whereas the minimum version string is represented by the general pattern.
606 *
607 * @see #ENV_PATTERN1
608 * @see #ENV_PATTERN2LOW
609 */
610 private final static String ENV_PATTERN2HIG = "^\\[.*"+SEP+"%s\\]$";
611
612 /**
613 * The minimum version (inclusive) contained in this interval.
614 */
615 private final Version min;
616
617 /**
618 * The maximum version (inclusive) contained in this interval.
619 */
620 private final Version max;
621
622 /**
623 * Creates a version interval from the converter and from the text string
624 * read from the version properties file.
625 *
626 * @param conv
627 * the converter for which to create the version interval.
628 * This is used mostly to determine {@link Converter#getVersionPattern()}.
629 * @param text
630 * the text representation for the interval to be created
631 * which is as described for {@link #toString()}.
632 * This may well be <code>null</code>.
633 * @throws IllegalStateException
634 * if either <code>text</code> is <code>null</code>
635 * which means that there is no version for <code>conv</code>
636 * or if this created version interval
637 * does not have the representation given by <code>text</code>.
638 */
639 VersionInterval(Converter conv, String text) {
640 String patternVrs = conv.getVersionPattern();
641 if (text == null) {
642 throw new IllegalStateException
643 ("Found no expected version for converter " + conv + ". ");
644 }
645 if (text.indexOf(SEP) == -1) {
646 // Here, we have an interval [element]
647 this.min = new Version(ENV_PATTERN1, patternVrs, text);
648 this.max = this.min;
649 if (!this.min.isMatching()) {
650 throw new IllegalStateException
651 (String.format("Expected version interval '%s' " +
652 "does not match expression '^\\[%s\\]$'. ",
653 text, patternVrs));
654 }
655 } else {
656 // Here, we have an interval [min;max]
657 this.min = new Version(ENV_PATTERN2LOW, patternVrs, text);
658 this.max = new Version(ENV_PATTERN2HIG, patternVrs, text);
659 if (!(this.min.isMatching() && this.max.isMatching())) {
660 throw new IllegalStateException
661 (String.format("Expected version interval '%s' " +
662 "does not match expression '^\\[%s%c%s\\]$'. ",
663 text, patternVrs, SEP, patternVrs));
664 }
665 }
666 String expVersionItvStr = toString();
667 if (!text.equals(expVersionItvStr)) {
668 throw new IllegalStateException
669 (String.format("Expected version '%s' reconstructed as '%s'. ",
670 text, expVersionItvStr));
671 }
672 }
673
674 /**
675 * Returns whether <code>version</code> is contained in this interval.
676 *
677 * @param version
678 * some version.
679 * @return
680 * whether <code>version</code> is contained in this interval.
681 */
682 boolean contains(Version version) {
683 return this.min.compareTo(version) <= 0
684 && this.max.compareTo(version) >= 0;
685 }
686
687 /**
688 * Returns a representation inspired by math and used in version property file.
689 * It is just the format
690 * which is read by the constructor {@link #VersionInterval(Converter, String)}.
691 *
692 * @return
693 * string representation of the form <code>[min;max]</code>
694 * except if <code>min</code> and <code>max</code> coincide,
695 * then it is just <code>[min]</code>.
696 */
697 @Override
698 public String toString() {
699 StringBuilder res = new StringBuilder();
700 res.append('[');
701 res.append(this.min.getString());
702
703 if (this.min != this.max) {
704 res.append(SEP);
705 res.append(this.max.getString());
706 }
707 res.append(']');
708 return res.toString();
709 }
710 } // class VersionInterval
711
712 /**
713 * Executor to find the version string.
714 */
715 private final CommandExecutor executor;
716
717
718 /**
719 * Logs information on versions.
720 * Typically, just info are logged,
721 * but if a version could not be read or if a version is not as expected,
722 * also a warning is logged.
723 */
724 private final LogWrapper log;
725
726 MetaInfo(CommandExecutor executor,
727 LogWrapper log) {
728 this.executor = executor;
729 this.log = log;
730 }
731
732 private final static String VERSION_PROPS_FILE = "version.properties";
733 private final static String TOOL_VERSION_FORMAT = "%s%-15s '%s'%s%s";
734
735 // CAUTION, depends on the maven-jar-plugin and its version
736 /**
737 * Prints meta information, mainly version information
738 * on this software and on the converters used.
739 * <p>
740 * WMI01: If the version string of a converter cannot be read.
741 * WMI02: If the version of a converter is not as expected.
742 * @return
743 * whether a warning has been issued.
744 * @throws BuildFailureException
745 * <ul>
746 * <li>TMI01: if the stream to either the manifest file
747 * or to a property file, either {@LINK #VERSION_PROPS_FILE}
748 * or {@link MetaInfo.GitProperties#GIT_PROPS_FILE} could not be created. </li>
749 * <li>TMI02: if the properties could not be read
750 * from one of the two property files mentioned above. </li>
751 * </ul>
752 */
753 public boolean printMetaInfo() throws BuildFailureException {
754 ManifestInfo manifestInfo = new ManifestInfo();
755 // TBC: how does maven determine that version??
756 //String versionMf = manifestInfo.getImplVersion();
757 //System.out.println("mf version: '" + versionMf + "'");
758 this.log.info("Manifest properties: ");
759 for (String line : manifestInfo.toStringArr()) {
760 this.log.info(line);
761 }
762
763 String mavenDir = META_FOLDER + "maven/";
764 URL url = MetaInfo.class.getClassLoader().getResource(mavenDir);
765 // try {
766 // //System.out.println("path: "+url);
767 // //System.out.println("path: "+url.toURI());
768 // //File[] files = new File(url.toURI()).listFiles();
769 // //System.out.println("cd maven; ls: "+java.util.Arrays.asList(files));
770 // } catch (URISyntaxException e) {
771 // // TODO Auto-generated catch block
772 // throw new IllegalStateException("Found unexpected type of url: "+url);
773 // }
774 String propertyFileName = META_FOLDER
775 + "maven/"
776 + "eu.simuline.m2latex/"
777 + "latex-maven-plugin/"
778 + "pom.properties";
779 this.log.info("pom properties:");
780 Properties properties = getProperties(propertyFileName);
781 assert "[groupId, artifactId, version]"
782 .equals(properties.stringPropertyNames().toString())
783 : "Found unexpected properties ";
784 String coordGroupId = properties.getProperty("groupId");
785 String coordArtifactId = properties.getProperty("artifactId");
786 String coordVersion = properties.getProperty("version");
787
788 this.log.info("coordinate.groupId: '" + coordGroupId + "'");
789 this.log.info("coordinate.artifactId: '" + coordArtifactId + "'");
790 this.log.info("coordinate.version: '" + coordVersion + "'");
791
792 // propertyFileName = "META-INF/"
793 // + "maven/"
794 // + "eu.simuline.m2latex/"
795 // + "latex-maven-plugin/"
796 // + "pom.xml";
797 // url = this.getClass().getClassLoader()
798 // .getResource(propertyFileName);
799 // System.out.println("url:"+url);
800 // MavenXpp3Reader reader = new MavenXpp3Reader();
801 // Model model = reader.read(new InputStreamReader(url.openStream()));
802
803
804 GitProperties gitProperties = new GitProperties();
805 this.log.info("git properties: ");
806 gitProperties.log();
807 String gitBuildVersion = gitProperties.getBuildVersion();
808 //System.out.println("git.build.version: " + gitBuildVersion);
809 assert gitBuildVersion.equals(manifestInfo.getImplVersion());
810
811 // String gitCommitIdDescribe = gitProperties.getCommitIdDescribe();
812 // System.out.println("git.commit.id.describe: " + gitCommitIdDescribe);
813 // String gitBuildTime = gitProperties.getBuildTime();
814 // System.out.println("git.build.time: " + gitBuildTime);
815
816 // TBD: rework; this is just the beginning
817 // System.out.println("version properties of converters: ");
818 // Properties properties = getProperties("version.properties");
819 //
820 // System.out.println("version.makeindex:"
821 // +properties.getProperty("version.makeindex"));
822
823 // headlines
824 this.log.info("tool versions: ");
825 this.log.info(String.format(TOOL_VERSION_FORMAT,
826 "?warn? ", "command:", "actual version", "(not)in", "[expected version interval]"));
827
828 Properties versionProperties = getProperties(VERSION_PROPS_FILE);
829 if (versionProperties.size() > Converter.values().length) {
830 // Relation < need not be checked since all converters are checked below
831 throw new IllegalStateException("Number of version properites " +
832 versionProperties.size() +
833 " does not fit number of converters " +
834 Converter.values().length + ". ");
835 }
836
837 String cmd, expVersion, logMsg, warn, incl;
838 Version actVersionObj;
839 VersionInterval expVersionItv;
840 boolean doWarn, doWarnAny = false;
841 for (Converter conv : Converter.values()) {
842 doWarn = false;
843 cmd = conv.getCommand();
844 actVersionObj = new Version(conv, this.executor);
845 expVersion = versionProperties.getProperty(cmd);
846 expVersionItv = new VersionInterval(conv, expVersion);
847
848 warn = " ";
849 incl = "in";
850 if (!actVersionObj.isMatching()) {
851 doWarn = true;
852 this.log.warn("WMI01: Version string from converter " + conv +
853 " did not match expected form: \n"+actVersionObj.getText());
854 incl = "not?in";
855 warn = " ";// mo warning number, still the above is valid
856 } else {
857 doWarn = !expVersionItv.contains(actVersionObj);
858 if (doWarn) {
859 incl = "not in";
860 warn = "WMI02: ";
861 }
862 }
863
864 logMsg = String.format(TOOL_VERSION_FORMAT,
865 warn, cmd+":", actVersionObj.getString(), incl, expVersion);
866 // this.log.info("actVersion: "+actVersionObj.getSegments());
867 // this.log.info("expVersion: "+expVersionObj.getSegments());
868 // this.log.info("actVersion: "+actVersionObj.getSegmentsAsStrings());
869 // this.log.info("expVersion: "+expVersionObj.getSegmentsAsStrings());
870 //this.log.info("actVersion?expVersion: "+actVersionObj.compareTo(expVersionObj));
871 if (doWarn) {
872 this.log.warn(logMsg);
873 } else {
874 this.log.info(logMsg);
875 }
876 doWarnAny |= doWarn;
877 } // for
878 // TBD: try to work for makeindex also
879 return doWarnAny;
880 }
881 }