cmCPackDragNDropGenerator.cxx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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 "cmCPackDragNDropGenerator.h"
  14. #include "cmCPackLog.h"
  15. #include "cmSystemTools.h"
  16. #include <cmsys/RegularExpression.hxx>
  17. //----------------------------------------------------------------------
  18. cmCPackDragNDropGenerator::cmCPackDragNDropGenerator()
  19. {
  20. }
  21. //----------------------------------------------------------------------
  22. cmCPackDragNDropGenerator::~cmCPackDragNDropGenerator()
  23. {
  24. }
  25. //----------------------------------------------------------------------
  26. int cmCPackDragNDropGenerator::InitializeInternal()
  27. {
  28. const std::string hdiutil_path = cmSystemTools::FindProgram("hdiutil",
  29. std::vector<std::string>(), false);
  30. if(hdiutil_path.empty())
  31. {
  32. cmCPackLogger(cmCPackLog::LOG_ERROR,
  33. "Cannot locate hdiutil command"
  34. << std::endl);
  35. return 0;
  36. }
  37. this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path.c_str());
  38. const std::string setfile_path = cmSystemTools::FindProgram("SetFile",
  39. std::vector<std::string>(1, "/Developer/Tools"), false);
  40. if(setfile_path.empty())
  41. {
  42. cmCPackLogger(cmCPackLog::LOG_ERROR,
  43. "Cannot locate SetFile command"
  44. << std::endl);
  45. return 0;
  46. }
  47. this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path.c_str());
  48. return this->Superclass::InitializeInternal();
  49. }
  50. //----------------------------------------------------------------------
  51. const char* cmCPackDragNDropGenerator::GetOutputExtension()
  52. {
  53. return ".dmg";
  54. }
  55. //----------------------------------------------------------------------
  56. int cmCPackDragNDropGenerator::CompressFiles(const char* outFileName,
  57. const char* toplevel, const std::vector<std::string>& files)
  58. {
  59. (void) files;
  60. // Get optional arguments ...
  61. const std::string cpack_package_icon = this->GetOption("CPACK_PACKAGE_ICON")
  62. ? this->GetOption("CPACK_PACKAGE_ICON") : "";
  63. // The staging directory contains everything that will end-up inside the
  64. // final disk image ...
  65. cmOStringStream staging;
  66. staging << toplevel;
  67. // Add a symlink to /Applications so users can drag-and-drop the bundle
  68. // into it
  69. cmOStringStream application_link;
  70. application_link << staging.str() << "/Applications";
  71. cmSystemTools::CreateSymlink("/Applications",
  72. application_link.str().c_str());
  73. // Optionally add a custom volume icon ...
  74. if(!cpack_package_icon.empty())
  75. {
  76. cmOStringStream package_icon_source;
  77. package_icon_source << cpack_package_icon;
  78. cmOStringStream package_icon_destination;
  79. package_icon_destination << staging.str() << "/.VolumeIcon.icns";
  80. if(!this->CopyFile(package_icon_source, package_icon_destination))
  81. {
  82. cmCPackLogger(cmCPackLog::LOG_ERROR,
  83. "Error copying disk volume icon. "
  84. "Check the value of CPACK_PACKAGE_ICON."
  85. << std::endl);
  86. return 0;
  87. }
  88. }
  89. // Create a temporary read-write disk image ...
  90. cmOStringStream temp_image;
  91. temp_image << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/temp.dmg";
  92. cmOStringStream temp_image_command;
  93. temp_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  94. temp_image_command << " create";
  95. temp_image_command << " -ov";
  96. temp_image_command << " -srcfolder \"" << staging.str() << "\"";
  97. temp_image_command << " -volname \""
  98. << this->GetOption("CPACK_PACKAGE_FILE_NAME") << "\"";
  99. temp_image_command << " -format UDRW";
  100. temp_image_command << " \"" << temp_image.str() << "\"";
  101. if(!this->RunCommand(temp_image_command))
  102. {
  103. cmCPackLogger(cmCPackLog::LOG_ERROR,
  104. "Error generating temporary disk image."
  105. << std::endl);
  106. return 0;
  107. }
  108. // Optionally set the custom icon flag for the image ...
  109. if(!cpack_package_icon.empty())
  110. {
  111. cmOStringStream temp_mount;
  112. cmOStringStream attach_command;
  113. attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  114. attach_command << " attach";
  115. attach_command << " \"" << temp_image.str() << "\"";
  116. std::string attach_output;
  117. if(!this->RunCommand(attach_command, &attach_output))
  118. {
  119. cmCPackLogger(cmCPackLog::LOG_ERROR,
  120. "Error attaching temporary disk image."
  121. << std::endl);
  122. return 0;
  123. }
  124. cmsys::RegularExpression mountpoint_regex(".*(/Volumes/[^\n]+)\n.*");
  125. mountpoint_regex.find(attach_output.c_str());
  126. temp_mount << mountpoint_regex.match(1);
  127. cmOStringStream setfile_command;
  128. setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
  129. setfile_command << " -a C";
  130. setfile_command << " \"" << temp_mount.str() << "\"";
  131. if(!this->RunCommand(setfile_command))
  132. {
  133. cmCPackLogger(cmCPackLog::LOG_ERROR,
  134. "Error assigning custom icon to temporary disk image."
  135. << std::endl);
  136. return 0;
  137. }
  138. cmOStringStream detach_command;
  139. detach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  140. detach_command << " detach";
  141. detach_command << " \"" << temp_mount.str() << "\"";
  142. if(!this->RunCommand(detach_command))
  143. {
  144. cmCPackLogger(cmCPackLog::LOG_ERROR,
  145. "Error detaching temporary disk image."
  146. << std::endl);
  147. return 0;
  148. }
  149. }
  150. // Create the final compressed read-only disk image ...
  151. cmOStringStream final_image_command;
  152. final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  153. final_image_command << " convert \"" << temp_image.str() << "\"";
  154. final_image_command << " -format UDZO";
  155. final_image_command << " -imagekey";
  156. final_image_command << " zlib-level=9";
  157. final_image_command << " -o \"" << outFileName << "\"";
  158. if(!this->RunCommand(final_image_command))
  159. {
  160. cmCPackLogger(cmCPackLog::LOG_ERROR,
  161. "Error compressing disk image."
  162. << std::endl);
  163. return 0;
  164. }
  165. return 1;
  166. }
  167. //----------------------------------------------------------------------
  168. bool cmCPackDragNDropGenerator::CopyFile(cmOStringStream& source,
  169. cmOStringStream& target)
  170. {
  171. if(!cmSystemTools::CopyFileIfDifferent(
  172. source.str().c_str(),
  173. target.str().c_str()))
  174. {
  175. cmCPackLogger(cmCPackLog::LOG_ERROR,
  176. "Error copying "
  177. << source.str()
  178. << " to "
  179. << target.str()
  180. << std::endl);
  181. return false;
  182. }
  183. return true;
  184. }
  185. //----------------------------------------------------------------------
  186. bool cmCPackDragNDropGenerator::RunCommand(cmOStringStream& command,
  187. std::string* output)
  188. {
  189. int exit_code = 1;
  190. bool result = cmSystemTools::RunSingleCommand(
  191. command.str().c_str(),
  192. output,
  193. &exit_code,
  194. 0,
  195. this->GeneratorVerbose,
  196. 0);
  197. if(!result || exit_code)
  198. {
  199. cmCPackLogger(cmCPackLog::LOG_ERROR,
  200. "Error executing: "
  201. << command.str()
  202. << std::endl);
  203. return false;
  204. }
  205. return true;
  206. }