CPack/DragNDrop: Optionally run an AppleScript when making a package

While the DragNDropGenerator supports custom DS_Store and backgrounds,
it is still very hard to automatically setup nice looking packages. The
primary issue is that the DS_Store embeds the name of the volume in the
path to backgrounds, which means that if a package embeds the version in
its volume name a new DS_Store must generated for each release.

Instead one now can use applescript to setup the DS_Store.

This change also ensures that temporary RW image has enough space for
these changes, creating 1 MB dummy padding file, that is later removed
from the image.

Co-Author: Adam Strzelecki <adam.strzelecki@java.pl>
This commit is contained in:
Robert Maynard 2014-09-26 14:38:38 -04:00 committed by Brad King
parent 9c1dfbfd60
commit 167a465565
2 changed files with 100 additions and 11 deletions

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)
@ -424,6 +450,25 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
}
}
bool remount_image = !cpack_package_icon.empty() ||
!cpack_dmg_ds_store_setup_script.empty();
// 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 creating dummy padding file."
<< std::endl);
return 0;
}
}
// Create a temporary read-write disk image ...
std::string temp_image = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
temp_image += "/temp.dmg";
@ -447,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");
@ -469,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;
@ -498,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