summaryrefslogtreecommitdiffstats
path: root/config-class-plugin
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /config-class-plugin
Publish
Diffstat (limited to 'config-class-plugin')
-rw-r--r--config-class-plugin/.gitignore2
-rw-r--r--config-class-plugin/OWNERS1
-rw-r--r--config-class-plugin/README.markdown60
-rw-r--r--config-class-plugin/pom.xml82
-rw-r--r--config-class-plugin/src/main/java/com/yahoo/vespa/CloverChecker.java53
-rw-r--r--config-class-plugin/src/main/java/com/yahoo/vespa/ConfigGenMojo.java185
-rw-r--r--config-class-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml18
7 files changed, 401 insertions, 0 deletions
diff --git a/config-class-plugin/.gitignore b/config-class-plugin/.gitignore
new file mode 100644
index 00000000000..39c0275a1b2
--- /dev/null
+++ b/config-class-plugin/.gitignore
@@ -0,0 +1,2 @@
+target
+/pom.xml.build
diff --git a/config-class-plugin/OWNERS b/config-class-plugin/OWNERS
new file mode 100644
index 00000000000..e0a00db5f4f
--- /dev/null
+++ b/config-class-plugin/OWNERS
@@ -0,0 +1 @@
+musum
diff --git a/config-class-plugin/README.markdown b/config-class-plugin/README.markdown
new file mode 100644
index 00000000000..5fa87da63e1
--- /dev/null
+++ b/config-class-plugin/README.markdown
@@ -0,0 +1,60 @@
+Vespa Config Generation
+=======================
+
+The vespa-configgen plugin is used to generate config-classes from .def files.
+
+Userguide
+---------
+Put your .def files in `src/main/vespa-configdef`
+
+Depend on this plugin in your `pom.xml`
+
+ <dependencies>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>vespa-configgen-plugin</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+
+Add the following to the 'build' section of your `pom.xml`
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>vespa-configgen-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>config-gen</id>
+ <goals>
+ <goal>config-gen</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+The .def files will now be processed during the generate-sources step, and produce output
+in the `target/generated-sources/vespa-configgen-plugin` directory. This directory
+is automatically added to the source path of your project.
+
+It is possible to configure the location(s) of def-files, and the output of the generated sources.
+Put the following configuration under the plugin in the build section:
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>vespa-configgen-plugin</artifactId>
+ <configuration>
+ <defFilesDirectories>etc, src/main/def-files</defFilesDirectories>
+ <outputDirectory>target/generated-sources/vespa-configgen-plugin</outputDirectory>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+To run only the config-gen goal from the command-line:
+$ mvn com.yahoo.vespa:vespa-configgen-plugin:config-gen
diff --git a/config-class-plugin/pom.xml b/config-class-plugin/pom.xml
new file mode 100644
index 00000000000..ce37260819b
--- /dev/null
+++ b/config-class-plugin/pom.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<!-- Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+<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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>parent</artifactId>
+ <version>6-SNAPSHOT</version>
+ <relativePath>../parent/pom.xml</relativePath>
+ </parent>
+ <artifactId>config-class-plugin</artifactId>
+ <packaging>maven-plugin</packaging>
+ <version>6-SNAPSHOT</version>
+ <name>Vespa ConfigGen Plugin</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>3.1.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-project</artifactId>
+ <version>2.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>configgen</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ <artifactId>maven-plugin-annotations</artifactId>
+ <version>3.2</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <configuration>
+ <updateReleaseInfo>true</updateReleaseInfo>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <additionalparam>-Xdoclint:${doclint} -Xdoclint:-missing</additionalparam>
+ <tags>
+ <tag>
+ <name>goal</name>
+ <placement>t</placement>
+ </tag>
+ <tag>
+ <name>phase</name>
+ <placement>t</placement>
+ </tag>
+ </tags>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+</project>
diff --git a/config-class-plugin/src/main/java/com/yahoo/vespa/CloverChecker.java b/config-class-plugin/src/main/java/com/yahoo/vespa/CloverChecker.java
new file mode 100644
index 00000000000..fc7fda28b1c
--- /dev/null
+++ b/config-class-plugin/src/main/java/com/yahoo/vespa/CloverChecker.java
@@ -0,0 +1,53 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa;
+
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.Predicate;
+
+/**
+ * @author tonytv
+ */
+class CloverChecker {
+ private final Log log;
+
+ CloverChecker(Log log) {
+ this.log = log;
+ }
+
+ @SuppressWarnings("unchecked") //getCompileSourceRoots() returns List instead of List<String>
+ public boolean isForkedCloverLifecycle(MavenProject project, Path outputDirectory) {
+ return "clover".equals(project.getArtifact().getClassifier()) &&
+ project.getCompileSourceRoots().stream().anyMatch(
+ equalsPathAbsolutely(regularOutputDirectory(project, outputDirectory)));
+ }
+
+ /*
+ * Regular output directory for generated classes,
+ * i.e. not the clover output directory.
+ *
+ * Example:
+ * If outputDirectory is target/clover/generated-sources/vespa-configgen-plugin,
+ * return target/generated-sources/vespa-configgen-plugin.
+ */
+ private Path regularOutputDirectory(MavenProject project, Path outputDirectory) {
+ Path cloverTargetPath = Paths.get(project.getBuild().getDirectory());
+ Path targetPath = cloverTargetPath.getParent();
+
+ if (!targetPath.endsWith("target")) {
+ log.warn("Guessing that target directory is " + targetPath + ", this might not be correct.");
+ }
+
+ Path outputDirectoryRelativeToCloverDirectory = cloverTargetPath.relativize(outputDirectory);
+ return targetPath.resolve(outputDirectoryRelativeToCloverDirectory);
+ }
+
+ private Predicate<String> equalsPathAbsolutely(Path path) {
+ Path absolutePath = path.toAbsolutePath();
+
+ return candidateStringPath -> Paths.get(candidateStringPath).toAbsolutePath().equals(absolutePath);
+ }
+}
diff --git a/config-class-plugin/src/main/java/com/yahoo/vespa/ConfigGenMojo.java b/config-class-plugin/src/main/java/com/yahoo/vespa/ConfigGenMojo.java
new file mode 100644
index 00000000000..941f8afc648
--- /dev/null
+++ b/config-class-plugin/src/main/java/com/yahoo/vespa/ConfigGenMojo.java
@@ -0,0 +1,185 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa;
+
+import com.yahoo.config.codegen.MakeConfig;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.apache.commons.io.FileUtils;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.Collection;
+import java.util.List;
+import java.util.ArrayList;
+
+
+/**
+ * Goal which generates config classes from def-files.
+ */
+@org.apache.maven.plugins.annotations.Mojo(name = "config-gen", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
+public class ConfigGenMojo extends AbstractMojo {
+ @Component
+ private MavenProject project;
+
+ /**
+ * Generate source to here.
+ */
+ @Parameter(property = "plugin.configuration.outputDirectory",
+ defaultValue = "${project.build.directory}/generated-sources/vespa-configgen-plugin",
+ required = true)
+ private File outputDirectory;
+
+ /**
+ * Location of def files to generate source from, comma separated list of directories.
+ */
+ @Parameter(property = "plugin.configuration.defFilesDirectories",
+ defaultValue = "src/main/resources/configdefinitions")
+ private String defFilesDirectories;
+
+ /**
+ * Set to 'false' to create pure data config classes without any vespa framework code
+ */
+ @Parameter(property = "plugin.configuration.useFramework", defaultValue = "true")
+ private Boolean useFramework;
+
+ /**
+ * Set to 'false' to allow generation of config classes that have the default namespace 'config'.
+ */
+ @Parameter(property = "plugin.configuration.requireNamespace", defaultValue = "true")
+ private Boolean requireNamespace;
+
+ /**
+ * Package prefix of generated configs. The resulting package name will be packagePrefix.namespace if specified.
+ */
+ @Parameter(property = "plugin.configuration.packagePrefix", defaultValue = "com.yahoo.")
+ private String packagePrefix;
+
+ /**
+ * If true, the config sources are only intended for use during testing.
+ *
+ */
+ @Parameter(property = "plugin.configuration.testConfig", defaultValue = "false", required = true)
+ private boolean testConfig;
+
+ /**
+ * Returns List of all def-files in all defFilesDirectories, including path.
+ * @return The list of def-files.
+ */
+ private List<String> getDefFileNames() {
+ List<String> defFileNames = new ArrayList<>();
+
+ String[] dirNames = defFilesDirectories.split(",");
+ List<File> dirs = new ArrayList<>();
+ for (String dirName : dirNames) {
+ File dir = new File(project.getBasedir(), dirName.trim());
+ if (dir.isDirectory() && dir.canRead()) {
+ dirs.add(dir);
+ }
+ }
+ for (File dir : dirs) {
+ String[] dirFiles = dir.list(new FilenameFilter () {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".def");
+ }
+ });
+ for (String filename : dirFiles) {
+ defFileNames.add(dir.toString() + File.separator + filename);
+ }
+ }
+ return defFileNames;
+ }
+
+ public void execute()
+ throws MojoExecutionException
+ {
+ if (new CloverChecker(getLog()).isForkedCloverLifecycle(project, outputDirectory.toPath())) {
+ getLog().info("Skipping config generation in forked clover lifecycle.");
+ return;
+ }
+
+ List<String> defFileNames = getDefFileNames();
+
+ // Silent failure when there are no def-files to process...
+ if (defFileNames.size() == 0) {
+ return;
+ }
+
+ // append all def-file names together
+ StringBuilder configSpec = new StringBuilder();
+ boolean notFirst = false;
+ for (String defFile : defFileNames) {
+ if (notFirst) { configSpec.append(","); } else { notFirst = true; }
+ configSpec.append(defFile);
+ }
+
+ boolean generateSources;
+ // optionally create the output directory
+ File f = outputDirectory;
+ if (!f.exists() ) {
+ f.mkdirs();
+ generateSources = true;
+ getLog().debug("Output dir does not exist");
+ } else {
+ getLog().debug("Output dir exists");
+ generateSources = isSomeGeneratedFileStale(outputDirectory, defFileNames);
+ }
+
+ if (generateSources) {
+ getLog().debug("Will generate config class files");
+ System.setProperty("config.useFramework", useFramework.toString());
+ System.setProperty("config.dest", outputDirectory.toString());
+ System.setProperty("config.spec", configSpec.toString());
+ System.setProperty("config.packagePrefix", packagePrefix);
+ System.setProperty("config.requireNamespace", requireNamespace.toString());
+ try {
+ MakeConfig.main(null);
+ } catch (java.io.IOException | InterruptedException e) {
+ System.out.println("Caught exception: " + e);
+ }
+ } else {
+ getLog().debug("No changes, will not generate config class files");
+ }
+
+ // We have created files, so add the output directory to the compile source root
+ addSourceRoot(outputDirectory.toString());
+ }
+
+ private boolean isSomeGeneratedFileStale(File outputDirectory, List<String> defFileNames) {
+ long oldestGeneratedModifiedTime = Long.MAX_VALUE;
+ final Collection<File> files = FileUtils.listFiles(outputDirectory, null, true);
+ if (files != null) {
+ for (File f : files) {
+ getLog().debug("Checking generated file " + f);
+ final long l = f.lastModified();
+ if (l < oldestGeneratedModifiedTime) {
+ oldestGeneratedModifiedTime = l;
+ }
+ }
+ }
+
+ long lastModifiedSource = 0;
+ for (String sourceFile : defFileNames) {
+ getLog().debug("Checking source file " + sourceFile);
+ File f = new File(sourceFile);
+ final long l = f.lastModified();
+ if (l > lastModifiedSource) {
+ lastModifiedSource = l;
+ }
+ }
+
+ getLog().debug("lastModifiedSource: " + lastModifiedSource + ", oldestTGeneratedModified: " + oldestGeneratedModifiedTime);
+ return lastModifiedSource > oldestGeneratedModifiedTime;
+ }
+
+ private void addSourceRoot(String outputDirectory) {
+ if (testConfig) {
+ project.addTestCompileSourceRoot(outputDirectory);
+ } else {
+ project.addCompileSourceRoot(outputDirectory);
+ }
+ }
+}
diff --git a/config-class-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml b/config-class-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml
new file mode 100644
index 00000000000..f5c8dbc78d1
--- /dev/null
+++ b/config-class-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml
@@ -0,0 +1,18 @@
+<!-- Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+<lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <goals>
+ <goal>config-gen</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <execute>
+ <runOnIncremental>false</runOnIncremental>
+ <runOnConfiguration>true</runOnConfiguration>
+ </execute>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+</lifecycleMappingMetadata>