编写maven代码行统计插件

编写maven插件的步骤

  1. 创建一个maven-plugin项目:插件本身也是maven项目,只是它的packaging是maven-plugin。
  2. 为插件编写目标:每个插件必须包含一个或多个目标,maven称之为Mojo。编写插件时必须提供一个或多个继承自AbstractMojo的类。
  3. 为目标提供配置点:大部分maven插件以及其目标都是可配置的,因此在编写Mojo的时候需要注意提供可配置的参数。
  4. 编写代码,实现目标。
  5. 错误处理以及日志,为客户提供足够的信息。
  6. 测试插件

一:创建maven-plugin项目

创建一个普通的maven项目,只是packaging改为maven-plugin,同时引入依赖maven-plugin-api。pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.sawyer.edu</groupId>
    <artifactId>maven-loc-plugin</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>maven-plugin</packaging>

    <properties>
        <maven.version>3.0</maven.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>${maven.version}</version>
        </dependency>
    </dependencies>

</project>

二:创建一个CountMojo类。该类所必要的三项工作:继承AbstractMojo、实现execute()方法、提供@goal标注。代码如下:

package com.sawyer.edu.tlsys.plugin;

import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * maven 代码统计插件
 * @author sawyer
 * @goal count
 */
public class CountMojo extends AbstractMojo {

    /**
     * default includes
     */
    private static final String[] INCLUDES_DEFAULT = {"java", "xml", "properties"};

    /**
     * @parameter expression = "${project.basedir}"
     * @required
     * @readonly
     */
    private File basedir;

    /**
     * @parameter expression = "${project.build.sourceDirectory}"
     * @required
     * @readonly
     */
    private File sourceDirectory;

    /**
     * @parameter expression = "${project.build.testSourceDirectory}"
     * @required
     * @readonly
     */
    private File testSourceDirectory;

    /**
     * @parameter expression = "${project.build.resources}"
     * @required
     * @readonly
     */
    private List<Resource> resources;

    /**
     * @parameter expression = "${project.build.testResources}"
     * @required
     * @readonly
     */
    private List<Resource> testResources;

    /**
     * file types which will be included for counting
     * @parameter
     */
    private String[] includes;

    /**
     * execute
     * @throws MojoExecutionException MojoExecutionException
     * @throws MojoFailureException MojoFailureException
     */
    public void execute() throws MojoExecutionException, MojoFailureException {
        if(includes == null || includes.length == 0){
            includes = INCLUDES_DEFAULT;
        }
        try{
            countDir(sourceDirectory);
            countDir(testSourceDirectory);
            for(Resource resource : resources){
                countDir(new File(resource.getDirectory()));
            }
            for(Resource testResource : testResources){
                countDir(new File(testResource.getDirectory()));
            }
        }catch (Exception e){
            throw new MojoExecutionException("count failed:", e);
        }
    }

    /**
     * 统计某个目录下文件的代码行
     * @param dir 目录
     * @throws IOException 文件异常
     */
    private void countDir (File dir) throws IOException{
        if(!dir.exists()){
            return;
        }
        List<File> collected = new ArrayList<File>();
        collectFiles(collected, dir);
        int lines = 0;
        for(File sourceFile : collected){
            lines += countLine(sourceFile);
        }
        String path = dir.getAbsolutePath().substring(basedir.getAbsolutePath().length());
        getLog().info(path + ": " + lines + " lines of code in " + collected.size() + "files");
    }

    /**
     * 递归获取文件列表
     * @param collected 文件列表list
     * @param file 文件
     */
    private void collectFiles(List<File> collected, File file){
        if(file.isFile()){
            for(String include : includes){
                if(file.getName().endsWith("." + include)){
                    collected.add(file);
                    break;
                }
            }
        }else{
            for(File sub : file.listFiles()){
                collectFiles(collected, sub);
            }
        }
    }

    /**
     * 读取文件的行数
     * @param file 文件对象
     * @return line
     * @throws IOException 文件操作异常
     */
    private int countLine(File file) throws IOException{
        BufferedReader reader = new BufferedReader(new FileReader(file));
        int line = 0;
        try{
            while(reader.ready()){
                reader.readLine();
                line++;
            }
        }finally {
            reader.close();
        }
        return  line;
    }
}

CountMojo代码

这里要关注的是@goal标注,这个标注就是这个类的目标,定义了目标之后,我们才可以在项目中配置该插件目标。

代码中还包含了basedir、sourceDirectory、testSourceDirectory等字段,它们都使用了@parameter标注,同时关键字expression表示从系统属性中读取这几个字段值。

其次,代码中的includes字段就是用来为用户提供该配置点的,它的类型为String数组,并且使用了@parameter参数表示用户可以自己在pom中配置该字段,使用该插件时的pom配置如下:

<plugin>
    <groupId>com.iflytek.edu</groupId>
    <artifactId>maven-loc-plugin</artifactId>
    <version>1.0-SNAPSHOT</version>
    <configuration>
        <includes>
            <include>java</include>
            <include>sql</include>
        </includes>
    </configuration>
    <executions>
        <execution>
            <phase>compile</phase>
            <goals>
                <goal>count</goal>
            </goals>
        </execution>
    </executions>
</plugin>

根据上面的pom配置,可以看到incuudes字段标识需要统计的文件后缀,phase表示该插件在compile阶段工作,使用该插件的时候可以看到如下输出信息:

[INFO] --- maven-loc-plugin:1.0-SNAPSHOT:count (default) @ ZX-jobmonitor-webapp ---
[INFO] \src\main\java: 778 lines of code in 6files
[INFO] \src\test\java: 0 lines of code in 0files
[INFO] \src\main\resources: 0 lines of code in 0files

使用mvn clean install命令将该插件项目构建并安装到本地仓库后,并按照上面的pom配置,就可以使用它统计项目的代码了。

三:错误处理和日志

上面的CountMojo类继承自AbstratctMojo,跟踪会发现该抽象类实现了类Mojo接口,execute()方法就是在这个接口中定义的。

void execute()
        throws MojoExecutionException, MojoFailureException;

这个方法可以抛出两种异常,

如果是MojoFailureException异常,则表示为发现了预期的错误,例如单元测试插件在发现测试失败时就会抛出该异常。

如果是MojoExcutionException异常,则表示发现了未预期的异常,例如上述代码中的IOException等。

四:测试

可在项目中直接集成该插件,也可以在项目目录下用命令行来测试该插件,命令如下:

mvn com.sawyer.edu:maven-loc-plugin:1.0-SNAPSHOT:count
时间: 2024-11-08 19:04:02

编写maven代码行统计插件的相关文章

Java代码行统计程序

1.统计粒度 能够统计包括:代码行数.注释.空行.总行数. 2.适用的编程语言 目前只测试过Java,其它编程语言暂时未知. 3.代码简析 代码行统计需要考虑的因素包括字符串匹配.编程语言本身的字符串,后者非常重要,往往导致难以发现的bug.该程序的核心在于递归的使用和栈的构造,需要深刻理解递归的原因和栈的几种状态. 4.参考程序 程序一:http://wenku.baidu.com/view/2a3dcbe3524de518964b7dec.html 程序二:http://www.downxi

Git代码行统计命令集

统计某人的代码提交量,包括增加,删除: git log --author="$(git config --get user.name)" --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf "added lines: %s removed lines : %s total lines: %s\n",add,subs,loc }' -

Java 代码行统计(转)

package codecounter; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; public class CodeCou

mac OSX下git代码行统计命令

1.统计某人的代码提交量,包括增加,删除 git log --author="$(git config --get user.name)" --since=2014-07-01 --until=2016-08-01 --pretty=tformat: --numstat | awk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf "added lines: %s removed lines : %s tota

TensorFlow 代码行统计

https://github.com/tensorflow/tensorflow.git

如何安装Pycharm官方统计代码行插件

最近一直想统计Pycharm的总计代码行数,找到了官方的统计行数插件,发现效果还不错. 官方代码统计插件指导: https://plugins.jetbrains.com/plugin/4509-statistic(英文版) (初级教程,大牛请忽略) ***该插件需要Java1.8环境变量支持,没有安装JRE的同学出门左转找百度,安装Java1.8,部署JRE环境. 完成JRE环境部署之后,请在上面网址下载Statistic.jar安装包 下载到本地后,进入Pycharm的setting 进入S

Python实现代码行数统计工具

我们经常想要统计项目的代码行数,但是如果想统计功能比较完善可能就不是那么简单了, 今天我们来看一下如何用python来实现一个代码行统计工具. 思路:首先获取所有文件,然后统计每个文件中代码的行数,最后将行数相加. 实现的功能: 统计每个文件的行数: 统计总行数: 统计运行时间: 支持指定统计文件类型,排除不想统计的文件类型: 递归统计文件夹下包括子文件件下的文件的行数: 排除空行: # coding=utf-8 import os import time basedir = '/root/sc

Android Studio代码行数统计插件Statistics

Android Studio 是没有提提供统计代码全部行数的功能的,但是对于开发者来说,这个功能确实必备的,Statistic统计代码行数非常方便,也很详细. 1,首先肯定是将插件下载下来,下载地址:https://plugins.jetbrains.com/plugin/4509 2,下载下来之后我们将插件安装到AS上面: 进入设置界面Setting之后点击plugins,如下图所示,显示的是已经安装的插件名称,我们将下载的插件安装,点击下面按钮: 点击之后,选择已经下载好的plugins插件

自制Xcode插件——XcodeCareer:统计亲手输入代码行数和时长

自制了一个简单的Xcode插件.主要功能是统计自安装插件以后,用户手动输入的代码行数,以及累计敲代码的时间.通过快捷键Shift + P查看累计数据. 已分享至我的Github:XcodeCareer 欢迎各位大神一起来完善项目. 统计规则简单的说明如下: 1.创建工程或者创建文件时,系统已经生成的代码不算. 2.直接复制第三方框架进项目(Add New File)时,复制进来的代码不算. 3.任何一次回车键换行会使累计代码量增加一行.退格键删除一行会使累计代码量减少一行. 4.五秒钟不写代码后