1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCPackDragNDropGenerator.cxx,v $
6 Date: $Date: 2009-02-24 14:34:03 $
7 Version: $Revision: 1.5 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
18 #include "cmCPackDragNDropGenerator.h"
19 #include "cmCPackLog.h"
20 #include "cmSystemTools.h"
21 #include "cmGeneratedFileStream.h"
23 #include <cmsys/RegularExpression.hxx>
25 static const char* SLAHeader
=
26 "data 'LPic' (5000) {\n"
27 " $\"0002 0011 0003 0001 0000 0000 0002 0000\"\n"
28 " $\"0008 0003 0000 0001 0004 0000 0004 0005\"\n"
29 " $\"0000 000E 0006 0001 0005 0007 0000 0007\"\n"
30 " $\"0008 0000 0047 0009 0000 0034 000A 0001\"\n"
31 " $\"0035 000B 0001 0020 000C 0000 0011 000D\"\n"
32 " $\"0000 005B 0004 0000 0033 000F 0001 000C\"\n"
33 " $\"0010 0000 000B 000E 0000\"\n"
37 static const char* SLASTREnglish
=
38 "resource 'STR#' (5002, \"English\") {\n"
45 " \"You agree to the License Agreement terms when you click \"\n"
46 " \"the \\\"Agree\\\" button.\",\n"
47 " \"Software License Agreement\",\n"
48 " \"This text cannot be saved. This disk may be full or locked, "
50 " \"file may be locked.\",\n"
51 " \"Unable to print. Make sure you have selected a printer.\"\n"
56 //----------------------------------------------------------------------
57 cmCPackDragNDropGenerator::cmCPackDragNDropGenerator()
61 //----------------------------------------------------------------------
62 cmCPackDragNDropGenerator::~cmCPackDragNDropGenerator()
66 //----------------------------------------------------------------------
67 int cmCPackDragNDropGenerator::InitializeInternal()
69 const std::string hdiutil_path
= cmSystemTools::FindProgram("hdiutil",
70 std::vector
<std::string
>(), false);
71 if(hdiutil_path
.empty())
73 cmCPackLogger(cmCPackLog::LOG_ERROR
,
74 "Cannot locate hdiutil command"
78 this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path
.c_str());
80 const std::string setfile_path
= cmSystemTools::FindProgram("SetFile",
81 std::vector
<std::string
>(1, "/Developer/Tools"), false);
82 if(setfile_path
.empty())
84 cmCPackLogger(cmCPackLog::LOG_ERROR
,
85 "Cannot locate SetFile command"
89 this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path
.c_str());
91 const std::string rez_path
= cmSystemTools::FindProgram("Rez",
92 std::vector
<std::string
>(1, "/Developer/Tools"), false);
95 cmCPackLogger(cmCPackLog::LOG_ERROR
,
96 "Cannot locate Rez command"
100 this->SetOptionIfNotSet("CPACK_COMMAND_REZ", rez_path
.c_str());
102 return this->Superclass::InitializeInternal();
105 //----------------------------------------------------------------------
106 const char* cmCPackDragNDropGenerator::GetOutputExtension()
111 //----------------------------------------------------------------------
112 int cmCPackDragNDropGenerator::CompressFiles(const char* outFileName
,
113 const char* toplevel
, const std::vector
<std::string
>& files
)
117 return this->CreateDMG(toplevel
, outFileName
);
120 //----------------------------------------------------------------------
121 bool cmCPackDragNDropGenerator::CopyFile(cmOStringStream
& source
,
122 cmOStringStream
& target
)
124 if(!cmSystemTools::CopyFileIfDifferent(
125 source
.str().c_str(),
126 target
.str().c_str()))
128 cmCPackLogger(cmCPackLog::LOG_ERROR
,
141 //----------------------------------------------------------------------
142 bool cmCPackDragNDropGenerator::RunCommand(cmOStringStream
& command
,
147 bool result
= cmSystemTools::RunSingleCommand(
148 command
.str().c_str(),
152 this->GeneratorVerbose
,
155 if(!result
|| exit_code
)
157 cmCPackLogger(cmCPackLog::LOG_ERROR
,
168 //----------------------------------------------------------------------
169 int cmCPackDragNDropGenerator::CreateDMG(const std::string
& toplevel
,
170 const std::string
& outFileName
)
172 // Get optional arguments ...
173 const std::string cpack_package_icon
= this->GetOption("CPACK_PACKAGE_ICON")
174 ? this->GetOption("CPACK_PACKAGE_ICON") : "";
176 // Get optional arguments ...
177 std::string cpack_license_file
=
178 this->GetOption("CPACK_RESOURCE_FILE_LICENSE") ?
179 this->GetOption("CPACK_RESOURCE_FILE_LICENSE") : "";
180 // only put license on dmg if is user provided
181 if(!cpack_license_file
.empty() &&
182 cpack_license_file
.find("CPack.GenericLicense.txt") != std::string::npos
)
184 cpack_license_file
= "";
187 // The staging directory contains everything that will end-up inside the
188 // final disk image ...
189 cmOStringStream staging
;
192 // Add a symlink to /Applications so users can drag-and-drop the bundle
194 cmOStringStream application_link
;
195 application_link
<< staging
.str() << "/Applications";
196 cmSystemTools::CreateSymlink("/Applications",
197 application_link
.str().c_str());
199 // Optionally add a custom volume icon ...
200 if(!cpack_package_icon
.empty())
202 cmOStringStream package_icon_source
;
203 package_icon_source
<< cpack_package_icon
;
205 cmOStringStream package_icon_destination
;
206 package_icon_destination
<< staging
.str() << "/.VolumeIcon.icns";
208 if(!this->CopyFile(package_icon_source
, package_icon_destination
))
210 cmCPackLogger(cmCPackLog::LOG_ERROR
,
211 "Error copying disk volume icon. "
212 "Check the value of CPACK_PACKAGE_ICON."
219 // Create a temporary read-write disk image ...
220 std::string temp_image
= this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
221 temp_image
+= "/temp.dmg";
223 cmOStringStream temp_image_command
;
224 temp_image_command
<< this->GetOption("CPACK_COMMAND_HDIUTIL");
225 temp_image_command
<< " create";
226 temp_image_command
<< " -ov";
227 temp_image_command
<< " -srcfolder \"" << staging
.str() << "\"";
228 temp_image_command
<< " -volname \""
229 << this->GetOption("CPACK_PACKAGE_FILE_NAME") << "\"";
230 temp_image_command
<< " -format UDRW";
231 temp_image_command
<< " \"" << temp_image
<< "\"";
233 if(!this->RunCommand(temp_image_command
))
235 cmCPackLogger(cmCPackLog::LOG_ERROR
,
236 "Error generating temporary disk image."
242 // Optionally set the custom icon flag for the image ...
243 if(!cpack_package_icon
.empty())
245 cmOStringStream temp_mount
;
247 cmOStringStream attach_command
;
248 attach_command
<< this->GetOption("CPACK_COMMAND_HDIUTIL");
249 attach_command
<< " attach";
250 attach_command
<< " \"" << temp_image
<< "\"";
252 std::string attach_output
;
253 if(!this->RunCommand(attach_command
, &attach_output
))
255 cmCPackLogger(cmCPackLog::LOG_ERROR
,
256 "Error attaching temporary disk image."
262 cmsys::RegularExpression
mountpoint_regex(".*(/Volumes/[^\n]+)\n.*");
263 mountpoint_regex
.find(attach_output
.c_str());
264 temp_mount
<< mountpoint_regex
.match(1);
266 cmOStringStream setfile_command
;
267 setfile_command
<< this->GetOption("CPACK_COMMAND_SETFILE");
268 setfile_command
<< " -a C";
269 setfile_command
<< " \"" << temp_mount
.str() << "\"";
271 if(!this->RunCommand(setfile_command
))
273 cmCPackLogger(cmCPackLog::LOG_ERROR
,
274 "Error assigning custom icon to temporary disk image."
280 cmOStringStream detach_command
;
281 detach_command
<< this->GetOption("CPACK_COMMAND_HDIUTIL");
282 detach_command
<< " detach";
283 detach_command
<< " \"" << temp_mount
.str() << "\"";
285 if(!this->RunCommand(detach_command
))
287 cmCPackLogger(cmCPackLog::LOG_ERROR
,
288 "Error detaching temporary disk image."
295 if(!cpack_license_file
.empty())
297 std::string sla_r
= this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
301 ifs
.open(cpack_license_file
.c_str());
304 cmGeneratedFileStream
osf(sla_r
.c_str());
307 osf
<< "data 'TEXT' (5002, \"English\") {\n";
311 std::getline(ifs
, line
);
312 osf
<< " \"" << line
<< "\\n\"\n";
316 osf
<< SLASTREnglish
;
322 std::string temp_udco
= this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
323 temp_udco
+= "/temp-udco.dmg";
325 cmOStringStream udco_image_command
;
326 udco_image_command
<< this->GetOption("CPACK_COMMAND_HDIUTIL");
327 udco_image_command
<< " convert \"" << temp_image
<< "\"";
328 udco_image_command
<< " -format UDCO";
329 udco_image_command
<< " -o \"" << temp_udco
<< "\"";
332 if(!this->RunCommand(udco_image_command
, &error
))
334 cmCPackLogger(cmCPackLog::LOG_ERROR
,
335 "Error converting to UDCO dmg for adding SLA." << std::endl
342 cmOStringStream unflatten_command
;
343 unflatten_command
<< this->GetOption("CPACK_COMMAND_HDIUTIL");
344 unflatten_command
<< " unflatten ";
345 unflatten_command
<< "\"" << temp_udco
<< "\"";
347 if(!this->RunCommand(unflatten_command
, &error
))
349 cmCPackLogger(cmCPackLog::LOG_ERROR
,
350 "Error unflattening dmg for adding SLA." << std::endl
357 cmOStringStream embed_sla_command
;
358 embed_sla_command
<< "/bin/bash -c \""; // need expansion of "*.r"
359 embed_sla_command
<< this->GetOption("CPACK_COMMAND_REZ");
360 embed_sla_command
<< " /Developer/Headers/FlatCarbon/*.r ";
361 embed_sla_command
<< "'" << sla_r
<< "'";
362 embed_sla_command
<< " -a -o ";
363 embed_sla_command
<< "'" << temp_udco
<< "'\"";
365 if(!this->RunCommand(embed_sla_command
, &error
))
367 cmCPackLogger(cmCPackLog::LOG_ERROR
,
368 "Error adding SLA." << std::endl
375 cmOStringStream flatten_command
;
376 flatten_command
<< this->GetOption("CPACK_COMMAND_HDIUTIL");
377 flatten_command
<< " flatten ";
378 flatten_command
<< "\"" << temp_udco
<< "\"";
380 if(!this->RunCommand(flatten_command
, &error
))
382 cmCPackLogger(cmCPackLog::LOG_ERROR
,
383 "Error flattening dmg for adding SLA." << std::endl
389 temp_image
= temp_udco
;
393 // Create the final compressed read-only disk image ...
394 cmOStringStream final_image_command
;
395 final_image_command
<< this->GetOption("CPACK_COMMAND_HDIUTIL");
396 final_image_command
<< " convert \"" << temp_image
<< "\"";
397 final_image_command
<< " -format UDZO";
398 final_image_command
<< " -imagekey";
399 final_image_command
<< " zlib-level=9";
400 final_image_command
<< " -o \"" << outFileName
<< "\"";
402 if(!this->RunCommand(final_image_command
))
404 cmCPackLogger(cmCPackLog::LOG_ERROR
,
405 "Error compressing disk image."