cmCPackBundleGenerator.cxx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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. //----------------------------------------------------------------------
  17. cmCPackBundleGenerator::cmCPackBundleGenerator()
  18. {
  19. }
  20. //----------------------------------------------------------------------
  21. cmCPackBundleGenerator::~cmCPackBundleGenerator()
  22. {
  23. }
  24. //----------------------------------------------------------------------
  25. int cmCPackBundleGenerator::InitializeInternal()
  26. {
  27. const std::string hdiutil_path = cmSystemTools::FindProgram("hdiutil",
  28. std::vector<std::string>(), false);
  29. if(hdiutil_path.empty())
  30. {
  31. cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate hdiutil command"
  32. << std::endl);
  33. return 0;
  34. }
  35. this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path.c_str());
  36. const std::string setfile_path = cmSystemTools::FindProgram("SetFile",
  37. std::vector<std::string>(1, "/Developer/Tools"), false);
  38. if(setfile_path.empty())
  39. {
  40. cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate SetFile command"
  41. << std::endl);
  42. return 0;
  43. }
  44. this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path.c_str());
  45. return this->Superclass::InitializeInternal();
  46. }
  47. //----------------------------------------------------------------------
  48. const char* cmCPackBundleGenerator::GetOutputExtension()
  49. {
  50. return ".dmg";
  51. }
  52. //----------------------------------------------------------------------
  53. const char* cmCPackBundleGenerator::GetPackagingInstallPrefix()
  54. {
  55. this->InstallPrefix = "/";
  56. this->InstallPrefix += this->GetOption("CPACK_BUNDLE_NAME");
  57. this->InstallPrefix += ".app/Contents/Resources";
  58. return this->InstallPrefix.c_str();
  59. }
  60. //----------------------------------------------------------------------
  61. int cmCPackBundleGenerator::CompressFiles(const char* outFileName,
  62. const char* toplevel, const std::vector<std::string>& files)
  63. {
  64. // The staging directory contains everything that will end-up inside the
  65. // final disk image ...
  66. cmOStringStream staging;
  67. staging << toplevel;
  68. cmOStringStream contents;
  69. contents << staging.str() << "/" << this->GetOption("CPACK_BUNDLE_NAME")
  70. << ".app/" << "Contents";
  71. cmOStringStream application;
  72. application << contents.str() << "/" << "MacOS";
  73. cmOStringStream resources;
  74. resources << contents.str() << "/" << "Resources";
  75. // Install a user-provided bundle metadata file ...
  76. if(this->GetOption("CPACK_BUNDLE_PLIST"))
  77. {
  78. cmOStringStream plist_source;
  79. plist_source << this->GetOption("CPACK_BUNDLE_PLIST");
  80. cmOStringStream plist_target;
  81. plist_target << contents.str() << "/" << "Info.plist";
  82. if(!this->CopyFile(plist_source, plist_target))
  83. {
  84. return 0;
  85. }
  86. }
  87. // Install a user-provided bundle icon ...
  88. if(this->GetOption("CPACK_BUNDLE_ICON"))
  89. {
  90. cmOStringStream icon_source;
  91. icon_source << this->GetOption("CPACK_BUNDLE_ICON");
  92. cmOStringStream icon_target;
  93. icon_target << resources.str() << "/"
  94. << this->GetOption("CPACK_BUNDLE_NAME") << ".icns";
  95. if(!this->CopyFile(icon_source, icon_target))
  96. {
  97. return 0;
  98. }
  99. }
  100. // Install a user-provided startup command (could be an executable or a
  101. // script) ...
  102. if(this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND"))
  103. {
  104. cmOStringStream command_source;
  105. command_source << this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND");
  106. cmOStringStream command_target;
  107. command_target << application.str() << "/"
  108. << this->GetOption("CPACK_BUNDLE_NAME");
  109. if(!this->CopyFile(command_source, command_target))
  110. {
  111. return 0;
  112. }
  113. cmSystemTools::SetPermissions(command_target.str().c_str(), 0777);
  114. }
  115. // Add a symlink to /Applications so users can drag-and-drop the bundle
  116. // into it
  117. cmOStringStream application_link;
  118. application_link << staging.str() << "/Applications";
  119. cmSystemTools::CreateSymlink("/Applications",
  120. application_link.str().c_str());
  121. // Optionally add a custom volume icon ...
  122. if(this->GetOption("CPACK_PACKAGE_ICON"))
  123. {
  124. cmOStringStream package_icon_source;
  125. package_icon_source << this->GetOption("CPACK_PACKAGE_ICON");
  126. cmOStringStream package_icon_destination;
  127. package_icon_destination << staging.str() << "/.VolumeIcon.icns";
  128. if(!this->CopyFile(package_icon_source, package_icon_destination))
  129. {
  130. return 0;
  131. }
  132. }
  133. // Create a temporary read-write disk image ...
  134. cmOStringStream temp_image;
  135. temp_image << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/temp.dmg";
  136. cmOStringStream temp_image_command;
  137. temp_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  138. temp_image_command << " create";
  139. temp_image_command << " -ov";
  140. temp_image_command << " -srcfolder \"" << staging.str() << "\"";
  141. temp_image_command << " -volname \""
  142. << this->GetOption("CPACK_PACKAGE_FILE_NAME") << "\"";
  143. temp_image_command << " -format UDRW";
  144. temp_image_command << " \"" << temp_image.str() << "\"";
  145. if(!this->RunCommand(temp_image_command))
  146. {
  147. return 0;
  148. }
  149. // Optionally set the custom icon flag for the image ...
  150. if(this->GetOption("CPACK_PACKAGE_ICON"))
  151. {
  152. cmOStringStream temp_mount;
  153. temp_mount << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/mnt";
  154. cmSystemTools::MakeDirectory(temp_mount.str().c_str());
  155. cmOStringStream attach_command;
  156. attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  157. attach_command << " attach";
  158. attach_command << " -mountpoint \"" << temp_mount.str() << "\"";
  159. attach_command << " \"" << temp_image.str() << "\"";
  160. if(!this->RunCommand(attach_command))
  161. {
  162. return 0;
  163. }
  164. cmOStringStream setfile_command;
  165. setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
  166. setfile_command << " -a C";
  167. setfile_command << " \"" << temp_mount.str() << "\"";
  168. if(!this->RunCommand(setfile_command))
  169. {
  170. return 0;
  171. }
  172. cmOStringStream detach_command;
  173. detach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  174. detach_command << " detach";
  175. detach_command << " \"" << temp_mount.str() << "\"";
  176. if(!this->RunCommand(detach_command))
  177. {
  178. return 0;
  179. }
  180. }
  181. // Create the final compressed read-only disk image ...
  182. cmOStringStream final_image_command;
  183. final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
  184. final_image_command << " convert \"" << temp_image.str() << "\"";
  185. final_image_command << " -format UDZO";
  186. final_image_command << " -imagekey";
  187. final_image_command << " zlib-level=9";
  188. final_image_command << " -o \"" << outFileName << "\"";
  189. if(!this->RunCommand(final_image_command))
  190. {
  191. return 0;
  192. }
  193. /*
  194. // Disk image directories
  195. std::string diskImageDirectory = toplevel;
  196. std::string diskImageBackgroundImageDir = diskImageDirectory
  197. + "/.background";
  198. // App bundle directories
  199. std::string packageDirFileName = toplevel;
  200. packageDirFileName += "/";
  201. packageDirFileName += this->GetOption("CPACK_PACKAGE_FILE_NAME");
  202. packageDirFileName += ".app";
  203. std::string contentsDirectory = packageDirFileName + "/Contents";
  204. std::string resourcesDirectory = contentsDirectory + "/Resources";
  205. std::string appDirectory = contentsDirectory + "/MacOS";
  206. const char* dir = resourcesDirectory.c_str();
  207. const char* appdir = appDirectory.c_str();
  208. const char* contDir = contentsDirectory.c_str();
  209. const char* iconFile = this->GetOption("CPACK_PACKAGE_ICON");
  210. if ( iconFile )
  211. {
  212. std::string iconFileName = cmsys::SystemTools::GetFilenameName(iconFile);
  213. if ( !cmSystemTools::FileExists(iconFile) )
  214. {
  215. cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find icon file: "
  216. << iconFile << ". Please check CPACK_PACKAGE_ICON setting."
  217. << std::endl);
  218. return 0;
  219. }
  220. std::string destFileName = resourcesDirectory + "/" + iconFileName;
  221. this->ConfigureFile(iconFile, destFileName.c_str(), true);
  222. this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str());
  223. }
  224. if (
  225. !this->CopyResourcePlistFile("VolumeIcon.icns",
  226. diskImageDirectory.c_str(),
  227. ".VolumeIcon.icns", true ) ||
  228. !this->CopyResourcePlistFile("DS_Store", diskImageDirectory.c_str(),
  229. ".DS_Store", true ) ||
  230. !this->CopyResourcePlistFile("background.png",
  231. diskImageBackgroundImageDir.c_str(), "background.png", true ) ||
  232. !this->CopyResourcePlistFile("RuntimeScript", dir) ||
  233. !this->CopyResourcePlistFile("Bundle.Info.plist", contDir,
  234. "Info.plist" ) ||
  235. !this->CopyResourcePlistFile("OSXScriptLauncher", appdir,
  236. this->GetOption("CPACK_PACKAGE_FILE_NAME"), true)
  237. )
  238. {
  239. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
  240. << std::endl);
  241. return 0;
  242. }
  243. */
  244. return 1;
  245. }
  246. //----------------------------------------------------------------------
  247. bool cmCPackBundleGenerator::CopyFile(cmOStringStream& source,
  248. cmOStringStream& target)
  249. {
  250. return cmSystemTools::CopyFileIfDifferent(source.str().c_str(),
  251. target.str().c_str());
  252. }
  253. //----------------------------------------------------------------------
  254. bool cmCPackBundleGenerator::RunCommand(cmOStringStream& command)
  255. {
  256. std::string output;
  257. int exit_code = 1;
  258. bool result = cmSystemTools::RunSingleCommand(command.str().c_str(),
  259. &output, &exit_code, 0, this->GeneratorVerbose, 0);
  260. if(!result || exit_code)
  261. {
  262. cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running command: "
  263. << command.str().c_str() << std::endl);
  264. return false;
  265. }
  266. return true;
  267. }