You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2008/07/01 06:10:57 UTC
svn commit: r672983 - in
/myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin:
./ src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/
Author: lu4242
Date: Mon Jun 30 21:10:57 2008
New Revision: 672983
URL: http://svn.apache.org/viewvc?rev=672983&view=rev
Log:
Add tagdoc-index and tagdoc-content goals (documentation like myfaces-tagdoc-plugin)
Added:
myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/
myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java (with props)
myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java (with props)
myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java (with props)
Modified:
myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/pom.xml
Modified: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/pom.xml
URL: http://svn.apache.org/viewvc/myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/pom.xml?rev=672983&r1=672982&r2=672983&view=diff
==============================================================================
--- myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/pom.xml (original)
+++ myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/pom.xml Mon Jun 30 21:10:57 2008
@@ -158,8 +158,28 @@
<version>1.1.7</version>
</dependency>
-->
+
+ <!-- Reporting required API-->
+ <dependency>
+ <groupId>org.apache.maven.reporting</groupId>
+ <artifactId>maven-reporting-impl</artifactId>
+ <version>2.0</version>
+ </dependency>
<dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-core</artifactId>
+ <version>1.0-alpha-7</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-site-renderer</artifactId>
+ <version>1.0-alpha-7</version>
+ </dependency>
+ <!-- End Reporting required API -->
+
+ <dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.13</version>
Added: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java
URL: http://svn.apache.org/viewvc/myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java?rev=672983&view=auto
==============================================================================
--- myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java (added)
+++ myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java Mon Jun 30 21:10:57 2008
@@ -0,0 +1,877 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.buildtools.maven2.plugin.tagdoc;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.digester.AbstractObjectCreationFactory;
+import org.apache.maven.artifact.DependencyResolutionRequiredException;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.MavenReportException;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.Flattener;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.IOUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ClassMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.TagMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.resource.ResourceManagerImpl;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
+import org.codehaus.plexus.util.xml.Xpp3DomWriter;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.xml.sax.Attributes;
+
+/**
+ *
+ * Generate the tag doc content pages using velocity. This is done before
+ * site, because maven-site-plugin use velocity and if we do this inside
+ * report generation, we cause a ClassLoader problem.
+ *
+ * @author Leonardo Uribe
+ * @goal tagdoc-content
+ * @phase generate-resources
+ */
+public class TagdocContentMojo extends AbstractMojo
+{
+ private Model _model;
+
+ /**
+ * Specifies the directory where the report will be generated
+ *
+ * @parameter default-value="${project.reporting.outputDirectory}"
+ * @required
+ */
+ private File outputDirectory;
+
+ /**
+ * Directory where the original site is present.
+ * (TRIED using ${baseDir}/src/site; that inserted a 'null' into
+ * the string for some reason. TRIED using ${siteDirectory},
+ * which was undefined. TRIED ${project.directory}src/site; which also
+ * inserted a null. ${project.build.directory}/../src/site seems to work,
+ * though it assumes that ${project.build.directory} is
+ * ${project.directory}/target.
+ *
+ * @parameter default-value="${project.build.directory}/../src/site/"
+ * @required
+ */
+ private File siteDirectory;
+
+ /**
+ * @parameter expression="${project}"
+ * @required
+ * @readonly
+ */
+ private MavenProject project;
+
+ /**
+ * @parameter
+ */
+ private Map taglibs;
+
+ /**
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
+ * @readonly
+ */
+ private File buildDirectory;
+
+ /**
+ * Injected name of file generated by earlier run of BuildMetaDataMojo goal.
+ *
+ * @parameter
+ */
+ private String metadataFile = "META-INF/myfaces-metadata.xml";
+
+ /**
+ * @parameter expression="src/main/resources/META-INF"
+ */
+ private File templateSourceDirectory;
+
+ /**
+ * @parameter expression="src/main/tagdoc"
+ */
+ private File baseFilesSourceDirectory;
+
+ /**
+ * @parameter
+ */
+ private List modelIds;
+
+ /**
+ * @parameter expression="xdoc-component.vm"
+ */
+ private String templateComponent;
+
+ /**
+ * @parameter expression="xdoc-converter.vm"
+ */
+ private String templateConverter;
+
+ /**
+ * @parameter expression="xdoc-validator.vm"
+ */
+ private String templateValidator;
+
+ /**
+ * @parameter expression="xdoc-tag.vm"
+ */
+ private String templateTag;
+
+ static private final String _DOC_SUBDIRECTORY = "tagdoc";
+
+ public void execute() throws MojoExecutionException, MojoFailureException
+ {
+ if (modelIds == null){
+ modelIds = new ArrayList();
+ modelIds.add(project.getArtifactId());
+ }
+
+ if (taglibs == null)
+ {
+ taglibs = new HashMap();
+ taglibs.put("t", "http://myfaces.apache.org/tomahawk");
+ }
+
+ try
+ {
+ _model = IOUtils.loadModel(new File(buildDirectory,
+ metadataFile));
+ new Flattener(_model).flatten();
+ _generateTagDocs();
+ }
+ catch (Exception e)
+ {
+ throw new MojoExecutionException("Couldn't generate tagdoc", e);
+ }
+ }
+
+ public boolean canGenerate(ClassMeta component)
+ {
+ if ( modelIds.contains(component.getModelId()))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public class CustomResourceManagerImpl extends ResourceManagerImpl{
+
+ public CustomResourceManagerImpl()
+ {
+ super();
+ }
+
+ }
+
+ private VelocityEngine initVelocity() throws MojoExecutionException
+ {
+ Properties p = new Properties();
+ p.setProperty( "resource.loader", "file, class" );
+ p.setProperty( "file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+ p.setProperty( "file.resource.loader.path", templateSourceDirectory.getPath());
+ p.setProperty( "class.resource.loader.class", "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.RelativeClasspathResourceLoader" );
+ p.setProperty( "class.resource.loader.path", "META-INF");
+ p.setProperty( "velocimacro.library", "componentClassMacros11.vm");
+ p.setProperty( "velocimacro.permissions.allow.inline","true");
+ p.setProperty( "velocimacro.permissions.allow.inline.local.scope", "true");
+ p.setProperty( "directive.foreach.counter.initial.value","0");
+ p.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+ "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.ConsoleLogSystem" );
+
+ VelocityEngine velocityEngine = new VelocityEngine();
+
+ try
+ {
+ velocityEngine.init(p);
+ }
+ catch (Exception e)
+ {
+ throw new MojoExecutionException("Error creating VelocityEngine", e);
+ }
+
+ return velocityEngine;
+
+ }
+
+ private void _generateTagDocs() throws Exception
+ {
+ Model model = getModel();
+ if (model.getComponents().size() == 0)
+ {
+ getLog().info("Nothing to generate - no components found");
+ return;
+ }
+
+ VelocityEngine velocityEngine = initVelocity();
+
+ VelocityContext baseContext = new VelocityContext();
+ baseContext.put("utils", new MyfacesUtils());
+ baseContext.put("tagdocUtils", new TagdocUtils());
+ baseContext.put("model",getModel());
+
+ Iterator components = model.components();
+
+ Iterator validators = model.validators();
+
+ Iterator converters = model.converters();
+
+ Iterator tags = model.tags();
+
+ Set componentPages = new TreeSet();
+ Set converterPages = new TreeSet();
+ Set validatorPages = new TreeSet();
+ Set tagsPages = new TreeSet();
+
+ int count = 0;
+ while (components.hasNext())
+ {
+ ComponentMeta component = (ComponentMeta) components.next();
+ if (canGenerate(component)){
+ String pageName = _generateComponentDoc(velocityEngine,baseContext,component);
+ if (pageName != null)
+ {
+ componentPages.add(pageName);
+ count++;
+ }
+ }
+ }
+ while (converters.hasNext())
+ {
+ ConverterMeta converter = (ConverterMeta) converters.next();
+ if (canGenerate(converter)){
+ String pageName = _generateConverterDoc(velocityEngine,baseContext,converter);
+ if (pageName != null)
+ {
+ converterPages.add(pageName);
+ count++;
+ }
+ }
+ }
+ while (validators.hasNext())
+ {
+ ValidatorMeta validator = (ValidatorMeta) validators.next();
+
+ if (canGenerate(validator)){
+ String pageName = _generateValidatorDoc(velocityEngine,baseContext,validator);
+ if (pageName != null)
+ {
+ validatorPages.add(pageName);
+ count++;
+ }
+ }
+ }
+ while (tags.hasNext())
+ {
+ TagMeta tag = (TagMeta) tags.next();
+
+ if (canGenerate(tag)){
+ String pageName = _generateTagDoc(velocityEngine,baseContext,tag);
+ if (pageName != null)
+ {
+ tagsPages.add(pageName);
+ count++;
+ }
+ }
+ }
+
+ Set otherPages = _gatherOtherTags();
+
+ getLog().info("Generated " + count + " page(s)");
+ }
+
+ private Set _gatherOtherTags()
+ {
+ TreeSet set = new TreeSet();
+ String subDir = _platformAgnosticPath(_platformAgnosticPath("xdoc/"
+ + _DOC_SUBDIRECTORY));
+ File siteSubDir = new File(siteDirectory, subDir);
+ if (siteSubDir.exists())
+ {
+ String[] files = siteSubDir.list();
+ for (int i = 0; i < files.length; i++)
+ {
+ String file = files[i];
+ if (file.endsWith(".xml"))
+ {
+ set.add(file.substring(0, file.length() - 4));
+ }
+ }
+ }
+
+ return set;
+ }
+
+ public boolean usePageLinkBar()
+ {
+ return false;
+ }
+
+ private String _toPageName(String qName)
+ {
+ return MyfacesUtils.getTagPrefix(qName) + "_" + MyfacesUtils.getTagName(qName);
+ }
+
+ private String _generateComponentDoc(VelocityEngine velocityEngine,
+ VelocityContext baseContext, ComponentMeta component)
+ throws Exception
+ {
+ if (component.getName() == null)
+ {
+ return null;
+ }
+ String pageName = _toPageName(component.getName());
+
+ Context context = new VelocityContext(baseContext);
+ context.put("component", component);
+
+ String baseContent = "";
+
+ File xmlBaseFile = new File(baseFilesSourceDirectory,
+ _platformAgnosticPath(pageName + "-base.xml"));
+
+ if (xmlBaseFile != null && xmlBaseFile.exists())
+ {
+ if (getLog().isDebugEnabled())
+ {
+ getLog().debug("using base content file: "+xmlBaseFile.getPath());
+ }
+
+ Reader reader = null;
+ try
+ {
+ reader = new FileReader(xmlBaseFile);
+ Xpp3Dom root = Xpp3DomBuilder.build(reader);
+
+ StringWriter writer = new StringWriter();
+
+ Xpp3Dom [] children = root.getChild("body").getChildren();
+
+ for (int i = 0; i< children.length; i++)
+ {
+ Xpp3Dom dom = children[i];
+ Xpp3DomWriter.write(writer, dom);
+ }
+ baseContent = writer.toString();
+ writer.close();
+ }
+ catch (XmlPullParserException e)
+ {
+ throw new MojoExecutionException(
+ "Error parsing base file: " + e.getMessage(), e);
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+
+ baseContext.put("baseContent", baseContent);
+
+ Writer out = null;
+
+ try
+ {
+ File targetDir = new File(outputDirectory.getParentFile(),
+ _platformAgnosticPath("generated-site/xdoc/"
+ + _DOC_SUBDIRECTORY));
+
+ if ( !targetDir.exists() )
+ {
+ targetDir.mkdirs();
+ }
+ File targetFile = new File(targetDir, pageName + ".xml");
+
+ out = new OutputStreamWriter(new FileOutputStream(targetFile),
+ "UTF-8");
+
+ Template template = velocityEngine.getTemplate(getTemplateComponent());
+
+ template.merge(context, out);
+
+ out.flush();
+ }
+ catch (Exception e)
+ {
+ throw new MojoExecutionException(
+ "Error merging velocity templates: " + e.getMessage(), e);
+ }
+ finally
+ {
+ IOUtil.close(out);
+ out = null;
+ }
+
+ return pageName;
+ }
+
+ private String _generateConverterDoc(VelocityEngine velocityEngine,
+ VelocityContext baseContext, ConverterMeta converter)
+ throws Exception
+ {
+ if (converter.getName() == null)
+ {
+ return null;
+ }
+
+ String pageName = _toPageName(converter.getName());
+
+ Context context = new VelocityContext(baseContext);
+ context.put("converter", converter);
+
+ String baseContent = "";
+
+ File xmlBaseFile = new File(baseFilesSourceDirectory,
+ _platformAgnosticPath(pageName + "-base.xml"));
+
+ if (xmlBaseFile != null && xmlBaseFile.exists())
+ {
+ if (getLog().isDebugEnabled())
+ {
+ getLog().debug("using base content file: "+xmlBaseFile.getPath());
+ }
+
+ Reader reader = null;
+ try
+ {
+ reader = new FileReader(xmlBaseFile);
+ Xpp3Dom root = Xpp3DomBuilder.build(reader);
+
+ StringWriter writer = new StringWriter();
+
+ Xpp3Dom [] children = root.getChild("body").getChildren();
+
+ for (int i = 0; i< children.length; i++)
+ {
+ Xpp3Dom dom = children[i];
+ Xpp3DomWriter.write(writer, dom);
+ }
+ baseContent = writer.toString();
+ writer.close();
+ }
+ catch (XmlPullParserException e)
+ {
+ throw new MojoExecutionException(
+ "Error parsing base file: " + e.getMessage(), e);
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+
+ baseContext.put("baseContent", baseContent);
+
+ Writer out = null;
+
+ try
+ {
+ File targetDir = new File(outputDirectory.getParentFile(),
+ _platformAgnosticPath("generated-site/xdoc/"
+ + _DOC_SUBDIRECTORY));
+
+ if ( !targetDir.exists() )
+ {
+ targetDir.mkdirs();
+ }
+ File targetFile = new File(targetDir, pageName + ".xml");
+
+ out = new OutputStreamWriter(new FileOutputStream(targetFile),
+ "UTF-8");
+
+ Template template = velocityEngine.getTemplate(getTemplateConverter());
+
+ template.merge(context, out);
+
+ out.flush();
+ }
+ catch (Exception e)
+ {
+ throw new MojoExecutionException(
+ "Error merging velocity templates: " + e.getMessage(), e);
+ }
+ finally
+ {
+ IOUtil.close(out);
+ out = null;
+ }
+
+ return pageName;
+ }
+
+ private String _generateValidatorDoc(VelocityEngine velocityEngine,
+ VelocityContext baseContext, ValidatorMeta validator)
+ throws Exception
+ {
+ if (validator.getName() == null)
+ {
+ return null;
+ }
+
+ String pageName = _toPageName(validator.getName());
+
+ Context context = new VelocityContext(baseContext);
+ context.put("validator", validator);
+
+ String baseContent = "";
+
+ File xmlBaseFile = new File(baseFilesSourceDirectory,
+ _platformAgnosticPath(pageName + "-base.xml"));
+
+ if (xmlBaseFile != null && xmlBaseFile.exists())
+ {
+ if (getLog().isDebugEnabled())
+ {
+ getLog().debug("using base content file: "+xmlBaseFile.getPath());
+ }
+
+ Reader reader = null;
+ try
+ {
+ reader = new FileReader(xmlBaseFile);
+ Xpp3Dom root = Xpp3DomBuilder.build(reader);
+
+ StringWriter writer = new StringWriter();
+
+ Xpp3Dom [] children = root.getChild("body").getChildren();
+
+ for (int i = 0; i< children.length; i++)
+ {
+ Xpp3Dom dom = children[i];
+ Xpp3DomWriter.write(writer, dom);
+ }
+ baseContent = writer.toString();
+ writer.close();
+ }
+ catch (XmlPullParserException e)
+ {
+ throw new MojoExecutionException(
+ "Error parsing base file: " + e.getMessage(), e);
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+
+ baseContext.put("baseContent", baseContent);
+
+ Writer out = null;
+
+ try
+ {
+ File targetDir = new File(outputDirectory.getParentFile(),
+ _platformAgnosticPath("generated-site/xdoc/"
+ + _DOC_SUBDIRECTORY));
+
+ if ( !targetDir.exists() )
+ {
+ targetDir.mkdirs();
+ }
+ File targetFile = new File(targetDir, pageName + ".xml");
+
+ out = new OutputStreamWriter(new FileOutputStream(targetFile),
+ "UTF-8");
+
+ Template template = velocityEngine.getTemplate(getTemplateValidator());
+
+ template.merge(context, out);
+
+ out.flush();
+ }
+ catch (Exception e)
+ {
+ throw new MojoExecutionException(
+ "Error merging velocity templates: " + e.getMessage(), e);
+ }
+ finally
+ {
+ IOUtil.close(out);
+ out = null;
+ }
+
+ return pageName;
+ }
+
+ private String _generateTagDoc(VelocityEngine velocityEngine,
+ VelocityContext baseContext, TagMeta tag)
+ throws Exception
+ {
+ if (tag.getName() == null)
+ {
+ return null;
+ }
+
+ String pageName = _toPageName(tag.getName());
+
+ Context context = new VelocityContext(baseContext);
+ context.put("tag", tag);
+
+ String baseContent = "";
+
+ File xmlBaseFile = new File(baseFilesSourceDirectory,
+ _platformAgnosticPath(pageName + "-base.xml"));
+
+ if (xmlBaseFile != null && xmlBaseFile.exists())
+ {
+ if (getLog().isDebugEnabled())
+ {
+ getLog().debug("using base content file: "+xmlBaseFile.getPath());
+ }
+
+ Reader reader = null;
+ try
+ {
+ reader = new FileReader(xmlBaseFile);
+ Xpp3Dom root = Xpp3DomBuilder.build(reader);
+
+ StringWriter writer = new StringWriter();
+
+ Xpp3Dom [] children = root.getChild("body").getChildren();
+
+ for (int i = 0; i< children.length; i++)
+ {
+ Xpp3Dom dom = children[i];
+ Xpp3DomWriter.write(writer, dom);
+ }
+ baseContent = writer.toString();
+ writer.close();
+ }
+ catch (XmlPullParserException e)
+ {
+ throw new MojoExecutionException(
+ "Error parsing base file: " + e.getMessage(), e);
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+
+ baseContext.put("baseContent", baseContent);
+
+ Writer out = null;
+
+ try
+ {
+ File targetDir = new File(outputDirectory.getParentFile(),
+ _platformAgnosticPath("generated-site/xdoc/"
+ + _DOC_SUBDIRECTORY));
+
+ if ( !targetDir.exists() )
+ {
+ targetDir.mkdirs();
+ }
+ File targetFile = new File(targetDir, pageName + ".xml");
+
+ out = new OutputStreamWriter(new FileOutputStream(targetFile),
+ "UTF-8");
+
+ Template template = velocityEngine.getTemplate(getTemplateTag());
+
+ template.merge(context, out);
+
+ out.flush();
+ }
+ catch (Exception e)
+ {
+ throw new MojoExecutionException(
+ "Error merging velocity templates: " + e.getMessage(), e);
+ }
+ finally
+ {
+ IOUtil.close(out);
+ out = null;
+ }
+
+ return pageName;
+ }
+
+
+ static private final String _platformAgnosticPath(String path)
+ {
+ return path.replace('/', File.separatorChar);
+ }
+
+ protected MavenProject getProject()
+ {
+ return project;
+ }
+
+ protected String getOutputDirectory()
+ {
+ return outputDirectory.getAbsolutePath();
+ }
+
+ public String getName(Locale locale)
+ {
+ return "JSF Tag Documentation";
+ }
+
+ public String getDescription(Locale locale)
+ {
+ return "Documentation for JSF Tags";
+ }
+
+ public String getOutputName()
+ {
+ return "tagdoc";
+ }
+
+ protected Model getModel()
+ {
+ return _model;
+ }
+
+ protected List getMasterConfigs(MavenProject project)
+ throws MavenReportException
+ {
+ String resourcePath = "META-INF/maven-faces-plugin/faces-config.xml";
+ return getCompileDependencyResources(project, resourcePath);
+ }
+
+ protected List getCompileDependencyResources(MavenProject project,
+ String resourcePath) throws MavenReportException
+ {
+ try
+ {
+ ClassLoader cl = createCompileClassLoader(project);
+ Enumeration e = cl.getResources(resourcePath);
+ List urls = new ArrayList();
+ while (e.hasMoreElements())
+ {
+ URL url = (URL) e.nextElement();
+ urls.add(url);
+ }
+ return Collections.unmodifiableList(urls);
+ }
+ catch (IOException e)
+ {
+ throw new MavenReportException("Unable to get resources for path "
+ + "\"" + resourcePath + "\"", e);
+ }
+
+ }
+
+ private ClassLoader createCompileClassLoader(MavenProject project)
+ throws MavenReportException
+ {
+ Thread current = Thread.currentThread();
+ ClassLoader cl = current.getContextClassLoader();
+
+ try
+ {
+ List classpathElements = project.getCompileClasspathElements();
+ if (!classpathElements.isEmpty())
+ {
+ String[] entries = (String[]) classpathElements
+ .toArray(new String[0]);
+ URL[] urls = new URL[entries.length];
+ for (int i = 0; i < urls.length; i++)
+ {
+ urls[i] = new File(entries[i]).toURL();
+ }
+ cl = new URLClassLoader(urls, cl);
+ }
+ }
+ catch (DependencyResolutionRequiredException e)
+ {
+ throw new MavenReportException("Error calculating scope classpath",
+ e);
+ }
+ catch (MalformedURLException e)
+ {
+ throw new MavenReportException("Error calculating scope classpath",
+ e);
+ }
+
+ return cl;
+ }
+
+ static public class URLCreationFactory extends
+ AbstractObjectCreationFactory
+ {
+ public Object createObject(Attributes attributes)
+ throws MalformedURLException
+ {
+ String href = attributes.getValue("href");
+ if (href == null)
+ throw new IllegalStateException("Missing href attribute");
+
+ URL master = (URL) digester.getRoot();
+ return new URL(master, href);
+ }
+ }
+
+ public String getTemplateComponent()
+ {
+ return templateComponent;
+ }
+
+ public String getTemplateConverter()
+ {
+ return templateConverter;
+ }
+
+ public String getTemplateValidator()
+ {
+ return templateValidator;
+ }
+
+ public String getTemplateTag()
+ {
+ return templateTag;
+ }
+
+}
Propchange: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java
URL: http://svn.apache.org/viewvc/myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java?rev=672983&view=auto
==============================================================================
--- myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java (added)
+++ myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java Mon Jun 30 21:10:57 2008
@@ -0,0 +1,475 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.buildtools.maven2.plugin.tagdoc;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Logger;
+
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.AbstractMavenReport;
+import org.apache.maven.reporting.MavenReportException;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.Flattener;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.IOUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ClassMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.TagMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils;
+import org.apache.velocity.runtime.resource.ResourceManagerImpl;
+import org.codehaus.doxia.sink.Sink;
+import org.codehaus.doxia.site.renderer.SiteRenderer;
+
+/**
+ * Report for generating JSF tagdoc index based on myfaces-metadata.xml parsing.
+ * The content is generated using velocity in xdoc files (see TagdocContentMojo).
+ *
+ * @author Leonardo Uribe
+ * @goal tagdoc-index
+ */
+public class TagdocIndexReport extends AbstractMavenReport
+{
+ final Logger log = Logger.getLogger(TagdocIndexReport.class.getName());
+
+ private Model _model;
+
+ /**
+ * Specifies the directory where the report will be generated
+ *
+ * @parameter default-value="${project.reporting.outputDirectory}"
+ * @required
+ */
+ private File outputDirectory;
+
+ /**
+ * Directory where the original site is present.
+ * (TRIED using ${baseDir}/src/site; that inserted a 'null' into
+ * the string for some reason. TRIED using ${siteDirectory},
+ * which was undefined. TRIED ${project.directory}src/site; which also
+ * inserted a null. ${project.build.directory}/../src/site seems to work,
+ * though it assumes that ${project.build.directory} is
+ * ${project.directory}/target.
+ *
+ * @parameter default-value="${project.build.directory}/../src/site/"
+ * @required
+ */
+ private File siteDirectory;
+
+ /**
+ * @parameter expression="${project}"
+ * @required
+ * @readonly
+ */
+ private MavenProject project;
+
+ /**
+ * @component
+ * @required
+ * @readonly
+ */
+ private SiteRenderer siteRenderer;
+
+ /**
+ * @parameter
+ */
+ private Map taglibs;
+
+ /**
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
+ * @readonly
+ */
+ private File buildDirectory;
+
+ /**
+ * Injected name of file generated by earlier run of BuildMetaDataMojo goal.
+ *
+ * @parameter
+ */
+ private String metadataFile = "META-INF/myfaces-metadata.xml";
+
+ /**
+ * @parameter
+ */
+ private List modelIds;
+
+ /**
+ * component role="org.codehaus.plexus.velocity.VelocityComponent" roleHint="tagdoc"
+ */
+ //private VelocityComponent velocityComponent;
+ static private final String _DOC_SUBDIRECTORY = "tagdoc";
+
+ protected void executeReport(Locale locale) throws MavenReportException
+ {
+
+ if (modelIds == null)
+ {
+ modelIds = new ArrayList();
+ modelIds.add(project.getArtifactId());
+ }
+
+ if (taglibs == null)
+ {
+ taglibs = new HashMap();
+ taglibs.put("t", "http://myfaces.apache.org/tomahawk");
+ }
+
+ try
+ {
+ _model = IOUtils.loadModel(new File(buildDirectory, metadataFile));
+ new Flattener(_model).flatten();
+ _generateTagDocs();
+ }
+ catch (Exception e)
+ {
+ throw new MavenReportException("Couldn't generate tagdoc", e);
+ }
+ }
+
+ public boolean canGenerate(ClassMeta component)
+ {
+ if (modelIds.contains(component.getModelId()))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public class CustomResourceManagerImpl extends ResourceManagerImpl
+ {
+
+ public CustomResourceManagerImpl()
+ {
+ super();
+ }
+
+ }
+
+ private void _generateTagDocs() throws Exception
+ {
+ Model model = getModel();
+ if (model.getComponents().size() == 0)
+ {
+ getLog().info("Nothing to generate - no components found");
+ return;
+ }
+
+ Iterator components = model.components();
+
+ Iterator validators = model.validators();
+
+ Iterator converters = model.converters();
+
+ Iterator tags = model.tags();
+
+ // =-=AEW Note that only updating out-of-date components, etc. is
+ // permanently tricky, even if we had proper detection in place,
+ // because the index always has to have all docs
+ /*
+ if (!components.hasNext() && !converters.hasNext() && !validators.hasNext())
+ {
+ getLog().info("Nothing to generate - all docs are up to date");
+ return;
+ }
+ */
+
+ Set componentPages = new TreeSet();
+ Set converterPages = new TreeSet();
+ Set validatorPages = new TreeSet();
+ Set tagsPages = new TreeSet();
+
+ int count = 0;
+ while (components.hasNext())
+ {
+ ComponentMeta component = (ComponentMeta) components.next();
+ if (canGenerate(component))
+ {
+ String pageName = _generateComponentDoc(component);
+ if (pageName != null)
+ {
+ componentPages.add(pageName);
+ count++;
+ }
+ }
+ }
+ while (converters.hasNext())
+ {
+ ConverterMeta converter = (ConverterMeta) converters.next();
+ if (canGenerate(converter))
+ {
+ String pageName = _generateConverterDoc(converter);
+ if (pageName != null)
+ {
+ converterPages.add(pageName);
+ count++;
+ }
+ }
+ }
+ while (validators.hasNext())
+ {
+ ValidatorMeta validator = (ValidatorMeta) validators.next();
+
+ if (canGenerate(validator))
+ {
+ String pageName = _generateValidatorDoc(validator);
+ if (pageName != null)
+ {
+ validatorPages.add(pageName);
+ count++;
+ }
+ }
+ }
+ while (tags.hasNext())
+ {
+ TagMeta tag = (TagMeta) tags.next();
+
+ if (canGenerate(tag)){
+ String pageName = _generateTagDoc(tag);
+ if (pageName != null)
+ {
+ tagsPages.add(pageName);
+ count++;
+ }
+ }
+ }
+
+ Set otherPages = _gatherOtherTags();
+
+ getLog().info("Generated " + count + " page(s)");
+
+ Sink sink = getSink();
+ sink.head();
+ sink.title();
+ sink.text("Tag library documentation");
+ sink.title_();
+ sink.head_();
+ sink.body();
+
+ sink.sectionTitle1();
+ sink.text("Tag library information");
+ sink.sectionTitle1_();
+ sink.section1();
+
+ for (Iterator i = taglibs.entrySet().iterator(); i.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ sink.paragraph();
+
+ sink.bold();
+ sink.text("Short name:");
+ sink.bold_();
+ sink.nonBreakingSpace();
+ sink.text(entry.getKey().toString());
+ sink.lineBreak();
+
+ sink.bold();
+ sink.text("Namespace:");
+ sink.bold_();
+ sink.nonBreakingSpace();
+ sink.text(entry.getValue().toString());
+ sink.lineBreak();
+
+ sink.paragraph_();
+ }
+
+ sink.section1_();
+
+ _writeIndexSection(sink, componentPages, "Components");
+ _writeIndexSection(sink, converterPages, "Converters");
+ _writeIndexSection(sink, validatorPages, "Validators");
+ _writeIndexSection(sink, tagsPages, "JSF Tags");
+ _writeIndexSection(sink, otherPages, "Miscellaneous");
+
+ sink.body_();
+ }
+
+ private Set _gatherOtherTags()
+ {
+ TreeSet set = new TreeSet();
+ String subDir = _platformAgnosticPath(_platformAgnosticPath("xdoc/"
+ + _DOC_SUBDIRECTORY));
+ File siteSubDir = new File(siteDirectory, subDir);
+ if (siteSubDir.exists())
+ {
+ String[] files = siteSubDir.list();
+ for (int i = 0; i < files.length; i++)
+ {
+ String file = files[i];
+ if (file.endsWith(".xml"))
+ {
+ set.add(file.substring(0, file.length() - 4));
+ }
+ }
+ }
+
+ return set;
+ }
+
+ private void _writeIndexSection(Sink sink, Set pages, String title)
+ {
+ if (pages.isEmpty())
+ return;
+
+ sink.sectionTitle1();
+ sink.text(title);
+ sink.sectionTitle1_();
+ sink.section1();
+ sink.table();
+ sink.tableRow();
+ sink.tableHeaderCell();
+ sink.text("Tag Name");
+ sink.tableHeaderCell_();
+ sink.tableRow_();
+
+ Iterator iter = pages.iterator();
+ while (iter.hasNext())
+ {
+ sink.tableRow();
+ sink.tableCell();
+
+ String name = (String) iter.next();
+ String tagName = "<" + name.replace('_', ':') + ">";
+
+ sink.link(_DOC_SUBDIRECTORY + "/" + name + ".html");
+ sink.text(tagName);
+ sink.link_();
+
+ sink.tableCell_();
+ sink.tableRow_();
+ }
+
+ sink.table_();
+ sink.section1_();
+ }
+
+ public boolean usePageLinkBar()
+ {
+ return false;
+ }
+
+ private String _toPageName(String qName)
+ {
+ return MyfacesUtils.getTagPrefix(qName) + "_"
+ + MyfacesUtils.getTagName(qName);
+ }
+
+ private String _generateComponentDoc(ComponentMeta component)
+ throws Exception
+ {
+ if (component.getName() == null)
+ {
+ return null;
+ }
+ String pageName = _toPageName(component.getName());
+
+ return pageName;
+ }
+
+ private String _generateConverterDoc(ConverterMeta converter)
+ throws IOException
+ {
+ if (converter.getName() == null)
+ {
+ return null;
+ }
+
+ String pageName = _toPageName(converter.getName());
+
+ return pageName;
+ }
+
+ private String _generateValidatorDoc(ValidatorMeta validator)
+ throws IOException
+ {
+ if (validator.getName() == null)
+ {
+ return null;
+ }
+
+ String pageName = _toPageName(validator.getName());
+
+ return pageName;
+ }
+
+ private String _generateTagDoc(TagMeta tag)
+ throws IOException
+ {
+ if (tag.getName() == null)
+ {
+ return null;
+ }
+
+ String pageName = _toPageName(tag.getName());
+
+ return pageName;
+ }
+
+ static private final String _platformAgnosticPath(String path)
+ {
+ return path.replace('/', File.separatorChar);
+ }
+
+ protected MavenProject getProject()
+ {
+ return project;
+ }
+
+ protected String getOutputDirectory()
+ {
+ return outputDirectory.getAbsolutePath();
+ }
+
+ protected SiteRenderer getSiteRenderer()
+ {
+ return siteRenderer;
+ }
+
+ public String getName(Locale locale)
+ {
+ return "JSF Tag Documentation";
+ }
+
+ public String getDescription(Locale locale)
+ {
+ return "Documentation for JSF Tags";
+ }
+
+ public String getOutputName()
+ {
+ return "tagdoc";
+ }
+
+ protected Model getModel()
+ {
+ return _model;
+ }
+
+}
\ No newline at end of file
Propchange: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java
URL: http://svn.apache.org/viewvc/myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java?rev=672983&view=auto
==============================================================================
--- myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java (added)
+++ myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java Mon Jun 30 21:10:57 2008
@@ -0,0 +1,138 @@
+package org.apache.myfaces.buildtools.maven2.plugin.tagdoc;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.AttributeHolder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.AttributeMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.FacetHolder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.FacetMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyHolder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.RenderKitMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.RendererMeta;
+
+public class TagdocUtils
+{
+
+ static public final String platformAgnosticPath(String path)
+ {
+ return path.replace('/', File.separatorChar);
+ }
+
+ static public String getDisplayType(String className, String name,
+ String type)
+ {
+ if (type.startsWith("java.lang."))
+ {
+ return type.substring("java.lang.".length());
+ }
+ else if ("binding".equals(name))
+ {
+ StringTokenizer tokens = new StringTokenizer(className, ".", true);
+ String out = "";
+ while (tokens.hasMoreTokens())
+ {
+ String token = tokens.nextToken();
+ out = out + token;
+ // Give ourselves an opportunity for a line break after "component.";
+ if (out.endsWith("component."))
+ out = out + "<wbr/>";
+ }
+
+ return out;
+ }
+
+ return type;
+ }
+
+ static public List getSortedPropertyList(PropertyHolder component)
+ {
+ // Sort the names
+ TreeSet attributes = new TreeSet();
+ Iterator attrs = component.properties();
+ while (attrs.hasNext())
+ {
+ PropertyMeta property = (PropertyMeta) attrs.next();
+ if (!property.isTagExcluded().booleanValue()){
+ attributes.add(property.getName());
+ }
+ }
+
+ // Now get a list of PropertyMetas
+ List list = new ArrayList();
+ Iterator iter = attributes.iterator();
+ while (iter.hasNext())
+ {
+ String attrName = (String) iter.next();
+ list.add(component.getProperty(attrName));
+ }
+ return list;
+ }
+
+ static public List getSortedFacetList(FacetHolder component)
+ {
+ TreeSet facetNames = new TreeSet();
+ Iterator iter = component.facets();
+ while (iter.hasNext())
+ {
+ facetNames.add(((FacetMeta) iter.next()).getName());
+ }
+
+ // Now get a list of PropertyMetas
+ List list = new ArrayList();
+ Iterator nameIter = facetNames.iterator();
+ while (nameIter.hasNext())
+ {
+ String name = (String) nameIter.next();
+ list.add(component.getFacet(name));
+ }
+ return list;
+ }
+
+ static public List getSortedAttributeList(AttributeHolder component)
+ {
+ // Sort the names
+ TreeSet attributes = new TreeSet();
+ Iterator attrs = component.attributes();
+ while (attrs.hasNext())
+ {
+ AttributeMeta attribute = (AttributeMeta) attrs.next();
+ attributes.add(attribute.getName());
+ }
+
+ // Now get a list of PropertyMetas
+ List list = new ArrayList();
+ Iterator iter = attributes.iterator();
+ while (iter.hasNext())
+ {
+ String attrName = (String) iter.next();
+ list.add(component.getAttribute(attrName));
+ }
+ return list;
+ }
+
+ static public Map getRendererClasses(ComponentMeta component, Model model)
+ {
+ Map componentRenderers = new HashMap();
+ List renderKits = model.getRenderKits();
+ if (renderKits != null){
+ for (Iterator it = renderKits.iterator();it.hasNext();)
+ {
+ RenderKitMeta renderkit = (RenderKitMeta) it.next();
+ RendererMeta renderer = renderkit.findRenderer(component.getFamily(), component.getRendererType());
+ if (renderer != null)
+ componentRenderers.put(renderkit.getRenderKitId(), renderer.getClassName());
+ }
+ }
+ return componentRenderers;
+ }
+}
Propchange: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL