Resync.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / CPack / cmCPackDebGenerator.cxx
blob00113ac667aadca6c7c3e617b0cb793a0bcd565c
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCPackDebGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2008/01/24 12:31:59 $
7 Version: $Revision: 1.20 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmCPackDebGenerator.h"
19 #include "cmSystemTools.h"
20 #include "cmMakefile.h"
21 #include "cmGeneratedFileStream.h"
22 #include "cmCPackLog.h"
24 #include <cmsys/SystemTools.hxx>
25 #include <cmsys/Glob.hxx>
27 #include <limits.h> // USHRT_MAX
29 // NOTE:
30 // A debian package .deb is simply an 'ar' archive. The only subtle difference
31 // is that debian uses the BSD ar style archive whereas most Linux distro have
32 // a GNU ar.
33 // See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
34 // Therefore we provide our own implementation of a BSD-ar:
35 static int ar_append(const char*archive,const std::vector<std::string>& files);
37 //----------------------------------------------------------------------
38 cmCPackDebGenerator::cmCPackDebGenerator()
42 //----------------------------------------------------------------------
43 cmCPackDebGenerator::~cmCPackDebGenerator()
47 //----------------------------------------------------------------------
48 int cmCPackDebGenerator::InitializeInternal()
50 this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
52 return this->Superclass::InitializeInternal();
55 //----------------------------------------------------------------------
56 int cmCPackDebGenerator::CompressFiles(const char* outFileName,
57 const char* toplevel,
58 const std::vector<std::string>& files)
60 this->ReadListFile("CPackDeb.cmake");
61 const char* cmakeExecutable = this->GetOption("CMAKE_COMMAND");
63 // debian-binary file
64 std::string dbfilename;
65 dbfilename = toplevel;
66 dbfilename += "/debian-binary";
67 { // the scope is needed for cmGeneratedFileStream
68 cmGeneratedFileStream out(dbfilename.c_str());
69 out << "2.0";
70 out << std::endl; // required for valid debian package
73 // control file
74 std::string ctlfilename;
75 ctlfilename = toplevel;
76 ctlfilename += "/control";
78 // debian policy enforce lower case for package name
79 // mandatory entries:
80 std::string debian_pkg_name = cmsys::SystemTools::LowerCase(
81 this->GetOption("CPACK_DEBIAN_PACKAGE_NAME") );
82 const char* debian_pkg_version =
83 this->GetOption("CPACK_DEBIAN_PACKAGE_VERSION");
84 const char* debian_pkg_section =
85 this->GetOption("CPACK_DEBIAN_PACKAGE_SECTION");
86 const char* debian_pkg_priority =
87 this->GetOption("CPACK_DEBIAN_PACKAGE_PRIORITY");
88 const char* debian_pkg_arch =
89 this->GetOption("CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
90 const char* maintainer = this->GetOption("CPACK_DEBIAN_PACKAGE_MAINTAINER");
91 const char* desc = this->GetOption("CPACK_DEBIAN_PACKAGE_DESCRIPTION");
93 // optional entries
94 const char* debian_pkg_dep = this->GetOption("CPACK_DEBIAN_PACKAGE_DEPENDS");
95 const char* debian_pkg_rec =
96 this->GetOption("CPACK_DEBIAN_PACKAGE_RECOMMENDS");
97 const char* debian_pkg_sug =
98 this->GetOption("CPACK_DEBIAN_PACKAGE_SUGGESTS");
100 { // the scope is needed for cmGeneratedFileStream
101 cmGeneratedFileStream out(ctlfilename.c_str());
102 out << "Package: " << debian_pkg_name << "\n";
103 out << "Version: " << debian_pkg_version << "\n";
104 out << "Section: " << debian_pkg_section << "\n";
105 out << "Priority: " << debian_pkg_priority << "\n";
106 out << "Architecture: " << debian_pkg_arch << "\n";
107 if(debian_pkg_dep)
109 out << "Depends: " << debian_pkg_dep << "\n";
111 if(debian_pkg_rec)
113 out << "Recommends: " << debian_pkg_rec << "\n";
115 if(debian_pkg_sug)
117 out << "Suggests: " << debian_pkg_sug << "\n";
119 out << "Maintainer: " << maintainer << "\n";
120 out << "Description: " << desc << "\n";
121 out << std::endl;
124 std::string cmd;
125 cmd = "\"";
126 cmd += cmakeExecutable;
127 cmd += "\" -E tar cfz data.tar.gz ./usr";
128 std::string output;
129 int retVal = -1;
130 int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output,
131 &retVal, toplevel, this->GeneratorVerbose, 0);
133 if ( !res || retVal )
135 std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
136 tmpFile += "/Deb.log";
137 cmGeneratedFileStream ofs(tmpFile.c_str());
138 ofs << "# Run command: " << cmd.c_str() << std::endl
139 << "# Working directory: " << toplevel << std::endl
140 << "# Output:" << std::endl
141 << output.c_str() << std::endl;
142 cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running tar command: "
143 << cmd.c_str() << std::endl
144 << "Please check " << tmpFile.c_str() << " for errors" << std::endl);
145 return 0;
148 std::string md5filename;
149 md5filename = toplevel;
150 md5filename += "/md5sums";
152 { // the scope is needed for cmGeneratedFileStream
153 cmGeneratedFileStream out(md5filename.c_str());
154 std::vector<std::string>::const_iterator fileIt;
155 std::string topLevelWithTrailingSlash = toplevel;
156 topLevelWithTrailingSlash += '/';
157 for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt )
159 cmd = "\"";
160 cmd += cmakeExecutable;
161 cmd += "\" -E md5sum \"";
162 cmd += *fileIt;
163 cmd += "\"";
164 //std::string output;
165 //int retVal = -1;
166 res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output,
167 &retVal, toplevel, this->GeneratorVerbose, 0);
168 // debian md5sums entries are like this:
169 // 014f3604694729f3bf19263bac599765 usr/bin/ccmake
170 // thus strip the full path (with the trailing slash)
171 cmSystemTools::ReplaceString(output,
172 topLevelWithTrailingSlash.c_str(), "");
173 out << output;
175 // each line contains a eol.
176 // Do not end the md5sum file with yet another (invalid)
180 cmd = "\"";
181 cmd += cmakeExecutable;
182 cmd += "\" -E tar cfz control.tar.gz ./control ./md5sums";
183 res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output,
184 &retVal, toplevel, this->GeneratorVerbose, 0);
186 if ( !res || retVal )
188 std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
189 tmpFile += "/Deb.log";
190 cmGeneratedFileStream ofs(tmpFile.c_str());
191 ofs << "# Run command: " << cmd.c_str() << std::endl
192 << "# Working directory: " << toplevel << std::endl
193 << "# Output:" << std::endl
194 << output.c_str() << std::endl;
195 cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running tar command: "
196 << cmd.c_str() << std::endl
197 << "Please check " << tmpFile.c_str() << " for errors" << std::endl);
198 return 0;
201 // ar -r your-package-name.deb debian-binary control.tar.gz data.tar.gz
202 // since debian packages require BSD ar (most Linux distros and even
203 // FreeBSD and NetBSD ship GNU ar) we use a copy of OpenBSD ar here.
204 std::vector<std::string> arFiles;
205 std::string topLevelString = toplevel;
206 topLevelString += "/";
207 arFiles.push_back(topLevelString + "debian-binary");
208 arFiles.push_back(topLevelString + "control.tar.gz");
209 arFiles.push_back(topLevelString + "data.tar.gz");
210 res = ar_append(outFileName, arFiles);
211 if ( res!=0 )
213 std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
214 tmpFile += "/Deb.log";
215 cmGeneratedFileStream ofs(tmpFile.c_str());
216 ofs << "# Problem creating archive using: " << res << std::endl;
217 return 0;
220 return 1;
223 // The following code is taken from OpenBSD ar:
224 // http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ar/
225 // It has been slightly modified:
226 // -return error codes instead exit() in functions
227 // -use the stdio file I/O functions instead the file descriptor based ones
228 // -merged into one cxx file
229 // -no additional options supported
230 // The coding style hasn't been modified.
233 * Copyright (c) 1990, 1993, 1994
234 * The Regents of the University of California. All rights reserved.
236 * This code is derived from software contributed to Berkeley by
237 * Hugh Smith at The University of Guelph.
239 * Redistribution and use in source and binary forms, with or without
240 * modification, are permitted provided that the following conditions
241 * are met:
242 * 1. Redistributions of source code must retain the above copyright
243 * notice, this list of conditions and the following disclaimer.
244 * 2. Redistributions in binary form must reproduce the above copyright
245 * notice, this list of conditions and the following disclaimer in the
246 * documentation and/or other materials provided with the distribution.
247 * 3. Neither the name of the University nor the names of its contributors
248 * may be used to endorse or promote products derived from this software
249 * without specific prior written permission.
251 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
252 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
253 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
254 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
255 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
257 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
258 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
259 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261 * SUCH DAMAGE.
264 #include <sys/types.h>
265 #include <sys/stat.h>
267 #include <stdio.h>
268 #include <string.h>
269 #include <stdlib.h>
271 #define ARMAG "!<arch>\n" /* ar "magic number" */
272 #define SARMAG 8 /* strlen(ARMAG); */
274 #define AR_EFMT1 "#1/" /* extended format #1 */
275 #define ARFMAG "`\n"
277 /* Header format strings. */
278 #define HDR1 "%s%-13d%-12ld%-6u%-6u%-8o%-10lld%2s"
279 #define HDR2 "%-16.16s%-12ld%-6u%-6u%-8o%-10lld%2s"
281 struct ar_hdr {
282 char ar_name[16]; /* name */
283 char ar_date[12]; /* modification time */
284 char ar_uid[6]; /* user id */
285 char ar_gid[6]; /* group id */
286 char ar_mode[8]; /* octal file permissions */
287 char ar_size[10]; /* size in bytes */
288 char ar_fmag[2]; /* consistency check */
291 /* Set up file copy. */
292 #define SETCF(from, fromname, to, toname, pad) { \
293 cf.rFile = from; \
294 cf.rname = fromname; \
295 cf.wFile = to; \
296 cf.wname = toname; \
297 cf.flags = pad; \
300 /* File copy structure. */
301 typedef struct {
302 FILE* rFile; /* read file descriptor */
303 const char *rname; /* read name */
304 FILE* wFile; /* write file descriptor */
305 const char *wname; /* write name */
306 #define NOPAD 0x00 /* don't pad */
307 #define WPAD 0x02 /* pad on writes */
308 unsigned int flags; /* pad flags */
309 } CF;
311 /* misc.c */
313 static const char * ar_rname(const char *path)
315 const char *ind = strrchr(path, '/');
316 return (ind ) ? ind + 1 : path;
319 /* archive.c */
321 typedef struct ar_hdr HDR;
322 static char ar_hb[sizeof(HDR) + 1]; /* real header */
324 static int ar_already_written;
326 /* copy_ar --
327 * Copy size bytes from one file to another - taking care to handle the
328 * extra byte (for odd size files) when reading archives and writing an
329 * extra byte if necessary when adding files to archive. The length of
330 * the object is the long name plus the object itself; the variable
331 * already_written gets set if a long name was written.
333 * The padding is really unnecessary, and is almost certainly a remnant
334 * of early archive formats where the header included binary data which
335 * a PDP-11 required to start on an even byte boundary. (Or, perhaps,
336 * because 16-bit word addressed copies were faster?) Anyhow, it should
337 * have been ripped out long ago.
339 static int copy_ar(CF *cfp, off_t size)
341 static char pad = '\n';
342 off_t sz = size;
343 size_t nr, nw;
344 char buf[8*1024];
346 if (sz == 0)
347 return 0;
349 FILE* from = cfp->rFile;
350 FILE* to = cfp->wFile;
351 while (sz &&
352 (nr = fread(buf, 1, sz < static_cast<off_t>(sizeof(buf))
353 ? static_cast<size_t>(sz) : sizeof(buf), from ))
354 > 0) {
355 sz -= nr;
356 for (size_t off = 0; off < nr; nr -= off, off += nw)
357 if ((nw = fwrite(buf + off, 1, nr, to)) < nr)
358 return -1;
360 if (sz)
361 return -2;
363 if (cfp->flags & WPAD && (size + ar_already_written) & 1
364 && fwrite(&pad, 1, 1, to) != 1)
365 return -4;
367 return 0;
370 /* put_arobj -- Write an archive member to a file. */
371 static int put_arobj(CF *cfp, struct stat *sb)
373 int result = 0;
374 struct ar_hdr *hdr;
376 /* If passed an sb structure, reading a file from disk. Get stat(2)
377 * information, build a name and construct a header. (Files are named
378 * by their last component in the archive.) */
379 const char* name = ar_rname(cfp->rname);
380 (void)stat(cfp->rname, sb);
382 /* If not truncating names and the name is too long or contains
383 * a space, use extended format 1. */
384 unsigned int lname = strlen(name);
385 uid_t uid = sb->st_uid;
386 gid_t gid = sb->st_gid;
387 if (uid > USHRT_MAX) {
388 uid = USHRT_MAX;
390 if (gid > USHRT_MAX) {
391 gid = USHRT_MAX;
393 if (lname > sizeof(hdr->ar_name) || strchr(name, ' '))
394 (void)sprintf(ar_hb, HDR1, AR_EFMT1, lname,
395 (long int)sb->st_mtime, uid, gid, sb->st_mode,
396 (long long)sb->st_size + lname, ARFMAG);
397 else {
398 lname = 0;
399 (void)sprintf(ar_hb, HDR2, name,
400 (long int)sb->st_mtime, uid, gid, sb->st_mode,
401 (long long)sb->st_size, ARFMAG);
403 off_t size = sb->st_size;
405 if (fwrite(ar_hb, 1, sizeof(HDR), cfp->wFile) != sizeof(HDR))
406 return -1;
408 if (lname) {
409 if (fwrite(name, 1, lname, cfp->wFile) != lname)
410 return -2;
411 ar_already_written = lname;
413 result = copy_ar(cfp, size);
414 ar_already_written = 0;
415 return result;
418 /* append.c */
420 /* append --
421 * Append files to the archive - modifies original archive or creates
422 * a new archive if named archive does not exist.
424 static int ar_append(const char* archive,const std::vector<std::string>& files)
426 int eval = 0;
427 FILE* aFile = fopen(archive, "wb+");
428 if (aFile!=NULL) {
429 fwrite(ARMAG, SARMAG, 1, aFile);
430 if (fseek(aFile, 0, SEEK_END) != -1) {
431 CF cf;
432 struct stat sb;
433 /* Read from disk, write to an archive; pad on write. */
434 SETCF(NULL, 0, aFile, archive, WPAD);
435 for(std::vector<std::string>::const_iterator fileIt = files.begin();
436 fileIt!=files.end(); ++fileIt) {
437 const char* filename = fileIt->c_str();
438 FILE* file = fopen(filename, "rb");
439 if (file == NULL) {
440 eval = -1;
441 continue;
443 cf.rFile = file;
444 cf.rname = filename;
445 int result = put_arobj(&cf, &sb);
446 (void)fclose(file);
447 if (result!=0) {
448 eval = -2;
449 break;
453 else {
454 eval = -3;
456 fclose(aFile);
458 else {
459 eval = -4;
461 return eval;