cmCPackArchiveGenerator.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmCPackArchiveGenerator.h"
  11. #include "cmCPackLog.h"
  12. #include "cmGeneratedFileStream.h"
  13. #include "cmGlobalGenerator.h"
  14. #include "cmMakefile.h"
  15. #include "cmSystemTools.h"
  16. #include "cmake.h"
  17. #include <errno.h>
  18. #include <cm_libarchive.h>
  19. #include <cmsys/Directory.hxx>
  20. #include <cmsys/SystemTools.hxx>
  21. cmCPackArchiveGenerator::cmCPackArchiveGenerator(cmArchiveWrite::Compress t,
  22. std::string const& format)
  23. {
  24. this->Compress = t;
  25. this->ArchiveFormat = format;
  26. }
  27. cmCPackArchiveGenerator::~cmCPackArchiveGenerator()
  28. {
  29. }
  30. int cmCPackArchiveGenerator::InitializeInternal()
  31. {
  32. this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1");
  33. return this->Superclass::InitializeInternal();
  34. }
  35. int cmCPackArchiveGenerator::addOneComponentToArchive(
  36. cmArchiveWrite& archive, cmCPackComponent* component)
  37. {
  38. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  39. " - packaging component: " << component->Name << std::endl);
  40. // Add the files of this component to the archive
  41. std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
  42. localToplevel += "/" + component->Name;
  43. std::string dir = cmSystemTools::GetCurrentWorkingDirectory();
  44. // Change to local toplevel
  45. cmSystemTools::ChangeDirectory(localToplevel);
  46. std::string filePrefix;
  47. if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
  48. filePrefix = this->GetOption("CPACK_PACKAGE_FILE_NAME");
  49. filePrefix += "/";
  50. }
  51. const char* installPrefix =
  52. this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
  53. if (installPrefix && installPrefix[0] == '/' && installPrefix[1] != 0) {
  54. // add to file prefix and remove the leading '/'
  55. filePrefix += installPrefix + 1;
  56. filePrefix += "/";
  57. }
  58. std::vector<std::string>::const_iterator fileIt;
  59. for (fileIt = component->Files.begin(); fileIt != component->Files.end();
  60. ++fileIt) {
  61. std::string rp = filePrefix + *fileIt;
  62. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file: " << rp << std::endl);
  63. archive.Add(rp, 0, CM_NULLPTR, false);
  64. if (!archive) {
  65. cmCPackLogger(cmCPackLog::LOG_ERROR, "ERROR while packaging files: "
  66. << archive.GetError() << std::endl);
  67. return 0;
  68. }
  69. }
  70. // Go back to previous dir
  71. cmSystemTools::ChangeDirectory(dir);
  72. return 1;
  73. }
  74. /*
  75. * The macro will open/create a file 'filename'
  76. * an declare and open the associated
  77. * cmArchiveWrite 'archive' object.
  78. */
  79. #define DECLARE_AND_OPEN_ARCHIVE(filename, archive) \
  80. cmGeneratedFileStream gf; \
  81. gf.Open(filename.c_str(), false, true); \
  82. if (!GenerateHeader(&gf)) { \
  83. cmCPackLogger(cmCPackLog::LOG_ERROR, \
  84. "Problem to generate Header for archive < " \
  85. << filename << ">." << std::endl); \
  86. return 0; \
  87. } \
  88. cmArchiveWrite archive(gf, this->Compress, this->ArchiveFormat); \
  89. if (!archive) { \
  90. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem to create archive < " \
  91. << filename << ">. ERROR =" << archive.GetError() \
  92. << std::endl); \
  93. return 0; \
  94. }
  95. int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
  96. {
  97. packageFileNames.clear();
  98. // The default behavior is to have one package by component group
  99. // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
  100. if (!ignoreGroup) {
  101. std::map<std::string, cmCPackComponentGroup>::iterator compGIt;
  102. for (compGIt = this->ComponentGroups.begin();
  103. compGIt != this->ComponentGroups.end(); ++compGIt) {
  104. cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: "
  105. << compGIt->first << std::endl);
  106. // Begin the archive for this group
  107. std::string packageFileName = std::string(toplevel);
  108. packageFileName += "/" +
  109. GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"),
  110. compGIt->first, true) +
  111. this->GetOutputExtension();
  112. // open a block in order to automatically close archive
  113. // at the end of the block
  114. {
  115. DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
  116. // now iterate over the component of this group
  117. std::vector<cmCPackComponent*>::iterator compIt;
  118. for (compIt = (compGIt->second).Components.begin();
  119. compIt != (compGIt->second).Components.end(); ++compIt) {
  120. // Add the files of this component to the archive
  121. addOneComponentToArchive(archive, *compIt);
  122. }
  123. }
  124. // add the generated package to package file names list
  125. packageFileNames.push_back(packageFileName);
  126. }
  127. // Handle Orphan components (components not belonging to any groups)
  128. std::map<std::string, cmCPackComponent>::iterator compIt;
  129. for (compIt = this->Components.begin(); compIt != this->Components.end();
  130. ++compIt) {
  131. // Does the component belong to a group?
  132. if (compIt->second.Group == CM_NULLPTR) {
  133. cmCPackLogger(
  134. cmCPackLog::LOG_VERBOSE, "Component <"
  135. << compIt->second.Name
  136. << "> does not belong to any group, package it separately."
  137. << std::endl);
  138. std::string localToplevel(
  139. this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
  140. std::string packageFileName = std::string(toplevel);
  141. localToplevel += "/" + compIt->first;
  142. packageFileName += "/" + GetComponentPackageFileName(
  143. this->GetOption("CPACK_PACKAGE_FILE_NAME"),
  144. compIt->first, false) +
  145. this->GetOutputExtension();
  146. {
  147. DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
  148. // Add the files of this component to the archive
  149. addOneComponentToArchive(archive, &(compIt->second));
  150. }
  151. // add the generated package to package file names list
  152. packageFileNames.push_back(packageFileName);
  153. }
  154. }
  155. }
  156. // CPACK_COMPONENTS_IGNORE_GROUPS is set
  157. // We build 1 package per component
  158. else {
  159. std::map<std::string, cmCPackComponent>::iterator compIt;
  160. for (compIt = this->Components.begin(); compIt != this->Components.end();
  161. ++compIt) {
  162. std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
  163. std::string packageFileName = std::string(toplevel);
  164. localToplevel += "/" + compIt->first;
  165. packageFileName += "/" +
  166. GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"),
  167. compIt->first, false) +
  168. this->GetOutputExtension();
  169. {
  170. DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
  171. // Add the files of this component to the archive
  172. addOneComponentToArchive(archive, &(compIt->second));
  173. }
  174. // add the generated package to package file names list
  175. packageFileNames.push_back(packageFileName);
  176. }
  177. }
  178. return 1;
  179. }
  180. int cmCPackArchiveGenerator::PackageComponentsAllInOne()
  181. {
  182. // reset the package file names
  183. packageFileNames.clear();
  184. packageFileNames.push_back(std::string(toplevel));
  185. packageFileNames[0] += "/" +
  186. std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
  187. this->GetOutputExtension();
  188. cmCPackLogger(cmCPackLog::LOG_VERBOSE,
  189. "Packaging all groups in one package..."
  190. "(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE is set)"
  191. << std::endl);
  192. DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
  193. // The ALL COMPONENTS in ONE package case
  194. std::map<std::string, cmCPackComponent>::iterator compIt;
  195. for (compIt = this->Components.begin(); compIt != this->Components.end();
  196. ++compIt) {
  197. // Add the files of this component to the archive
  198. addOneComponentToArchive(archive, &(compIt->second));
  199. }
  200. // archive goes out of scope so it will finalized and closed.
  201. return 1;
  202. }
  203. int cmCPackArchiveGenerator::PackageFiles()
  204. {
  205. cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
  206. if (WantsComponentInstallation()) {
  207. // CASE 1 : COMPONENT ALL-IN-ONE package
  208. // If ALL COMPONENTS in ONE package has been requested
  209. // then the package file is unique and should be open here.
  210. if (componentPackageMethod == ONE_PACKAGE) {
  211. return PackageComponentsAllInOne();
  212. }
  213. // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
  214. // There will be 1 package for each component group
  215. // however one may require to ignore component group and
  216. // in this case you'll get 1 package for each component.
  217. else {
  218. return PackageComponents(componentPackageMethod ==
  219. ONE_PACKAGE_PER_COMPONENT);
  220. }
  221. }
  222. // CASE 3 : NON COMPONENT package.
  223. DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
  224. std::vector<std::string>::const_iterator fileIt;
  225. std::string dir = cmSystemTools::GetCurrentWorkingDirectory();
  226. cmSystemTools::ChangeDirectory(toplevel);
  227. for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
  228. // Get the relative path to the file
  229. std::string rp =
  230. cmSystemTools::RelativePath(toplevel.c_str(), fileIt->c_str());
  231. archive.Add(rp, 0, CM_NULLPTR, false);
  232. if (!archive) {
  233. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem while adding file< "
  234. << *fileIt << "> to archive <" << packageFileNames[0]
  235. << "> .ERROR =" << archive.GetError() << std::endl);
  236. return 0;
  237. }
  238. }
  239. cmSystemTools::ChangeDirectory(dir);
  240. // The destructor of cmArchiveWrite will close and finish the write
  241. return 1;
  242. }
  243. int cmCPackArchiveGenerator::GenerateHeader(std::ostream*)
  244. {
  245. return 1;
  246. }
  247. bool cmCPackArchiveGenerator::SupportsComponentInstallation() const
  248. {
  249. // The Component installation support should only
  250. // be activated if explicitly requested by the user
  251. // (for backward compatibility reason)
  252. return IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL");
  253. }