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()); } }