FELIX-4822 : Create markers in m2e for baseline warnings/errors
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1663619 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/pom.xml b/bundleplugin/pom.xml
index f431070..9b59cc1 100644
--- a/bundleplugin/pom.xml
+++ b/bundleplugin/pom.xml
@@ -155,5 +155,4 @@
</plugin>
</plugins>
</reporting>
-
</project>
diff --git a/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java b/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java
index 83dcc25..91df749 100644
--- a/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java
+++ b/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java
@@ -87,7 +87,7 @@
*
* @goal bundle
* @phase package
- * @requiresDependencyResolution test
+ * @requiresDependencyResolution compile
* @description build an OSGi bundle jar
* @threadSafe
*/
diff --git a/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/AbstractBaselinePlugin.java b/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/AbstractBaselinePlugin.java
index 441a01b..c167b61 100644
--- a/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/AbstractBaselinePlugin.java
+++ b/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/AbstractBaselinePlugin.java
@@ -32,7 +32,6 @@
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
-import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
@@ -40,6 +39,7 @@
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
@@ -93,6 +93,13 @@
protected MavenProject project;
/**
+ * @parameter expression="${session}"
+ * @required
+ * @readonly
+ */
+ protected MavenSession session;
+
+ /**
* @parameter expression="${project.build.directory}"
* @required
* @readonly
@@ -117,13 +124,6 @@
protected ArtifactFactory factory;
/**
- * @parameter default-value="${localRepository}"
- * @required
- * @readonly
- */
- protected ArtifactRepository localRepository;
-
- /**
* @component
*/
private ArtifactMetadataSource metadataSource;
@@ -157,7 +157,7 @@
*
* @parameter
*/
- protected List supportedProjectTypes = Arrays.asList( new String[] { "jar", "bundle" } );
+ protected List<String> supportedProjectTypes = Arrays.asList( new String[] { "jar", "bundle" } );
public final void execute()
throws MojoExecutionException, MojoFailureException
@@ -209,37 +209,55 @@
packageFilters = new Instructions( Arrays.asList( filters ) );
}
- // go!
- context = this.init(context);
String generationDate = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm'Z'" ).format( new Date() );
- Reporter reporter = new Processor();
+ final Reporter reporter = new Processor();
+
+ final Info[] infos;
+ try
+ {
+ final Set<Info> infoSet = new Baseline( reporter, new DiffPluginImpl() )
+ .baseline( currentBundle, previousBundle, packageFilters );
+ infos = infoSet.toArray( new Info[infoSet.size()] );
+ Arrays.sort( infos, new InfoComparator() );
+ }
+ catch ( final Exception e )
+ {
+ throw new MojoExecutionException( "Impossible to calculate the baseline", e );
+ }
+ finally
+ {
+ closeJars( currentBundle, previousBundle );
+ }
try
{
- Set<Info> infoSet = new Baseline( reporter, new DiffPluginImpl() )
- .baseline( currentBundle, previousBundle, packageFilters );
+ this.reportErrors(infos);
+ }
+ catch ( final IOException ioe )
+ {
+ throw new MojoExecutionException("Unable to parse baselining information.", ioe);
+ }
+ try
+ {
+ // go!
+ context = this.init(context);
startBaseline( context, generationDate, project.getArtifactId(), project.getVersion(), previousArtifact.getVersion() );
- final Info[] infos = infoSet.toArray( new Info[infoSet.size()] );
- Arrays.sort( infos, new InfoComparator() );
-
- for ( Info info : infos )
+ for ( final Info info : infos )
{
DiffMessage diffMessage = null;
- Version newerVersion = info.newerVersion;
- Version suggestedVersion = info.suggestedVersion;
- if ( suggestedVersion != null )
+ if ( info.suggestedVersion != null )
{
- if ( newerVersion.compareTo( suggestedVersion ) > 0 )
+ if ( info.newerVersion.compareTo( info.suggestedVersion ) > 0 )
{
diffMessage = new DiffMessage( "Excessive version increase", DiffMessage.Type.warning );
reporter.warning( "%s: %s; detected %s, suggested %s",
info.packageName, diffMessage, info.newerVersion, info.suggestedVersion );
}
- else if ( newerVersion.compareTo( suggestedVersion ) < 0 )
+ else if ( info.newerVersion.compareTo( info.suggestedVersion ) < 0 )
{
diffMessage = new DiffMessage( "Version increase required", DiffMessage.Type.error );
reporter.error( "%s: %s; detected %s, suggested %s",
@@ -247,16 +265,10 @@
}
}
- Diff packageDiff = info.packageDiff;
-
- Delta delta = packageDiff.getDelta();
-
- switch ( delta )
+ switch ( info.packageDiff.getDelta() )
{
case UNCHANGED:
- if ( ( suggestedVersion.getMajor() != newerVersion.getMajor() )
- || ( suggestedVersion.getMicro() != newerVersion.getMicro() )
- || ( suggestedVersion.getMinor() != newerVersion.getMinor() ) )
+ if ( info.newerVersion.compareTo( info.suggestedVersion ) != 0 )
{
diffMessage = new DiffMessage( "Version has been increased but analysis detected no changes", DiffMessage.Type.warning );
reporter.warning( "%s: %s; detected %s, suggested %s",
@@ -279,28 +291,20 @@
break;
}
- boolean mismatch = info.mismatch;
- String packageName = info.packageName;
- String shortDelta = getShortDelta( info.packageDiff.getDelta() );
- String deltaString = StringUtils.lowerCase( String.valueOf( info.packageDiff.getDelta() ) );
- String newerVersionString = String.valueOf( info.newerVersion );
- String olderVersionString = String.valueOf( info.olderVersion );
- String suggestedVersionString = String.valueOf( ( info.suggestedVersion == null ) ? "-" : info.suggestedVersion );
- Map<String,String> attributes = info.attributes;
-
- startPackage( context, mismatch,
- packageName,
- shortDelta,
- deltaString,
- newerVersionString,
- olderVersionString,
- suggestedVersionString,
+ startPackage( context,
+ info.mismatch,
+ info.packageName,
+ getShortDelta( info.packageDiff.getDelta() ),
+ StringUtils.lowerCase( String.valueOf( info.packageDiff.getDelta() ) ),
+ info.newerVersion,
+ info.olderVersion,
+ info.suggestedVersion,
diffMessage,
- attributes );
+ info.attributes );
- if ( Delta.REMOVED != delta )
+ if ( Delta.REMOVED != info.packageDiff.getDelta() )
{
- doPackageDiff( context, packageDiff );
+ doPackageDiff( context, info.packageDiff );
}
endPackage(context);
@@ -308,13 +312,8 @@
endBaseline(context);
}
- catch ( Exception e )
- {
- throw new MojoExecutionException( "Impossible to calculate the baseline", e );
- }
finally
{
- closeJars( currentBundle, previousBundle );
this.close(context);
}
@@ -406,9 +405,9 @@
String name,
String shortDelta,
String delta,
- String newerVersion,
- String olderVersion,
- String suggestedVersion,
+ Version newerVersion,
+ Version olderVersion,
+ Version suggestedVersion,
DiffMessage diffMessage,
Map<String,String> attributes );
@@ -425,6 +424,12 @@
protected abstract void endBaseline(final Object context);
+ protected void reportErrors(final Info[] infos)
+ throws IOException
+ {
+ // nothing to do, will be overridden by baseline plugin
+ }
+
// internals
private Jar getCurrentBundle()
@@ -476,7 +481,7 @@
@SuppressWarnings( "unchecked" )
// type is konwn
List<ArtifactVersion> availableVersions =
- metadataSource.retrieveAvailableVersions( previousArtifact, localRepository,
+ metadataSource.retrieveAvailableVersions( previousArtifact, session.getLocalRepository(),
project.getRemoteArtifactRepositories() );
filterSnapshots( availableVersions );
ArtifactVersion version = range.matchVersion( availableVersions );
@@ -503,11 +508,11 @@
try
{
- resolver.resolve( previousArtifact, project.getRemoteArtifactRepositories(), localRepository );
+ resolver.resolve( previousArtifact, project.getRemoteArtifactRepositories(), session.getLocalRepository() );
}
catch ( ArtifactResolutionException are )
{
- throw new MojoExecutionException( "Artifact " + previousArtifact + " cannot be resolved", are );
+ throw new MojoExecutionException( "Artifact " + previousArtifact + " cannot be resolved : " + are.getMessage(), are );
}
catch ( ArtifactNotFoundException anfe )
{
@@ -530,20 +535,20 @@
}
}
- private static Jar openJar( File file )
+ private static Jar openJar( final File file )
throws MojoExecutionException
{
try
{
return new Jar( file );
}
- catch ( IOException e )
+ catch ( final IOException e )
{
throw new MojoExecutionException( "An error occurred while opening JAR directory: " + file, e );
}
}
- private static void closeJars( Jar...jars )
+ private static void closeJars( final Jar...jars )
{
for ( Jar jar : jars )
{
@@ -607,5 +612,4 @@
return String.valueOf( deltaString.charAt( 0 ) );
}
}
-
}
diff --git a/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/BaselinePlugin.java b/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/BaselinePlugin.java
index 722e0b6..8ef49b5 100644
--- a/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/BaselinePlugin.java
+++ b/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/BaselinePlugin.java
@@ -21,18 +21,29 @@
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.StringReader;
import java.util.Map;
import java.util.Map.Entry;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
import org.codehaus.plexus.util.xml.XMLWriter;
import org.sonatype.plexus.build.incremental.BuildContext;
+import aQute.bnd.differ.Baseline.Info;
+import aQute.bnd.service.diff.Delta;
+import aQute.bnd.service.diff.Diff;
+import aQute.bnd.service.diff.Type;
+import aQute.bnd.version.Version;
+
/**
* BND Baseline check between two bundles.
*
* @goal baseline
* @phase verify
+ * @requiresDependencyResolution test
* @threadSafe true
* @since 2.4.1
*/
@@ -159,9 +170,9 @@
String name,
String shortDelta,
String delta,
- String newerVersion,
- String olderVersion,
- String suggestedVersion,
+ Version newerVersion,
+ Version olderVersion,
+ Version suggestedVersion,
DiffMessage diffMessage,
Map<String,String> attributes )
{
@@ -185,9 +196,12 @@
xmlWriter.addAttribute( "name", name );
xmlWriter.addAttribute( "delta", delta );
simpleElement( xmlWriter, "mismatch", String.valueOf( mismatch ) );
- simpleElement( xmlWriter, "newerVersion", newerVersion );
- simpleElement( xmlWriter, "olderVersion", olderVersion );
- simpleElement( xmlWriter, "suggestedVersion", suggestedVersion );
+ simpleElement( xmlWriter, "newerVersion", newerVersion.toString() );
+ simpleElement( xmlWriter, "olderVersion", olderVersion.toString() );
+ if ( suggestedVersion != null )
+ {
+ simpleElement( xmlWriter, "suggestedVersion", suggestedVersion.toString() );
+ }
if ( diffMessage != null )
{
@@ -288,4 +302,224 @@
xmlWriter.endElement();
}
+ @Override
+ protected void reportErrors(final Info[] infos)
+ throws IOException
+ {
+ for ( final Info info : infos )
+ {
+ // clear previous messages
+ final FileMarker packageMarker = findMarkerLocationForPackage(info.packageName);
+
+ if ( info.suggestedVersion != null )
+ {
+ if ( info.newerVersion.compareTo( info.suggestedVersion ) > 0 )
+ {
+ final String msg = "Excessive version increase: detected " + info.newerVersion + ", suggested " + info.suggestedVersion;
+
+ this.buildContext.addMessage(packageMarker.file, packageMarker.line, packageMarker.col, msg, BuildContext.SEVERITY_WARNING, null);
+ }
+ else if ( info.newerVersion.compareTo( info.suggestedVersion ) < 0 )
+ {
+ final String msg = "Version increase required: detected " + info.newerVersion + ", suggested " + info.suggestedVersion;
+
+ this.buildContext.addMessage(packageMarker.file, packageMarker.line, packageMarker.col, msg, BuildContext.SEVERITY_ERROR, null);
+ }
+ }
+
+ if ( info.packageDiff.getDelta() == Delta.UNCHANGED && info.newerVersion.compareTo( info.suggestedVersion ) != 0 )
+ {
+ final String msg = "Version has been increased but analysis detected no changes: detected " + info.newerVersion + ", suggested " + info.suggestedVersion;
+ this.buildContext.addMessage(packageMarker.file, packageMarker.line, packageMarker.col, msg, BuildContext.SEVERITY_WARNING, null);
+ }
+ generateStructuralChangeMarkers(info);
+ }
+ }
+
+ private File getPackageFile(final String packageName)
+ {
+ final String sourceDir = this.project.getBuild().getSourceDirectory();
+ final File packageDir = new File((sourceDir + '/' + packageName.replace('.', '/')).replace('/', File.separatorChar));
+
+ return packageDir;
+ }
+
+ private File getSourceFile(final String className)
+ {
+ final String sourceDir = this.project.getBuild().getSourceDirectory();
+ final File packageDir = new File((sourceDir + '/' + className.replace('.', '/') + ".java").replace('/', File.separatorChar));
+
+ return packageDir;
+ }
+
+ private static final class FileMarker
+ {
+ public File file;
+ public int line;
+ public int col;
+ }
+
+ /**
+ * Find marker location for a package
+ * and clear old markers.
+ */
+ private FileMarker findMarkerLocationForPackage(final String packageName)
+ throws IOException
+ {
+ final File packageDir = getPackageFile(packageName);
+ this.buildContext.removeMessages(packageDir);
+
+ final File packageInfoFile = new File(packageDir, "packageinfo");
+ this.buildContext.removeMessages(packageInfoFile);
+
+ final File packageInfoJavaFile = new File(packageDir, "package-info.java");
+ this.buildContext.removeMessages(packageInfoJavaFile);
+
+ // package-info.java has precedence
+ if ( packageInfoJavaFile != null && packageInfoJavaFile.exists() )
+ {
+ return findVersionLocationInPackageInfoJava(packageInfoJavaFile);
+ }
+ // packageinfo next
+ if ( packageInfoFile != null && packageInfoFile.exists() )
+ {
+ return findVersionLocationInPackageInfo(packageInfoFile);
+ }
+
+ final FileMarker defaultMarker = new FileMarker();
+ defaultMarker.file = packageDir;
+
+ return defaultMarker;
+ }
+
+ private FileMarker findVersionLocationInPackageInfo(final File file)
+ throws IOException
+ {
+ final FileMarker marker = new FileMarker();
+ marker.file = file;
+ final String contents = FileUtils.fileRead(file);
+ final LineNumberReader reader = new LineNumberReader(new StringReader(contents));
+ try
+ {
+ String line;
+ while ( (line = reader.readLine()) != null )
+ {
+ final int pos = line.indexOf("version ");
+ if ( pos > -1 )
+ {
+ marker.col = pos;
+ marker.line = reader.getLineNumber();
+
+ break;
+ }
+ }
+ }
+ finally
+ {
+ IOUtil.close(reader);
+ }
+ return marker;
+ }
+
+ private FileMarker findVersionLocationInPackageInfoJava(final File file)
+ throws IOException
+ {
+ final FileMarker marker = new FileMarker();
+ marker.file = file;
+ final String contents = FileUtils.fileRead(file);
+ final LineNumberReader reader = new LineNumberReader(new StringReader(contents));
+ try
+ {
+ String line;
+ while ( (line = reader.readLine()) != null )
+ {
+ final int pos = line.indexOf("@Version");
+ if ( pos > -1 )
+ {
+ marker.col = pos;
+ marker.line = reader.getLineNumber();
+
+ break;
+ }
+ }
+ }
+ finally
+ {
+ IOUtil.close(reader);
+ }
+ return marker;
+ }
+
+ private void generateStructuralChangeMarkers(final Info baselineInfo)
+ {
+ final Delta packageDelta = baselineInfo.packageDiff.getDelta();
+
+ // Iterate into the package member diffs
+ for (final Diff pkgMemberDiff : baselineInfo.packageDiff.getChildren())
+ {
+ // only deal with interfaces and classes
+ if ( pkgMemberDiff.getType() != Type.INTERFACE && pkgMemberDiff.getType() != Type.CLASS )
+ {
+ continue;
+ }
+
+ // clear old marker
+ final String className = pkgMemberDiff.getName();
+ final File classFile = this.getSourceFile(className);
+ this.buildContext.removeMessages(classFile);
+
+ // Skip deltas that have lesser significance than the overall package delta
+ if (pkgMemberDiff.getDelta().ordinal() < packageDelta.ordinal())
+ {
+ continue;
+ }
+
+ if (Delta.ADDED == pkgMemberDiff.getDelta())
+ {
+ // TODO
+ }
+ else if (Delta.REMOVED == pkgMemberDiff.getDelta())
+ {
+ // TODO
+ }
+ else
+ {
+ // Iterate into the class member diffs
+ for (final Diff classMemberDiff : pkgMemberDiff.getChildren())
+ {
+ // Skip deltas that have lesser significance than the overall package delta (again)
+ if (classMemberDiff.getDelta().ordinal() < packageDelta.ordinal())
+ continue;
+
+ if (Delta.ADDED == classMemberDiff.getDelta())
+ {
+ addAddedMarker(classFile, classMemberDiff);
+ }
+ else if (Delta.REMOVED == classMemberDiff.getDelta())
+ {
+ addRemovedMarker(classFile, classMemberDiff);
+ }
+ else if (Delta.CHANGED == classMemberDiff.getDelta())
+ {
+ addChangedMarker(classFile, classMemberDiff);
+ }
+ }
+ }
+ }
+ }
+
+ private void addAddedMarker(final File classFile, final Diff diff)
+ {
+ this.buildContext.addMessage(classFile, 0, 0, diff.getType() + " " + diff.getName() + " has been added.", BuildContext.SEVERITY_ERROR, null);
+ }
+
+ private void addRemovedMarker(final File classFile, final Diff diff)
+ {
+ this.buildContext.addMessage(classFile, 0, 0, diff.getType() + " " + diff.getName() + " has been removed.", BuildContext.SEVERITY_ERROR, null);
+ }
+
+ private void addChangedMarker(final File classFile, final Diff diff)
+ {
+ this.buildContext.addMessage(classFile, 0, 0, diff.getType() + " " + diff.getName() + " has been changed.", BuildContext.SEVERITY_ERROR, null);
+ }
}
diff --git a/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/BaselineReport.java b/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/BaselineReport.java
index b25f1ad..72997ab 100644
--- a/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/BaselineReport.java
+++ b/bundleplugin/src/main/java/org/apache/felix/bundleplugin/baseline/BaselineReport.java
@@ -32,6 +32,8 @@
import org.apache.maven.reporting.MavenReportException;
import org.codehaus.plexus.util.IOUtil;
+import aQute.bnd.version.Version;
+
/**
* BND Baseline report.
*
@@ -121,7 +123,8 @@
}
@Override
- protected void startBaseline( final Object context, String generationDate, String bundleName, String currentVersion, String previousVersion )
+ protected void startBaseline( final Object context, String generationDate, String bundleName,
+ String currentVersion, String previousVersion )
{
final Context ctx = (Context)context;
final Sink sink = ctx.sink;
@@ -190,9 +193,9 @@
String packageName,
String shortDelta,
String delta,
- String newerVersion,
- String olderVersion,
- String suggestedVersion,
+ Version newerVersion,
+ Version olderVersion,
+ Version suggestedVersion,
DiffMessage diffMessage,
Map<String,String> attributes )
{
@@ -223,15 +226,18 @@
sink.italic_();
sink.text( " (newer version: " );
sink.monospaced();
- sink.text( newerVersion );
+ sink.text( newerVersion.toString() );
sink.monospaced_();
sink.text( ", older version: " );
sink.monospaced();
- sink.text( olderVersion );
- sink.monospaced_();
- sink.text( ", suggested version: " );
- sink.monospaced();
- sink.text( suggestedVersion );
+ sink.text( olderVersion.toString() );
+ if ( suggestedVersion != null )
+ {
+ sink.monospaced_();
+ sink.text( ", suggested version: " );
+ sink.monospaced();
+ sink.text( suggestedVersion.toString() );
+ }
sink.monospaced_();
sink.text( ")" );
}
diff --git a/bundleplugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml b/bundleplugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml
new file mode 100644
index 0000000..f0c0290
--- /dev/null
+++ b/bundleplugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml
@@ -0,0 +1,34 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <goals>
+ <goal>baseline</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <execute>
+ <runOnIncremental>true</runOnIncremental>
+ </execute>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+</lifecycleMappingMetadata>