首页 > 其他分享 >maven fmpp 插件开发说明

maven fmpp 插件开发说明

时间:2022-12-15 17:57:59浏览次数:66  
标签:插件 format org maven fmpp import new

实际上已经有几个 fmpp maven 插件,但是不是很好用,dremio 自己包装了一个,然后fork 了dremio fmpp 插件的代码独立包装了一些
同时发布到github repo 中,方便使用

参考代码

  • pom.xml
 
<?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.rongfengliang</groupId>
    <artifactId>fmpp-maven-plugin</artifactId>
    <packaging>maven-plugin</packaging>
    <version>1.0</version>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <commons-io.version>2.11.0</commons-io.version>
        <guava.version>31.1-jre</guava.version>
        <fmpp.version>0.9.16</fmpp.version>
        <freemarker.version>2.3.31</freemarker.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>${guava.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-core</artifactId>
            <version>3.3.9</version>
            <scope>provided</scope>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>3.3.9</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.plugin-tools</groupId>
            <artifactId>maven-plugin-annotations</artifactId>
            <version>3.6.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.fmpp</groupId>
            <artifactId>fmpp</artifactId>
            <version>${fmpp.version}</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>${freemarker.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-plugin-plugin</artifactId>
                <version>3.6.2</version>
                <configuration>
                    <goalPrefix>rongfengliang-fmpp</goalPrefix>
                </configuration>
                <executions>
                    <execution>
                        <id>default-descriptor</id>
                        <goals>
                            <goal>descriptor</goal>
                        </goals>
                        <phase>process-classes</phase>
                    </execution>
                    <execution>
                        <id>help-descriptor</id>
                        <goals>
                            <goal>helpmojo</goal>
                        </goals>
                        <phase>process-classes</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <distributionManagement>
        <repository>
            <id>github</id>
            <name>fmpp maven plugin</name>
            <url>https://maven.pkg.github.com/rongfengliang/fmpp-maven-plugin</url>
        </repository>
    </distributionManagement>
</project>
  • 核心插件代码
    FMPPMojo.java 核心是使用fmpp 的api 进行构建,同时进行配置参数设置,运行的阶段是生成source
    fmpp 包含了配置,模版以及输出目录,当然dremio 还扩展了支持data,实际上基于配置就可以加载数据
    数据加载dremio 配置了自己的MavenDataLoader
 
package com.rongfengliang;
 
import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch;
import fmpp.Engine;
import fmpp.ProgressListener;
import fmpp.progresslisteners.TerseConsoleProgressListener;
import fmpp.setting.Settings;
import fmpp.util.MiscUtil;
import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
 
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
 
import static java.lang.String.format;
 
/**
 * a maven plugin to run the freemarker generation incrementally
 * (if output has not changed, the files are not touched)
 */
@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class FMPPMojo extends AbstractMojo {
 
  /**
   * Used to add new source directories to the build.
   **/
  @Parameter(defaultValue = "${project}", readonly = true, required = true)
  private MavenProject project;
 
  /**
   * Where to find the FreeMarker template files.
   */
  @Parameter(defaultValue = "src/main/resources/fmpp/templates/", required = true)
  private File templates;
 
  /**
   * Where to write the generated files of the output files.
   */
  @Parameter(defaultValue = "${project.build.directory}/generated-sources/fmpp/", required = true)
  private File output;
 
  /**
   * Location of the FreeMarker config file.
   */
  @Parameter(defaultValue = "src/main/resources/fmpp/config.fmpp", required = true)
  private File config;
 
  /**
   * compilation scope to be added to ("compile" or "test")
   */
  @Parameter(defaultValue = "compile", required = true)
  private String scope;
 
  @Parameter
  private String data;
 
  /**
   * if maven properties are added as data
   */
  @Parameter(defaultValue = "true", required = true)
  private boolean addMavenDataLoader;
 
  @Override
  public void execute() throws MojoExecutionException, MojoFailureException {
    if (project == null) {
      throw new MojoExecutionException("This plugin can only be used inside a project.");
    }
    String outputPath = output.getAbsolutePath();
    if ((!output.exists() && !output.mkdirs()) || !output.isDirectory()) {
      throw new MojoFailureException("can not write to output dir: " + outputPath);
    }
    String templatesPath = templates.getAbsolutePath();
    if (!templates.exists() || !templates.isDirectory()) {
      throw new MojoFailureException("templates not found in dir: " + outputPath);
    }
 
    // add the output directory path to the project source directories
    switch (scope) {
      case "compile":
        project.addCompileSourceRoot(outputPath);
      break;
      case "test":
        project.addTestCompileSourceRoot(outputPath);
      break;
      default:
        throw new MojoFailureException("scope must be compile or test");
    }
 
    final Stopwatch sw = Stopwatch.createStarted();
    try {
      getLog().info(format("Freemarker generation:\n scope: %s,\n config: %s,\n templates: %s",
          scope, config.getAbsolutePath(), templatesPath));
      final File tmp = Files.createTempDirectory("freemarker-tmp").toFile();
      String tmpPath = tmp.getAbsolutePath();
      final String tmpPathNormalized = tmpPath.endsWith(File.separator) ? tmpPath : tmpPath + File.separator;
      Settings settings = new Settings(new File("."));
      settings.set(Settings.NAME_SOURCE_ROOT, templatesPath);
      settings.set(Settings.NAME_OUTPUT_ROOT, tmp.getAbsolutePath());
      settings.load(config);
      settings.addProgressListener(new TerseConsoleProgressListener());
      settings.addProgressListener(new ProgressListener() {
        @Override
        public void notifyProgressEvent(
            Engine engine, int event,
            File src, int pMode,
            Throwable error, Object param)
            throws Exception {
          if (event == EVENT_END_PROCESSING_SESSION) {
            getLog().info(format("Freemarker generation took %dms", sw.elapsed(TimeUnit.MILLISECONDS)));
            sw.reset();
            Report report = moveIfChanged(tmp, tmpPathNormalized);
            if (!tmp.delete()) {
              throw new MojoFailureException(format("can not delete %s", tmp));
            }
            getLog().info(format("Incremental output update took %dms", sw.elapsed(TimeUnit.MILLISECONDS)));
            getLog().info(format("new: %d", report.newFiles));
            getLog().info(format("changed: %d", report.changedFiles));
            getLog().info(format("unchanged: %d", report.unchangedFiles));
          }
        }
      } );
      List<String> dataValues = new ArrayList<>();
      if (addMavenDataLoader) {
        getLog().info("Adding maven data loader");
        settings.setEngineAttribute(MavenDataLoader.MAVEN_DATA_ATTRIBUTE, new MavenDataLoader.MavenData(project));
        dataValues.add(format("maven: %s()", MavenDataLoader.class.getName()));
      }
      if (data != null) {
        dataValues.add(data);
      }
      if(!dataValues.isEmpty()) {
        String dataString = Joiner.on(",").join(dataValues);
        getLog().info("Setting data loader "+ dataString);
 
        settings.add(Settings.NAME_DATA, dataString);
      }
      settings.execute();
    } catch (Exception e) {
      throw new MojoFailureException(MiscUtil.causeMessages(e), e);
    }
  }
 
  private static final class Report {
    private int changedFiles;
    private int unchangedFiles;
    private int newFiles;
    Report(int changedFiles, int unchangedFiles, int newFiles) {
      super();
      this.changedFiles = changedFiles;
      this.unchangedFiles = unchangedFiles;
      this.newFiles = newFiles;
    }
    public Report() {
      this(0, 0, 0);
    }
    void add(Report other) {
      changedFiles += other.changedFiles;
      unchangedFiles += other.unchangedFiles;
      newFiles += other.newFiles;
    }
    public void addChanged() {
      ++ changedFiles;
    }
    public void addNew() {
      ++ newFiles;
    }
    public void addUnchanged() {
      ++ unchangedFiles;
    }
  }
 
  private Report moveIfChanged(File root, String tmpPath) throws MojoFailureException, IOException {
    Report report = new Report();
    for (File file : root.listFiles()) {
      if (file.isDirectory()) {
        report.add(moveIfChanged(file, tmpPath));
        if (!file.delete()) {
          throw new MojoFailureException(format("can not delete %s", file));
        }
      } else {
        String absPath = file.getAbsolutePath();
        if (!absPath.startsWith(tmpPath)) {
          throw new MojoFailureException(format("%s should start with %s", absPath, tmpPath));
        }
        String relPath = absPath.substring(tmpPath.length());
        File outputFile = new File(output, relPath);
        if (!outputFile.exists()) {
          report.addNew();
        } else if (!FileUtils.contentEquals(file, outputFile)) {
          getLog().info(format("%s has changed", relPath));
          if (!outputFile.delete()) {
            throw new MojoFailureException(format("can not delete %s", outputFile));
          }
          report.addChanged();
        } else {
          report.addUnchanged();
        }
        if (!outputFile.exists()) {
          File parentDir = outputFile.getParentFile();
          if (parentDir.exists() && !parentDir.isDirectory()) {
            throw new MojoFailureException(format("can not move %s to %s as %s is not a dir", file, outputFile, parentDir));
          }
          if (!parentDir.exists() && !parentDir.mkdirs()) {
            throw new MojoFailureException(format("can not move %s to %s as dir %s can not be created", file, outputFile, parentDir));
          }
          FileUtils.moveFile(file, outputFile);
        } else {
          if (!file.delete()) {
            throw new MojoFailureException(format("can not delete %s", file));
          }
        }
      }
    }
    return report;
  }
}
  • 构建以及发布
    直接基于了github repo 进行发布,配置好账户token 就可以了
 
mvn clean package deploy

说明

最近在研究dremio sql 解析部分,使用到了fmpp 工具,为了方便使用,基于dremio 的源码,自己构建了一个

参考资料

https://github.com/rongfengliang/fmpp-maven-plugin
https://github.com/dremio/dremio-oss/tree/master/tools/fmpp-maven-plugin
https://fmpp.sourceforge.net/manual.html
https://fmpp.sourceforge.net/writefrontend.html

标签:插件,format,org,maven,fmpp,import,new
From: https://www.cnblogs.com/rongfengliang/p/16985698.html

相关文章

  • maven fmpp+javacc 集成使用简单说明
    dremio以及apachecalcite使用到fmpp+javacc进行代码生成处理,以下是一个简单的集成测试fmpp的作用fmpp实际上是包装了freemarker,提供了cli以及javaapi可以方......
  • java maven工程打出可执行jar包
    javamaven工程打出可执行jar包,在pom.xml中添加如下配置即可<build><plugins><!--设置编译版本--><plugin><groupId>org.apache.maven.......
  • maven安装与配置
    maven安装与配置下载mavenhttps://maven.apache.org配置环境变量我的电脑/此电脑-》属性-》高级系统设置-》环境变量-》系统-》系统变量-》新建......
  • 安装Elasticsearch和插件
    说明:es7版本以后,软件包的有带和不带jdk版本,都需要配置环境变量,有jdk版本路径:/usr/share/elasticsearch/jdk无jdk版本:需要配置环境变量。1.安装JDKopenjdk安......
  • 【分享一个工具】通过定义proto3来自动生成多进程模式的插件代码
    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客zhihuGithub公众号:一本正经的瞎扯我在多进程插件框架hashicorp/go-plugin的基础上,使用pro......
  • 【实战】企业级持续集成(DevOps/TestOps自动化平台):git + gitlab + jenkins + pipeline
    为什么要写企业级持续集成(jenkins+pipeline+k8s)?目前网上自动化持续集成的资料很多,但基本上都是局限于jenkins自由风格的job,结合shell脚本来实现持续集成,这种方式的缺点......
  • 一文直击什么是小程序插件。
    小程序插件功能简介1.怎么去理解插件呢?插件:英文名可称作“Plug-in、Plugin、add-in、addin、add-on、addon或extension”,是一个依附于主程序的辅助程序,透过和主程序的互动,用......
  • KBU610-ASEMI插件整流桥KBU610
    编辑:llKBU610-ASEMI插件整流桥KBU610型号:KBU610品牌:ASEMI封装:KBU-4特性:整流桥正向电流:6A反向耐压:1000V恢复时间:>2000ns引脚数量:4芯片个数:4芯片尺寸:88MIL浪涌电流:250A 漏电流......
  • maven安装和配置
    下载链接链接:https://pan.baidu.com/s/1YBRYbIK9Y5i0Vgr5vBSb8w提取码:p3kr文件解压后放到指定目录  D:\ProgramFiles\maven\apache-maven-3.8.4  ......
  • idea热加载插件Jrebel的使用
    1.安装插件在idea内部安装即可。 2.激活插件进入激活界面:激活方式可参考该博客: 3.设置Jrebel这里的刻度是class刷新时间间隔,上面的是我自己的,其余的设置保持默认即可。 ......