cmCPackArchiveGenerator.cxx 11 KB

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