Merge topic 'better_looking_mac_package'

4bca9401 Improve appearance of CMake .dmg package on OS X
c4b9ee18 CPack/DragNDrop: Update documentation to include new variables
167a4655 CPack/DragNDrop: Optionally run an AppleScript when making a package
9c1dfbfd CPack/DragNDrop: Place the background image file in a hidden folder
47302038 CPack/DragNDrop: Use source file extension for background image
This commit is contained in:
Brad King 2015-11-13 08:53:40 -05:00 committed by CMake Topic Stage
commit 9feb24e514
7 changed files with 172 additions and 26 deletions

View File

@ -183,6 +183,13 @@ if("${CPACK_GENERATOR}" STREQUAL "PackageMaker")
endif()
endif()
if("${CPACK_GENERATOR}" STREQUAL "DragNDrop")
set(CPACK_DMG_BACKGROUND_IMAGE
"@CMake_SOURCE_DIR@/Packaging/CMakeDMGBackground.tif")
set(CPACK_DMG_DS_STORE_SETUP_SCRIPT
"@CMake_SOURCE_DIR@/Packaging/CMakeDMGSetup.scpt")
endif()
if("${CPACK_GENERATOR}" STREQUAL "WIX")
# Reset CPACK_PACKAGE_VERSION to deal with WiX restriction.
# But the file names still use the full CMake_VERSION value:

View File

@ -0,0 +1,8 @@
better-looking-mac-packages
---------------------------
* The :module:`CPackDMG` module learned new variable to specify AppleScript
file run to customize appearance of ``DragNDrop`` installer folder,
including background image setting using supplied PNG or multi-resolution
TIFF file. See the :variable:`CPACK_DMG_DS_STORE_SETUP_SCRIPT` and
:variable:`CPACK_DMG_BACKGROUND_IMAGE` variables.

View File

@ -26,15 +26,25 @@
# Path to a custom DS_Store file. This .DS_Store file e.g. can be used to
# specify the Finder window position/geometry and layout (such as hidden
# toolbars, placement of the icons etc.). This file has to be generated by
# the Finder (either manually or through OSA-script) using a normal folder
# the Finder (either manually or through AppleScript) using a normal folder
# from which the .DS_Store file can then be extracted.
#
# .. variable:: CPACK_DMG_DS_STORE_SETUP_SCRIPT
#
# Path to a custom AppleScript file. This AppleScript is used to generate
# a .DS_Store file which specifies the Finder window position/geometry and
# layout (such as hidden toolbars, placement of the icons etc.).
# By specifying a custom AppleScript there is no need to use
# CPACK_DMG_DS_STORE, as the .DS_Store that is generated by the AppleScript
# will be packaged.
#
# .. variable:: CPACK_DMG_BACKGROUND_IMAGE
#
# Path to a background image file. This file will be used as the background
# for the Finder Window when the disk image is opened. By default no
# background image is set. The background image is applied after applying the
# custom .DS_Store file.
# Path to an image file to be used as the background. This file will be
# copied to .background/background.<ext>, where ext is the original image file
# extension. The background image is installed into the image before
# CPACK_DMG_DS_STORE_SETUP_SCRIPT is executed or CPACK_DMG_DS_STORE is
# installed. By default no background image is set.
#
# .. variable:: CPACK_DMG_SLA_DIR
#

Binary file not shown.

View File

@ -0,0 +1,42 @@
on run argv
set image_name to item 1 of argv
tell application "Finder"
tell disk image_name
-- open the image the first time and save a DS_Store with just
-- background and icon setup
open
set current view of container window to icon view
set theViewOptions to the icon view options of container window
set background picture of theViewOptions to file ".background:background.tif"
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 128
delay 1
close
-- next setup the position of the app and Applications symlink
-- plus hide all the window decoration
open
update without registering applications
tell container window
set sidebar width to 0
set statusbar visible to false
set toolbar visible to false
set the bounds to { 400, 100, 900, 465 }
set position of item "CMake.app" to { 133, 200 }
set position of item "Applications" to { 378, 200 }
end tell
update without registering applications
delay 1
close
-- one last open and close so you can see everything looks correct
open
delay 5
close
end tell
delay 1
end tell
end run

View File

@ -270,6 +270,28 @@ bool cmCPackDragNDropGenerator::CopyFile(std::ostringstream& source,
return true;
}
//----------------------------------------------------------------------
bool cmCPackDragNDropGenerator::CreateEmptyFile(std::ostringstream& target,
size_t size)
{
cmsys::ofstream fout(target.str().c_str(),
std::ios::out | std::ios::binary);
if(!fout)
{
return false;
}
else
{
// Seek to desired size - 1 byte
fout.seekp(size - 1, std::ios_base::beg);
char byte = 0;
// Write one byte to ensure file grows
fout.write(&byte, 1);
}
return true;
}
//----------------------------------------------------------------------
bool cmCPackDragNDropGenerator::RunCommand(std::ostringstream& command,
std::string* output)
@ -331,6 +353,10 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
this->GetOption("CPACK_DMG_LANGUAGES")
? this->GetOption("CPACK_DMG_LANGUAGES") : "";
const std::string cpack_dmg_ds_store_setup_script =
this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT")
? this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT") : "";
// only put license on dmg if is user provided
if(!cpack_license_file.empty() &&
cpack_license_file.find("CPack.GenericLicense.txt") != std::string::npos)
@ -399,13 +425,18 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
}
// Optionally add a custom background image ...
// Make sure the background file type is the same as the custom image
// and that the file is hidden so it doesn't show up.
if(!cpack_dmg_background_image.empty())
{
const std::string extension =
cmSystemTools::GetFilenameLastExtension(cpack_dmg_background_image);
std::ostringstream package_background_source;
package_background_source << cpack_dmg_background_image;
std::ostringstream package_background_destination;
package_background_destination << staging.str() << "/background.png";
package_background_destination << staging.str()
<< "/.background/background" << extension;
if(!this->CopyFile(package_background_source,
package_background_destination))
@ -417,18 +448,22 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
return 0;
}
}
std::ostringstream temp_background_hiding_command;
temp_background_hiding_command << this->GetOption("CPACK_COMMAND_SETFILE");
temp_background_hiding_command << " -a V \"";
temp_background_hiding_command << package_background_destination.str();
temp_background_hiding_command << "\"";
bool remount_image = !cpack_package_icon.empty() ||
!cpack_dmg_ds_store_setup_script.empty();
if(!this->RunCommand(temp_background_hiding_command))
// Create 1 MB dummy padding file in staging area when we need to remount
// image, so we have enough space for storing changes ...
if(remount_image)
{
std::ostringstream dummy_padding;
dummy_padding << staging.str() << "/.dummy-padding-file";
if(!this->CreateEmptyFile(dummy_padding, 1048576))
{
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error setting attributes on disk volume background image."
<< std::endl);
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error creating dummy padding file."
<< std::endl);
return 0;
}
@ -457,10 +492,11 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
return 0;
}
// Optionally set the custom icon flag for the image ...
if(!cpack_package_icon.empty())
if(remount_image)
{
std::ostringstream temp_mount;
// Store that we have a failure so that we always unmount the image
// before we exit.
bool had_error = false;
std::ostringstream attach_command;
attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
@ -479,20 +515,57 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
cmsys::RegularExpression mountpoint_regex(".*(/Volumes/[^\n]+)\n.*");
mountpoint_regex.find(attach_output.c_str());
std::ostringstream temp_mount;
temp_mount << mountpoint_regex.match(1);
std::ostringstream setfile_command;
setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
setfile_command << " -a C";
setfile_command << " \"" << temp_mount.str() << "\"";
if(!this->RunCommand(setfile_command))
// Remove dummy padding file so we have enough space on RW image ...
std::ostringstream dummy_padding;
dummy_padding << temp_mount.str() << "/.dummy-padding-file";
if(!cmSystemTools::RemoveFile(dummy_padding.str()))
{
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error assigning custom icon to temporary disk image."
"Error removing dummy padding file."
<< std::endl);
return 0;
had_error = true;
}
// Optionally set the custom icon flag for the image ...
if(!had_error && !cpack_package_icon.empty())
{
std::ostringstream setfile_command;
setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
setfile_command << " -a C";
setfile_command << " \"" << temp_mount.str() << "\"";
if(!this->RunCommand(setfile_command))
{
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error assigning custom icon to temporary disk image."
<< std::endl);
had_error = true;
}
}
// Optionally we can execute a custom apple script to generate
// the .DS_Store for the volume folder ...
if(!had_error && !cpack_dmg_ds_store_setup_script.empty())
{
std::ostringstream setup_script_command;
setup_script_command << "osascript"
<< " \"" << cpack_dmg_ds_store_setup_script << "\""
<< " \"" << cpack_dmg_volume_name << "\"";
std::string error;
if(!this->RunCommand(setup_script_command, &error))
{
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error executing custom script on disk image." << std::endl
<< error
<< std::endl);
had_error = true;
}
}
std::ostringstream detach_command;
@ -508,6 +581,11 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
return 0;
}
if(had_error)
{
return 0;
}
}
if(!cpack_license_file.empty() || !slaDirectory.empty())

View File

@ -36,6 +36,7 @@ protected:
bool CopyFile(std::ostringstream& source, std::ostringstream& target);
bool CreateEmptyFile(std::ostringstream& target, size_t size);
bool RunCommand(std::ostringstream& command, std::string* output = 0);
std::string