001: package de.masters_of_disaster.ant.tasks.deb;
002:
003: import de.masters_of_disaster.ant.tasks.ar.Ar;
004: import de.masters_of_disaster.ant.tasks.ar.Ar.ArFileSet;
005: import java.io.File;
006: import java.util.Enumeration;
007: import java.util.Vector;
008: import org.apache.tools.ant.BuildException;
009: import org.apache.tools.ant.Project;
010: import org.apache.tools.ant.Task;
011: import org.apache.tools.ant.taskdefs.Checksum;
012: import org.apache.tools.ant.taskdefs.Echo;
013: import org.apache.tools.ant.taskdefs.Echo.EchoLevel;
014: import org.apache.tools.ant.taskdefs.Mkdir;
015: import org.apache.tools.ant.taskdefs.MatchingTask;
016: import org.apache.tools.ant.taskdefs.Tar;
017: import org.apache.tools.ant.taskdefs.Tar.TarCompressionMethod;
018: import org.apache.tools.ant.taskdefs.Tar.TarFileSet;
019: import org.apache.tools.ant.util.FileUtils;
020: import org.apache.tools.ant.util.MergingMapper;
021: import org.apache.tools.ant.util.SourceFileScanner;
022:
023: /**
024: * Creates a deb package.
025: *
026: * @ant.task category="packaging"
027: */
028: public class Deb extends MatchingTask {
029: Vector controlFileSets = new Vector();
030: Vector dataFileSets = new Vector();
031: File baseDir;
032: File destFile;
033: File tempDir;
034: boolean deleteTempFiles = true;
035: boolean includeMd5sums = false;
036: Tar controlTarGz = new Tar();
037: Tar dataTarGz = new Tar();
038: Ar debPackage = new Ar();
039:
040: {
041: fileset = dataTarGz.createTarFileSet();
042: }
043:
044: /**
045: * Add a new fileset for the control files with the option to specify permissions
046: *
047: * @return the tar fileset to be used as the nested element.
048: */
049: public TarFileSet createControlFileSet() {
050: TarFileSet fileSet = controlTarGz.createTarFileSet();
051: controlFileSets.addElement(fileSet);
052: return fileSet;
053: }
054:
055: /**
056: * Add a new fileset for the data files with the option to specify permissions
057: *
058: * @return the tar fileset to be used as the nested element.
059: */
060: public TarFileSet createDataFileSet() {
061: TarFileSet fileSet = dataTarGz.createTarFileSet();
062: dataFileSets.addElement(fileSet);
063: return fileSet;
064: }
065:
066: /**
067: * Set the name/location of where to create the deb file.
068: *
069: * @param destFile The output of the deb
070: */
071: public void setDestFile(File destFile) {
072: this .destFile = destFile;
073: debPackage.setDestFile(destFile);
074: }
075:
076: /**
077: * This is the base directory to look in for things to include in the data files.
078: *
079: * @param baseDir the base directory.
080: */
081: public void setBaseDir(File baseDir) {
082: this .baseDir = baseDir;
083: fileset.setDir(baseDir);
084: }
085:
086: /**
087: * This is the temp directory where to create the temporary files.
088: * If not set, the current projects baseDir is used.
089: *
090: * @param tempDir the temp directory.
091: */
092: public void setTempDir(File tempDir) {
093: this .tempDir = tempDir;
094: }
095:
096: /**
097: * This specifies if the temporary files should get deleted.
098: *
099: * @param deleteTempFiles whether to delete the temporary files or not.
100: */
101: public void setDeleteTempFiles(boolean deleteTempFiles) {
102: this .deleteTempFiles = deleteTempFiles;
103: }
104:
105: /**
106: * This specifies if the MD5 sums of the files in the data section should be
107: * included in the file "md5sums" in the control section.
108: *
109: * @param includeMd5sums whether to include MD5 sums in the control section or not.
110: */
111: public void setIncludeMd5sums(boolean includeMd5sums) {
112: this .includeMd5sums = includeMd5sums;
113: }
114:
115: /**
116: * do the business
117: *
118: * @throws BuildException on error
119: */
120: public void execute() throws BuildException {
121: prepareTask(controlTarGz);
122: prepareTask(dataTarGz);
123: prepareTask(debPackage);
124: TarFileSet tarFileSet = controlTarGz.createTarFileSet();
125: tarFileSet.setFile(new File(System.getProperty("user.dir")));
126: tarFileSet.setUserName("root");
127: tarFileSet.setGroup("root");
128: tarFileSet.setFullpath("./");
129: tarFileSet = dataTarGz.createTarFileSet();
130: tarFileSet.setFile(new File(System.getProperty("user.dir")));
131: tarFileSet.setUserName("root");
132: tarFileSet.setGroup("root");
133: tarFileSet.setFullpath("./");
134:
135: if (null == tempDir) {
136: tempDir = getProject().getBaseDir();
137: }
138:
139: if (null != baseDir) {
140: // add the main fileset to the list of filesets to process.
141: dataFileSets.addElement(fileset);
142: } else {
143: fileset.setDir(new File(System.getProperty("user.dir")));
144: fileset.setExcludes("**");
145: }
146:
147: boolean controlFound = false;
148: for (Enumeration e = controlFileSets.elements(); e
149: .hasMoreElements();) {
150: TarFileSet fileSet = (TarFileSet) e.nextElement();
151: String[] files = fileSet.getFiles(getProject());
152: int i = 0;
153: int c;
154:
155: for (c = files.length; i < c && !controlFound; i++) {
156: if (files[i].endsWith("control")
157: && (new File(fileSet.getDir(getProject()),
158: files[i])).isFile()) {
159: controlFound = true;
160: }
161: }
162: }
163: if (!controlFound) {
164: throw new BuildException(
165: "The control fileset must contain a file \"control\"",
166: getLocation());
167: }
168:
169: // check if deb is out of date with respect to each fileset
170: boolean upToDate = true;
171: for (Enumeration e = controlFileSets.elements(); e
172: .hasMoreElements();) {
173: TarFileSet fileSet = (TarFileSet) e.nextElement();
174: String[] files = fileSet.getFiles(getProject());
175:
176: if (!packageIsUpToDate(files, fileSet.getDir(getProject()))) {
177: upToDate = false;
178: }
179: }
180:
181: for (Enumeration e = dataFileSets.elements(); e
182: .hasMoreElements();) {
183: TarFileSet fileSet = (TarFileSet) e.nextElement();
184: String[] files = fileSet.getFiles(getProject());
185:
186: if (!packageIsUpToDate(files, fileSet.getDir(getProject()))) {
187: upToDate = false;
188: }
189: }
190:
191: if (upToDate) {
192: log("Nothing to do: " + destFile.getAbsolutePath()
193: + " is up to date.", Project.MSG_INFO);
194: return;
195: }
196:
197: log("Building deb: " + destFile.getAbsolutePath(),
198: Project.MSG_INFO);
199:
200: Mkdir mkdir = new Mkdir();
201: prepareTask(mkdir);
202: mkdir.setDir(tempDir);
203: mkdir.perform();
204:
205: Echo echo = new Echo();
206: prepareTask(echo);
207: EchoLevel echoLevel = new EchoLevel();
208: echoLevel.setValue("error");
209: File debianBinaryFile = new File(tempDir, "debian-binary");
210: echo.setFile(debianBinaryFile);
211: echo.setLevel(echoLevel);
212: echo.setMessage("2.0\n");
213: echo.perform();
214:
215: for (Enumeration e = controlFileSets.elements(); e
216: .hasMoreElements();) {
217: TarFileSet fileSet = (TarFileSet) e.nextElement();
218: String prefix = fileSet.getPrefix();
219: String fullpath = fileSet.getFullpath();
220: if ("".equals(fullpath) && !prefix.startsWith("./")) {
221: if (prefix.startsWith("/")) {
222: fileSet.setPrefix("." + prefix);
223: } else {
224: fileSet.setPrefix("./" + prefix);
225: }
226: }
227: if ((fullpath.length() > 0) && !fullpath.startsWith("./")) {
228: fileSet.setPrefix("");
229: if (fullpath.startsWith("/")) {
230: fileSet.setFullpath("." + fullpath);
231: } else {
232: fileSet.setFullpath("./" + fullpath);
233: }
234: }
235: if ((0 == fileSet.getUid())
236: && ("" == fileSet.getUserName())) {
237: fileSet.setUserName("root");
238: }
239: if ((0 == fileSet.getGid()) && ("" == fileSet.getGroup())) {
240: fileSet.setGroup("root");
241: }
242: }
243:
244: for (Enumeration e = dataFileSets.elements(); e
245: .hasMoreElements();) {
246: TarFileSet fileSet = (TarFileSet) e.nextElement();
247: String prefix = fileSet.getPrefix();
248: String fullpath = fileSet.getFullpath();
249: if ("".equals(fullpath) && !prefix.startsWith("./")) {
250: if (prefix.startsWith("/")) {
251: fileSet.setPrefix("." + prefix);
252: } else {
253: fileSet.setPrefix("./" + prefix);
254: }
255: }
256: if ((fullpath.length() > 0) && !fullpath.startsWith("./")) {
257: fileSet.setPrefix("");
258: if (fullpath.startsWith("/")) {
259: fileSet.setFullpath("." + fullpath);
260: } else {
261: fileSet.setFullpath("./" + fullpath);
262: }
263: }
264: if ((0 == fileSet.getUid())
265: && ("" == fileSet.getUserName())) {
266: fileSet.setUserName("root");
267: }
268: if ((0 == fileSet.getGid()) && ("" == fileSet.getGroup())) {
269: fileSet.setGroup("root");
270: }
271: }
272:
273: File md5sumsFile = new File(tempDir, "md5sums");
274: if (includeMd5sums) {
275: Checksum md5 = new Checksum();
276: prepareTask(md5);
277: int md5Count = 0;
278: StringBuffer md5sums = new StringBuffer();
279: for (Enumeration e = dataFileSets.elements(); e
280: .hasMoreElements();) {
281: TarFileSet fileSet = (TarFileSet) e.nextElement();
282: String[] files = fileSet.getDirectoryScanner(
283: getProject()).getIncludedFiles();
284: File fileSetDir = fileSet.getDir(getProject());
285: for (int i = 0, c = files.length; i < c; i++) {
286: md5.setFile(new File(fileSetDir, files[i]));
287: md5.setProperty("md5_" + md5Count);
288: md5.perform();
289: md5sums
290: .append(
291: getProject().getProperty(
292: "md5_" + md5Count)).append(
293: " ");
294: String fullpath = fileSet.getFullpath();
295: if (fullpath.length() > 0) {
296: md5sums.append(fullpath.substring(2));
297: } else {
298: md5sums
299: .append(
300: fileSet.getPrefix()
301: .substring(2)).append(
302: files[i].replace('\\', '/'));
303: }
304: md5sums.append("\n");
305: md5Count++;
306: }
307: }
308: echo.setFile(md5sumsFile);
309: echo.setMessage(md5sums.toString());
310: echo.perform();
311: tarFileSet = controlTarGz.createTarFileSet();
312: tarFileSet.setFile(md5sumsFile);
313: tarFileSet.setUserName("root");
314: tarFileSet.setGroup("root");
315: tarFileSet.setPrefix("./");
316: }
317:
318: TarCompressionMethod tarCompressionMethod = new TarCompressionMethod();
319: tarCompressionMethod.setValue("gzip");
320: controlTarGz.setCompression(tarCompressionMethod);
321: File controlTarGzFile = new File(tempDir, "control.tar.gz");
322: controlTarGz.setDestFile(controlTarGzFile);
323: controlTarGz.perform();
324:
325: dataTarGz.setCompression(tarCompressionMethod);
326: File dataTarGzFile = new File(tempDir, "data.tar.gz");
327: dataTarGz.setDestFile(dataTarGzFile);
328: dataTarGz.perform();
329:
330: FileUtils.delete(destFile);
331: ArFileSet fileSet = debPackage.createArFileSet();
332: fileSet.setFile(debianBinaryFile);
333: fileSet = debPackage.createArFileSet();
334: fileSet.setFile(controlTarGzFile);
335: fileSet = debPackage.createArFileSet();
336: fileSet.setFile(dataTarGzFile);
337: debPackage.perform();
338:
339: if (deleteTempFiles) {
340: FileUtils.delete(debianBinaryFile);
341: FileUtils.delete(controlTarGzFile);
342: FileUtils.delete(dataTarGzFile);
343: FileUtils.delete(md5sumsFile);
344: }
345: }
346:
347: /**
348: * Checks whether the package is up to date in relationship to a list of files.
349: *
350: * @param files the files to check
351: * @param dir the base directory for the files.
352: * @return true if the archive is up to date.
353: */
354: protected boolean packageIsUpToDate(String[] files, File dir) {
355: SourceFileScanner sfs = new SourceFileScanner(this );
356: MergingMapper mm = new MergingMapper();
357: mm.setTo(destFile.getAbsolutePath());
358: return sfs.restrict(files, dir, null, mm).length == 0;
359: }
360:
361: /**
362: * Prepares a task for execution.
363: *
364: * @param task the task to prepare
365: */
366: protected void prepareTask(Task task) {
367: task.setProject(getProject());
368: task.setOwningTarget(getOwningTarget());
369: task.setTaskName(getTaskName());
370: task.setTaskType(getTaskType());
371: }
372: }
|