You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

322 lines
11 KiB

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