diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /config-class-plugin |
Publish
Diffstat (limited to 'config-class-plugin')
-rw-r--r-- | config-class-plugin/.gitignore | 2 | ||||
-rw-r--r-- | config-class-plugin/OWNERS | 1 | ||||
-rw-r--r-- | config-class-plugin/README.markdown | 60 | ||||
-rw-r--r-- | config-class-plugin/pom.xml | 82 | ||||
-rw-r--r-- | config-class-plugin/src/main/java/com/yahoo/vespa/CloverChecker.java | 53 | ||||
-rw-r--r-- | config-class-plugin/src/main/java/com/yahoo/vespa/ConfigGenMojo.java | 185 | ||||
-rw-r--r-- | config-class-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml | 18 |
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> |