You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mp...@apache.org on 2006/01/09 18:12:06 UTC

svn commit: r367339 - in /maven/plugins/trunk/maven-pmd-plugin/src: main/java/org/apache/maven/plugin/pmd/CpdReport.java main/java/org/apache/maven/plugin/pmd/CpdReportGenerator.java main/resources/cpd-report.properties site/apt/howto.apt

Author: mperham
Date: Mon Jan  9 09:12:00 2006
New Revision: 367339

URL: http://svn.apache.org/viewcvs?rev=367339&view=rev
Log:
PR: MPMD-10
Add CPD report support

Added:
    maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java   (with props)
    maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReportGenerator.java   (with props)
    maven/plugins/trunk/maven-pmd-plugin/src/main/resources/cpd-report.properties   (with props)
Modified:
    maven/plugins/trunk/maven-pmd-plugin/src/site/apt/howto.apt

Added: maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java
URL: http://svn.apache.org/viewcvs/maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java?rev=367339&view=auto
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java (added)
+++ maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java Mon Jan  9 09:12:00 2006
@@ -0,0 +1,247 @@
+package org.apache.maven.plugin.pmd;
+
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import net.sourceforge.pmd.cpd.CPD;
+import net.sourceforge.pmd.cpd.CSVRenderer;
+import net.sourceforge.pmd.cpd.JavaLanguage;
+import net.sourceforge.pmd.cpd.Renderer;
+import net.sourceforge.pmd.cpd.SimpleRenderer;
+import net.sourceforge.pmd.cpd.XMLRenderer;
+
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.AbstractMavenReport;
+import org.apache.maven.reporting.MavenReportException;
+import org.codehaus.doxia.sink.Sink;
+import org.codehaus.doxia.site.renderer.SiteRenderer;
+
+/**
+ * Report for PMD's CPD tool.  See http://pmd.sourceforge.net/cpd.html
+ * for more detail.
+ *
+ * @author Mike Perham
+ * @version $Id: PmdReport.java,v 1.3 2005/02/23 00:08:53 brett Exp $
+ * @goal cpd
+ * @todo needs to support the multiple source roots
+ */
+public class CpdReport
+    extends AbstractMavenReport
+{
+    /**
+     * @parameter expression="${project.reporting.outputDirectory}"
+     * @required
+     */
+    private String outputDirectory;
+
+    /**
+     * @component
+     */
+    private SiteRenderer siteRenderer;
+
+    /**
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * Set the output format type.  Defaults to "html".  Must be one of:
+     * "html", "csv", "xml", "txt" or the full class name of the PMD renderer to use.
+     * See the net.sourceforge.pmd.cpd package javadoc for available renderers.
+     * 
+     * @parameter
+     */
+    private String format = "html";
+
+    /**
+     * Link the violation line numbers to the source xref.
+     * @parameter
+     * 
+     * TODO Can we automagically determine if xfer is being run and enable this?
+     */
+    private boolean linkXref;
+
+    /**
+     * The location of the xref pages relative to the location of the pmd report.
+     * @parameter
+     */
+    private String xrefLocation = "xref";
+
+    /**
+     * The file encoding to use when reading the java source.
+     * @parameter 
+     */
+    private String sourceEncoding;
+
+    /**
+     * @parameter
+     */
+    private int minimumTokens = 100;
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale)
+     */
+    public String getName( Locale locale )
+    {
+        return getBundle( locale ).getString( "report.cpd.name" );
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getDescription(java.util.Locale)
+     */
+    public String getDescription( Locale locale )
+    {
+        return getBundle( locale ).getString( "report.cpd.description" );
+    }
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#getOutputDirectory()
+     */
+    protected String getOutputDirectory()
+    {
+        return outputDirectory;
+    }
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#getProject()
+     */
+    protected MavenProject getProject()
+    {
+        return project;
+    }
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#getSiteRenderer()
+     */
+    protected SiteRenderer getSiteRenderer()
+    {
+        return siteRenderer;
+    }
+
+    private boolean isHtml()
+    {
+        return "html".equals( format );
+    }
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#executeReport(java.util.Locale)
+     */
+    public void executeReport( Locale locale )
+        throws MavenReportException
+    {
+        Sink sink = getSink();
+
+        CPD cpd = new CPD( minimumTokens, new JavaLanguage() );
+        String src = getProject().getBuild().getSourceDirectory();
+        try
+        {
+            // TODO: use source roots instead
+            cpd.addRecursively( src );
+        }
+        catch ( IOException e )
+        {
+            throw new MavenReportException( e.getMessage(), e );
+        }
+        cpd.go();
+        
+        CpdReportGenerator gen = new CpdReportGenerator(getSink(), src, getBundle( locale ), xrefLocation );
+        gen.generate( cpd.getMatches() );
+
+        if ( !isHtml() )
+        {
+            Renderer r = createRenderer();
+            String buffer = r.render( cpd.getMatches() );
+            try
+            {
+                Writer writer = new FileWriter( new File( this.getReportOutputDirectory(), "cpd." + format ) );
+                writer.write( buffer, 0, buffer.length() );
+                writer.close();
+            }
+            catch ( IOException ioe )
+            {
+                throw new MavenReportException( ioe.getMessage(), ioe );
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getOutputName()
+     */
+    public String getOutputName()
+    {
+        return "cpd";
+    }
+
+    private static ResourceBundle getBundle( Locale locale )
+    {
+        return ResourceBundle.getBundle( "cpd-report", locale, CpdReport.class.getClassLoader() );
+    }
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#canGenerateReport()
+     */
+    public boolean canGenerateReport()
+    {
+        ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler();
+        return ( "java".equals( artifactHandler.getLanguage() ) );
+    }
+
+    /**
+     * Create and return the correct renderer for the output type.
+     * @return the renderer based on the configured output
+     * @throws MavenReportException if no renderer found for the output type
+     */
+    public final Renderer createRenderer()
+        throws MavenReportException
+    {
+        if ( format.equals( "xml" ) )
+        {
+            return new XMLRenderer();
+        }
+        else if ( format.equals( "txt" ) )
+        {
+            return new SimpleRenderer();
+        }
+        else if ( format.equals( "csv" ) )
+        {
+            return new CSVRenderer();
+        }
+        if ( !format.equals( "" ) )
+        {
+            try
+            {
+                return (Renderer) Class.forName( format ).newInstance();
+            }
+            catch ( Exception e )
+            {
+                throw new MavenReportException( "Can't find the custom format " + format + ": "
+                    + e.getClass().getName() );
+            }
+        }
+
+        throw new MavenReportException( "Can't create report with format of " + format );
+    }
+}

Propchange: maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReportGenerator.java
URL: http://svn.apache.org/viewcvs/maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReportGenerator.java?rev=367339&view=auto
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReportGenerator.java (added)
+++ maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReportGenerator.java Mon Jan  9 09:12:00 2006
@@ -0,0 +1,156 @@
+package org.apache.maven.plugin.pmd;
+
+import java.util.Iterator;
+import java.util.ResourceBundle;
+
+import net.sourceforge.pmd.cpd.Match;
+
+import org.codehaus.doxia.sink.Sink;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * @author mperham
+ * @version $Id: $
+ */
+public class CpdReportGenerator
+{
+    private Sink sink;
+
+    private String sourceDirectory;
+
+    private ResourceBundle bundle;
+
+    private String xrefLocation;
+
+    public CpdReportGenerator( Sink sink, String sourceDirectory, ResourceBundle bundle, String xrefLocation )
+    {
+        this.sink = sink;
+        this.sourceDirectory = sourceDirectory;
+        this.bundle = bundle;
+        this.xrefLocation = xrefLocation;
+    }
+
+    private String getTitle()
+    {
+        return bundle.getString( "report.cpd.title" );
+    }
+
+    public void beginDocument()
+    {
+        sink.head();
+        sink.title();
+        sink.text( getTitle() );
+        sink.title_();
+        sink.head_();
+
+        sink.body();
+
+        sink.section1();
+        sink.sectionTitle1();
+        sink.text( getTitle() );
+        sink.sectionTitle1_();
+
+        sink.paragraph();
+        sink.text( bundle.getString( "report.cpd.cpdlink" ) + " " );
+        sink.link( "http://pmd.sourceforge.net/cpd.html" );
+        sink.text( "CPD" );
+        sink.link_();
+        sink.paragraph_();
+
+        // TODO overall summary
+
+        sink.section1_();
+        sink.section1();
+        sink.sectionTitle1();
+        sink.text( bundle.getString( "report.cpd.dupes" ) );
+        sink.sectionTitle1_();
+
+        // TODO files summary
+    }
+
+    public void generate( Iterator matches )
+    {
+        beginDocument();
+        
+        while ( matches.hasNext() )
+        {
+            Match match = (Match) matches.next();
+            String filename1 = match.getFirstMark().getTokenSrcID();
+            filename1 = StringUtils.substring( filename1, sourceDirectory.length() + 1 );
+
+            String filename2 = match.getSecondMark().getTokenSrcID();
+            filename2 = StringUtils.substring( filename2, sourceDirectory.length() + 1 );
+            
+            String code = match.getSourceCodeSlice();
+            int line1 = match.getFirstMark().getBeginLine();
+            int line2 = match.getSecondMark().getBeginLine();
+
+            sink.paragraph();
+            sink.table();
+            sink.tableRow();
+            sink.tableHeaderCell();
+            sink.text( bundle.getString( "report.cpd.column.file" ) );
+            sink.tableHeaderCell_();
+            sink.tableHeaderCell();
+            sink.text( bundle.getString( "report.cpd.column.line" ) );
+            sink.tableHeaderCell_();
+            sink.tableRow_();
+
+            // File 1
+            sink.tableRow();
+            sink.tableCell();
+            sink.text( filename1 );
+            sink.tableCell_();
+            sink.tableCell();
+
+            if ( xrefLocation != null )
+            {
+                sink.link( xrefLocation + "/" + filename1.replaceAll( "\\.java$", ".html" ) + "#" + line1 );
+            }
+            sink.text( String.valueOf( line1 ) );
+            if ( xrefLocation != null )
+            {
+                sink.link_();
+            }
+
+            sink.tableCell_();
+            sink.tableRow_();
+
+            // File 2
+            sink.tableRow();
+            sink.tableCell();
+            sink.text( filename2 );
+            sink.tableCell_();
+            sink.tableCell();
+            if ( xrefLocation != null )
+            {
+                sink.link( xrefLocation + "/" + filename2.replaceAll( "\\.java$", ".html" ) + "#" + line2 );
+            }
+            sink.text( String.valueOf( line2 ) );
+            if ( xrefLocation != null )
+            {
+                sink.link_();
+            }
+            sink.tableCell_();
+            sink.tableRow_();
+
+            // Source snippet
+            sink.tableRow();
+            
+            // TODO Cleaner way to do this?
+            sink.rawText("<td colspan='2'>");
+            sink.verbatim(false);
+            sink.text( code );
+            sink.verbatim_();
+            sink.rawText("</td>");
+            sink.tableRow_();
+            sink.table();
+            sink.paragraph_();
+        }
+
+        sink.section1_();
+        sink.body_();
+        sink.flush();
+        sink.close();
+    }
+}

Propchange: maven/plugins/trunk/maven-pmd-plugin/src/main/java/org/apache/maven/plugin/pmd/CpdReportGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/plugins/trunk/maven-pmd-plugin/src/main/resources/cpd-report.properties
URL: http://svn.apache.org/viewcvs/maven/plugins/trunk/maven-pmd-plugin/src/main/resources/cpd-report.properties?rev=367339&view=auto
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/main/resources/cpd-report.properties (added)
+++ maven/plugins/trunk/maven-pmd-plugin/src/main/resources/cpd-report.properties Mon Jan  9 09:12:00 2006
@@ -0,0 +1,7 @@
+report.cpd.name=CPD Report
+report.cpd.description=Duplicate code detection.
+report.cpd.title=CPD Results
+report.cpd.column.file=File
+report.cpd.column.line=Line
+report.cpd.cpdlink=The following document contains the results of PMD's 
+report.cpd.dupes=Duplications

Propchange: maven/plugins/trunk/maven-pmd-plugin/src/main/resources/cpd-report.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: maven/plugins/trunk/maven-pmd-plugin/src/site/apt/howto.apt
URL: http://svn.apache.org/viewcvs/maven/plugins/trunk/maven-pmd-plugin/src/site/apt/howto.apt?rev=367339&r1=367338&r2=367339&view=diff
==============================================================================
--- maven/plugins/trunk/maven-pmd-plugin/src/site/apt/howto.apt (original)
+++ maven/plugins/trunk/maven-pmd-plugin/src/site/apt/howto.apt Mon Jan  9 09:12:00 2006
@@ -9,21 +9,25 @@
   The {{{http://pmd.sourceforge.net/}PMD}} plugin allows you to automatically run the PMD code analysis tool
   on your project's source code and generate a site report with its results.
 
-   * pmd:pmd (default): run PMD and generate the report
+   * pmd:pmd - run PMD and generate the report
+   * pmd:cpd - run PMD's Copy/Paste Detector tool and generate a report
 
 Configuration
 
-  To configure the PMD plugin, you use the standard m2 report plugin conventions.  For example, the following
-  tells Maven to run the PMD report as part of the site report generation, use the 'basic' and 'controversial'
+  The PMD and CPD reports share the same configuration.  For example, the following
+  tells Maven to run the PMD and CPD report as part of the site report generation, use the 'basic' and 'controversial'
   PMD rulesets and output the report in XML format.  The rulesets are assumed to reside in /rulesets/[name].xml 
   in the classpath.  Note that HTML is always generated in addition to any other alternate format.  Legal formats
   are "html", "csv", "xml" and "txt".
   
-  The PMD report will link directly to the cross-referenced source if you enable this with the linkXref parameter.
+  The reports will link directly to the cross-referenced source if you enable this with the linkXref parameter.
   See the {{{http://mojo.codehaus.org/jxr-maven-plugin/}JXR}} plugin for more details.
 
   If your source uses a non-default encoding, you can use the sourceEncoding parameter to tell Maven which
   encoding to use when reading the java source.
+  
+  You can configure the minimum code size which trips the CPD.  The default of 100 tokens cooresponds
+  to approxiamately 5-10 lines of code.
 
 +--------
     <reporting>
@@ -39,6 +43,7 @@
                     <format>xml</format>
                     <linkXref>true</linkXref>
                     <sourceEncoding>utf-8</sourceEncoding>
+                    <minimumTokens>100</minimumTokens>
                 </configuration>
             </plugin>
         </plugins>