| /******************************************************************************* |
| * 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> |
| * <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"> |
| * <path name="Mylyn/User_Guide" title="Mylyn User Guide" generateToc="true"/> |
| * <path name="Mylyn/FAQ" title="Mylyn FAQ" generateToc="true"/> |
| * <stylesheet url="book.css"/> |
| * <pageAppendum> |
| * |
| * = Updating This Document = |
| * |
| * This document is maintained in a collaborative wiki. If you wish to update or modify this document please visit |
| * {url}</pageAppendum> |
| * </mediawiki-to-eclipse-help> |
| * </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; |
| } |
| |
| } |