package io.takari.maven.plugins.exportpackage; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.inject.Inject; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableSet; import io.takari.incrementalbuild.Output; import io.takari.incrementalbuild.aggregator.AggregatorBuildContext; import io.takari.incrementalbuild.aggregator.InputSet; import io.takari.incrementalbuild.aggregator.MetadataAggregator; import io.takari.maven.plugins.TakariLifecycleMojo; @Mojo(name = "export-package", defaultPhase = LifecyclePhase.PROCESS_CLASSES, threadSafe = true) public class ExportPackageMojo extends TakariLifecycleMojo { public static final String PATH_EXPORT_PACKAGE = "META-INF/takari/export-package"; public static final char EOL = '\n'; @Parameter(defaultValue = "${project.build.outputDirectory}/" + PATH_EXPORT_PACKAGE) private File outputFile; @Parameter(defaultValue = "${project.build.outputDirectory}") private File classesDirectory; @Parameter private Set<String> exportIncludes = ImmutableSet.of(); @Parameter private Set<String> exportExcludes = ImmutableSet.of("**/internal/**", "**/impl/**"); @Inject private AggregatorBuildContext buildContext; @Override protected void executeMojo() throws MojoExecutionException { try { classesDirectory = classesDirectory.getCanonicalFile(); generateOutput(); } catch (IOException e) { throw new MojoExecutionException("Could not generate export-package file", e); } } private void generateOutput() throws IOException { InputSet output = buildContext.newInputSet(); output.addInputs(classesDirectory, getIncludes(), exportExcludes); output.aggregateIfNecessary(outputFile, new MetadataAggregator<String>() { @Override public Map<String, String> glean(File input) throws IOException { return Collections.singletonMap(getPackageName(classesDirectory, input), null); } @Override public void aggregate(Output<File> output, Map<String, String> metadata) throws IOException { Set<String> exportedPackages = new TreeSet<>(metadata.keySet()); try (BufferedWriter w = new BufferedWriter(new OutputStreamWriter(output.newOutputStream(), Charsets.UTF_8))) { for (String exportedPackage : exportedPackages) { w.write(exportedPackage); w.write(EOL); } } } }); } private Collection<String> getIncludes() { if (exportIncludes.isEmpty()) { return ImmutableSet.of("**/*.class"); } Set<String> includes = new HashSet<>(); for (String include : this.exportIncludes) { include = include.replace('\\', '/'); if (!include.endsWith("/")) { include = include + "/"; } include = include + "*.class"; } return includes; } static String getPackageName(File basedir, File file) { String relpath = basedir.toPath().relativize(file.getParentFile().toPath()).toString(); return relpath.replace('\\', '/').replace('/', '.'); } }