浏览代码

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 <[email protected]>
Robert Maynard 11 年之前
父节点
当前提交
167a465565
共有 2 个文件被更改,包括 100 次插入11 次删除
  1. 99 11
      Source/CPack/cmCPackDragNDropGenerator.cxx
  2. 1 0
      Source/CPack/cmCPackDragNDropGenerator.h

+ 99 - 11
Source/CPack/cmCPackDragNDropGenerator.cxx

@@ -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())

+ 1 - 0
Source/CPack/cmCPackDragNDropGenerator.h

@@ -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