diff lib/mod/src/de/masters_of_disaster/ant/tasks/deb/Deb.java @ 33:3d86f0391168

Work on improving the build system.
author David Barts <davidb@stashtea.com>
date Fri, 24 Apr 2020 19:45:57 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/mod/src/de/masters_of_disaster/ant/tasks/deb/Deb.java	Fri Apr 24 19:45:57 2020 -0700
@@ -0,0 +1,354 @@
+package de.masters_of_disaster.ant.tasks.deb;
+
+import de.masters_of_disaster.ant.tasks.ar.Ar;
+import de.masters_of_disaster.ant.tasks.ar.Ar.ArFileSet;
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Checksum;
+import org.apache.tools.ant.taskdefs.Echo;
+import org.apache.tools.ant.taskdefs.Echo.EchoLevel;
+import org.apache.tools.ant.taskdefs.Mkdir;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.Tar;
+import org.apache.tools.ant.taskdefs.Tar.TarCompressionMethod;
+import org.apache.tools.ant.taskdefs.Tar.TarFileSet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.MergingMapper;
+import org.apache.tools.ant.util.SourceFileScanner;
+
+/**
+ * Creates a deb package.
+ *
+ * @ant.task category="packaging"
+ */
+public class Deb extends MatchingTask {
+    Vector controlFileSets = new Vector();
+    Vector dataFileSets = new Vector();
+    File baseDir;
+    File destFile;
+    File tempDir;
+    boolean deleteTempFiles = true;
+    boolean includeMd5sums = false;
+    Tar controlTarGz = new Tar();
+    Tar dataTarGz = new Tar();
+    Ar debPackage = new Ar();
+
+    {
+        fileset = dataTarGz.createTarFileSet();
+    }
+
+    /**
+     * Add a new fileset for the control files with the option to specify permissions
+     * 
+     * @return the tar fileset to be used as the nested element.
+     */
+    public TarFileSet createControlFileSet() {
+        TarFileSet fileSet = controlTarGz.createTarFileSet();
+        controlFileSets.addElement(fileSet);
+        return fileSet;
+    }
+
+    /**
+     * Add a new fileset for the data files with the option to specify permissions
+     * 
+     * @return the tar fileset to be used as the nested element.
+     */
+    public TarFileSet createDataFileSet() {
+        TarFileSet fileSet = dataTarGz.createTarFileSet();
+        dataFileSets.addElement(fileSet);
+        return fileSet;
+    }
+
+    /**
+     * Set the name/location of where to create the deb file.
+     * 
+     * @param destFile The output of the deb
+     */
+    public void setDestFile(File destFile) {
+        this.destFile = destFile;
+        debPackage.setDestFile(destFile);
+    }
+
+    /**
+     * This is the base directory to look in for things to include in the data files.
+     * 
+     * @param baseDir the base directory.
+     */
+    public void setBaseDir(File baseDir) {
+        this.baseDir = baseDir;
+        fileset.setDir(baseDir);
+    }
+
+    /**
+     * This is the temp directory where to create the temporary files.
+     * If not set, the current projects baseDir is used.
+     * 
+     * @param tempDir the temp directory.
+     */
+    public void setTempDir(File tempDir) {
+        this.tempDir = tempDir;
+    }
+
+    /**
+     * This specifies if the temporary files should get deleted.
+     * 
+     * @param deleteTempFiles whether to delete the temporary files or not.
+     */
+    public void setDeleteTempFiles(boolean deleteTempFiles) {
+        this.deleteTempFiles = deleteTempFiles;
+    }
+
+    /**
+     * This specifies if the MD5 sums of the files in the data section should be
+     * included in the file "md5sums" in the control section.
+     * 
+     * @param includeMd5sums whether to include MD5 sums in the control section or not.
+     */
+    public void setIncludeMd5sums(boolean includeMd5sums) {
+        this.includeMd5sums = includeMd5sums;
+    }
+
+    /**
+     * do the business
+     * 
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        prepareTask(controlTarGz);
+        prepareTask(dataTarGz);
+        prepareTask(debPackage);
+        TarFileSet tarFileSet = controlTarGz.createTarFileSet();
+        tarFileSet.setFile(new File(System.getProperty("user.dir")));
+        tarFileSet.setUserName("root");
+        tarFileSet.setGroup("root");
+        tarFileSet.setFullpath("./");
+        tarFileSet = dataTarGz.createTarFileSet();
+        tarFileSet.setFile(new File(System.getProperty("user.dir")));
+        tarFileSet.setUserName("root");
+        tarFileSet.setGroup("root");
+        tarFileSet.setFullpath("./");
+
+        if (null == tempDir) {
+            tempDir = getProject().getBaseDir();
+        }
+
+        if (null != baseDir) {
+            // add the main fileset to the list of filesets to process.
+            dataFileSets.addElement(fileset);
+        } else {
+            fileset.setDir(new File(System.getProperty("user.dir")));
+            fileset.setExcludes("**");
+        }
+
+        boolean controlFound = false;
+        for (Enumeration e=controlFileSets.elements() ; e.hasMoreElements() ; ) {
+            TarFileSet fileSet = (TarFileSet)e.nextElement();
+            String[] files = fileSet.getFiles(getProject());
+            int i = 0;
+            int c;
+
+            for (c=files.length ; i<c && !controlFound ; i++) {
+                if (files[i].endsWith("control")
+                      && (new File(fileSet.getDir(getProject()),files[i])).isFile()) {
+                    controlFound = true;
+                }
+            }
+        }
+        if (!controlFound) {
+            throw new BuildException("The control fileset must contain a file \"control\"", getLocation());
+        }
+
+        // check if deb is out of date with respect to each fileset
+        boolean upToDate = true;
+        for (Enumeration e=controlFileSets.elements() ; e.hasMoreElements() ; ) {
+            TarFileSet fileSet = (TarFileSet)e.nextElement();
+            String[] files = fileSet.getFiles(getProject());
+
+            if (!packageIsUpToDate(files,fileSet.getDir(getProject()))) {
+                upToDate = false;
+            }
+        }
+
+        for (Enumeration e=dataFileSets.elements() ; e.hasMoreElements() ; ) {
+            TarFileSet fileSet = (TarFileSet)e.nextElement();
+            String[] files = fileSet.getFiles(getProject());
+
+            if (!packageIsUpToDate(files,fileSet.getDir(getProject()))) {
+                upToDate = false;
+            }
+        }
+
+        if (upToDate) {
+            log("Nothing to do: " + destFile.getAbsolutePath()
+                + " is up to date.", Project.MSG_INFO);
+            return;
+        }
+
+        log("Building deb: " + destFile.getAbsolutePath(), Project.MSG_INFO);
+
+        Mkdir mkdir = new Mkdir();
+        prepareTask(mkdir);
+        mkdir.setDir(tempDir);
+        mkdir.perform();
+
+        EchoLevel echoLevel = new EchoLevel();
+        echoLevel.setValue("error");
+        File debianBinaryFile = new File(tempDir,"debian-binary");
+        Echo echo = new Echo();
+        prepareTask(echo);
+        echo.setFile(debianBinaryFile);
+        echo.setLevel(echoLevel);
+        echo.setMessage("2.0\n");
+        echo.perform();
+
+        for (Enumeration e=controlFileSets.elements() ; e.hasMoreElements() ; ) {
+            TarFileSet fileSet = (TarFileSet)e.nextElement();
+            String prefix = fileSet.getPrefix();
+            String fullpath = fileSet.getFullpath();
+            if ("".equals(fullpath) && !prefix.startsWith("./")) {
+                if (prefix.startsWith("/")) {
+                    fileSet.setPrefix("." + prefix);
+                } else {
+                    fileSet.setPrefix("./" + prefix);
+                }
+            }
+            if ((fullpath.length() > 0) && !fullpath.startsWith("./")) {
+                fileSet.setPrefix("");
+                if (fullpath.startsWith("/")) {
+                    fileSet.setFullpath("." + fullpath);
+                } else {
+                    fileSet.setFullpath("./" + fullpath);
+                }
+            }
+            if ((0 == fileSet.getUid()) && ("" == fileSet.getUserName())) {
+                fileSet.setUserName("root");
+            }
+            if ((0 == fileSet.getGid()) && ("" == fileSet.getGroup())) {
+                fileSet.setGroup("root");
+            }
+        }
+
+        for (Enumeration e=dataFileSets.elements() ; e.hasMoreElements() ; ) {
+            TarFileSet fileSet = (TarFileSet)e.nextElement();
+            String prefix = fileSet.getPrefix();
+            String fullpath = fileSet.getFullpath();
+            if ("".equals(fullpath) && !prefix.startsWith("./")) {
+                if (prefix.startsWith("/")) {
+                    fileSet.setPrefix("." + prefix);
+                } else {
+                    fileSet.setPrefix("./" + prefix);
+                }
+            }
+            if ((fullpath.length() > 0) && !fullpath.startsWith("./")) {
+                fileSet.setPrefix("");
+                if (fullpath.startsWith("/")) {
+                    fileSet.setFullpath("." + fullpath);
+                } else {
+                    fileSet.setFullpath("./" + fullpath);
+                }
+            }
+            if ((0 == fileSet.getUid()) && ("" == fileSet.getUserName())) {
+                fileSet.setUserName("root");
+            }
+            if ((0 == fileSet.getGid()) && ("" == fileSet.getGroup())) {
+                fileSet.setGroup("root");
+            }
+        }
+
+        File md5sumsFile = new File(tempDir,"md5sums");
+        if (includeMd5sums) {
+            Checksum md5 = new Checksum();
+            prepareTask(md5);
+            int md5Count = 0;
+            StringBuffer md5sums = new StringBuffer();
+            for (Enumeration e=dataFileSets.elements() ; e.hasMoreElements() ; ) {
+                TarFileSet fileSet = (TarFileSet)e.nextElement();
+                String[] files = fileSet.getDirectoryScanner(getProject()).getIncludedFiles();
+                File fileSetDir = fileSet.getDir(getProject());
+                for (int i=0, c=files.length ; i<c ; i++) {
+                    md5.setFile(new File(fileSetDir,files[i]));
+                    md5.setProperty("md5_"+md5Count);
+                    md5.perform();
+                    md5sums.append(getProject().getProperty("md5_"+md5Count)).append("  ");
+                    String fullpath = fileSet.getFullpath();
+                    if (fullpath.length() > 0) {
+                        md5sums.append(fullpath.substring(2));
+                    } else {
+                        md5sums.append(fileSet.getPrefix().substring(2)).append(files[i].replace('\\','/'));
+                    }
+                    md5sums.append("\n");
+                    md5Count++;
+                }
+            }
+            echo = new Echo();
+            prepareTask(echo);
+            echo.setFile(md5sumsFile);
+            echo.setLevel(echoLevel);
+            echo.setMessage(md5sums.toString());
+            echo.perform();
+            tarFileSet = controlTarGz.createTarFileSet();
+            tarFileSet.setFile(md5sumsFile);
+            tarFileSet.setUserName("root");
+            tarFileSet.setGroup("root");
+            tarFileSet.setPrefix("./");
+        }
+
+        TarCompressionMethod tarCompressionMethod = new TarCompressionMethod();
+        tarCompressionMethod.setValue("gzip");
+        controlTarGz.setCompression(tarCompressionMethod);
+        File controlTarGzFile = new File(tempDir,"control.tar.gz");
+        controlTarGz.setDestFile(controlTarGzFile);
+        controlTarGz.perform();
+
+        dataTarGz.setCompression(tarCompressionMethod);
+        File dataTarGzFile = new File(tempDir,"data.tar.gz");
+        dataTarGz.setDestFile(dataTarGzFile);
+        dataTarGz.perform();
+
+        FileUtils.delete(destFile);
+        ArFileSet fileSet = debPackage.createArFileSet();
+        fileSet.setFile(debianBinaryFile);
+        fileSet = debPackage.createArFileSet();
+        fileSet.setFile(controlTarGzFile);
+        fileSet = debPackage.createArFileSet();
+        fileSet.setFile(dataTarGzFile);
+        debPackage.perform();
+
+        if (deleteTempFiles) {
+            FileUtils.delete(debianBinaryFile);
+            FileUtils.delete(controlTarGzFile);
+            FileUtils.delete(dataTarGzFile);
+            FileUtils.delete(md5sumsFile);
+        }
+    }
+
+    /**
+     * Checks whether the package is up to date in relationship to a list of files.
+     * 
+     * @param files the files to check
+     * @param dir   the base directory for the files.
+     * @return true if the archive is up to date.
+     */
+    protected boolean packageIsUpToDate(String[] files, File dir) {
+        SourceFileScanner sfs = new SourceFileScanner(this);
+        MergingMapper mm = new MergingMapper();
+        mm.setTo(destFile.getAbsolutePath());
+        return sfs.restrict(files, dir, null, mm).length == 0;
+    }
+
+    /**
+     * Prepares a task for execution.
+     * 
+     * @param task the task to prepare
+     */
+    protected void prepareTask(Task task) {
+        task.setProject(getProject());
+        task.setOwningTarget(getOwningTarget());
+        task.setTaskName(getTaskName());
+        task.setTaskType(getTaskType());
+    }
+}