cmCPackBundleGenerator.cxx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmCPackBundleGenerator.h"
  14. #include "cmCPackLog.h"
  15. #include "cmSystemTools.h"
  16. #include <cmsys/RegularExpression.hxx>
  17. //----------------------------------------------------------------------
  18. cmCPackBundleGenerator::cmCPackBundleGenerator()
  19. {
  20. }
  21. //----------------------------------------------------------------------
  22. cmCPackBundleGenerator::~cmCPackBundleGenerator()
  23. {
  24. }
  25. //----------------------------------------------------------------------
  26. int cmCPackBundleGenerator::InitializeInternal()
  27. {
  28. const char* name = this->GetOption("CPACK_BUNDLE_NAME");
  29. if(0 == name)
  30. {
  31. cmCPackLogger(cmCPackLog::LOG_ERROR,
  32. "CPACK_BUNDLE_NAME must be set to use the Bundle generator."
  33. << std::endl);
  34. return 0;
  35. }
  36. return this->Superclass::InitializeInternal();
  37. }
  38. //----------------------------------------------------------------------
  39. const char* cmCPackBundleGenerator::GetPackagingInstallPrefix()
  40. {
  41. this->InstallPrefix = "/";
  42. this->InstallPrefix += this->GetOption("CPACK_BUNDLE_NAME");
  43. this->InstallPrefix += ".app/Contents/Resources";
  44. return this->InstallPrefix.c_str();
  45. }
  46. //----------------------------------------------------------------------
  47. int cmCPackBundleGenerator::CompressFiles(const char* outFileName,
  48. const char* toplevel, const std::vector<std::string>& files)
  49. {
  50. (void) files;
  51. // Get required arguments ...
  52. const std::string cpack_bundle_name = this->GetOption("CPACK_BUNDLE_NAME")
  53. ? this->GetOption("CPACK_BUNDLE_NAME") : "";
  54. if(cpack_bundle_name.empty())
  55. {
  56. cmCPackLogger(cmCPackLog::LOG_ERROR,
  57. "CPACK_BUNDLE_NAME must be set."
  58. << std::endl);
  59. return 0;
  60. }
  61. const std::string cpack_bundle_plist = this->GetOption("CPACK_BUNDLE_PLIST")
  62. ? this->GetOption("CPACK_BUNDLE_PLIST") : "";
  63. if(cpack_bundle_plist.empty())
  64. {
  65. cmCPackLogger(cmCPackLog::LOG_ERROR,
  66. "CPACK_BUNDLE_PLIST must be set."
  67. << std::endl);
  68. return 0;
  69. }
  70. const std::string cpack_bundle_icon = this->GetOption("CPACK_BUNDLE_ICON")
  71. ? this->GetOption("CPACK_BUNDLE_ICON") : "";
  72. if(cpack_bundle_icon.empty())
  73. {
  74. cmCPackLogger(cmCPackLog::LOG_ERROR,
  75. "CPACK_BUNDLE_ICON must be set."
  76. << std::endl);
  77. return 0;
  78. }
  79. // Get optional arguments ...
  80. const std::string cpack_package_icon = this->GetOption("CPACK_PACKAGE_ICON")
  81. ? this->GetOption("CPACK_PACKAGE_ICON") : "";
  82. const std::string cpack_bundle_startup_command =
  83. this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
  84. ? this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND") : "";
  85. // The staging directory contains everything that will end-up inside the
  86. // final disk image ...
  87. cmOStringStream staging;
  88. staging << toplevel;
  89. cmOStringStream contents;
  90. contents << staging.str() << "/" << cpack_bundle_name
  91. << ".app/" << "Contents";
  92. cmOStringStream application;
  93. application << contents.str() << "/" << "MacOS";
  94. cmOStringStream resources;
  95. resources << contents.str() << "/" << "Resources";
  96. // Install a required, user-provided bundle metadata file ...
  97. cmOStringStream plist_source;
  98. plist_source << cpack_bundle_plist;
  99. cmOStringStream plist_target;
  100. plist_target << contents.str() << "/" << "Info.plist";
  101. if(!this->CopyFile(plist_source, plist_target))
  102. {
  103. cmCPackLogger(cmCPackLog::LOG_ERROR,
  104. "Error copying plist. Check the value of CPACK_BUNDLE_PLIST."
  105. << std::endl);
  106. return 0;
  107. }
  108. // Install a user-provided bundle icon ...
  109. cmOStringStream icon_source;
  110. icon_source << cpack_bundle_icon;
  111. cmOStringStream icon_target;
  112. icon_target << resources.str() << "/" << cpack_bundle_name << ".icns";
  113. if(!this->CopyFile(icon_source, icon_target))
  114. {
  115. cmCPackLogger(cmCPackLog::LOG_ERROR,
  116. "Error copying bundle icon. Check the value of CPACK_BUNDLE_ICON."
  117. << std::endl);
  118. return 0;
  119. }
  120. // Optionally a user-provided startup command (could be an
  121. // executable or a script) ...
  122. if(!cpack_bundle_startup_command.empty())
  123. {
  124. cmOStringStream command_source;
  125. command_source << cpack_bundle_startup_command;
  126. cmOStringStream command_target;
  127. command_target << application.str() << "/" << cpack_bundle_name;
  128. if(!this->CopyFile(command_source, command_target))
  129. {
  130. cmCPackLogger(cmCPackLog::LOG_ERROR,
  131. "Error copying startup command. "
  132. " Check the value of CPACK_BUNDLE_STARTUP_COMMAND."
  133. << std::endl);
  134. return 0;
  135. }
  136. cmSystemTools::SetPermissions(command_target.str().c_str(), 0777);
  137. }
  138. // Add a symlink to /Applications so users can drag-and-drop the bundle
  139. // into it
  140. cmOStringStream application_link;
  141. application_link << staging.str() << "/Applications";
  142. cmSystemTools::CreateSymlink("/Applications",
  143. application_link.str().c_str());
  144. // Optionally add a custom volume icon ...
  145. if(!cpack_package_icon.empty())
  146. {
  147. cmOStringStream package_icon_source;
  148. package_icon_source << cpack_package_icon;
  149. cmOStringStream package_icon_destination;
  150. package_icon_destination << staging.str() << "/.VolumeIcon.icns";
  151. if(!this->CopyFile(package_icon_source, package_icon_destination))
  152. {
  153. cmCPackLogger(cmCPackLog::LOG_ERROR,
  154. "Error copying disk volume icon. "
  155. "Check the value of CPACK_PACKAGE_ICON."
  156. << std::endl);
  157. return 0;
  158. }
  159. }
  160. // Create a temporary read-write disk image ...
  161. cmOStringStream temp_image;
  162. temp_image << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/temp.dmg";
  163. cmOStringStream temp_image_command;
  164. temp_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  165. temp_image_command << " create";
  166. temp_image_command << " -ov";
  167. temp_image_command << " -srcfolder \"" << staging.str() << "\"";
  168. temp_image_command << " -volname \""
  169. << this->GetOption("CPACK_PACKAGE_FILE_NAME") << "\"";
  170. temp_image_command << " -format UDRW";
  171. temp_image_command << " \"" << temp_image.str() << "\"";
  172. if(!this->RunCommand(temp_image_command))
  173. {
  174. cmCPackLogger(cmCPackLog::LOG_ERROR,
  175. "Error generating temporary disk image."
  176. << std::endl);
  177. return 0;
  178. }
  179. // Optionally set the custom icon flag for the image ...
  180. if(!cpack_package_icon.empty())
  181. {
  182. cmOStringStream temp_mount;
  183. cmOStringStream attach_command;
  184. attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  185. attach_command << " attach";
  186. attach_command << " \"" << temp_image.str() << "\"";
  187. std::string attach_output;
  188. if(!this->RunCommand(attach_command, &attach_output))
  189. {
  190. cmCPackLogger(cmCPackLog::LOG_ERROR,
  191. "Error attaching temporary disk image."
  192. << std::endl);
  193. return 0;
  194. }
  195. cmsys::RegularExpression mountpoint_regex(".*(/Volumes/[^\n]+)\n.*");
  196. mountpoint_regex.find(attach_output.c_str());
  197. temp_mount << mountpoint_regex.match(1);
  198. cmOStringStream setfile_command;
  199. setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
  200. setfile_command << " -a C";
  201. setfile_command << " \"" << temp_mount.str() << "\"";
  202. if(!this->RunCommand(setfile_command))
  203. {
  204. cmCPackLogger(cmCPackLog::LOG_ERROR,
  205. "Error assigning custom icon to temporary disk image."
  206. << std::endl);
  207. return 0;
  208. }
  209. cmOStringStream detach_command;
  210. detach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  211. detach_command << " detach";
  212. detach_command << " \"" << temp_mount.str() << "\"";
  213. if(!this->RunCommand(detach_command))
  214. {
  215. cmCPackLogger(cmCPackLog::LOG_ERROR,
  216. "Error detaching temporary disk image."
  217. << std::endl);
  218. return 0;
  219. }
  220. }
  221. // Create the final compressed read-only disk image ...
  222. cmOStringStream final_image_command;
  223. final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  224. final_image_command << " convert \"" << temp_image.str() << "\"";
  225. final_image_command << " -format UDZO";
  226. final_image_command << " -imagekey";
  227. final_image_command << " zlib-level=9";
  228. final_image_command << " -o \"" << outFileName << "\"";
  229. if(!this->RunCommand(final_image_command))
  230. {
  231. cmCPackLogger(cmCPackLog::LOG_ERROR,
  232. "Error compressing disk image."
  233. << std::endl);
  234. return 0;
  235. }
  236. return 1;
  237. }