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/src/main/java |
Publish
Diffstat (limited to 'config-class-plugin/src/main/java')
-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 |
2 files changed, 238 insertions, 0 deletions
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); + } + } +} |