Implemented a TarCat Ant task to slurp tars directly into other tars. This allows us to preserve things like permissions and symlinks on hostile operating systems. git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@174 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/build-tools/ant-gwt/build.xml b/build-tools/ant-gwt/build.xml new file mode 100644 index 0000000..43c0f27 --- /dev/null +++ b/build-tools/ant-gwt/build.xml
@@ -0,0 +1,34 @@ +<project name="ant-gwt" default="build" basedir="."> + <property name="gwt.root" location="../.." /> + <property name="project.tail" value="build-tools/ant-gwt" /> + <import file="${gwt.root}/common.ant.xml" /> + + <target name="compile" description="Compiles this project"> + <mkdir dir="${javac.out}" /> + <gwt.javac> + <classpath> + <pathelement location="${gwt.tools.lib}/apache/ant-1.6.5.jar" /> + </classpath> + </gwt.javac> + </target> + + <target name="build" depends="compile" description="Packages this project into a jar"> + <mkdir dir="${gwt.build.lib}" /> + <gwt.jar destfile="${gwt.build.lib}/${ant.project.name}.jar"> + <fileset dir="src" /> + <fileset dir="${javac.out}" /> + </gwt.jar> + </target> + + <target name="checkstyle" description="Static analysis of source"> + <gwt.checkstyle> + <fileset dir="src" /> + </gwt.checkstyle> + </target> + + <target name="clean" description="Cleans this project's intermediate and output files"> + <delete dir="${project.build}" /> + <delete file="${project.lib}" /> + </target> + +</project>
diff --git a/build-tools/ant-gwt/src/com/google/gwt/ant/taskdefs/TarCat.java b/build-tools/ant-gwt/src/com/google/gwt/ant/taskdefs/TarCat.java new file mode 100644 index 0000000..45f12b9 --- /dev/null +++ b/build-tools/ant-gwt/src/com/google/gwt/ant/taskdefs/TarCat.java
@@ -0,0 +1,261 @@ +/* + * Copyright 2006 Google Inc. + * + * Licensed 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 com.google.gwt.ant.taskdefs; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.taskdefs.Tar; +import org.apache.tools.ant.types.EnumeratedAttribute; +import org.apache.tools.bzip2.CBZip2InputStream; +import org.apache.tools.tar.TarEntry; +import org.apache.tools.tar.TarInputStream; +import org.apache.tools.tar.TarOutputStream; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Vector; +import java.util.zip.GZIPInputStream; + +/** + * An extension to the Ant Tar task that supports slurping in other tar files + * without loss of information (such as permissions or symlinks). It behaves in + * all respects like the basic Tar task, but adds the nested element + * <includetar> which declares another tar file whose <i>contents</i> + * should be added to the file being created. + * + * In addition to preserving permissions and symlinks no matter what the host + * operating system is, there are performance advantages to this approach. + * Bypassing the file system cuts the disk activity to 50% or less. The + * intermediate files normally generated require data the size of the tar itself + * to be both written and read, not to mention the overhead of creating the + * individual files, which will generally have to be deleted later. Furthurmore, + * since the source and target are often zipped, the savings can be well over + * 50%. + * + * Example use: + * + * <pre> + * <taskdef name="tar.cat" + * classname="com.google.gwt.ant.taskdefs.TarCat" + * classpath="${gwt.build.lib}/ant-gwt.jar" /> + * <tar.cat destfile="foo.tar.gz" compression="gzip" longfile="gnu"> + * <!-- all normal tar attributes and elements supported --> + * <tarfileset dir="foo/src"> + * <include name="*.class" /> + * </tarfileset> + * <!-- tar.cat adds the ability to directly slurp in other tar files --> + * <includetar src="bar.tar.gz" compression="gzip" prefix="bar/" /> + * </tar.cat> + * </pre> + */ +public class TarCat extends Tar { + + /** + * This is a tar file that should be included into a tar operation. + */ + public static class IncludeTar { + /** + * The compression method to use to access the included tar file. + */ + private UntarCompressionMethod compression = new UntarCompressionMethod(); + + /** + * An association from a super Tar to a derived TarCat. + */ + private TarFileSet wrapper; + + /** + * Constructs a new IncludeTar. + * + * @param wrapper the association from a super Tar to a derived TarExt + */ + public IncludeTar(TarFileSet wrapper) { + this.wrapper = wrapper; + } + + /** + * Set decompression algorithm to use; default=none. + * + * Allowable values are + * <ul> + * <li>none - no compression + * <li>gzip - Gzip compression + * <li>bzip2 - Bzip2 compression + * </ul> + * + * @param method compression method + */ + public void setCompression(UntarCompressionMethod method) { + compression = method; + } + + /** + * If the prefix attribute is set, all files in the fileset are prefixed + * with that path in the archive. optional. + * + * @param prefix the path prefix. + */ + public void setPrefix(String prefix) { + wrapper.setPrefix(prefix); + } + + /** + * Set the name/location of a tar file to add to a tar operation. + * + * @param tarFile the tar file to read + */ + public void setSrc(File tarFile) { + wrapper.setFile(tarFile); + } + } + + /** + * Straight copy from + * {@link org.apache.tools.ant.taskdefs.Untar.UntarCompressionMethod} due to + * access restrictions. + */ + public static final class UntarCompressionMethod extends EnumeratedAttribute { + + private static final String BZIP2 = "bzip2"; + private static final String GZIP = "gzip"; + private static final String NONE = "none"; + + public UntarCompressionMethod() { + super(); + setValue(NONE); + } + + public String[] getValues() { + return new String[] {NONE, GZIP, BZIP2}; + } + + private InputStream decompress(final File file, final InputStream istream) + throws IOException, BuildException { + final String value = getValue(); + if (GZIP.equals(value)) { + return new GZIPInputStream(istream); + } else { + if (BZIP2.equals(value)) { + final char[] magic = new char[] {'B', 'Z'}; + for (int i = 0; i < magic.length; i++) { + if (istream.read() != magic[i]) { + throw new BuildException("Invalid bz2 file." + file.toString()); + } + } + return new CBZip2InputStream(istream); + } + } + return istream; + } + } + + /** + * The set of tars to include in this tar operation. + */ + Vector includeTars = new Vector(); + + /** + * A set of tarfileset wrappers mapped to includeTars. + */ + Vector includeTarWrappers = new Vector(); + + /** + * Creates a TarExt task instance. + */ + public TarCat() { + } + + /** + * Add a new tar to include in this tar operation. + */ + public IncludeTar createIncludeTar() { + /* + * Create a dummy tarfileset to hold our own includeTars and add it to the + * super class. This is how we get the super class to call us back during + * execution. + */ + TarFileSet wrapper = super.createTarFileSet(); + IncludeTar includeTar = new IncludeTar(wrapper); + includeTars.addElement(includeTar); + includeTarWrappers.add(wrapper); + return includeTar; + } + + protected void tarFile(File file, TarOutputStream tOut, String vPath, + TarFileSet tarFileSet) throws IOException { + // See if it's one of ours + int index = includeTarWrappers.indexOf(tarFileSet); + if (index < 0) { + super.tarFile(file, tOut, vPath, tarFileSet); + return; + } + IncludeTar includeTar = (IncludeTar) includeTars.get(index); + TarInputStream tIn = null; + try { + tIn = new TarInputStream(includeTar.compression.decompress(file, + new BufferedInputStream(new FileInputStream(file)))); + TarEntry te = null; + while ((te = tIn.getNextEntry()) != null) { + vPath = te.getName(); + + // don't add "" to the archive + if (vPath.length() <= 0) { + continue; + } + + if (te.isDirectory() && !vPath.endsWith("/")) { + vPath += "/"; + } + + String prefix = tarFileSet.getPrefix(); + // '/' is appended for compatibility with the zip task. + if (prefix.length() > 0 && !prefix.endsWith("/")) { + prefix = prefix + "/"; + } + vPath = prefix + vPath; + + te.setName(vPath); + tOut.putNextEntry(te); + + if (te.getSize() > 0) { + byte[] buffer = new byte[8 * 1024]; + while (true) { + int count = tIn.read(buffer, 0, buffer.length); + if (count < 0) { + break; + } + tOut.write(buffer, 0, count); + } + } + tOut.closeEntry(); + } + + } catch (IOException ioe) { + throw new BuildException("Error while expanding " + file.getPath(), ioe, + getLocation()); + } finally { + if (tIn != null) { + try { + tIn.close(); + } catch (IOException e) { + // ignore + } + } + } + } +}
diff --git a/build-tools/build.xml b/build-tools/build.xml index 7846150..e16d42c 100644 --- a/build-tools/build.xml +++ b/build-tools/build.xml
@@ -6,6 +6,10 @@ <!-- "build" is the default when subprojects are directly targetted --> <property name="target" value="build" /> + <target name="ant-gwt" description="Builds GWT specific Ant extensions"> + <gwt.ant dir="ant-gwt" /> + </target> + <target name="customchecks" description="Build the checkstyle extensions"> <gwt.ant dir="customchecks" /> </target> @@ -14,7 +18,7 @@ <gwt.ant dir="doctool" /> </target> - <target name="-do" depends="customchecks, doctool" description="Run all subprojects"/> + <target name="-do" depends="ant-gwt, customchecks, doctool" description="Run all subprojects"/> <target name="build" description="Builds GWT"> <antcall target="-do">
diff --git a/common.ant.xml b/common.ant.xml index c01d278..cddd93f 100755 --- a/common.ant.xml +++ b/common.ant.xml
@@ -143,17 +143,14 @@ </sequential> </macrodef> - <macrodef name="gwt.untar"> - <attribute name="src" /> - <attribute name="dest" /> + <macrodef name="gwt.tgz.cat"> + <attribute name="destfile" /> + <element name="tar.elements" implicit="true" optional="true" /> <sequential> - <!-- GNU tar handles permissions and symlinks correctly --> - <exec executable="tar" failonerror="true"> - <arg value="-xpzf" /> - <arg file="@{src}" /> - <arg value="-C" /> - <arg file="@{dest}" /> - </exec> + <taskdef name="tar.cat" classname="com.google.gwt.ant.taskdefs.TarCat" classpath="${gwt.build.lib}/ant-gwt.jar" /> + <tar.cat destfile="${project.dist}" compression="gzip" longfile="gnu"> + <tar.elements /> + </tar.cat> </sequential> </macrodef>
diff --git a/distro-source/common.ant.xml b/distro-source/common.ant.xml index 5f344c9..082fde8 100755 --- a/distro-source/common.ant.xml +++ b/distro-source/common.ant.xml
@@ -6,6 +6,18 @@ <property name="project.distname" value="gwt-${dist.platform}-${gwt.version}" /> <property name="project.staging" location="${gwt.build.staging}/${project.distname}" /> + <patternset id="chmod.executables"> + <include name="*Creator*" /> + <include name="samples/*/*-shell" /> + <include name="samples/*/*-compile" /> + </patternset> + + <patternset id="chmod.not.executables"> + <exclude name="*Creator*" /> + <exclude name="samples/*/*-shell*" /> + <exclude name="samples/*/*-compile*" /> + </patternset> + <!-- copies a single sample into the staging directory --> <macrodef name="stage.sample"> <attribute name="lname" /> @@ -24,12 +36,6 @@ <include name="*" /> </fileset> </copy> - <chmod perm="a+x"> - <fileset dir="${project.staging}/samples/@{uname}"> - <include name="@{uname}-compile*" /> - <include name="@{uname}-shell*" /> - </fileset> - </chmod> </sequential> </macrodef> @@ -69,14 +75,9 @@ <stage.sample lname="simplexml" uname="SimpleXML" /> <antcall target="stage.platform" /> - <chmod perm="a+r"> - <dirset dir="${project.staging}" /> - <fileset dir="${project.staging}" /> - </chmod> - <chmod perm="a+x"> - <dirset dir="${project.staging}" /> + <chmod perm="755"> <fileset dir="${project.staging}"> - <include name="*Creator*" /> + <patternset refid="chmod.executables" /> </fileset> </chmod> </target>
diff --git a/distro-source/linux/build.xml b/distro-source/linux/build.xml index cefc2cb..27e4773 100755 --- a/distro-source/linux/build.xml +++ b/distro-source/linux/build.xml
@@ -4,7 +4,7 @@ <property name="project.dist" location="${gwt.build.dist}/${project.distname}.tar.gz" /> <target name="stage.platform" description="Copies platform-specific items into the staging area"> - <gwt.untar src="${gwt.tools.redist}/mozilla/mozilla-1.7.12.tar.gz" dest="${project.staging}" /> + <untar src="${gwt.tools.redist}/mozilla/mozilla-1.7.12.tar.gz" dest="${project.staging}" compression="gzip" /> <copy todir="${project.staging}"> <fileset dir="${gwt.tools.lib}/eclipse"> <include name="libswt-*gtk-3235.so" /> @@ -14,13 +14,18 @@ <target name="build" depends="stage" description="Packages the distro staging area"> <mkdir dir="${gwt.build.dist}" /> - <!-- GNU tar handles permissions and symlinks correctly --> - <exec executable="tar" failonerror="true"> - <arg value="-cpzf" /> - <arg value="${project.dist}" /> - <arg value="-C" /> - <arg file="${gwt.build.staging}" /> - <arg value="${project.distname}" /> - </exec> + <gwt.tgz.cat destfile="${project.dist}"> + <tarfileset dir="${gwt.build.staging}/${project.distname}" prefix="${project.distname}"> + <!-- Mozilla pulled in through includetar --> + <exclude name="mozilla-1.7.12/**" /> + <patternset refid="chmod.not.executables" /> + </tarfileset> + <tarfileset dir="${gwt.build.staging}/${project.distname}" prefix="${project.distname}" mode="755"> + <!-- Mozilla pulled in through includetar --> + <exclude name="mozilla-1.7.12/**" /> + <patternset refid="chmod.executables" /> + </tarfileset> + <includetar src="${gwt.tools.redist}/mozilla/mozilla-1.7.12.tar.gz" compression="gzip" prefix="${project.distname}" /> + </gwt.tgz.cat> </target> </project>
diff --git a/distro-source/mac/build.xml b/distro-source/mac/build.xml index 4c9d901..cb4e146 100755 --- a/distro-source/mac/build.xml +++ b/distro-source/mac/build.xml
@@ -4,7 +4,16 @@ <property name="project.dist" location="${gwt.build.dist}/${project.distname}.tar.gz" /> <target name="stage.platform" description="Copies platform-specific items into the staging area"> - <gwt.untar src="${gwt.tools.redist}/webkit/WebKit-418.9.tar.gz" dest="${project.staging}" /> + <!-- + Try to untar WebKit into the staging directory. GNU tar handles + permissions and symlinks correctly. It's okay if we fail here. + --> + <exec executable="tar" failifexecutionfails="false" failonerror="false"> + <arg value="-xpzf" /> + <arg file="${gwt.tools.redist}/webkit/WebKit-418.9.tar.gz" /> + <arg value="-C" /> + <arg file="${project.staging}" /> + </exec> <copy todir="${project.staging}"> <fileset dir="${gwt.tools.lib}/eclipse"> <include name="libswt-*carbon-3235.jnilib" /> @@ -16,13 +25,18 @@ <target name="build" depends="stage" description="Packages the distro staging area"> <mkdir dir="${gwt.build.dist}" /> - <!-- GNU tar handles permissions and symlinks correctly --> - <exec executable="tar" failonerror="true"> - <arg value="-cpzf" /> - <arg value="${project.dist}" /> - <arg value="-C" /> - <arg file="${gwt.build.staging}" /> - <arg value="${project.distname}" /> - </exec> + <gwt.tgz.cat destfile="${project.dist}"> + <tarfileset dir="${gwt.build.staging}/${project.distname}" prefix="${project.distname}"> + <!-- Frameworks pulled in through includetar --> + <exclude name="Frameworks/**" /> + <patternset refid="chmod.not.executables" /> + </tarfileset> + <tarfileset dir="${gwt.build.staging}/${project.distname}" prefix="${project.distname}" mode="755"> + <!-- Frameworks pulled in through includetar --> + <exclude name="Frameworks/**" /> + <patternset refid="chmod.executables" /> + </tarfileset> + <includetar src="${gwt.tools.redist}/webkit/WebKit-418.9.tar.gz" compression="gzip" prefix="${project.distname}" /> + </gwt.tgz.cat> </target> </project>
diff --git a/distro-source/windows/build.xml b/distro-source/windows/build.xml index 38361a3..5bc73f7 100755 --- a/distro-source/windows/build.xml +++ b/distro-source/windows/build.xml
@@ -14,9 +14,7 @@ <target name="build" depends="stage" description="Packages the distro staging area"> <mkdir dir="${gwt.build.dist}" /> <zip destfile="${project.dist}"> - <fileset dir="${gwt.build.staging}"> - <include name="${project.distname}/**" /> - </fileset> + <zipfileset dir="${gwt.build.staging}/${project.distname}" prefix="${project.distname}" /> </zip> </target> </project>
diff --git a/eclipse/build-tools/ant-gwt/.checkstyle b/eclipse/build-tools/ant-gwt/.checkstyle new file mode 100644 index 0000000..afcc9b2 --- /dev/null +++ b/eclipse/build-tools/ant-gwt/.checkstyle
@@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<fileset-config file-format-version="1.2.0" simple-config="false"> + <fileset name="all" enabled="true" check-config-name="GWT Checks" local="false"> + <file-match-pattern match-pattern="." include-pattern="true"/> + </fileset> +</fileset-config>
diff --git a/eclipse/build-tools/ant-gwt/.classpath b/eclipse/build-tools/ant-gwt/.classpath new file mode 100644 index 0000000..727a3f7 --- /dev/null +++ b/eclipse/build-tools/ant-gwt/.classpath
@@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="core/src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/ant-launcher-1.6.5.jar"/> + <classpathentry kind="output" path="bin"/> +</classpath>
diff --git a/eclipse/build-tools/ant-gwt/.project b/eclipse/build-tools/ant-gwt/.project new file mode 100644 index 0000000..5a5195a --- /dev/null +++ b/eclipse/build-tools/ant-gwt/.project
@@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>ant-gwt</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.atlassw.tools.eclipse.checkstyle.CheckstyleBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>com.atlassw.tools.eclipse.checkstyle.CheckstyleNature</nature> + </natures> + <linkedResources> + <link> + <name>core</name> + <type>2</type> + <location>GWT_ROOT/build-tools/ant-gwt</location> + </link> + </linkedResources> +</projectDescription>