You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by dj...@apache.org on 2011/03/11 00:44:43 UTC

svn commit: r1080400 - in /karaf/trunk: assemblies/features/framework/ features/core/src/main/java/org/apache/karaf/features/internal/model/ tooling/features-maven-plugin/ tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/

Author: djencks
Date: Thu Mar 10 23:44:42 2011
New Revision: 1080400

URL: http://svn.apache.org/viewvc?rev=1080400&view=rev
Log:
KARAF-424 Add dependency change detection

Modified:
    karaf/trunk/assemblies/features/framework/pom.xml
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
    karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
    karaf/trunk/tooling/features-maven-plugin/pom.xml
    karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ArchiveKarMojo.java
    karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateFeaturesXmlMojo2.java

Modified: karaf/trunk/assemblies/features/framework/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/pom.xml?rev=1080400&r1=1080399&r2=1080400&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/pom.xml (original)
+++ karaf/trunk/assemblies/features/framework/pom.xml Thu Mar 10 23:44:42 2011
@@ -29,6 +29,7 @@
 
     <artifactId>karaf-framework</artifactId>
     <packaging>pom</packaging>
+    <!--<packaging>kar</packaging>-->
     <name>Apache Karaf :: Assemblies :: Framework KAR</name>
 
     <properties>

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Bundle.java?rev=1080400&r1=1080399&r2=1080400&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Bundle.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/Bundle.java Thu Mar 10 23:44:42 2011
@@ -172,4 +172,27 @@ public class Bundle implements BundleInf
         this.dependency = value;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Bundle bundle = (Bundle) o;
+
+        if (dependency != bundle.dependency) return false;
+        if (start != bundle.start) return false;
+        if (startLevel != bundle.startLevel) return false;
+        if (value != null ? !value.equals(bundle.value) : bundle.value != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = value != null ? value.hashCode() : 0;
+        result = 31 * result + startLevel;
+        result = 31 * result + (start ? 1 : 0);
+        result = 31 * result + (dependency ? 1 : 0);
+        return result;
+    }
 }

Modified: karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
URL: http://svn.apache.org/viewvc/karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java?rev=1080400&r1=1080399&r2=1080400&view=diff
==============================================================================
--- karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java (original)
+++ karaf/trunk/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java Thu Mar 10 23:44:42 2011
@@ -24,6 +24,7 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Writer;
 
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBElement;
@@ -79,6 +80,15 @@ public class JaxbUtil {
         marshaller.marshal(object, out);
     }
 
+    public static <T> void marshal(Class<T> type, Object object, Writer out) throws JAXBException {
+        JAXBContext ctx2 = JAXBContext.newInstance(type);
+        Marshaller marshaller = ctx2.createMarshaller();
+
+        marshaller.setProperty("jaxb.formatted.output", true);
+
+        marshaller.marshal(object, out);
+    }
+
 
     /**
      * Read in a T from the input stream.

Modified: karaf/trunk/tooling/features-maven-plugin/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/tooling/features-maven-plugin/pom.xml?rev=1080400&r1=1080399&r2=1080400&view=diff
==============================================================================
--- karaf/trunk/tooling/features-maven-plugin/pom.xml (original)
+++ karaf/trunk/tooling/features-maven-plugin/pom.xml Thu Mar 10 23:44:42 2011
@@ -53,6 +53,16 @@
             <artifactId>maven-project</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.maven.shared</groupId>
+            <artifactId>maven-filtering</artifactId>
+            <version>1.0-beta-4</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-utils</artifactId>
+            <version>1.5.10</version>
+        </dependency>
+        <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>maven-bundle-plugin</artifactId>
         </dependency>

Modified: karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ArchiveKarMojo.java
URL: http://svn.apache.org/viewvc/karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ArchiveKarMojo.java?rev=1080400&r1=1080399&r2=1080400&view=diff
==============================================================================
--- karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ArchiveKarMojo.java (original)
+++ karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/ArchiveKarMojo.java Thu Mar 10 23:44:42 2011
@@ -46,7 +46,6 @@ import org.codehaus.plexus.archiver.jar.
  * @version $Revision: 1.1 $
  * @goal archive-kar
  * @phase package
- * @execute phase="package"
  * @requiresDependencyResolution runtime
  * @inheritByDefault true
  * @description Assemble a kar archive from a features.xml file

Modified: karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateFeaturesXmlMojo2.java
URL: http://svn.apache.org/viewvc/karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateFeaturesXmlMojo2.java?rev=1080400&r1=1080399&r2=1080400&view=diff
==============================================================================
--- karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateFeaturesXmlMojo2.java (original)
+++ karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateFeaturesXmlMojo2.java Thu Mar 10 23:44:42 2011
@@ -17,13 +17,20 @@
  */
 package org.apache.karaf.tooling.features;
 
+import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
 import java.io.PrintStream;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -47,6 +54,7 @@ import org.apache.maven.artifact.resolve
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.Mojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
@@ -57,7 +65,12 @@ import org.apache.maven.project.MavenPro
 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
 import org.apache.maven.shared.dependency.tree.DependencyNode;
 import org.apache.maven.shared.dependency.tree.DependencyTreeResolutionListener;
+import org.apache.maven.shared.filtering.MavenFileFilter;
+import org.apache.maven.shared.filtering.MavenFilteringException;
+import org.apache.maven.shared.filtering.MavenResourcesFiltering;
 import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
 import org.xml.sax.SAXException;
 
 
@@ -67,7 +80,6 @@ import org.xml.sax.SAXException;
  * @version $Revision: 1.1 $
  * @goal generate-features-xml2
  * @phase compile
- * @execute phase="compile"
  * @requiresDependencyResolution runtime
  * @inheritByDefault true
  * @description Generates the features XML file
@@ -198,7 +210,7 @@ public class GenerateFeaturesXmlMojo2 ex
         try {
             getDependencies(project, true);
             File dir = outputFile.getParentFile();
-            if (dir.mkdirs()) {
+            if (dir.isDirectory() || dir.mkdirs()) {
                 PrintStream out = new PrintStream(new FileOutputStream(outputFile));
                 try {
                     writeFeatures(out);
@@ -286,11 +298,17 @@ public class GenerateFeaturesXmlMojo2 ex
         }
 
         JaxbUtil.marshal(Features.class, features, out);
+        try {
+            checkChanges(features, objectFactory);
+        } catch (Exception e) {
+            throw new MojoExecutionException("Features contents have changed", e);
+        }
         getLogger().info("...done!");
     }
 
     private Features readFeaturesFile(File featuresFile) throws XMLStreamException, JAXBException, IOException {
-        Features features;InputStream in = new FileInputStream(featuresFile);
+        Features features;
+        InputStream in = new FileInputStream(featuresFile);
         try {
             features = JaxbUtil.unmarshal(in, false);
         } finally {
@@ -449,4 +467,270 @@ public class GenerateFeaturesXmlMojo2 ex
         return artifact.getType().equals("kar") || FEATURE_CLASSIFIER.equals(artifact.getClassifier());
     }
 
+    //------------------------------------------------------------------------//
+    // dependency change detection
+
+    /**
+     * Whether to look for changed dependencies at all
+     *
+     * @parameter
+     */
+    private boolean checkDependencyChange;
+
+    /**
+     * Whether to fail on changed dependencies
+     *
+     * @parameter
+     */
+    private boolean warnOnDependencyChange;
+
+    /**
+     * Whether to show changed dependencies in log
+     *
+     * @parameter
+     */
+    private boolean logDependencyChanges;
+
+    /**
+     * Whether to overwrite dependencies.xml if it has changed
+     *
+     * @parameter
+     */
+    private boolean overwriteChangedDependencies;
+
+    /**
+     * Location of existing dependency file.
+     *
+     * @parameter expression="${basedir}/src/main/history/dependencies.xml"
+     * @required
+     */
+    private File dependencyFile;
+
+    /**
+     * Location of filtered dependency file.
+     *
+     * @parameter expression="${basedir}/target/history/dependencies.xml"
+     * @required
+     */
+    private File filteredDependencyFile;
+
+    //filtering support
+    /**
+     * The character encoding scheme to be applied when filtering resources.
+     *
+     * @parameter expression="${encoding}" default-value="${project.build.sourceEncoding}"
+     */
+    protected String encoding;
+
+    /**
+     * @component role="org.apache.maven.shared.filtering.MavenResourcesFiltering" role-hint="default"
+     * @required
+     */
+    protected MavenResourcesFiltering mavenResourcesFiltering;
+
+    /**
+     * @parameter expression="${session}"
+     * @readonly
+     * @required
+     */
+    protected MavenSession session;
+
+    /**
+     * Expression preceded with the String won't be interpolated
+     * \${foo} will be replaced with ${foo}
+     *
+     * @parameter expression="${maven.resources.escapeString}"
+     * @since 2.3
+     */
+    protected String escapeString = "\\";
+
+    /**
+     * @plexus.requirement role-hint="default"
+     * @component
+     * @required
+     */
+    protected MavenFileFilter mavenFileFilter;
+    /**
+     * System properties.
+     *
+     * @parameter
+     */
+    protected Map<String, String> systemProperties;
+    private Map<String, String> previousSystemProperties;
+
+    private void checkChanges(Features newFeatures, ObjectFactory objectFactory) throws Exception, IOException, JAXBException, XMLStreamException {
+        if (checkDependencyChange) {
+            //combine all the dependencies to one feature and strip out versions
+            Features features = objectFactory.createFeaturesRoot();
+            features.setName(newFeatures.getName());
+            Feature feature = objectFactory.createFeature();
+            features.getFeature().add(feature);
+            for (Feature f : newFeatures.getFeature()) {
+                for (Bundle b : f.getBundle()) {
+                    Bundle bundle = objectFactory.createBundle();
+                    bundle.setLocation(b.getLocation());
+                    feature.getBundle().add(bundle);
+                }
+                for (Dependency d : f.getFeature()) {
+                    Dependency dependency = objectFactory.createDependency();
+                    dependency.setName(d.getName());
+                    feature.getFeature().add(dependency);
+                }
+            }
+
+            Collections.sort(feature.getBundle(), new Comparator<Bundle>() {
+
+                public int compare(Bundle bundle, Bundle bundle1) {
+                    return bundle.getLocation().compareTo(bundle1.getLocation());
+                }
+            });
+            Collections.sort(feature.getFeature(), new Comparator<Dependency>() {
+                public int compare(Dependency dependency, Dependency dependency1) {
+                    return dependency.getName().compareTo(dependency1.getName());
+                }
+            });
+
+            if (dependencyFile.exists()) {
+                //filter dependencies file
+                filter(dependencyFile, filteredDependencyFile);
+                //read dependency types, convert to dependencies, compare.
+                Features oldfeatures = readFeaturesFile(filteredDependencyFile);
+                Feature oldFeature = oldfeatures.getFeature().get(0);
+
+                List<Bundle> addedBundles = new ArrayList<Bundle>(feature.getBundle());
+                List<Bundle> removedBundles = new ArrayList<Bundle>();
+                for (Bundle test : oldFeature.getBundle()) {
+                    boolean t1 = addedBundles.contains(test);
+                    int s1 = addedBundles.size();
+                    boolean t2 = addedBundles.remove(test);
+                    int s2 = addedBundles.size();
+                    if (t1 != t2) {
+                        getLogger().warn("dependencies.contains: " + t1 + ", dependencies.remove(test): " + t2);
+                    }
+                    if (t1 == (s1 == s2)) {
+                        getLogger().warn("dependencies.contains: " + t1 + ", size before: " + s1 + ", size after: " + s2);
+                    }
+                    if (!t2) {
+                        removedBundles.add(test);
+                    }
+                }
+
+                List<Dependency> addedDependencys = new ArrayList<Dependency>(feature.getFeature());
+                List<Dependency> removedDependencys = new ArrayList<Dependency>();
+                for (Dependency test : oldFeature.getFeature()) {
+                    boolean t1 = addedDependencys.contains(test);
+                    int s1 = addedDependencys.size();
+                    boolean t2 = addedDependencys.remove(test);
+                    int s2 = addedDependencys.size();
+                    if (t1 != t2) {
+                        getLogger().warn("dependencies.contains: " + t1 + ", dependencies.remove(test): " + t2);
+                    }
+                    if (t1 == (s1 == s2)) {
+                        getLogger().warn("dependencies.contains: " + t1 + ", size before: " + s1 + ", size after: " + s2);
+                    }
+                    if (!t2) {
+                        removedDependencys.add(test);
+                    }
+                }
+                if (!addedBundles.isEmpty() || !removedBundles.isEmpty() || !addedDependencys.isEmpty() || !removedDependencys.isEmpty()) {
+                    saveDependencyChanges(addedBundles, removedBundles, addedDependencys, removedDependencys, objectFactory);
+                    if (overwriteChangedDependencies) {
+                        writeDependencies(features, dependencyFile);
+                    }
+                }
+
+            } else {
+                writeDependencies(features, dependencyFile);
+            }
+
+        }
+    }
+
+    protected void saveDependencyChanges(Collection<Bundle> addedBundles, Collection<Bundle> removedBundles, Collection<Dependency> addedDependencys, Collection<Dependency> removedDependencys, ObjectFactory objectFactory)
+            throws Exception {
+        File addedFile = new File(filteredDependencyFile.getParentFile(), "dependencies.added.xml");
+        Features added = toFeatures(addedBundles, addedDependencys, objectFactory);
+        writeDependencies(added,  addedFile);
+
+        File removedFile = new File(filteredDependencyFile.getParentFile(), "dependencies.removed.xml");
+        Features removed = toFeatures(removedBundles, removedDependencys, objectFactory);
+        writeDependencies(removed,  removedFile);
+
+        File treeListing = saveTreeListing();
+
+        StringWriter out = new StringWriter();
+        out.write("Dependencies have changed:\n");
+        if (!addedBundles.isEmpty() || ! addedDependencys.isEmpty()) {
+            out.write("\tAdded dependencies are saved here: " + addedFile.getAbsolutePath() + "\n");
+            if (logDependencyChanges) {
+                JaxbUtil.marshal(Features.class, added, out);
+            }
+        }
+        if (!removedBundles.isEmpty() || !removedDependencys.isEmpty()) {
+            out.write("\tRemoved dependencies are saved here: " + removedFile.getAbsolutePath() + "\n");
+            if (logDependencyChanges) {
+                JaxbUtil.marshal(Features.class, removed, out);
+            }
+        }
+        out.write("\tTree listing is saved here: " + treeListing.getAbsolutePath() + "\n");
+        out.write("Delete " + dependencyFile.getAbsolutePath()
+                + " if you are happy with the dependency changes.");
+
+        if (warnOnDependencyChange) {
+            getLog().warn(out.toString());
+        } else {
+            throw new MojoFailureException(out.toString());
+        }
+    }
+
+    private Features toFeatures(Collection<Bundle> addedBundles, Collection<Dependency> addedDependencys, ObjectFactory objectFactory) {
+        Features features = objectFactory.createFeaturesRoot();
+        Feature feature = objectFactory.createFeature();
+        feature.getBundle().addAll(addedBundles);
+        feature.getFeature().addAll(addedDependencys);
+        features.getFeature().add(feature);
+        return features;
+    }
+
+
+    private void writeDependencies(Features features, File file) throws JAXBException, IOException {
+        FileOutputStream out = new FileOutputStream(file);
+        try {
+            JaxbUtil.marshal(Features.class, features, out);
+        } finally {
+            out.close();
+        }
+    }
+
+    protected void filter(File sourceFile, File targetFile)
+            throws MojoExecutionException {
+        try {
+
+            if (StringUtils.isEmpty(encoding)) {
+                getLog().warn(
+                        "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
+                                + ", i.e. build is platform dependent!");
+            }
+            targetFile.getParentFile().mkdirs();
+            List filters = mavenFileFilter.getDefaultFilterWrappers(project, null, true, session, null);
+            mavenFileFilter.copyFile(sourceFile, targetFile, true, filters, encoding, true);
+        } catch (MavenFilteringException e) {
+            throw new MojoExecutionException(e.getMessage(), e);
+        }
+    }
+
+
+    protected File saveTreeListing() throws IOException {
+        File treeListFile = new File(filteredDependencyFile.getParentFile(), "treeListing.txt");
+        OutputStream os = new FileOutputStream(treeListFile);
+        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
+        try {
+            writer.write(treeListing);
+        } finally {
+            writer.close();
+        }
+        return treeListFile;
+    }
+
+
 }