click-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sa...@apache.org
Subject svn commit: r795360 - in /incubator/click/trunk/tools/standalone: ./ dev-tasks/src/ dev-tasks/src/org/apache/click/tools/deploy/
Date Sat, 18 Jul 2009 13:11:42 GMT
Author: sabob
Date: Sat Jul 18 13:11:42 2009
New Revision: 795360

URL: http://svn.apache.org/viewvc?rev=795360&view=rev
Log:
added ant deploy task

Added:
    incubator/click/trunk/tools/standalone/CHANGELOG.txt   (with props)
    incubator/click/trunk/tools/standalone/README.txt
      - copied, changed from r728294, incubator/click/trunk/tools/standalone/readme.text
    incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/
    incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/Deploy.java
    incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReport.java
    incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReportEntry.java
    incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployTask.java
    incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/TaskUtils.java
    incubator/click/trunk/tools/standalone/dev-tasks/src/report-template.html   (with props)
Removed:
    incubator/click/trunk/tools/standalone/readme.text
Modified:
    incubator/click/trunk/tools/standalone/NOTICE.txt
    incubator/click/trunk/tools/standalone/build.xml

Added: incubator/click/trunk/tools/standalone/CHANGELOG.txt
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/CHANGELOG.txt?rev=795360&view=auto
==============================================================================
--- incubator/click/trunk/tools/standalone/CHANGELOG.txt (added)
+++ incubator/click/trunk/tools/standalone/CHANGELOG.txt Sat Jul 18 13:11:42 2009
@@ -0,0 +1,13 @@
+Changelog
+=========
+
+Version 1.1 - 2009-08-15
+------------------------
+
+* Added DeployTask to deploy static resources during build time.
+  [https://issues.apache.org/jira/browse/CLK-564]
+
+Version 1.0 - 2009-02-15
+------------------------
+
+* Initial release

Propchange: incubator/click/trunk/tools/standalone/CHANGELOG.txt
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/click/trunk/tools/standalone/NOTICE.txt
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/NOTICE.txt?rev=795360&r1=795359&r2=795360&view=diff
==============================================================================
--- incubator/click/trunk/tools/standalone/NOTICE.txt (original)
+++ incubator/click/trunk/tools/standalone/NOTICE.txt Sat Jul 18 13:11:42 2009
@@ -1,5 +1,5 @@
 Apache Click
-Copyright 2008 The Apache Software Foundation
+Copyright 2008-2009 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).

Copied: incubator/click/trunk/tools/standalone/README.txt (from r728294, incubator/click/trunk/tools/standalone/readme.text)
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/README.txt?p2=incubator/click/trunk/tools/standalone/README.txt&p1=incubator/click/trunk/tools/standalone/readme.text&r1=728294&r2=795360&rev=795360&view=diff
==============================================================================
--- incubator/click/trunk/tools/standalone/readme.text (original)
+++ incubator/click/trunk/tools/standalone/README.txt Sat Jul 18 13:11:42 2009
@@ -1,6 +1,10 @@
 Standalone Tools for the Click Framework
 ========================================
 
-* dev-tasks - a set of ANT tasks to help in the development of Click Framework
-  itself, Click based 3rd party controls and Click based webapplications.
+This project contains the following packages:
+
+* deploy - provides an Ant task to deploy Click resources from a given source
+  folder to a target folder.
 
+* devtasks - a set of ANT tasks to help in the development of Click Framework
+  itself, Click based 3rd party controls and Click based webapplications.

Modified: incubator/click/trunk/tools/standalone/build.xml
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/build.xml?rev=795360&r1=795359&r2=795360&view=diff
==============================================================================
--- incubator/click/trunk/tools/standalone/build.xml (original)
+++ incubator/click/trunk/tools/standalone/build.xml Sat Jul 18 13:11:42 2009
@@ -3,7 +3,7 @@
     <!--
     Project Properties
     -->
-    <property name="version" value="1.0"/>
+    <property name="version" value="1.1"/>
 
     <!--
     Path Definitions
@@ -23,6 +23,7 @@
         </copy>
  	      <copy file="LICENSE.txt" todir="dev-tasks/classes/META-INF"/>
  	      <copy file="NOTICE.txt" todir="dev-tasks/classes/META-INF"/>
+        <copy file="README.txt" todir="dev-tasks/classes/META-INF"/>
 
         <!-- 1. Compile the tasks -->
         <javac srcdir="dev-tasks/src"
@@ -30,7 +31,7 @@
                debug="true"
                excludes="**/Test*"
                encoding="ISO-8859-1"
-               source="1.4">
+               source="1.5">
             <classpath refid="classpath.dev-tasks"/>
         </javac>
 

Added: incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/Deploy.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/Deploy.java?rev=795360&view=auto
==============================================================================
--- incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/Deploy.java (added)
+++ incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/Deploy.java Sat Jul 18 13:11:42 2009
@@ -0,0 +1,364 @@
+/*
+ * 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.click.tools.deploy;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Provides resourceName deployment operations to copying resources from a source
+ * jar/folder to a target folder.
+ * <p/>
+ * This class also tracks which resources were deployed, skipped or outdated.
+ * This information can then be used to write a summary report of the resources.
+ */
+class Deploy {
+
+    // -------------------------------------------------------------- Variables
+
+    /** The outdated report entries. */
+    private List<DeployReportEntry> outdated = new ArrayList();
+
+    /** The deployed report entries. */
+    private List<DeployReportEntry> deployed = new ArrayList();
+
+    // ------------------------------------------------------ Public Properties
+
+    /**
+     * Return the outdated report entries.
+     *
+     * @return the outdated report entries.
+     */
+    public List<DeployReportEntry> getOutdated() {
+        return outdated;
+    }
+
+    /**
+     * Return the deployed report entries.
+     *
+     * @return the deployed report entries.
+     */
+    public List<DeployReportEntry> getDeployed() {
+        return deployed;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Deploy all resources from the jar to the given target folder.
+     *
+     * @param jar the jar file to extract resources from
+     * @param target the target folder to deploy the resources to
+     * @return true if resources was deployed, false otherwise
+     * @throws IOException if a IO exception occurs
+     */
+    public boolean deployResourcesInJar(File jar, File target) throws IOException {
+        boolean hasDeployed = false;
+
+        // Mark the size of the reportEntries before deployment
+        int before1 = deployed.size();
+        int before2 = outdated.size();
+
+        // example jar    -> lib/click-core-2.1.0.jar
+        // example target -> c:/dev/webapp/
+        if (jar == null) {
+            throw new IllegalArgumentException("Jar cannot be null");
+        }
+
+        JarFile jarFile = null;
+
+        try {
+
+            jarFile = new JarFile(jar);
+            JarEntry jarEntry = null;
+
+            // Indicates whether feedback should be logged on the jar being
+            // deployed
+            boolean logFeedback = true;
+            Enumeration<JarEntry> en = jarFile.entries();
+
+            while (en.hasMoreElements()) {
+                jarEntry = en.nextElement();
+
+                // jarEntryName example -> META-INF/web/click/table.css
+                String jarEntryName = jarEntry.getName();
+
+                String prefix = "META-INF/web/";
+                // Only deploy resources from "META-INF/web/"
+                int pathIndex = jarEntryName.indexOf(prefix);
+                if (pathIndex == 0) {
+                    if (logFeedback) {
+                        System.out.println("deploy files from jar -> "
+                                         + jar.getCanonicalPath());
+
+                        // Only provide feedback once per jar
+                        logFeedback = false;
+                    }
+                    pathIndex += prefix.length();
+                    // resourceName example -> click/table.css
+                    String resourceName = jarEntryName.substring(pathIndex);
+                    int index = resourceName.lastIndexOf('/');
+
+                    File targetDir = new File(target.getPath());
+                    if (index != -1) {
+                        // resourceDir example -> click
+                        String resourceDir =
+                            resourceName.substring(0, index);
+                        targetDir = new File(targetDir, resourceDir);
+                    }
+
+                    InputStream inputStream = null;
+                    try {
+                        inputStream = jarFile.getInputStream(jarEntry);
+                        byte[] resourceData = TaskUtils.toByteArray(inputStream);
+
+                        // Copy resources to web folder
+                        deployFile(jarEntryName, resourceData, targetDir);
+
+                    } finally {
+                        TaskUtils.close(inputStream);
+                    }
+                }
+            }
+        } finally {
+            TaskUtils.close(jarFile);
+        }
+
+        int after1 = deployed.size();
+        int after2 = outdated.size();
+
+        // If new reportEntries was added, set hasDeployeed to true
+        if (before1 != after1 || before2 != after2) {
+            hasDeployed = true;
+        }
+        return hasDeployed;
+    }
+
+    /**
+     * Deploy all resources from the source folder to the given target folder.
+     *
+     * @param jar the jar file to extract resources from
+     * @param target the target folder to deploy the resources to
+     * @return true if resources was deployed, false otherwise
+     * @throws IOException if a IO exception occurs
+     */
+    public boolean deployResourcesInDir(File source, File target) throws IOException {
+        boolean hasDeployed = false;
+
+        // Mark the size of the reportEntries before deployment
+        int before1 = deployed.size();
+        int before2 = outdated.size();
+
+        // example source -> c:/source/webapp/WEB-INF/classes
+        // example target -> c:/dev/webapp/
+        if (source == null) {
+            throw new IllegalArgumentException("Jar cannot be null");
+        }
+
+        final String prefix = "META-INF/web";
+
+        if (source.exists()) {
+
+            Iterator files = TaskUtils.listFiles(new File(source, prefix), new FilenameFilter() {
+                public boolean accept(File file, String name) {
+                    if (file.isDirectory()) {
+                        return false;
+                    }
+                    
+                    String path = file.getAbsolutePath();
+                    path = path.replace('\\', '/');
+                    return path.indexOf(prefix) >= 0;
+                }
+            }).iterator();
+
+            boolean logFeedback = true;
+            while (files.hasNext()) {
+                // example file -> c:/source/webapp/WEB-INF/classes/META-INF/web/click/table.css
+                File file = (File) files.next();
+
+                // Guard against loading folders -> META-INF/web/click/
+                if (file.isDirectory()) {
+                    continue;
+                }
+
+                String fileName = file.getCanonicalPath().replace('\\', '/');
+
+                // Only deploy resources from "META-INF/web/"
+                int pathIndex = fileName.indexOf(prefix);
+                if (pathIndex != -1) {
+                    if (logFeedback) {
+                        System.out.println("load files from folder -> " +
+                            source.getAbsolutePath());
+
+                        // Only provide feedback once per source
+                        logFeedback = false;
+                    }
+                    pathIndex += prefix.length();
+
+                    fileName = fileName.substring(pathIndex);
+                    int index = fileName.lastIndexOf('/');
+
+                    File targetDir = new File(target.getPath());
+                    if (index != -1) {
+                        // resourceDir example -> click
+                        String resourceDir =
+                            fileName.substring(0, index);
+                        targetDir = new File(targetDir, resourceDir);
+                    }
+
+                    InputStream inputStream = null;
+                    try {
+                        inputStream = new FileInputStream(file);
+                        byte[] resourceData = TaskUtils.toByteArray(inputStream);
+
+                        // Copy resources to web folder
+                        deployFile(fileName, resourceData, targetDir);
+
+                    } finally {
+                        TaskUtils.close(inputStream);
+                    }
+                }
+            }
+        }
+
+        int after1 = deployed.size();
+        int after2 = outdated.size();
+
+        // If new reportEntries was added, set hasDeployeed to true
+        if (before1 != after1 || before2 != after2) {
+            hasDeployed = true;
+        }
+
+        return hasDeployed;
+    }
+
+    /**
+     * Deploy a resource consisting of the resourceName and resourceData to the
+     * target folder.
+     *
+     * @param resourceName the name of the resource to deploy
+     * @param resourceData the resource data as a byte array
+     * @param target the target folder to deploy the resource to
+     * @throws IOException if a IO exception occurs
+     */
+    private void deployFile(String resourceName, byte[] resourceData, File target) {
+
+        if (TaskUtils.isBlank(resourceName)) {
+            String msg = "resource parameter cannot be empty";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (target == null) {
+            String msg = "Null targetDir parameter";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (resourceData == null) {
+            String msg = "Null resourceData parameter";
+            throw new IllegalArgumentException(msg);
+        }
+
+        try {
+
+            // Create files deployment directory
+            if (!target.mkdirs()) {
+                if (!target.exists()) {
+                    String msg = "could not create deployment directory: "
+                        + target.getCanonicalPath();
+                    throw new IOException(msg);
+                }
+            }
+
+            String destination = resourceName;
+            int index = resourceName.lastIndexOf('/');
+            if (index != -1) {
+                destination = resourceName.substring(index + 1);
+            }
+
+            File destinationFile = new File(target, destination);
+
+            if (destinationFile.exists()) {
+
+                // Skip directories
+                if (!destinationFile.isDirectory()) {
+
+                    InputStream existingResource = new FileInputStream(
+                        destinationFile);
+                    try {
+                        byte[] existingResourceData =
+                            TaskUtils.toByteArray(existingResource);
+
+                        boolean contentEquals = TaskUtils.areEqual(resourceData,
+                            existingResourceData);
+
+                        if (!contentEquals) {
+                            // Indicate that an updated version of the resourceName
+                            // is available
+                            outdated.add(new DeployReportEntry(resourceName, resourceName.replace("META-INF/web", "")));
+                        }
+
+                    } finally {
+                        TaskUtils.close(existingResource);
+                    }
+                }
+
+            } else {
+
+                FileOutputStream fos = null;
+                try {
+                    fos = new FileOutputStream(destinationFile);
+                    fos.write(resourceData, 0, resourceData.length);
+
+                    int lastIndex =
+                        destination.lastIndexOf(File.separatorChar);
+                    if (lastIndex != -1) {
+                        destination =
+                            destination.substring(lastIndex + 1);
+                    }
+                    deployed.add(new DeployReportEntry(resourceName, resourceName.replace("META-INF/web", "")));
+
+                } finally {
+                    TaskUtils.close(fos);
+                }
+            }
+
+        } catch (IOException ioe) {
+            String msg =
+                "error occured deploying resource " + resourceName
+                + ", error " + ioe;
+            throw new RuntimeException(msg, ioe);
+
+        } catch (SecurityException se) {
+            String msg =
+                "error occured deploying resource " + resourceName
+                + ", error " + se;
+            throw new RuntimeException(msg, se);
+        }
+    }
+}

Added: incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReport.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReport.java?rev=795360&view=auto
==============================================================================
--- incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReport.java (added)
+++ incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReport.java Sat Jul 18 13:11:42 2009
@@ -0,0 +1,114 @@
+/*
+ * 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.click.tools.deploy;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.List;
+
+/**
+ * Provides a entries writer for deployed resources.
+ */
+class DeployReport {
+
+    /**
+     * Write the given entries entries to the given writer.
+     *
+     * @param source the source folder where the resources are located
+     * @param destination the destination folder where the resources are
+     * deployed to
+     * @param deployed the list of resources that was deployed
+     * @param outdated the list of resources that was outdated
+     * @param writer the writer to write the entries to
+     * @throws IOException if a write error occurs
+     */
+    public void writeReport(String source, String destination,
+        List<DeployReportEntry> deployed, List<DeployReportEntry> outdated,
+        Writer writer) throws IOException {
+
+        if (source == null) {
+            throw new IllegalArgumentException("source is null");
+        }
+        if (destination == null) {
+            throw new IllegalArgumentException("destination is null");
+        }
+        if (writer == null) {
+            throw new IllegalArgumentException("writer is null");
+        }
+
+        if (deployed.size() < 0 && outdated.size() < 0) {
+            return;
+        }
+
+        writer.append("<div class='container'>\n");
+        writer.append("<h4><a name='").append(TaskUtils.getFilename(source)).append("'></a>");
+        if (source.endsWith(".jar")) {
+            writer.append("Jar: ");
+        } else {
+            writer.append("Folder: ");
+        }
+        writer.append(source);
+        writer.append("</h4>\n");
+
+        if (deployed.size() > 0) {
+            writer.append("<div class='deployedHeader'>Deployed Successfully</div>\n");
+            writeReportEntries(source, destination, deployed, writer);
+        }
+        if (outdated.size() > 0) {
+            writer.append("<div class='outdatedHeader'>Outdated</div>\n");
+            writeReportEntries(source, destination, outdated, writer);
+        }
+
+        writer.append("</div>\n");
+    }
+
+    /**
+     * Write the given entries entries to the given writer.
+     *
+     * @param source the source folder where the resources are located
+     * @param destination the destination folder where the resources are
+     * deployed to
+     * @param entries the list of resources that was deployed
+     * @param writer the writer to write the entries to
+     * @throws IOException if a write error occurs
+     */
+    private void writeReportEntries(String source, String destination,
+        List<DeployReportEntry> entries, Writer writer) throws IOException {
+
+        if (entries.size() > 0) {
+            writer.append("<table>\n");
+            writer.append("<tr>");
+            writer.append("<th>Destination - ").append(destination).append("</th>");
+            writer.append("<th>Source - ").append(source).append("</th>");
+            writer.append("</tr>\n");
+            for (DeployReportEntry entry : entries) {
+                writer.append("<tr>");
+                writer.append("<td>");
+                writer.append(entry.destination);
+                writer.append("</td>");
+                writer.append("<td>");
+                writer.append(entry.source);
+                writer.append("</td>");
+                writer.append("</tr>\n");
+            }
+            writer.append("</table>\n");
+        }
+
+    }
+}

Added: incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReportEntry.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReportEntry.java?rev=795360&view=auto
==============================================================================
--- incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReportEntry.java (added)
+++ incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployReportEntry.java Sat Jul 18 13:11:42 2009
@@ -0,0 +1,42 @@
+/*
+ * 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.click.tools.deploy;
+
+/**
+ * Provides a report entry.
+ */
+class DeployReportEntry {
+
+    /** Specify the destination path of a resource. */
+    public String destination;
+
+    /** Specify the source path of a resource. */
+    public String source;
+
+    /**
+     * Default constructor for the given source and destination.
+     *
+     * @param source path of a resource
+     * @param destination path of a resource
+     */
+    public DeployReportEntry(String source, String destination) {
+        this.source = source;
+        this.destination = destination;
+    }
+}

Added: incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployTask.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployTask.java?rev=795360&view=auto
==============================================================================
--- incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployTask.java (added)
+++ incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/DeployTask.java Sat Jul 18 13:11:42 2009
@@ -0,0 +1,295 @@
+/*
+ * 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.click.tools.deploy;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.jar.JarFile;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Provides an Ant task to deploy Click resources from a given source folder to
+ * a target folder.
+ * <p/>
+ * An HTML report is generated which summarizes resources that was deployed and
+ * resources that are outdated.
+ */
+public class DeployTask extends Task {
+
+    // -------------------------------------------------------------- Variables
+
+    /** Directory where filenames can be found. */
+    private File dir;
+
+    /** Directory where filenames should be deployed to. */
+    private File toDir;
+
+    /** The include filter to use when scanning {@link #dir}. */
+    private String includes;
+
+    /** The exclude filter to use when scanning {@link #dir}. */
+    private String excludes;
+
+    /** FileSet that specifies jars and folders to check for filenames. */
+    private FileSet fileSet;
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Creates a default DeployTask instance.
+     */
+    public DeployTask() {
+        fileSet = new FileSet();
+    }
+
+    // ------------------------------------------------------ Public properties
+
+    /**
+     * Set the directory consisting of JARs and folders where filenames are
+     * deployed from.
+     *
+     * @param dir the directory consisting of JARs and folders where filenames
+     * are deployed from.
+     */
+    public void setDir(File dir) {
+        this.dir = dir;
+    }
+
+    /**
+     * Set the target directory where filenames are deployed to.
+     *
+     * @param toDir the target directory where filenames are deployed to.
+     */
+    public void setToDir(File toDir) {
+        this.toDir = toDir;
+    }
+
+    /**
+     * Set the Ant <tt>excludes</tt> pattern for the source {@link #dir}.
+     *
+     * @param excludes the Ant <tt>excludes</tt> pattern for the source
+     * {@link #dir}.
+     */
+    public void setExcludes(String excludes) {
+        this.excludes = excludes;
+        fileSet.setExcludes(excludes);
+    }
+
+    /**
+     * Set the Ant <tt>includes</tt> pattern for the source {@link #dir}.
+     *
+     * @param includes the Ant <tt>includes</tt> pattern for the source
+     * {@link #dir}.
+     */
+    public void setIncludes(String includes) {
+        this.includes = includes;
+        fileSet.setIncludes(includes);
+    }
+
+    /**
+     * Return the Ant <tt>includes</tt> pattern for the source {@link #dir}.
+     *
+     * @return the Ant <tt>includes</tt> pattern for the source {@link #dir}.
+     */
+    public String getIncludes() {
+        return includes;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Execute the task.
+     *
+     * @throws BuildException if the build fails
+     */
+    public void execute() throws BuildException {
+        if(dir == null) {
+            throw new BuildException("dir attribute must be set!");
+        }
+        if(!dir.exists()) {
+            throw new BuildException("dir does not exist!");
+        }
+        if(!dir.isDirectory()) {
+            throw new BuildException("dir is not a directory!");
+        }
+
+        if(toDir == null) {
+            throw new BuildException("todir attribute must be set!");
+        }
+        if(!toDir.exists()) {
+            if (!toDir.mkdirs()) {
+                throw new BuildException("Could not create todir '" + toDir + "'!");
+            }
+            System.out.println("todir '" + toDir + "' created.");
+        }
+        if(!toDir.isDirectory()) {
+            throw new BuildException("todir is not a directory!");
+        }
+
+        fileSet.setDir(dir);
+        fileSet.setDefaultexcludes(true);
+        if (getIncludes() == null) {
+            // Set default standard includes
+            fileSet.setIncludes("**/*.jar, classes");
+        }
+        DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject());
+        String files[] = directoryScanner.getIncludedFiles();
+        String dirs[] = directoryScanner.getIncludedDirectories();
+        String resources[] = (String[]) TaskUtils.addAll(files, dirs);
+
+        deployResources(resources);
+    }
+
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * Deploy the resources specified by the given filenames.
+     *
+     * @param filenames the filenames for the resources to deploy.
+     */
+    private void deployResources(String filenames[]) {
+        Writer reportWriter = null;
+        try {
+
+            InputStream is = TaskUtils.getResourceAsStream("/report-template.html", DeployTask.class);
+            String template = null;
+
+            if (is == null) {
+                System.out.println("The report template 'report-template.html' could not be found on the classpath. No report will be generated.");
+            } else {
+                template = TaskUtils.toString(is);
+            }
+
+            DeployReport report = new DeployReport();
+
+            StringWriter writer = new StringWriter();
+            for (int i = 0; i < filenames.length; i++) {
+                String filename = filenames[i];
+                String path = getCurrentPath();
+                File file = new File(dir, filename);
+
+                Deploy deploy = new Deploy();
+
+                boolean deployed = false;
+
+                if (filename.indexOf(".jar") >= 0) {
+                    deployed = deploy.deployResourcesInJar(file, toDir);
+                } else {
+                    deployed = deploy.deployResourcesInDir(file, toDir);
+                }
+
+                if (deployed) {
+                    report.writeReport(path + filename, toDir.getCanonicalPath(),
+                        deploy.getDeployed(), deploy.getOutdated(), reportWriter);
+                }
+            }
+
+            if (template != null) {
+                String reportContent = template;
+                reportContent = reportContent.replace("{0}", dir.getCanonicalPath());
+                reportContent = reportContent.replace("{1}", toDir.getCanonicalPath());
+                reportContent = reportContent.replace("{2}", toHtml(filenames));
+
+                String reportEntries = writer.toString();
+
+                // If no report entries were made, print a success message
+                if (TaskUtils.isBlank(reportEntries)) {
+                    reportContent = reportContent.replace("{3}", "<h3 class='success'>All resources are successfully deployed</h3>");
+                } else {
+                    reportContent = reportContent.replace("{3}", writer.toString());
+                }
+
+                File reportFile = new File("report.html");
+                reportWriter = new FileWriter(reportFile);
+                reportWriter.append(reportContent);
+                System.out.println("See report: " + reportFile.getCanonicalPath());
+            }
+
+        } catch(IOException ioe) {
+            throw new BuildException(ioe.getClass().getName() + ":" + ioe.getMessage(), ioe);
+
+        } finally {
+            TaskUtils.close(reportWriter);
+        }
+    }
+
+    /**
+     * Returns the current path.
+     *
+     * @return the current path
+     * @throws IOException if the path cannot be looked up
+     */
+    private String getCurrentPath() throws IOException {
+        String path = dir.getCanonicalPath();
+        return path.endsWith(File.separator) ? path : path + File.separator;
+    }
+
+    /**
+     * Return the HTML representation of the given filenames.
+     *
+     * @param filenames the filenames to represent as HTML
+     * @return return HTML representation of the given filenames
+     * @throws IOException if an IO exception occurs
+     */
+    private String toHtml(String[] filenames) throws IOException {
+        StringBuilder buffer = new StringBuilder();
+
+        if (filenames != null && filenames.length > 0) {
+            String path = getCurrentPath();
+
+            for (String filename : filenames) {
+                if (filename.endsWith(".jar")) {
+                    JarFile jarFile = new JarFile(new File(path, filename));
+                    if (jarFile.getEntry("META-INF/web") != null) {
+                        render(buffer, filename);
+                    }
+                } else {
+                    File file = new File(path, filename);
+                    file = new File(file, "META-INF/web");
+                    if (file.exists()) {
+                        render(buffer, filename);
+                    }
+                }
+            }
+        }
+
+        return buffer.toString();
+    }
+
+    /**
+     * Render the HTML represenation of the given filename.
+     *
+     * @param buffer the buffer to render the HTML representation to
+     * @param filename the filename to render
+     */
+    private void render(StringBuilder buffer, String filename) {
+        buffer.append("<li><a href='#");
+        buffer.append(TaskUtils.getFilename(filename));
+        buffer.append("'>");
+        buffer.append(filename);
+        buffer.append("</a></li>");
+    }
+}

Added: incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/TaskUtils.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/TaskUtils.java?rev=795360&view=auto
==============================================================================
--- incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/TaskUtils.java (added)
+++ incubator/click/trunk/tools/standalone/dev-tasks/src/org/apache/click/tools/deploy/TaskUtils.java Sat Jul 18 13:11:42 2009
@@ -0,0 +1,448 @@
+/*
+ * 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.click.tools.deploy;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.JarFile;
+
+/**
+ * Provides common String and Stream utility methods.
+ */
+class TaskUtils {
+
+    // -------------------------------------------------------------- Constants
+
+    /** Default buffer size for writing files. */
+    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Return the input stream for the given name and class.
+     *
+     * @param name the name of the resource to return
+     * @param aClass the class which class loader to use
+     * @return the input stream for the given name and class
+     */
+    public static InputStream getResourceAsStream(String name, Class aClass) {
+        if (isBlank(name)) {
+            throw new IllegalArgumentException("Parameter name cannot be blank");
+        };
+
+        if (aClass == null) {
+            throw new IllegalArgumentException("Parameter aClass is null");
+        }
+
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+        InputStream inputStream = classLoader.getResourceAsStream(name);
+        if (inputStream == null) {
+            inputStream = aClass.getResourceAsStream(name);
+        }
+
+        return inputStream;
+    }
+
+    /**
+     * Extract and return the filename from the path.
+     *
+     * @param path the path to extract the filename from
+     * @return the path filename
+     */
+    public static String getFilename(String path) {
+        if (isBlank(path)) {
+            return "";
+        }
+        path = path.replace('\\', '/');
+        int index = path.lastIndexOf("/");
+        if (index >= 0) {
+            return path.substring(index + 1);
+        }
+        return path;
+    }
+
+    /**
+     * Return all the files in the specified directory and sub-directories. The
+     * given filter can be used to accept or reject files.
+     *
+     * @param directory the directory which files to return
+     * @param filter a filter to accept or reject files
+     * @return the list of files in the directory and sub-directories
+     */
+    public static List<File> listFiles(File directory, FilenameFilter filter) {
+        List<File> files = new ArrayList<File>();
+
+        File[] entries = directory.listFiles();
+
+        for (File entry : entries) {
+            if (filter == null || filter.accept(entry, entry.getName())) {
+                files.add(entry);
+            }
+
+            if (entry.isDirectory()) {
+                files.addAll(listFiles(entry, filter));
+            }
+        }
+
+        return files;
+    }
+
+    // --------------------------------------------- Copied from Apache Commons
+
+    /**
+     * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
+     * <p>
+     * This method buffers the input internally, so there is no need to use a
+     * <code>BufferedInputStream</code>.
+     *
+     * @param input  the <code>InputStream</code> to read from
+     * @return the requested byte array
+     * @throws NullPointerException if the input is null
+     * @throws IOException if an I/O error occurs
+     */
+    public static byte[] toByteArray(InputStream input) throws IOException {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        copy(input, output);
+        return output.toByteArray();
+    }
+
+    /**
+     * Get the contents of an <code>InputStream</code> as a String
+     * using the default character encoding of the platform.
+     * <p/>
+     * This method buffers the input internally, so there is no need to use a
+     * <code>BufferedInputStream</code>.
+     * 
+     * @param input  the <code>InputStream</code> to read from
+     * @return the requested String
+     * @throws NullPointerException if the input is null
+     * @throws IOException if an I/O error occurs
+     */
+    public static String toString(InputStream input) throws IOException {
+        StringWriter sw = new StringWriter();
+        copy(input, sw);
+        return sw.toString();
+    }
+
+    /**
+     * Copy bytes from an <code>InputStream</code> to an
+     * <code>OutputStream</code>.
+     * <p>
+     * This method buffers the input internally, so there is no need to use a
+     * <code>BufferedInputStream</code>.
+     * <p>
+     * Large streams (over 2GB) will return a bytes copied value of
+     * <code>-1</code> after the copy has completed since the correct
+     * number of bytes cannot be returned as an int. For large streams
+     * use the <code>copyLarge(InputStream, OutputStream)</code> method.
+     *
+     * @param input  the <code>InputStream</code> to read from
+     * @param output  the <code>OutputStream</code> to write to
+     * @return the number of bytes copied
+     * @throws NullPointerException if the input or output is null
+     * @throws IOException if an I/O error occurs
+     * @throws ArithmeticException if the byte count is too large
+     * @since Commons IO 1.1
+     */
+    public static int copy(InputStream input, OutputStream output) throws IOException {
+        long count = copyLarge(input, output);
+        if (count > Integer.MAX_VALUE) {
+            return -1;
+        }
+        return (int) count;
+    }
+
+    /**
+     * Copy bytes from an <code>InputStream</code> to chars on a
+     * <code>Writer</code> using the default character encoding of the platform.
+     * <p>
+     * This method buffers the input internally, so there is no need to use a
+     * <code>BufferedInputStream</code>.
+     * <p>
+     * This method uses {@link InputStreamReader}.
+     *
+     * @param input  the <code>InputStream</code> to read from
+     * @param output  the <code>Writer</code> to write to
+     * @throws NullPointerException if the input or output is null
+     * @throws IOException if an I/O error occurs
+     * @since Commons IO 1.1
+     */
+    public static void copy(InputStream input, Writer output)
+            throws IOException {
+        InputStreamReader in = new InputStreamReader(input);
+        copy(in, output);
+    }
+
+    /**
+     * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
+     * <p>
+     * This method buffers the input internally, so there is no need to use a
+     * <code>BufferedReader</code>.
+     * <p>
+     * Large streams (over 2GB) will return a chars copied value of
+     * <code>-1</code> after the copy has completed since the correct
+     * number of chars cannot be returned as an int. For large streams
+     * use the <code>copyLarge(Reader, Writer)</code> method.
+     *
+     * @param input  the <code>Reader</code> to read from
+     * @param output  the <code>Writer</code> to write to
+     * @return the number of characters copied
+     * @throws NullPointerException if the input or output is null
+     * @throws IOException if an I/O error occurs
+     * @throws ArithmeticException if the character count is too large
+     * @since Commons IO 1.1
+     */
+    public static int copy(Reader input, Writer output) throws IOException {
+        long count = copyLarge(input, output);
+        if (count > Integer.MAX_VALUE) {
+            return -1;
+        }
+        return (int) count;
+    }
+
+    /**
+     * Copy bytes from a large (over 2GB) <code>InputStream</code> to an
+     * <code>OutputStream</code>.
+     * <p>
+     * This method buffers the input internally, so there is no need to use a
+     * <code>BufferedInputStream</code>.
+     *
+     * @param input  the <code>InputStream</code> to read from
+     * @param output  the <code>OutputStream</code> to write to
+     * @return the number of bytes copied
+     * @throws NullPointerException if the input or output is null
+     * @throws IOException if an I/O error occurs
+     * @since Commons IO 1.3
+     */
+    public static long copyLarge(InputStream input, OutputStream output)
+            throws IOException {
+        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+        long count = 0;
+        int n = 0;
+        while (-1 != (n = input.read(buffer))) {
+            output.write(buffer, 0, n);
+            count += n;
+        }
+        return count;
+    }
+
+    /**
+     * Copy chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
+     * <p>
+     * This method buffers the input internally, so there is no need to use a
+     * <code>BufferedReader</code>.
+     *
+     * @param input  the <code>Reader</code> to read from
+     * @param output  the <code>Writer</code> to write to
+     * @return the number of characters copied
+     * @throws NullPointerException if the input or output is null
+     * @throws IOException if an I/O error occurs
+     * @since Commons IO 1.3
+     */
+    public static long copyLarge(Reader input, Writer output) throws IOException {
+        char[] buffer = new char[DEFAULT_BUFFER_SIZE];
+        long count = 0;
+        int n = 0;
+        while (-1 != (n = input.read(buffer))) {
+            output.write(buffer, 0, n);
+            count += n;
+        }
+        return count;
+    }
+
+    /**
+     * Compares two byte arrays for equality.
+     *
+     * @param a A byte[].
+     * @param b A byte[].
+     * @return True if the arrays have identical contents.
+     */
+    public static boolean areEqual(byte[] a, byte[] b) {
+        int aLength = a.length;
+        if (aLength != b.length) {
+            return false;
+        }
+
+        for (int i = 0; i < aLength; i++) {
+            if (a[i] != b[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Checks if a String is whitespace, empty ("") or null.
+     * <p/>
+     *
+     * @param str  the String to check, may be null
+     * @return <code>true</code> if the String is null, empty or whitespace
+     */
+    public static boolean isBlank(String str) {
+        int strLen;
+        if (str == null || (strLen = str.length()) == 0) {
+            return true;
+        }
+        for (int i = 0; i < strLen; i++) {
+            if ((Character.isWhitespace(str.charAt(i)) == false)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Checks if a String is not empty (""), not null and not whitespace only.
+     * <p/>
+     *
+     * @param str  the String to check, may be null
+     * @return <code>true</code> if the String is not empty and not null and not
+     * whitespace
+     */
+    public static boolean isNotBlank(String str) {
+        return !isBlank(str);
+    }
+
+    /**
+     * <p>Adds all the elements of the given arrays into a new array.</p>
+     * <p>The new array contains all of the element of <code>array1</code> followed
+     * by all of the elements <code>array2</code>. When an array is returned, it is always
+     * a new array.</p>
+     *
+     * <pre>
+     * ArrayUtils.addAll(null, null)     = null
+     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
+     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
+     * ArrayUtils.addAll([], [])         = []
+     * ArrayUtils.addAll([null], [null]) = [null, null]
+     * ArrayUtils.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"]
+     * </pre>
+     *
+     * @param array1  the first array whose elements are added to the new array, may be <code>null</code>
+     * @param array2  the second array whose elements are added to the new array, may be <code>null</code>
+     * @return The new array, <code>null</code> if <code>null</code> array inputs.
+     *      The type of the new array is the type of the first array.
+     * @since 2.1
+     */
+    public static Object[] addAll(Object[] array1, Object[] array2) {
+        if (array1 == null) {
+            return clone(array2);
+        } else if (array2 == null) {
+            return clone(array1);
+        }
+        Object[] joinedArray = (Object[]) Array.newInstance(array1.getClass().getComponentType(),
+            array1.length + array2.length);
+
+        System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+        System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+        return joinedArray;
+    }
+
+    /**
+     * <p>Shallow clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>The objects in the array are not cloned, thus there is no special
+     * handling for multi-dimensional arrays.</p>
+     *
+     * <p>This method returns <code>null</code> for a <code>null</code> input array.</p>
+     *
+     * @param array  the array to shallow clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static Object[] clone(Object[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (Object[]) array.clone();
+    }
+
+    
+    /**
+     * Close the given input stream and ignore any exceptions thrown.
+     *
+     * @param stream the input stream to close.
+     */
+    public static void close(InputStream stream) {
+        if (stream != null) {
+            try {
+                stream.close();
+            } catch (IOException ex) {
+                // Ignore.
+            }
+        }
+    }
+
+    /**
+     * Close the given writer and ignore any exceptions thrown.
+     *
+     * @param stream the writer to close.
+     */
+    public static void close(Writer writer) {
+        if (writer != null) {
+            try {
+                writer.close();
+            } catch (IOException ex) {
+                // Ignore.
+            }
+        }
+    }
+
+    /**
+     * Close the given output stream and ignore any exceptions thrown.
+     *
+     * @param stream the output stream to close.
+     */
+    public static void close(OutputStream stream) {
+        if (stream != null) {
+            try {
+                stream.close();
+            } catch (IOException ex) {
+                // Ignore.
+            }
+        }
+    }
+
+    /**
+     * Close the given jar file and ignore any exceptions thrown.
+     *
+     * @param file the jar file to close.
+     */
+    public static void close(JarFile file) {
+        if (file != null) {
+            try {
+                file.close();
+            } catch (IOException ex) {
+                // Ignore.
+            }
+        }
+    }
+}

Added: incubator/click/trunk/tools/standalone/dev-tasks/src/report-template.html
URL: http://svn.apache.org/viewvc/incubator/click/trunk/tools/standalone/dev-tasks/src/report-template.html?rev=795360&view=auto
==============================================================================
--- incubator/click/trunk/tools/standalone/dev-tasks/src/report-template.html (added)
+++ incubator/click/trunk/tools/standalone/dev-tasks/src/report-template.html Sat Jul 18 13:11:42 2009
@@ -0,0 +1,101 @@
+<!doctype html>
+
+<html>
+    <head>
+        <style rel="stylesheet" type="text/css">
+            body, table, td, p {
+                font-family: verdana, arial, helvetica, lucida-sans, sans-serif;
+                font-size: 10pt;
+            }
+            .success {
+                padding: 3px;
+                float: left;
+            }
+            .success, .deployed {
+                background-color: #0F8800;
+                color: white;
+                font-weight: bold;
+            }
+            .outdated {
+                background-color: #FF1400;
+                color: white;
+                font-weight: bold;
+            }
+
+            .deployedHeader, .outdatedHeader {
+                text-align: left;
+                color: white;
+                font-weight: bold;
+                margin: 1px;
+                padding: 2px;
+                border: 1px solid #CCC;
+            }
+            .deployedHeader {
+                background-color: #0F8800;
+            }
+            .outdatedHeader {
+                background-color: #FF1400;
+            }
+            .container {
+                margin-top: 1em;
+                padding: 0px 0px 10px;
+                border: 1px solid gray;
+                background-color: #EEE;
+            }
+            .container h4 {
+                background-color: #CCC;
+                padding: 3px;
+                margin: 0;
+                border-bottom: 1px solid gray;
+            }
+            .container table {
+                width: 100%;
+            }
+            .container th {
+                text-align: left;
+                width: 50%;
+            }
+        </style>
+    </head>
+
+    <body>
+
+        <h3>Apache Click - Resource Deployment Report</h3>
+
+        This report shows the JavaScript, CSS, images and other resources found
+        under the folder "<tt>{0}</tt>" that was deployed to the target folder
+        "<tt>{1}</tt>".
+
+        <p/>
+
+        The following JARs and folders contains deployable resources
+        (deployable resources are found in JARs and folders under <tt>WEB-INF/web</tt>):
+
+        <ul>
+            {2}
+        </ul>
+
+        Resources can have one of three states:
+
+        <ul>
+            <li>Deployed - the resource was deployed from the JAR to the target folder</li>
+            <li>Outdated <span style="color:red">*</span> - the resource was already
+                deployed, but a newer version of the resource is available</li>
+            <li>Current - the resource was already deployed, no redeploy was necessary.
+                Please note, this state is not shown in the detailed report as it is redundent information</li>
+        </ul>
+
+        <span style="color:red">*</span> Outdated resources must be
+        manually redeployed by either deleting the existing resource and executing
+        the deploy task again, or if the existing resource was customized, it must
+        be merged by your IDE diff utility.
+
+        <p/>
+
+        Below is the detailed report for the resources that was <tt>Deployed Successfully
+        </tt> or <tt>Outdated</tt>.
+
+        {3}
+        
+    </body>
+</html>

Propchange: incubator/click/trunk/tools/standalone/dev-tasks/src/report-template.html
------------------------------------------------------------------------------
    svn:mime-type = text/html



Mime
View raw message