From 65b4b94c20ac65b8c882b421d2524abb38b2f038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Tue, 19 Mar 2024 10:56:37 +0100 Subject: [PATCH] Add an option to enhance the compile log with baseline problems --- .../tycho/apitools/ApiAnalysisMojo.java | 79 +++++-- .../tycho/apitools/LogFileEnhancer.java | 171 ---------------- .../internal/ClassfileComparator.java | 4 +- .../tycho/core/EcJLogFileEnhancer.java | 192 ++++++++++++++++++ .../tycho/plugins/p2/BaselineValidator.java | 30 ++- .../tycho/plugins/p2/P2MetadataMojo.java | 26 ++- 6 files changed, 306 insertions(+), 196 deletions(-) delete mode 100644 tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/LogFileEnhancer.java create mode 100644 tycho-core/src/main/java/org/eclipse/tycho/core/EcJLogFileEnhancer.java diff --git a/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/ApiAnalysisMojo.java b/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/ApiAnalysisMojo.java index 692f2c5685..5f3fd7cc80 100644 --- a/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/ApiAnalysisMojo.java +++ b/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/ApiAnalysisMojo.java @@ -19,10 +19,10 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -48,7 +48,9 @@ import org.eclipse.tycho.MavenRepositoryLocation; import org.eclipse.tycho.TargetEnvironment; import org.eclipse.tycho.TychoConstants; +import org.eclipse.tycho.core.EcJLogFileEnhancer; import org.eclipse.tycho.core.TychoProjectManager; +import org.eclipse.tycho.core.EcJLogFileEnhancer.Source; import org.eclipse.tycho.core.osgitools.DefaultReactorProject; import org.eclipse.tycho.model.project.EclipseProject; import org.eclipse.tycho.osgi.framework.EclipseApplication; @@ -207,22 +209,14 @@ public void execute() throws MojoExecutionException, MojoFailureException { } if (enhanceLogs && logDirectory != null && logDirectory.isDirectory()) { try { - AtomicInteger notMapped = new AtomicInteger(); - LogFileEnhancer.enhanceXml(logDirectory, analysisResult, notfound -> { - notMapped.incrementAndGet(); - if (printProblems) { - // it was already printed before... - return; + Map> problemsMap = analysisResult.problems().collect( + Collectors.groupingBy(problem -> Objects.requireNonNullElse(problem.getResourcePath(), + "no-path-" + System.identityHashCode(problem)))); + if (!problemsMap.isEmpty()) { + try (EcJLogFileEnhancer enhancer = EcJLogFileEnhancer.create(logDirectory)) { + enhanceLog(enhancer, problemsMap); } - if (ApiPlugin.SEVERITY_ERROR == notfound.getSeverity()) { - printProblem(notfound, "API ERROR", log::error); - } else if (ApiPlugin.SEVERITY_WARNING == notfound.getSeverity()) { - printProblem(notfound, "API WARNING", log::warn); - } - }); - int count = notMapped.get(); - if (count > 0) { - log.warn(count + " API problems can't be mapped to the compiler log!"); + return; } } catch (IOException e) { log.warn("Can't enhance logs in directory " + logDirectory); @@ -253,13 +247,61 @@ public void execute() throws MojoExecutionException, MojoFailureException { } } + private void enhanceLog(EcJLogFileEnhancer enhancer, Map> problemsMap) { + Log log = getLog(); + int notMapped = 0; + for (Entry> problemEntry : problemsMap.entrySet()) { + String path = problemEntry.getKey(); + List problemsList = problemEntry.getValue(); + List list = enhancer.sources().filter(source -> { + String pathAttribute = source.getPath(); + return pathAttribute != null && !pathAttribute.isEmpty() && pathAttribute.endsWith(path); + }).toList(); + if (list.isEmpty()) { + for (IApiProblem notfound : problemsList) { + notMapped++; + if (printProblems) { + // it was already printed before... + continue; + } + if (ApiPlugin.SEVERITY_ERROR == notfound.getSeverity()) { + printProblem(notfound, "API ERROR", log::error); + } else if (ApiPlugin.SEVERITY_WARNING == notfound.getSeverity()) { + printProblem(notfound, "API WARNING", log::warn); + } + } + } else { + Map> problemsBySeverity = problemsList.stream() + .collect(Collectors.groupingBy(IApiProblem::getSeverity)); + List errors = problemsBySeverity.getOrDefault(ApiPlugin.SEVERITY_ERROR, List.of()); + List warnings = problemsBySeverity.getOrDefault(ApiPlugin.SEVERITY_WARNING, List.of()); + for (Source sourceEntry : list) { + for (IApiProblem problem : warnings) { + sourceEntry.addProblem(EcJLogFileEnhancer.SEVERITY_WARNING, problem.getLineNumber(), + problem.getCharStart(), problem.getCharEnd(), problem.getCategory(), problem.getId(), + problem.getMessage()); + } + for (IApiProblem problem : errors) { + sourceEntry.addProblem(EcJLogFileEnhancer.SEVERITY_ERROR, problem.getLineNumber(), + problem.getCharStart(), problem.getCharEnd(), problem.getCategory(), problem.getId(), + problem.getMessage()); + } + } + + } + } + if (notMapped > 0) { + log.warn(notMapped + " API problems can't be mapped to the compiler log!"); + } + + } + private ApiAnalysisResult performAnalysis(Collection baselineBundles, Collection dependencyBundles, EclipseFramework eclipseFramework, EclipseProject eclipseProject) throws MojoExecutionException { try { ApiAnalysis analysis = new ApiAnalysis(baselineBundles, dependencyBundles, project.getName(), eclipseProject.getFile(fileToPath(apiFilter)), eclipseProject.getFile(fileToPath(apiPreferences)), - fileToPath(project.getBasedir()), debug, - fileToPath(project.getArtifact().getFile()), + fileToPath(project.getBasedir()), debug, fileToPath(project.getArtifact().getFile()), stringToPath(project.getBuild().getOutputDirectory())); return eclipseFramework.execute(analysis); } catch (Exception e) { @@ -345,7 +387,6 @@ private Collection getBaselineEnvironments() { return targetEnvironments; } - private String time(long start) { long ms = System.currentTimeMillis() - start; if (ms < 1000) { diff --git a/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/LogFileEnhancer.java b/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/LogFileEnhancer.java deleted file mode 100644 index 1560b441a7..0000000000 --- a/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/LogFileEnhancer.java +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2024 Christoph Läubrich and others. - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Christoph Läubrich - initial API and implementation - *******************************************************************************/ -package org.eclipse.tycho.apitools; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; -import java.util.function.Consumer; -import java.util.stream.Collectors; - -import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; -import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem; - -import de.pdark.decentxml.Document; -import de.pdark.decentxml.Element; -import de.pdark.decentxml.XMLIOSource; -import de.pdark.decentxml.XMLParser; -import de.pdark.decentxml.XMLWriter; - -public class LogFileEnhancer { - - private static final String SEVERITY_ERROR = "ERROR"; - private static final String SEVERITY_WARNING = "WARNING"; - private static final String ATTRIBUTES_WARNINGS = "warnings"; - private static final String ELEMENT_PROBLEMS = "problems"; - private static final String ATTRIBUTES_PROBLEMS = "problems"; - private static final String ATTRIBUTES_INFOS = "infos"; - private static final String ATTRIBUTES_ERRORS = "errors"; - - public static void enhanceXml(File logDirectory, ApiAnalysisResult analysisResult, - Consumer notFoundConsumer) throws IOException { - Map> problems = analysisResult.problems() - .collect(Collectors.groupingBy(problem -> Objects.requireNonNullElse(problem.getResourcePath(), - "no-path-" + System.identityHashCode(problem)))); - if (problems.isEmpty()) { - return; - } - Set needsUpdate = new HashSet<>(); - Map documents = readDocuments(logDirectory); - for (Entry> problemEntry : problems.entrySet()) { - String path = problemEntry.getKey(); - boolean found = false; - for (Entry documentEntry : documents.entrySet()) { - Document document = documentEntry.getValue(); - Element statsElement = getStatsElement(document); - for (Element sources : document.getRootElement().getChildren("sources")) { - for (Element source : sources.getChildren("source")) { - String pathAttribute = source.getAttributeValue("path"); - if (pathAttribute != null && !pathAttribute.isEmpty() && pathAttribute.endsWith(path)) { - found = true; - needsUpdate.add(documentEntry.getKey()); - Element problemsElement = getProblemsElement(source); - List list = problemEntry.getValue(); - Map> problemsBySeverity = list.stream() - .collect(Collectors.groupingBy(IApiProblem::getSeverity)); - List errors = problemsBySeverity.getOrDefault(ApiPlugin.SEVERITY_ERROR, - List.of()); - List warnings = problemsBySeverity.getOrDefault(ApiPlugin.SEVERITY_WARNING, - List.of()); - incrementAttribute(problemsElement, ATTRIBUTES_PROBLEMS, list.size()); - incrementAttribute(problemsElement, ATTRIBUTES_WARNINGS, warnings.size()); - incrementAttribute(problemsElement, ATTRIBUTES_ERRORS, errors.size()); - if (statsElement != null) { - incrementAttribute(statsElement, ATTRIBUTES_PROBLEMS, list.size()); - incrementAttribute(statsElement, ATTRIBUTES_WARNINGS, warnings.size()); - incrementAttribute(statsElement, ATTRIBUTES_ERRORS, errors.size()); - } - for (IApiProblem problem : warnings) { - addProblem(problemsElement, problem, SEVERITY_WARNING); - } - for (IApiProblem problem : errors) { - addProblem(problemsElement, problem, SEVERITY_ERROR); - } - } - } - } - } - if (!found) { - problemEntry.getValue().forEach(notFoundConsumer); - } - } - writeDocuments(needsUpdate, documents); - } - - private static Element getStatsElement(Document document) { - for (Element stats : document.getRootElement().getChildren("stats")) { - for (Element problem_summary : stats.getChildren("problem_summary")) { - return problem_summary; - } - } - return null; - } - - private static void addProblem(Element problemsElement, IApiProblem problem, String severity) { - Element element = new Element("problem"); - element.setAttribute("line", Integer.toString(problem.getLineNumber())); - element.setAttribute("severity", severity); - element.setAttribute("charStart", Integer.toString(problem.getCharStart())); - element.setAttribute("charEnd", Integer.toString(problem.getCharEnd())); - element.setAttribute("categoryID", Integer.toString(problem.getCategory())); - element.setAttribute("problemID", Integer.toString(problem.getId())); - Element messageElement = new Element("message"); - messageElement.setAttribute("value", problem.getMessage()); - element.addNode(messageElement); - problemsElement.addNode(element); - } - - private static void incrementAttribute(Element element, String attribute, int increment) { - if (increment > 0) { - int current = Integer.parseInt(element.getAttributeValue(attribute)); - element.setAttribute(attribute, Integer.toString(current + increment)); - } - } - - private static void writeDocuments(Set needsUpdate, Map documents) - throws IOException, FileNotFoundException { - for (File file : needsUpdate) { - Document document = documents.get(file); - try (Writer w = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8); - XMLWriter xw = new XMLWriter(w)) { - document.toXML(xw); - } - } - } - - private static Map readDocuments(File logDirectory) throws IOException { - XMLParser parser = new XMLParser(); - Map documents = new HashMap<>(); - for (File child : logDirectory.listFiles()) { - if (child.getName().toLowerCase().endsWith(".xml")) { - documents.put(child, parser.parse(new XMLIOSource(child))); - } - } - return documents; - } - - private static Element getProblemsElement(Element source) { - Element element = source.getChild(ELEMENT_PROBLEMS); - if (element == null) { - element = new Element(ELEMENT_PROBLEMS); - element.setAttribute(ATTRIBUTES_ERRORS, "0"); - element.setAttribute(ATTRIBUTES_INFOS, "0"); - element.setAttribute(ATTRIBUTES_PROBLEMS, "0"); - element.setAttribute(ATTRIBUTES_WARNINGS, "0"); - source.addNode(0, element); - } - return element; - } - -} diff --git a/tycho-artifactcomparator/src/main/java/org/eclipse/tycho/zipcomparator/internal/ClassfileComparator.java b/tycho-artifactcomparator/src/main/java/org/eclipse/tycho/zipcomparator/internal/ClassfileComparator.java index 217686424e..0c10927ad3 100644 --- a/tycho-artifactcomparator/src/main/java/org/eclipse/tycho/zipcomparator/internal/ClassfileComparator.java +++ b/tycho-artifactcomparator/src/main/java/org/eclipse/tycho/zipcomparator/internal/ClassfileComparator.java @@ -81,12 +81,12 @@ public boolean matches(String extension) { return TYPE.equalsIgnoreCase(extension); } - private static final class ClassfileArtifactDelta extends SimpleArtifactDelta { + public static final class ClassfileArtifactDelta extends SimpleArtifactDelta { private ComparatorInputStream baselineStream; private ComparatorInputStream reactorStream; - public ClassfileArtifactDelta(String baseline, String reactor, ComparatorInputStream baselineStream, + ClassfileArtifactDelta(String baseline, String reactor, ComparatorInputStream baselineStream, ComparatorInputStream reactorStream) { super("different", baseline, reactor); this.baselineStream = baselineStream; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/EcJLogFileEnhancer.java b/tycho-core/src/main/java/org/eclipse/tycho/core/EcJLogFileEnhancer.java new file mode 100644 index 0000000000..617c4b812a --- /dev/null +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/EcJLogFileEnhancer.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2024 Christoph Läubrich and others. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.tycho.core; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Stream; + +import de.pdark.decentxml.Document; +import de.pdark.decentxml.Element; +import de.pdark.decentxml.XMLIOSource; +import de.pdark.decentxml.XMLParser; +import de.pdark.decentxml.XMLWriter; + +/** + * This allows to enhance the ECJ logfile with additional warnings/problem if needed + */ +public class EcJLogFileEnhancer implements AutoCloseable { + + public static final String SEVERITY_ERROR = "ERROR"; + public static final String SEVERITY_WARNING = "WARNING"; + private static final String ATTRIBUTES_WARNINGS = "warnings"; + private static final String ELEMENT_PROBLEMS = "problems"; + private static final String ATTRIBUTES_PROBLEMS = "problems"; + private static final String ATTRIBUTES_INFOS = "infos"; + private static final String ATTRIBUTES_ERRORS = "errors"; + + private Set needsUpdate = new HashSet<>(); + private Map documents; + + private EcJLogFileEnhancer(Map documents) { + this.documents = documents; + } + + public Stream sources() { + return documents.entrySet().stream().flatMap(documentEntry -> { + Document document = documentEntry.getValue(); + Element statsElement = getStatsElement(document); + File file = documentEntry.getKey(); + return document.getRootElement().getChildren("sources").stream() + .flatMap(sources -> sources.getChildren("source").stream()) + .map(source -> new Source(source, statsElement, () -> needsUpdate.add(file))); + }); + } + + @Override + public void close() throws IOException { + writeDocuments(needsUpdate, documents); + } + + public static EcJLogFileEnhancer create(File logDirectory) throws IOException { + Map documents = readDocuments(logDirectory); + return new EcJLogFileEnhancer(documents); + } + + private static Element getStatsElement(Document document) { + for (Element stats : document.getRootElement().getChildren("stats")) { + for (Element problem_summary : stats.getChildren("problem_summary")) { + return problem_summary; + } + } + return null; + } + + private static void incrementAttribute(Element element, String attribute, int increment) { + if (increment > 0) { + int current = Integer.parseInt(element.getAttributeValue(attribute)); + element.setAttribute(attribute, Integer.toString(current + increment)); + } + } + + private static void writeDocuments(Set needsUpdate, Map documents) + throws IOException, FileNotFoundException { + for (File file : needsUpdate) { + Document document = documents.get(file); + try (Writer w = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8); + XMLWriter xw = new XMLWriter(w)) { + document.toXML(xw); + } + } + } + + private static Map readDocuments(File logDirectory) throws IOException { + XMLParser parser = new XMLParser(); + Map documents = new HashMap<>(); + for (File child : logDirectory.listFiles()) { + if (child.getName().toLowerCase().endsWith(".xml")) { + documents.put(child, parser.parse(new XMLIOSource(child))); + } + } + return documents; + } + + private static Element getProblemsElement(Element source) { + Element element = source.getChild(ELEMENT_PROBLEMS); + if (element == null) { + element = new Element(ELEMENT_PROBLEMS); + element.setAttribute(ATTRIBUTES_ERRORS, "0"); + element.setAttribute(ATTRIBUTES_INFOS, "0"); + element.setAttribute(ATTRIBUTES_PROBLEMS, "0"); + element.setAttribute(ATTRIBUTES_WARNINGS, "0"); + source.addNode(0, element); + } + return element; + } + + public static class Source { + + private Element source; + private Element statsElement; + private Runnable needsUpdate; + + Source(Element source, Element statsElement, Runnable needsUpdate) { + this.source = source; + this.statsElement = statsElement; + this.needsUpdate = needsUpdate; + } + + public String getPath() { + return source.getAttributeValue("path"); + } + + public String getOutputDirectory() { + return source.getAttributeValue("output"); + } + + public String getPackage() { + return source.getAttributeValue("package"); + } + + public void addProblem(String severity, int lineNumber, int charStart, int charEnd, int categoryId, + int problemId, String message) { + Element problemsElement = getProblemsElement(source); + Element element = new Element("problem"); + element.setAttribute("line", Integer.toString(lineNumber)); + element.setAttribute("severity", severity); + element.setAttribute("charStart", Integer.toString(charStart)); + element.setAttribute("charEnd", Integer.toString(charEnd)); + element.setAttribute("categoryID", Integer.toString(categoryId)); + element.setAttribute("problemID", Integer.toString(problemId)); + Element messageElement = new Element("message"); + messageElement.setAttribute("value", message); + element.addNode(messageElement); + incrementAttribute(problemsElement, ATTRIBUTES_PROBLEMS, 1); + if (SEVERITY_ERROR.equals(severity)) { + incrementAttribute(problemsElement, ATTRIBUTES_ERRORS, 1); + } + if (SEVERITY_WARNING.equals(severity)) { + incrementAttribute(problemsElement, ATTRIBUTES_WARNINGS, 1); + } + if (statsElement != null) { + incrementAttribute(statsElement, ATTRIBUTES_PROBLEMS, 1); + if (SEVERITY_ERROR.equals(severity)) { + incrementAttribute(statsElement, ATTRIBUTES_ERRORS, 1); + } + if (SEVERITY_WARNING.equals(severity)) { + incrementAttribute(statsElement, ATTRIBUTES_WARNINGS, 1); + } + } + problemsElement.addNode(element); + needsUpdate.run(); + } + + public boolean hasClass(String classFile) { + return source.getChildren("classfile").stream().map(elem -> elem.getAttributeValue("path")).filter(Objects::nonNull) + .anyMatch(path -> path.endsWith(classFile)); + } + + } + +} diff --git a/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/BaselineValidator.java b/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/BaselineValidator.java index 606be054f8..944f3b4bcc 100644 --- a/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/BaselineValidator.java +++ b/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/BaselineValidator.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import org.apache.commons.lang3.reflect.MethodUtils; @@ -41,9 +42,11 @@ import org.eclipse.tycho.artifactcomparator.ArtifactComparator; import org.eclipse.tycho.artifactcomparator.ArtifactComparator.ComparisonData; import org.eclipse.tycho.artifactcomparator.ArtifactDelta; +import org.eclipse.tycho.core.EcJLogFileEnhancer; import org.eclipse.tycho.core.osgitools.BaselineService; import org.eclipse.tycho.core.osgitools.DefaultReactorProject; import org.eclipse.tycho.p2.metadata.IP2Artifact; +import org.eclipse.tycho.zipcomparator.internal.ClassfileComparator.ClassfileArtifactDelta; import org.eclipse.tycho.zipcomparator.internal.CompoundArtifactDelta; import org.eclipse.tycho.zipcomparator.internal.SimpleArtifactDelta; @@ -78,7 +81,7 @@ public void writeDetails(File destination) throws IOException { public Map validateAndReplace(MavenProject project, ComparisonData data, Map reactorMetadata, List baselineRepositories, BaselineMode baselineMode, - BaselineReplace baselineReplace) throws IOException, MojoExecutionException { + BaselineReplace baselineReplace, EcJLogFileEnhancer enhancer) throws IOException, MojoExecutionException { Map result = reactorMetadata; @@ -105,7 +108,12 @@ public Map validateAndReplace(MavenProject project, Compari classifier.getValue().writeDetails(new File(logdir, classifier.getKey())); } } - if (shouldFail(baselineMode, delta)) { + boolean shouldFail = shouldFail(baselineMode, delta); + if (enhancer != null) { + enhanceLogWithClassDiffs(delta, enhancer, + shouldFail ? EcJLogFileEnhancer.SEVERITY_ERROR : EcJLogFileEnhancer.SEVERITY_WARNING); + } + if (shouldFail) { throw new MojoExecutionException(delta.getDetailedMessage()); } else if (shouldWarn(baselineMode, delta)) { log.warn(project.toString() + ": " + delta.getDetailedMessage()); @@ -198,6 +206,24 @@ public Map validateAndReplace(MavenProject project, Compari return result; } + private AtomicInteger logId = new AtomicInteger((int) System.currentTimeMillis()); + + private void enhanceLogWithClassDiffs(CompoundArtifactDelta compoundDelta, EcJLogFileEnhancer enhancer, + String serv) { + for (Entry entry : compoundDelta.getMembers().entrySet()) { + ArtifactDelta childDelta = entry.getValue(); + if (childDelta instanceof ClassfileArtifactDelta) { + String key = entry.getKey(); + //TODO it would be good if we can gather the line information from the classfile where the first diff is found... + enhancer.sources().filter(source -> source.hasClass(key)).findFirst() + .ifPresent(source -> source.addProblem(serv, -1, -1, -1, 99999, logId.incrementAndGet(), + "baseline and build for " + key + " have different contents")); + } else if (childDelta instanceof CompoundArtifactDelta c) { + enhanceLogWithClassDiffs(c, enhancer, serv); + } + } + } + private static boolean shouldFail(BaselineMode baselineMode, CompoundArtifactDelta delta) { return baselineMode == fail || (baselineMode == failCommon && !isMissingOnlyDelta(delta)); } diff --git a/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/P2MetadataMojo.java b/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/P2MetadataMojo.java index 3dd612dc94..66639bf382 100644 --- a/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/P2MetadataMojo.java +++ b/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/P2MetadataMojo.java @@ -35,6 +35,7 @@ import org.eclipse.tycho.ReactorProject; import org.eclipse.tycho.TychoConstants; import org.eclipse.tycho.artifactcomparator.ArtifactComparator.ComparisonData; +import org.eclipse.tycho.core.EcJLogFileEnhancer; import org.eclipse.tycho.core.osgitools.DefaultReactorProject; import org.eclipse.tycho.p2.metadata.IP2Artifact; import org.eclipse.tycho.p2.metadata.P2Generator; @@ -143,6 +144,16 @@ public class P2MetadataMojo extends AbstractMojo { @Component private IProvisioningAgent agent; + @Parameter(defaultValue = "false") + private boolean enhanceLogs; + + /** + * If given a folder, enhances the ECJ compiler logs with class compare errors so it can be + * analyzed by tools understanding that format + */ + @Parameter(defaultValue = "${project.build.directory}/compile-logs") + private File logDirectory; + @Override public void execute() throws MojoExecutionException, MojoFailureException { synchronized (LOCK) { @@ -169,8 +180,19 @@ protected void attachP2Metadata() throws MojoExecutionException { if (baselineMode != BaselineMode.disable) { ComparisonData data = new ComparisonData(ignoredPatterns, writeComparatorDelta); - generatedMetadata = baselineValidator.validateAndReplace(project, data, generatedMetadata, - baselineRepositories, baselineMode, baselineReplace); + if (enhanceLogs && logDirectory != null && logDirectory.isDirectory()) { + try { + try (EcJLogFileEnhancer enhancer = EcJLogFileEnhancer.create(logDirectory)) { + generatedMetadata = baselineValidator.validateAndReplace(project, data, generatedMetadata, + baselineRepositories, baselineMode, baselineReplace, enhancer); + } + } catch (IOException e) { + getLog().warn("Can't enhance logs in directory " + logDirectory); + } + } else { + generatedMetadata = baselineValidator.validateAndReplace(project, data, generatedMetadata, + baselineRepositories, baselineMode, baselineReplace, null); + } } FileInfo info = p2generator.persistMetadata(generatedMetadata, project);