You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2022/03/24 10:48:41 UTC

[tomcat] branch main updated: The javadoc needs to be reproducible.

This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/main by this push:
     new 61194ee  The javadoc needs to be reproducible.
61194ee is described below

commit 61194eebde1d5466ddaf48f161623141a14d81a2
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Mar 23 12:52:58 2022 +0000

    The javadoc needs to be reproducible.
    
    Some files generated by Javadoc have platform specific line endings
    The zip files generated by Javadoc are platform specific as well as
    having current last modified times. Re-build the zip files in a
    platform neutral format with fixed last mofified times.
---
 build.xml                                          |  20 +++-
 .../apache/tomcat/buildutil/RepeatableArchive.java | 114 +++++++++++++++++++++
 2 files changed, 133 insertions(+), 1 deletion(-)

diff --git a/build.xml b/build.xml
index 902ade5..a231c17 100644
--- a/build.xml
+++ b/build.xml
@@ -2865,7 +2865,25 @@ skip.installer property in build.properties" />
       <patternset refid="text.files" />
     </fixcrlf>
 
-    <!-- Reproducible builds: consistent timestamps for distributed files -->
+    <!-- Reproducible builds: consistent timestamps for distributed files.   -->
+    <!-- Javadocs need additional processing.                                -->
+    <!-- 1. line endings vary between platforms for some files               -->
+    <!-- 2. The contents of generated zip files don't have fixed timestamps  --> 
+    <!-- Process the zip files first as the resulting zip files will need    -->
+    <!-- the last modified timestamp to be changed as well.                  -->
+    <fixcrlf srcdir="${tomcat.dist}/webapps/docs" eol="lf"
+        encoding="UTF-8" fixlast="false" >
+      <include name="**/*.js" />
+      <include name="**/element-list" />
+    </fixcrlf>
+    <taskdef name="repeatableArchive"
+             classname="org.apache.tomcat.buildutil.RepeatableArchive"
+             classpath="${tomcat.classes}" />
+    <repeatableArchive datetime="${ant.tstamp.now}">
+      <fileset dir="${tomcat.dist}/webapps/docs">
+        <include name="**/*.zip"/>
+      </fileset>
+    </repeatableArchive>
     <touch datetime="${tstamp.file}" pattern="yyyy-MM-dd HH:mm:ss">
       <fileset dir="${tomcat.dist}"/>
     </touch>
diff --git a/java/org/apache/tomcat/buildutil/RepeatableArchive.java b/java/org/apache/tomcat/buildutil/RepeatableArchive.java
new file mode 100644
index 0000000..2997588
--- /dev/null
+++ b/java/org/apache/tomcat/buildutil/RepeatableArchive.java
@@ -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.tomcat.buildutil;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.FileTime;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+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;
+
+/**
+ * Ant task to assist with repeatable builds.
+ * <p>
+ * While originally written to address an issue with Javadoc output, this task
+ * takes a generic approach that could be used with any archive. The task takes
+ * a set of zip (or jar, war etc) files as its input and sets the last modified
+ * time of every file in the archive to be the same as the last modified time
+ * of the archive.
+ */
+public class RepeatableArchive extends Task {
+
+    private final List<FileSet> filesets = new LinkedList<>();
+
+    private long datetime;
+
+    /**
+     * Sets the files to be processed
+     *
+     * @param fs The fileset to be processed.
+     */
+    public void addFileset(FileSet fs) {
+        filesets.add(fs);
+    }
+
+
+    public void setDatetime(long datetime) {
+        this.datetime = datetime;
+    }
+
+
+    @Override
+    public void execute() throws BuildException {
+
+        byte[] buf = new byte[8192];
+        FileTime lastModified = FileTime.fromMillis(datetime);
+
+        for (FileSet fs : filesets) {
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            File basedir = ds.getBasedir();
+            String[] files = ds.getIncludedFiles();
+            for (String file : files) {
+                File archive = new File(basedir, file);
+                File oldArchive = new File(basedir, file + ".old");
+
+                try {
+                    Files.move(archive.toPath(), oldArchive.toPath(), StandardCopyOption.ATOMIC_MOVE);
+
+                    try (ZipFile oldZipFile = new ZipFile(oldArchive);
+                            ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(archive))) {
+
+                        Enumeration<? extends ZipEntry> oldEntries = oldZipFile.entries();
+                        while (oldEntries.hasMoreElements()) {
+                            ZipEntry oldEntry = oldEntries.nextElement();
+
+                            ZipEntry entry = new ZipEntry(oldEntry.getName());
+                            entry.setLastModifiedTime(lastModified);
+
+                            zipOut.putNextEntry(entry);
+
+                            InputStream is = oldZipFile.getInputStream(oldEntry);
+
+                            int numRead;
+                            while ((numRead = is.read(buf)) >= 0) {
+                                zipOut.write(buf, 0, numRead);
+                            }
+                        }
+                    }
+
+                    archive.setLastModified(lastModified.toMillis());
+                    Files.delete(oldArchive.toPath());
+                } catch (IOException ioe) {
+                    throw new BuildException(ioe);
+                }
+            }
+        }
+    }
+}

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org