cmCPackBundleGenerator.cxx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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. const char* cmCPackBundleGenerator::GetPackagingInstallPrefix()
  27. {
  28. this->InstallPrefix = "/";
  29. this->InstallPrefix += this->GetOption("CPACK_BUNDLE_NAME");
  30. this->InstallPrefix += ".app/Contents/Resources";
  31. return this->InstallPrefix.c_str();
  32. }
  33. //----------------------------------------------------------------------
  34. int cmCPackBundleGenerator::CompressFiles(const char* outFileName,
  35. const char* toplevel, const std::vector<std::string>& files)
  36. {
  37. (void) files;
  38. // Get required arguments ...
  39. const std::string cpack_bundle_name = this->GetOption("CPACK_BUNDLE_NAME")
  40. ? this->GetOption("CPACK_BUNDLE_NAME") : "";
  41. if(cpack_bundle_name.empty())
  42. {
  43. cmCPackLogger(cmCPackLog::LOG_ERROR,
  44. "CPACK_BUNDLE_NAME must be set."
  45. << std::endl);
  46. return 0;
  47. }
  48. const std::string cpack_bundle_plist = this->GetOption("CPACK_BUNDLE_PLIST")
  49. ? this->GetOption("CPACK_BUNDLE_PLIST") : "";
  50. if(cpack_bundle_plist.empty())
  51. {
  52. cmCPackLogger(cmCPackLog::LOG_ERROR,
  53. "CPACK_BUNDLE_PLIST must be set."
  54. << std::endl);
  55. return 0;
  56. }
  57. const std::string cpack_bundle_icon = this->GetOption("CPACK_BUNDLE_ICON")
  58. ? this->GetOption("CPACK_BUNDLE_ICON") : "";
  59. if(cpack_bundle_icon.empty())
  60. {
  61. cmCPackLogger(cmCPackLog::LOG_ERROR,
  62. "CPACK_BUNDLE_ICON must be set."
  63. << std::endl);
  64. return 0;
  65. }
  66. // Get optional arguments ...
  67. const std::string cpack_package_icon = this->GetOption("CPACK_PACKAGE_ICON")
  68. ? this->GetOption("CPACK_PACKAGE_ICON") : "";
  69. const std::string cpack_bundle_startup_command =
  70. this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
  71. ? this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND") : "";
  72. // The staging directory contains everything that will end-up inside the
  73. // final disk image ...
  74. cmOStringStream staging;
  75. staging << toplevel;
  76. cmOStringStream contents;
  77. contents << staging.str() << "/" << cpack_bundle_name
  78. << ".app/" << "Contents";
  79. cmOStringStream application;
  80. application << contents.str() << "/" << "MacOS";
  81. cmOStringStream resources;
  82. resources << contents.str() << "/" << "Resources";
  83. // Install a required, user-provided bundle metadata file ...
  84. cmOStringStream plist_source;
  85. plist_source << cpack_bundle_plist;
  86. cmOStringStream plist_target;
  87. plist_target << contents.str() << "/" << "Info.plist";
  88. if(!this->CopyFile(plist_source, plist_target))
  89. {
  90. cmCPackLogger(cmCPackLog::LOG_ERROR,
  91. "Error copying plist. Check the value of CPACK_BUNDLE_PLIST."
  92. << std::endl);
  93. return 0;
  94. }
  95. // Install a user-provided bundle icon ...
  96. cmOStringStream icon_source;
  97. icon_source << cpack_bundle_icon;
  98. cmOStringStream icon_target;
  99. icon_target << resources.str() << "/" << cpack_bundle_name << ".icns";
  100. if(!this->CopyFile(icon_source, icon_target))
  101. {
  102. cmCPackLogger(cmCPackLog::LOG_ERROR,
  103. "Error copying bundle icon. Check the value of CPACK_BUNDLE_ICON."
  104. << std::endl);
  105. return 0;
  106. }
  107. // Optionally a user-provided startup command (could be an
  108. // executable or a script) ...
  109. if(!cpack_bundle_startup_command.empty())
  110. {
  111. cmOStringStream command_source;
  112. command_source << cpack_bundle_startup_command;
  113. cmOStringStream command_target;
  114. command_target << application.str() << "/" << cpack_bundle_name;
  115. if(!this->CopyFile(command_source, command_target))
  116. {
  117. cmCPackLogger(cmCPackLog::LOG_ERROR,
  118. "Error copying startup command. "
  119. " Check the value of CPACK_BUNDLE_STARTUP_COMMAND."
  120. << std::endl);
  121. return 0;
  122. }
  123. cmSystemTools::SetPermissions(command_target.str().c_str(), 0777);
  124. }
  125. // Add a symlink to /Applications so users can drag-and-drop the bundle
  126. // into it
  127. cmOStringStream application_link;
  128. application_link << staging.str() << "/Applications";
  129. cmSystemTools::CreateSymlink("/Applications",
  130. application_link.str().c_str());
  131. // Optionally add a custom volume icon ...
  132. if(!cpack_package_icon.empty())
  133. {
  134. cmOStringStream package_icon_source;
  135. package_icon_source << cpack_package_icon;
  136. cmOStringStream package_icon_destination;
  137. package_icon_destination << staging.str() << "/.VolumeIcon.icns";
  138. if(!this->CopyFile(package_icon_source, package_icon_destination))
  139. {
  140. cmCPackLogger(cmCPackLog::LOG_ERROR,
  141. "Error copying disk volume icon. "
  142. "Check the value of CPACK_PACKAGE_ICON."
  143. << std::endl);
  144. return 0;
  145. }
  146. }
  147. // Create a temporary read-write disk image ...
  148. cmOStringStream temp_image;
  149. temp_image << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/temp.dmg";
  150. cmOStringStream temp_image_command;
  151. temp_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  152. temp_image_command << " create";
  153. temp_image_command << " -ov";
  154. temp_image_command << " -srcfolder \"" << staging.str() << "\"";
  155. temp_image_command << " -volname \""
  156. << this->GetOption("CPACK_PACKAGE_FILE_NAME") << "\"";
  157. temp_image_command << " -format UDRW";
  158. temp_image_command << " \"" << temp_image.str() << "\"";
  159. if(!this->RunCommand(temp_image_command))
  160. {
  161. cmCPackLogger(cmCPackLog::LOG_ERROR,
  162. "Error generating temporary disk image."
  163. << std::endl);
  164. return 0;
  165. }
  166. // Optionally set the custom icon flag for the image ...
  167. if(!cpack_package_icon.empty())
  168. {
  169. cmOStringStream temp_mount;
  170. cmOStringStream attach_command;
  171. attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  172. attach_command << " attach";
  173. attach_command << " \"" << temp_image.str() << "\"";
  174. std::string attach_output;
  175. if(!this->RunCommand(attach_command, &attach_output))
  176. {
  177. cmCPackLogger(cmCPackLog::LOG_ERROR,
  178. "Error attaching temporary disk image."
  179. << std::endl);
  180. return 0;
  181. }
  182. cmsys::RegularExpression mountpoint_regex(".*(/Volumes/[^\n]+)\n.*");
  183. mountpoint_regex.find(attach_output.c_str());
  184. temp_mount << mountpoint_regex.match(1);
  185. cmOStringStream setfile_command;
  186. setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
  187. setfile_command << " -a C";
  188. setfile_command << " \"" << temp_mount.str() << "\"";
  189. if(!this->RunCommand(setfile_command))
  190. {
  191. cmCPackLogger(cmCPackLog::LOG_ERROR,
  192. "Error assigning custom icon to temporary disk image."
  193. << std::endl);
  194. return 0;
  195. }
  196. cmOStringStream detach_command;
  197. detach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  198. detach_command << " detach";
  199. detach_command << " \"" << temp_mount.str() << "\"";
  200. if(!this->RunCommand(detach_command))
  201. {
  202. cmCPackLogger(cmCPackLog::LOG_ERROR,
  203. "Error detaching temporary disk image."
  204. << std::endl);
  205. return 0;
  206. }
  207. }
  208. // Create the final compressed read-only disk image ...
  209. cmOStringStream final_image_command;
  210. final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  211. final_image_command << " convert \"" << temp_image.str() << "\"";
  212. final_image_command << " -format UDZO";
  213. final_image_command << " -imagekey";
  214. final_image_command << " zlib-level=9";
  215. final_image_command << " -o \"" << outFileName << "\"";
  216. if(!this->RunCommand(final_image_command))
  217. {
  218. cmCPackLogger(cmCPackLog::LOG_ERROR,
  219. "Error compressing disk image."
  220. << std::endl);
  221. return 0;
  222. }
  223. return 1;
  224. }