blob: b95981b7c6e0c877145aa1d931cf96f6f643e445 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2015 David Green 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:
* David Green - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.wikitext.mediawiki.core.tasks;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.eclipse.mylyn.internal.wikitext.core.ant.MarkupTask;
import org.eclipse.mylyn.internal.wikitext.core.parser.builder.DefaultSplittingStrategy;
import org.eclipse.mylyn.internal.wikitext.core.parser.builder.NoSplittingStrategy;
import org.eclipse.mylyn.internal.wikitext.core.parser.builder.SplitOutlineItem;
import org.eclipse.mylyn.internal.wikitext.core.parser.builder.SplittingHtmlDocumentBuilder;
import org.eclipse.mylyn.internal.wikitext.core.parser.builder.SplittingMarkupToEclipseToc;
import org.eclipse.mylyn.internal.wikitext.core.parser.builder.SplittingOutlineParser;
import org.eclipse.mylyn.internal.wikitext.core.parser.builder.SplittingStrategy;
import org.eclipse.mylyn.internal.wikitext.core.validation.StandaloneMarkupValidator;
import org.eclipse.mylyn.internal.wikitext.mediawiki.core.PageMapping;
import org.eclipse.mylyn.internal.wikitext.mediawiki.core.WikiTemplateResolver;
import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage;
import org.eclipse.mylyn.wikitext.core.parser.outline.OutlineItem;
import org.eclipse.mylyn.wikitext.core.validation.ValidationProblem;
import org.eclipse.mylyn.wikitext.core.validation.ValidationProblem.Severity;
import org.eclipse.mylyn.wikitext.mediawiki.core.MediaWikiLanguage;
/**
* An Ant task for generating Eclipse help content from one or more MediaWiki pages. Example usage:
*
* <pre>
* <code>
* &lt;mediawiki-to-eclipse-help
* wikiBaseUrl="${mylyn.help.doc.url.base}"
* validate="true"
* failonvalidationerror="true"
* prependImagePrefix="${imageFolder}"
* formatoutput="true"
* defaultAbsoluteLinkTarget="mylyn_external"
* dest="${basedir}"
* title="Mylyn"
* generateUnifiedToc="false"&gt;
* &lt;path name="Mylyn/User_Guide" title="Mylyn User Guide" generateToc="true"/&gt;
* &lt;path name="Mylyn/FAQ" title="Mylyn FAQ" generateToc="true"/&gt;
* &lt;stylesheet url="book.css"/&gt;
* &lt;pageAppendum&gt;
*
* = Updating This Document =
*
* This document is maintained in a collaborative wiki. If you wish to update or modify this document please visit
* {url}&lt;/pageAppendum&gt;
* &lt;/mediawiki-to-eclipse-help&gt;
* </code>
* </pre>
*
* @author David Green
*/
public class WikiToDocTask extends MarkupTask {
protected String htmlFilenameFormat = "$1.html"; //$NON-NLS-1$
private String wikiBaseUrl;
private List<Path> paths = new ArrayList<Path>();
private File dest;
private PageAppendum pageAppendum;
private final List<Stylesheet> stylesheets = new ArrayList<Stylesheet>();
protected String linkRel;
protected boolean multipleOutputFiles = true;
protected boolean formatOutput = false;
protected boolean navigationImages = true;
protected String prependImagePrefix = "images"; //$NON-NLS-1$
private final boolean useInlineCssStyles = true;
private final boolean suppressBuiltInCssStyles = false;
private String defaultAbsoluteLinkTarget;
private final boolean xhtmlStrict = false;
private final boolean emitDoctype = true;
private final String htmlDoctype = null;
private String helpPrefix;
private boolean fetchImages = true;
private File tocFile;
private String title;
private boolean generateUnifiedToc = true;
private String templateExcludes;
private boolean titleParameter;
public WikiToDocTask() {
}
@Override
public void execute() throws ConfigurationException {
if (dest == null) {
throw new ConfigurationException(Messages.getString("WikiToDocTask_specify_dest")); //$NON-NLS-1$
}
if (wikiBaseUrl == null) {
throw new ConfigurationException(Messages.getString("WikiToDocTask_specify_wikiBaseUrl")); //$NON-NLS-1$
}
if (paths.isEmpty()) {
throw new ConfigurationException(Messages.getString("WikiToDocTask_specify_paths")); //$NON-NLS-1$
}
if (getInternalLinkPattern() == null) {
setInternalLinkPattern(computeDefaultInternalLinkPattern());
}
Set<String> pathNames = new HashSet<String>();
for (Path path : paths) {
if (path.name == null) {
throw new ConfigurationException(Messages.getString("WikiToDocTask_path_must_have_name")); //$NON-NLS-1$
}
if (path.name != null) {
if (!pathNames.add(path.name)) {
throw new ConfigurationException(MessageFormat
.format(Messages.getString("WikiToDocTask_path_name_must_be_unique"), path.name)); //$NON-NLS-1$
}
}
if (!path.includeInUnifiedToc && path.getTocParentName() != null) {
throw new ConfigurationException(MessageFormat
.format(Messages.getString("WikiToDocTask_tocParentName_not_in_unified_toc"), path.name)); //$NON-NLS-1$
}
}
if (generateUnifiedToc) {
for (Path path : paths) {
if (path.getTocParentName() != null) {
if (!pathNames.contains(path.getTocParentName())) {
throw new ConfigurationException(MessageFormat.format(
Messages.getString("WikiToDocTask_unknown_tocParentName"), path.getTocParentName())); //$NON-NLS-1$
}
}
}
}
MediaWikiLanguage markupLanguage = (MediaWikiLanguage) createMarkupLanguage();
WikiTemplateResolver templateResolver = new WikiTemplateResolver();
templateResolver.setWikiBaseUrl(wikiBaseUrl);
markupLanguage.getTemplateProviders().add(templateResolver);
markupLanguage.setTemplateExcludes(templateExcludes);
for (Stylesheet stylesheet : stylesheets) {
if (stylesheet.url == null && stylesheet.file == null) {
throw new BuildException(Messages.getString("WikiToDocTask_stylesheet_file_or_url")); //$NON-NLS-1$
}
if (stylesheet.url != null && stylesheet.file != null) {
throw new BuildException(Messages.getString("WikiToDocTask_stylesheet_not_both")); //$NON-NLS-1$
}
if (stylesheet.file != null) {
if (!stylesheet.file.exists()) {
throw new BuildException(
MessageFormat.format(Messages.getString("WikiToDocTask_stylesheet_file_not_exist"), //$NON-NLS-1$
stylesheet.file));
}
if (!stylesheet.file.isFile()) {
throw new BuildException(
MessageFormat.format(Messages.getString("WikiToDocTask_stylesheet_file_not_file"), //$NON-NLS-1$
stylesheet.file));
}
if (!stylesheet.file.canRead()) {
throw new BuildException(MessageFormat
.format(Messages.getString("WikiToDocTask_stylesheet_file_cannot_read"), stylesheet.file)); //$NON-NLS-1$
}
}
}
if (!dest.exists()) {
if (!dest.mkdirs()) {
throw new BuildException(
MessageFormat.format("Cannot create dest folder: {0}", dest.getAbsolutePath())); //$NON-NLS-1$
}
}
if (tocFile == null) {
tocFile = new File(dest, "toc.xml"); //$NON-NLS-1$
}
Map<String, String> pathNameToContent = new HashMap<String, String>();
Map<String, SplitOutlineItem> pathNameToOutline = new HashMap<String, SplitOutlineItem>();
for (Path path : paths) {
getProject().log(
MessageFormat.format(Messages.getString("WikiToDocTask_fetching_content_for_page"), path.name), //$NON-NLS-1$
Project.MSG_VERBOSE);
URL pathUrl = computeRawUrl(path.name);
try {
Reader input = createInputReader(pathUrl);
try {
String content = readFully(input);
content = preprocessMarkup(path, content);
pathNameToContent.put(path.name, content);
final File targetFile = computeHtmlOutputFile(path);
SplitOutlineItem outline = computeOutline(path, markupLanguage, targetFile, content);
outline.setResourcePath(targetFile.getAbsolutePath());
pathNameToOutline.put(path.name, outline);
} finally {
input.close();
}
} catch (final IOException e) {
final String message = MessageFormat.format("Cannot read from {0}: {1}", pathUrl, e.getMessage()); //$NON-NLS-1$
throw new BuildException(message, e);
}
}
for (Path path : paths) {
getProject().log(MessageFormat.format(Messages.getString("WikiToDocTask_processing_page"), path.name), //$NON-NLS-1$
Project.MSG_DEBUG);
String markupContent = pathNameToContent.get(path.name);
if (isValidate()) {
performValidation(markupLanguage, path, markupContent);
}
Set<String> imageFilenames = null;
if (!fetchImages) {
getProject().log(Messages.getString("WikiToDocTask_skipping_images"), Project.MSG_WARN); //$NON-NLS-1$
} else {
imageFilenames = fetchImages(markupLanguage, path);
}
markupToDoc(markupLanguage, path, markupContent, pathNameToOutline, imageFilenames);
if (path.isGenerateToc()) {
createToc(path, pathNameToOutline.get(path.name));
}
}
if (generateUnifiedToc) {
createToc(paths, pathNameToOutline);
}
}
protected Reader createInputReader(URL pathUrl) throws IOException {
return new InputStreamReader(new BufferedInputStream(pathUrl.openStream()), "UTF-8"); //$NON-NLS-1$
}
protected void performValidation(MarkupLanguage markupLanguage, Path path, String markupContent) {
getProject().log(MessageFormat.format("Validating {0}", path.name), Project.MSG_VERBOSE); //$NON-NLS-1$
StandaloneMarkupValidator markupValidator = StandaloneMarkupValidator.getValidator(markupLanguage.getName());
List<ValidationProblem> problems = markupValidator.validate(markupContent);
int errorCount = 0;
int warningCount = 0;
for (ValidationProblem problem : problems) {
int messageLevel = Project.MSG_ERR;
if (problem.getSeverity() == Severity.ERROR) {
++errorCount;
} else if (problem.getSeverity() == Severity.WARNING) {
++warningCount;
messageLevel = Project.MSG_WARN;
}
log(String.format("%s:%s %s", path.name, problem.getOffset(), problem.getMessage()), messageLevel); //$NON-NLS-1$
}
if ((errorCount > 0 && isFailOnValidationError()) || (warningCount > 0 && isFailOnValidationWarning())) {
throw new BuildException(
MessageFormat.format("Validation failed with {0} errors and {1} warnings: {0}", errorCount, //$NON-NLS-1$
warningCount, path.name));
}
}
private void createToc(final Path path, OutlineItem rootItem) {
SplittingMarkupToEclipseToc markupToEclipseToc = new SplittingMarkupToEclipseToc() {
@Override
protected String computeFile(OutlineItem item) {
if (item instanceof SplitOutlineItem) {
return computeTocRelativeFile(item, path);
}
return super.computeFile(item);
}
};
markupToEclipseToc.setBookTitle(path.getTitle());
markupToEclipseToc.setHtmlFile(computeTocRelativeFile(rootItem, path));
String tocContents = markupToEclipseToc.createToc(rootItem);
File tocFile = new File(dest, path.name.replaceAll("[^a-zA-Z0-9]", "-") + "-toc.xml"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
try {
Writer writer = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(tocFile)), "UTF-8"); //$NON-NLS-1$
try {
writer.write(tocContents);
} finally {
writer.close();
}
} catch (IOException e) {
String message = MessageFormat.format("Cannot write {0}: {1}", tocFile, e.getMessage()); //$NON-NLS-1$
throw new BuildException(message, e);
}
}
private String computeTocRelativeFile(Map<OutlineItem, Path> outlineItemToPath, final OutlineItem item) {
Path path = outlineItemToPath.get(item);
OutlineItem pathItem = item;
while (path == null && pathItem.getParent() != null) {
pathItem = pathItem.getParent();
path = outlineItemToPath.get(pathItem);
}
return computeTocRelativeFile(item, path);
}
private String computeTocRelativeFile(OutlineItem item, Path path) {
String name = ((SplitOutlineItem) item).getSplitTarget();
File pathDestDir = computeDestDir(path);
File tocParentFile = tocFile.getParentFile();
String prefix = computePrefixPath(pathDestDir, tocParentFile);
String relativePath = prefix + '/' + name;
relativePath = relativePath.replace('\\', '/');
if (helpPrefix != null) {
String helpPath = helpPrefix;
helpPath = helpPath.replace('\\', '/');
if (!helpPath.endsWith("/")) { //$NON-NLS-1$
helpPath += "/"; //$NON-NLS-1$
}
relativePath = helpPath + relativePath;
}
relativePath = relativePath.replaceAll("/{2,}", "/"); //$NON-NLS-1$//$NON-NLS-2$
return relativePath;
}
private String computePrefixPath(File destDir, File tocParentFile) {
String prefix = destDir.getAbsolutePath().substring(tocParentFile.getAbsolutePath().length());
prefix = prefix.replace('\\', '/');
if (prefix.startsWith("/")) { //$NON-NLS-1$
prefix = prefix.substring(1);
}
if (prefix.endsWith("/")) { //$NON-NLS-1$
prefix = prefix.substring(0, prefix.length() - 1);
}
return prefix;
}
private void createToc(List<Path> paths, final Map<String, SplitOutlineItem> pathNameToOutline) {
getProject().log(MessageFormat.format(Messages.getString("WikiToDocTask_writing_toc"), tocFile), //$NON-NLS-1$
Project.MSG_VERBOSE);
final OutlineItem rootItem = new OutlineItem(null, 0, "<root>", 0, -1, //$NON-NLS-1$
title == null ? computeTitle(paths.get(0)) : title);
final Map<OutlineItem, Path> outlineItemToPath = new HashMap<OutlineItem, Path>();
final Map<String, OutlineItem> nameToItem = new HashMap<String, OutlineItem>();
// create root-level items
for (Path path : paths) {
if (path.includeInUnifiedToc) {
SplitOutlineItem pathItem = pathNameToOutline.get(path.name);
outlineItemToPath.put(pathItem, path);
nameToItem.put(path.name, pathItem);
if (path.getTocParentName() == null) {
rootItem.getChildren().add(pathItem);
}
}
}
for (Path path : paths) {
if (path.includeInUnifiedToc) {
if (path.getTocParentName() != null) {
SplitOutlineItem pathItem = pathNameToOutline.get(path.name);
if (nameToItem.containsKey(path.getTocParentName())) {
nameToItem.get(path.getTocParentName()).getChildren().add(pathItem);
} else {
throw new ConfigurationException(MessageFormat.format(
Messages.getString("WikiToDocTask_unknown_tocParentName"), path.getTocParentName())); //$NON-NLS-1$
}
}
}
}
SplittingMarkupToEclipseToc markupToEclipseToc = new SplittingMarkupToEclipseToc() {
@Override
protected String computeFile(OutlineItem item) {
if (item instanceof SplitOutlineItem) {
return computeTocRelativeFile(outlineItemToPath, item);
}
return super.computeFile(item);
}
};
markupToEclipseToc.setBookTitle(rootItem.getLabel());
markupToEclipseToc.setHtmlFile(computeTocRelativeFile(outlineItemToPath, rootItem.getChildren().get(0)));
String tocContents = markupToEclipseToc.createToc(rootItem);
try {
Writer writer = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(tocFile)), "UTF-8"); //$NON-NLS-1$
try {
writer.write(tocContents);
} finally {
writer.close();
}
} catch (IOException e) {
String message = MessageFormat.format("Cannot write {0}: {1}", tocFile, e.getMessage()); //$NON-NLS-1$
throw new BuildException(message, e);
}
}
private String computeDefaultInternalLinkPattern() {
String internalLinkPattern = wikiBaseUrl;
if (!internalLinkPattern.endsWith("/")) { //$NON-NLS-1$
internalLinkPattern += "/"; //$NON-NLS-1$
}
if (titleParameter) {
// parameter encoding is handled in AbstractMediaWikiLanguage
internalLinkPattern += "index.php?title={0}"; //$NON-NLS-1$
} else {
internalLinkPattern += "{0}"; //$NON-NLS-1$
}
return internalLinkPattern;
}
protected Set<String> fetchImages(MarkupLanguage markupLanguage, Path path) {
File dest = computeDestDir(path);
if (prependImagePrefix != null) {
dest = new File(dest, prependImagePrefix);
if (!dest.exists()) {
if (!dest.mkdirs()) {
throw new BuildException(
MessageFormat.format("Cannot create images folder: {0}", dest.getAbsolutePath())); //$NON-NLS-1$
}
}
}
getProject().log(MessageFormat.format(Messages.getString("WikiToDocTask_fetching_images_for_page"), path.name), //$NON-NLS-1$
Project.MSG_VERBOSE);
MediaWikiApiImageFetchingStrategy imageFetchingStrategy = new MediaWikiApiImageFetchingStrategy();
imageFetchingStrategy.setTask(this);
imageFetchingStrategy.setDest(dest);
imageFetchingStrategy.setPageName(path.name);
try {
imageFetchingStrategy.setUrl(new URL(wikiBaseUrl));
} catch (MalformedURLException e) {
throw new BuildException(e);
}
return imageFetchingStrategy.fetchImages();
}
private String preprocessMarkup(Path path, String content) {
if (pageAppendum != null) {
String pageAppendum = this.pageAppendum.text;
String qualifiedUrl = computeQualifiedWebPageUrl(path.name);
String appendum = pageAppendum.replace("{url}", qualifiedUrl); //$NON-NLS-1$
appendum = appendum.replace("{name}", path.name); //$NON-NLS-1$
appendum = appendum.replace("{title}", computeTitle(path)); //$NON-NLS-1$
content += appendum;
getProject()
.log(MessageFormat.format(Messages.getString("WikiToDocTask_appending_markup_to_page"), path.name, //$NON-NLS-1$
appendum), Project.MSG_VERBOSE);
}
return content;
}
private void markupToDoc(MarkupLanguage markupLanguage, Path path, String markupContent,
Map<String, SplitOutlineItem> pathNameToOutline, Set<String> imageFilenames) throws BuildException {
File htmlOutputFile = computeHtmlOutputFile(path);
File pathDir = htmlOutputFile.getParentFile();
if (!pathDir.exists()) {
if (!pathDir.mkdirs()) {
throw new BuildException(
MessageFormat.format(Messages.getString("WikiToDocTask_cannot_create_dest_folder"), //$NON-NLS-1$
pathDir.getAbsolutePath()));
}
}
Writer writer;
try {
writer = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(htmlOutputFile)), "utf-8"); //$NON-NLS-1$
} catch (Exception e) {
throw new BuildException(
MessageFormat.format(Messages.getString("WikiToDocTask_cannot_create_output_file"), htmlOutputFile, //$NON-NLS-1$
e.getMessage()),
e);
}
try {
HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer, formatOutput);
for (Stylesheet stylesheet : stylesheets) {
HtmlDocumentBuilder.Stylesheet builderStylesheet = createBuilderStylesheet(pathDir, stylesheet);
builder.addCssStylesheet(builderStylesheet);
}
builder.setTitle(computeTitle(path));
builder.setEmitDtd(emitDoctype);
if (emitDoctype && htmlDoctype != null) {
builder.setHtmlDtd(htmlDoctype);
}
builder.setUseInlineStyles(useInlineCssStyles);
builder.setSuppressBuiltInStyles(suppressBuiltInCssStyles);
builder.setLinkRel(linkRel);
builder.setDefaultAbsoluteLinkTarget(defaultAbsoluteLinkTarget);
builder.setPrependImagePrefix(prependImagePrefix);
builder.setXhtmlStrict(xhtmlStrict);
MarkupLanguage markupLanguageClone = markupLanguage.clone();
if (markupLanguageClone instanceof MediaWikiLanguage) {
MediaWikiLanguage mediaWikiLanguage = (MediaWikiLanguage) markupLanguageClone;
mediaWikiLanguage.setPageMapping(new PathPageMapping(path, paths, pathNameToOutline));
if (imageFilenames != null) {
mediaWikiLanguage.setImageNames(imageFilenames);
}
}
SplitOutlineItem item = pathNameToOutline.get(path.name);
SplittingHtmlDocumentBuilder splittingBuilder = new SplittingHtmlDocumentBuilder();
splittingBuilder.setRootBuilder(builder);
splittingBuilder.setOutline(item);
splittingBuilder.setRootFile(htmlOutputFile);
splittingBuilder.setNavigationImages(navigationImages);
splittingBuilder.setFormatting(formatOutput);
splittingBuilder.setNavigationImagePath(computeNavigationImagePath(pathDir));
MarkupParser parser = new MarkupParser();
parser.setMarkupLanguage(markupLanguageClone);
parser.setBuilder(splittingBuilder);
parser.parse(markupContent);
} finally {
try {
writer.close();
} catch (Exception e) {
throw new BuildException(MessageFormat.format(
Messages.getString("WikiToDocTask_cannot_write_output_file"), htmlOutputFile, //$NON-NLS-1$
e.getMessage()), e);
}
}
}
public HtmlDocumentBuilder.Stylesheet createBuilderStylesheet(File pathDir, Stylesheet stylesheet) {
HtmlDocumentBuilder.Stylesheet builderStylesheet;
if (stylesheet.url != null) {
URI uri = URI.create(stylesheet.url);
if (uri.isAbsolute()) {
builderStylesheet = new HtmlDocumentBuilder.Stylesheet(stylesheet.url);
} else {
String relativePath = ""; //$NON-NLS-1$
File currentDest = pathDir;
while (!currentDest.equals(dest)) {
currentDest = currentDest.getParentFile();
relativePath += "../"; //$NON-NLS-1$
}
builderStylesheet = new HtmlDocumentBuilder.Stylesheet(relativePath + stylesheet.url);
}
} else {
builderStylesheet = new HtmlDocumentBuilder.Stylesheet(stylesheet.file);
}
builderStylesheet.getAttributes().putAll(stylesheet.attributes);
return builderStylesheet;
}
protected String computeTitle(Path path) {
return path.title == null ? path.name : path.title;
}
private String computeNavigationImagePath(File pathDir) {
String relativePath = ""; //$NON-NLS-1$
File currentDest = pathDir;
while (!currentDest.equals(dest)) {
currentDest = currentDest.getParentFile();
relativePath += "../"; //$NON-NLS-1$
}
return relativePath + "images"; //$NON-NLS-1$
}
protected SplitOutlineItem computeOutline(Path path, MarkupLanguage markupLanguage, File defaultFile,
String markupContent) {
SplittingStrategy splittingStrategy = multipleOutputFiles
? new DefaultSplittingStrategy()
: new NoSplittingStrategy();
SplittingOutlineParser outlineParser = new SplittingOutlineParser();
outlineParser.setMarkupLanguage(markupLanguage);
outlineParser.setSplittingStrategy(splittingStrategy);
SplitOutlineItem item = outlineParser.parse(markupContent);
item.setSplitTarget(defaultFile.getName());
item.setLabel(computeTitle(path));
return item;
}
protected File computeDestDir(Path path) {
String name = path.name;
name.replace(' ', '_');
File dest = new File(this.dest, name);
return dest;
}
public File computeHtmlOutputFile(Path path) {
File dest = computeDestDir(path);
String fileName = computeHtmlFilename(path.name);
return new File(dest, fileName);
}
private String readFully(Reader input) throws IOException {
StringWriter content = new StringWriter(1024 * 8);
int i;
while ((i = input.read()) != -1) {
content.write(i);
}
return content.toString();
}
private URL computeRawUrl(String path) {
try {
String qualifiedUrl = wikiBaseUrl;
if (!qualifiedUrl.endsWith("/")) { //$NON-NLS-1$
qualifiedUrl += "/"; //$NON-NLS-1$
}
// ignore titleParameter here, we always reference index.php when getting the raw page content
qualifiedUrl += "index.php?title=" + URLEncoder.encode(path, "UTF-8") + "&action=raw"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
return new URL(qualifiedUrl);
} catch (IOException e) {
throw new BuildException(
MessageFormat.format(Messages.getString("WikiToDocTask_cannot_compute_raw_url"), path, //$NON-NLS-1$
e.getMessage()),
e);
}
}
private String computeQualifiedWebPageUrl(String path) {
String qualifiedUrl = wikiBaseUrl;
if (!qualifiedUrl.endsWith("/")) { //$NON-NLS-1$
qualifiedUrl += "/"; //$NON-NLS-1$
}
if (titleParameter) {
try {
qualifiedUrl += "index.php?title=" + URLEncoder.encode(path, "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (IOException e) {
throw new BuildException(
MessageFormat.format(Messages.getString("WikiToDocTask_cannot_compute_url"), path, //$NON-NLS-1$
e.getMessage()),
e);
}
} else {
qualifiedUrl += path;
}
return qualifiedUrl;
}
protected String computeHtmlFilename(String name) {
if (name.lastIndexOf('/') != -1) {
name = name.substring(name.lastIndexOf('/') + 1);
}
return htmlFilenameFormat.replace("$1", name.replaceAll("\\s|_", "-")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public static class Path {
private String title;
private String name;
private boolean generateToc = false;
private boolean includeInUnifiedToc = true;
private String tocParentName;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isGenerateToc() {
return generateToc;
}
public void setGenerateToc(boolean generateToc) {
this.generateToc = generateToc;
}
public boolean isIncludeInUnifiedToc() {
return includeInUnifiedToc;
}
public void setIncludeInUnifiedToc(boolean includeInUnifiedToc) {
this.includeInUnifiedToc = includeInUnifiedToc;
}
public String getTocParentName() {
return tocParentName;
}
public void setTocParentName(String tocParentName) {
this.tocParentName = tocParentName;
}
@Override
public String toString() {
String s = name;
if (tocParentName != null) {
s = tocParentName + '/' + s;
}
return s;
}
}
public static class Attribute {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public static class Stylesheet {
private File file;
private String url;
private final Map<String, String> attributes = new HashMap<String, String>();
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public void addConfiguredAttribute(Attribute attribute) {
attributes.put(attribute.getName(), attribute.getValue());
}
}
private static final Pattern PAGE_NAME_PATTERN = Pattern.compile("([^#]*)(?:#(.*))?"); //$NON-NLS-1$
public static class PageAppendum {
String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public void addText(String text) {
if (this.text == null) {
this.text = text;
} else {
this.text += text;
}
}
}
private class PathPageMapping implements PageMapping {
private final Path currentPath;
private final Map<String, Path> nameToPath = new HashMap<String, Path>();
private final Map<String, SplitOutlineItem> pathNameToOutline;
private PathPageMapping(Path currentPath, List<Path> paths, Map<String, SplitOutlineItem> pathNameToOutline) {
this.currentPath = currentPath;
this.pathNameToOutline = pathNameToOutline;
for (Path path : paths) {
nameToPath.put(path.name.replace(' ', '_'), path);
}
}
public String mapPageNameToHref(String pageName) {
Matcher matcher = PAGE_NAME_PATTERN.matcher(pageName);
if (matcher.matches()) {
String name = matcher.group(1);
String hashId = matcher.group(2);
if (currentPath.name.equals(name)) {
return "#" + (hashId == null ? "" : hashId); //$NON-NLS-1$ //$NON-NLS-2$
}
name = name.replace(' ', '_');
Path path = nameToPath.get(name);
if (path != null) {
File destDir = computeDestDir(path);
File currentDest = computeDestDir(currentPath);
String relativePath = ""; //$NON-NLS-1$
while (!currentDest.equals(dest)) {
currentDest = currentDest.getParentFile();
relativePath += "../"; //$NON-NLS-1$
}
String relativeDir = destDir.getAbsolutePath().substring(dest.getAbsolutePath().length());
//URL path separator is always forward slash
if (File.separatorChar == '\\') {
relativeDir = relativeDir.replace('\\', '/');
}
if (relativeDir.startsWith("/")) { //$NON-NLS-1$
relativeDir = relativeDir.substring(1);
}
relativePath += relativeDir;
if (!relativePath.endsWith("/")) { //$NON-NLS-1$
relativePath += "/"; //$NON-NLS-1$
}
String fileName = computeHtmlFilename(name);
// FIXME handle hashId mapping to split files
if (hashId != null) {
SplitOutlineItem outline = pathNameToOutline.get(name);
SplitOutlineItem item = outline.getOutlineItemById(hashId);
if (item == null) {
getProject().log(MessageFormat.format(
Messages.getString("WikiToDocTask_missing_id_in_page_reference"), hashId, //$NON-NLS-1$
name, currentPath.name), Project.MSG_WARN);
} else {
fileName = item.getSplitTarget();
}
relativePath += fileName;
relativePath += '#' + hashId;
} else {
relativePath += fileName;
}
return relativePath;
}
}
return null;
}
}
public String getWikiBaseUrl() {
return wikiBaseUrl;
}
public void setWikiBaseUrl(String wikiBaseUrl) {
this.wikiBaseUrl = wikiBaseUrl;
}
public List<Path> getPaths() {
return paths;
}
public void setPaths(List<Path> paths) {
this.paths = paths;
}
public File getDest() {
return dest;
}
public void setDest(File dest) {
this.dest = dest;
}
public String getLinkRel() {
return linkRel;
}
public void setLinkRel(String linkRel) {
this.linkRel = linkRel;
}
public boolean isMultipleOutputFiles() {
return multipleOutputFiles;
}
public void setMultipleOutputFiles(boolean multipleOutputFiles) {
this.multipleOutputFiles = multipleOutputFiles;
}
public boolean isFormatOutput() {
return formatOutput;
}
public void setFormatOutput(boolean formatOutput) {
this.formatOutput = formatOutput;
}
public boolean isNavigationImages() {
return navigationImages;
}
public void setNavigationImages(boolean navigationImages) {
this.navigationImages = navigationImages;
}
public String getPrependImagePrefix() {
return prependImagePrefix;
}
public void setPrependImagePrefix(String prependImagePrefix) {
this.prependImagePrefix = prependImagePrefix;
}
public String getDefaultAbsoluteLinkTarget() {
return defaultAbsoluteLinkTarget;
}
public void setDefaultAbsoluteLinkTarget(String defaultAbsoluteLinkTarget) {
this.defaultAbsoluteLinkTarget = defaultAbsoluteLinkTarget;
}
public List<Stylesheet> getStylesheets() {
return stylesheets;
}
public boolean isUseInlineCssStyles() {
return useInlineCssStyles;
}
public boolean isSuppressBuiltInCssStyles() {
return suppressBuiltInCssStyles;
}
public boolean isXhtmlStrict() {
return xhtmlStrict;
}
public boolean isEmitDoctype() {
return emitDoctype;
}
public String getHtmlDoctype() {
return htmlDoctype;
}
public String getHelpPrefix() {
return helpPrefix;
}
public void setHelpPrefix(String helpPrefix) {
this.helpPrefix = helpPrefix;
}
public void addStylesheet(Stylesheet stylesheet) {
if (stylesheet == null) {
throw new IllegalArgumentException();
}
stylesheets.add(stylesheet);
}
public void addPath(Path path) {
if (path == null) {
throw new IllegalArgumentException();
}
paths.add(path);
}
@Override
protected MarkupLanguage createMarkupLanguage() throws BuildException {
if (getMarkupLanguage() == null) {
MediaWikiLanguage markupLanguage = new MediaWikiLanguage();
if (getInternalLinkPattern() != null) {
markupLanguage.setInternalLinkPattern(getInternalLinkPattern());
}
if (getMarkupLanguageConfiguration() != null) {
markupLanguage.configure(getMarkupLanguageConfiguration());
}
return markupLanguage;
}
return super.createMarkupLanguage();
}
public String getHtmlFilenameFormat() {
return htmlFilenameFormat;
}
public void setHtmlFilenameFormat(String htmlFilenameFormat) {
this.htmlFilenameFormat = htmlFilenameFormat;
}
public boolean isFetchImages() {
return fetchImages;
}
public void setFetchImages(boolean fetchImages) {
this.fetchImages = fetchImages;
}
public void setPageAppendum(PageAppendum pageAppendum) {
this.pageAppendum = pageAppendum;
}
public PageAppendum getPageAppendum() {
return pageAppendum;
}
public void addPageAppendum(PageAppendum pageAppendum) {
if (pageAppendum == null) {
throw new IllegalArgumentException();
}
if (this.pageAppendum != null) {
throw new BuildException(Messages.getString("WikiToDocTask_only_one_page_appendum")); //$NON-NLS-1$
}
this.pageAppendum = pageAppendum;
}
public File getTocFile() {
return tocFile;
}
public void setTocFile(File tocFile) {
this.tocFile = tocFile;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isGenerateUnifiedToc() {
return generateUnifiedToc;
}
public void setGenerateUnifiedToc(boolean generateUnifiedToc) {
this.generateUnifiedToc = generateUnifiedToc;
}
public String getTemplateExcludes() {
return templateExcludes;
}
public void setTemplateExcludes(String templateExcludes) {
this.templateExcludes = templateExcludes;
}
/**
* indicates if the title should be provided as an HTTP parameter, for example <code>index.php?title=Main</code>
*
* @return true if index.php and HTTP parameters should be used in the URL, otherwise false. Defaults to false.
* @since 1.8
*/
public boolean isTitleParameter() {
return titleParameter;
}
/**
* indicates if the title should be provided as an HTTP parameter, for example <code>index.php?title=Main</code>
*
* @param titleParameter
* true if index.php and HTTP parameters should be used in the URL, otherwise false.
* @since 1.8
*/
public void setTitleParameter(boolean titleParameter) {
this.titleParameter = titleParameter;
}
}