blob: f2ee6248c5fb9a51d23454673b04cdd925b487e1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2015 IBH SYSTEMS GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBH SYSTEMS GmbH - initial API and implementation
* Obeo - Fix bug #440546
*******************************************************************************/
package org.eclipse.tycho.extras.docbundle;
import java.io.File;
import java.io.PrintStream;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.apache.commons.exec.OS;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.toolchain.Toolchain;
import org.apache.maven.toolchain.ToolchainManager;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
import org.codehaus.plexus.util.cli.DefaultConsumer;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.tycho.core.osgitools.BundleReader;
import org.eclipse.tycho.core.osgitools.OsgiManifest;
public class JavadocRunner {
private File output;
private ToolchainManager toolchainManager;
private MavenSession session;
private Set<File> sourceFolders = Collections.<File> emptySet();
private Set<File> manifestFiles = Collections.<File> emptySet();
private Log log;
private JavadocOptions options;
private File buildDirectory;
private BundleReader bundleReader;
private Collection<String> classPath = Collections.<String> emptyList();
private String lineSeparator = System.getProperty("line.separator");
private DocletArtifactsResolver docletArtifactsResolver;
private PackageNameMatcher includeMatcher;
private PackageNameMatcher excludeMatcher;
public JavadocRunner() {
}
public void setBundleReader(final BundleReader bundleReader) {
this.bundleReader = bundleReader;
}
public void setBuildDirectory(final File buildDirectory) {
this.buildDirectory = buildDirectory;
}
public void setOptions(final JavadocOptions options) {
this.options = options;
if (this.options == null) {
this.options = new JavadocOptions();
}
}
public void setLog(final Log log) {
this.log = log;
}
public void setSession(final MavenSession session) {
this.session = session;
}
public void setOutput(final File output) {
this.output = output;
}
public void run() throws Exception {
this.output.mkdirs();
this.buildDirectory.mkdirs();
final File optionsFile = new File(this.buildDirectory, "javadoc.options.txt");
final Commandline cli = createCommandLine(optionsFile.getAbsolutePath());
try (PrintStream ps = new PrintStream(optionsFile)) {
ps.print(createOptionsFileContent());
ps.close();
this.log.info("Calling: " + cli);
final int rc = CommandLineUtils.executeCommandLine(cli, new DefaultConsumer(), new DefaultConsumer());
if (rc != 0) {
if (!this.options.isIgnoreError()) {
throw new MojoExecutionException("Failed to execute javadoc - rc = " + rc);
} else {
this.log.info("execution failed with rc = " + rc);
}
}
}
}
/* VisibleForTesting */Commandline createCommandLine(String optionsFileAbsolutePath) {
Commandline cli = new Commandline();
cli.setExecutable(getExecutable());
cli.setWorkingDirectory(this.output);
cli.createArg().setValue("@" + optionsFileAbsolutePath);
addJvmArgs(cli);
return cli;
}
/* VisibleForTesting */String createOptionsFileContent() throws Exception {
// initialize include/exclude filters
if (options != null) {
if (!options.getIncludes().isEmpty()) {
includeMatcher = PackageNameMatcher.compile(options.getIncludes());
this.log.info("Including packages matching " + includeMatcher);
}
if (!options.getExcludes().isEmpty()) {
excludeMatcher = PackageNameMatcher.compile(options.getExcludes());
this.log.info("Excluding packages matching " + excludeMatcher);
}
}
StringBuilder sb = new StringBuilder();
addSourcePaths(sb);
addClassPath(sb);
addDoclet(sb);
addDocletPaths(sb);
addEncoding(sb);
addArguments(sb);
final int count = addPackages(sb);
if (count <= 0) {
this.log.warn("No packages found");
}
return sb.toString();
}
private void addEncoding(final StringBuilder sb) {
if (this.options.getEncoding() != null) {
sb.append("-encoding ").append(this.options.getEncoding()).append(lineSeparator);
}
}
private void addDoclet(final StringBuilder sb) {
if (this.options.getDoclet() == null) {
return;
}
sb.append("-doclet ").append(this.options.getDoclet()).append(lineSeparator);
}
private void addDocletPaths(final StringBuilder sb) throws MojoExecutionException {
Set<String> resolvedArtifactJars = docletArtifactsResolver.resolveArtifacts(this.options.getDocletArtifacts());
addPathArgument(sb, "-docletpath", resolvedArtifactJars);
}
private void addClassPath(final StringBuilder sb) {
addPathArgument(sb, "-classpath", this.classPath);
}
private void addArguments(final StringBuilder sb) {
for (final String argument : this.options.getAdditionalArguments()) {
sb.append(argument).append(lineSeparator);
}
}
private void addJvmArgs(final Commandline cli) {
for (final String arg : this.options.getJvmOptions()) {
cli.createArg().setValue("-J" + arg);
}
}
private int addPackages(final StringBuilder sb) throws Exception {
int count = 0;
for (final File manifestFile : this.manifestFiles) {
if (!manifestFile.canRead()) {
this.log.debug("No readable manifest: " + manifestFile);
continue;
}
final OsgiManifest bundle = this.bundleReader.loadManifest(manifestFile);
count += addPackages(sb, bundle.getManifestElements("Export-Package"));
}
return count;
}
private int addPackages(final StringBuilder sb, final ManifestElement[] manifestElements) {
if (manifestElements == null) {
return 0;
}
for (final ManifestElement ele : manifestElements) {
final String pkg = ele.getValue();
final boolean include = includeMatcher != null ? includeMatcher.matches(pkg) : true;
final boolean exclude = excludeMatcher != null ? excludeMatcher.matches(pkg) : false;
if (include && !exclude) {
sb.append(pkg).append(lineSeparator);
}
}
return manifestElements.length;
}
private void addPath(final StringBuilder sb, final Collection<?> path) {
boolean first = true;
for (final Object ele : path) {
if (ele == null) {
continue;
}
// convert black slashes to forward slashes for javadoc
final String pathEle = ele.toString().replace('\\', '/');
if (!first) {
sb.append(File.pathSeparator);
} else {
first = false;
}
sb.append(pathEle);
}
}
private void addSourcePaths(final StringBuilder sb) {
addPathArgument(sb, "-sourcepath", this.sourceFolders);
}
private void addPathArgument(final StringBuilder sb, final String arg, final Collection<?> path) {
if (path.isEmpty()) {
return;
}
sb.append(arg);
sb.append(" '");
addPath(sb, path);
sb.append("'" + lineSeparator);
}
protected String getExecutable() {
log.debug("Find javadoc executable");
if (this.options.getExecutable() != null) {
// prefer the specific one
log.debug("Using specified javadoc: " + options.getExecutable());
return this.options.getExecutable();
}
log.debug("Toolchain manager: " + toolchainManager);
if (this.toolchainManager != null) {
// try the toolchain
final Toolchain tc = this.toolchainManager.getToolchainFromBuildContext("jdk", this.session);
log.debug("Toolchain: " + tc);
if (tc != null) {
final String exe = tc.findTool("javadoc");
log.debug("Toolchain Tool: " + exe);
if (exe != null) {
return exe;
}
}
}
String javaHome = System.getProperty("java.home");
String javadocFromJavaHome;
// derive path to javac from java.home similar to org.codehaus.plexus.compiler.javac.JavacCompiler.getJavacExecutable() in plexus-compiler-javac
if (OS.isFamilyMac()) {
javadocFromJavaHome = javaHome + File.separator + "bin" + File.separator + "javadoc";
} else {
javadocFromJavaHome = javaHome + File.separator + ".." + File.separator + "bin" + File.separator
+ "javadoc";
}
if (OS.isFamilyWindows()) {
javadocFromJavaHome += ".exe";
}
log.debug("Testing javadoc from java.home = " + javadocFromJavaHome);
if (new File(javadocFromJavaHome).canExecute()) {
return javadocFromJavaHome;
}
log.debug("Using path fallback");
// fall back
return "javadoc";
}
public void setToolchainManager(final ToolchainManager toolchainManager) {
this.toolchainManager = toolchainManager;
}
public void setSourceFolders(final Set<File> sourceFolders) {
this.sourceFolders = sourceFolders;
}
public void setClassPath(final Collection<String> classPath) {
this.classPath = classPath;
}
public void setManifestFiles(Set<File> manifestFiles) {
this.manifestFiles = manifestFiles;
}
public void setDocletArtifactsResolver(DocletArtifactsResolver docletArtifactsResolver) {
this.docletArtifactsResolver = docletArtifactsResolver;
}
}