Browse Source

BUG: Fix issue #8402. Add a drag and drop bundle generator to the Mac build of CPack. Add a test of it in the CPackComponents test. Thanks to Clinton Stimpson for the patch.

David Cole 16 years ago
parent
commit
3a4f76949a

+ 3 - 1
Modules/CPack.cmake

@@ -708,6 +708,7 @@ if(NOT CPACK_GENERATOR)
     else(CYGWIN)
       if(APPLE)
         option(CPACK_BINARY_BUNDLE       "Enable to build OSX bundles"      OFF)
+        option(CPACK_BINARY_DRAGNDROP    "Enable to build OSX Drag And Drop package" OFF)
         option(CPACK_BINARY_PACKAGEMAKER "Enable to build PackageMaker packages" ON)
         option(CPACK_BINARY_OSXX11       "Enable to build OSX X11 packages"      OFF)
       else(APPLE)
@@ -726,6 +727,7 @@ if(NOT CPACK_GENERATOR)
   endif(UNIX)
   
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_BUNDLE       Bundle)
+  cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_DRAGNDROP    DragNDrop)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_PACKAGEMAKER PackageMaker)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_OSXX11       OSXX11)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_CYGWIN       CygwinBinary)
@@ -768,7 +770,7 @@ mark_as_advanced(CPACK_BINARY_CYGWIN CPACK_BINARY_PACKAGEMAKER CPACK_BINARY_OSXX
                  CPACK_BINARY_DEB    CPACK_BINARY_RPM          CPACK_BINARY_TZ     
                  CPACK_BINARY_NSIS CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE
                  CPACK_SOURCE_CYGWIN CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ 
-                 CPACK_SOURCE_TZ CPACK_SOURCE_ZIP)
+                 CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP)
 
 # Set some other variables
 cpack_set_if_not_set(CPACK_INSTALL_CMAKE_PROJECTS

+ 1 - 0
Source/CMakeLists.txt

@@ -378,6 +378,7 @@ ENDIF(UNIX)
 IF(APPLE)
   SET(CPACK_SRCS ${CPACK_SRCS}
     CPack/cmCPackBundleGenerator.cxx
+    CPack/cmCPackDragNDropGenerator.cxx
     CPack/cmCPackOSXX11Generator.cxx
     CPack/cmCPackPackageMakerGenerator.cxx
     )

+ 0 - 82
Source/CPack/cmCPackBundleGenerator.cxx

@@ -31,40 +31,6 @@ cmCPackBundleGenerator::~cmCPackBundleGenerator()
 {
 }
 
-//----------------------------------------------------------------------
-int cmCPackBundleGenerator::InitializeInternal()
-{
-  const std::string hdiutil_path = cmSystemTools::FindProgram("hdiutil",
-    std::vector<std::string>(), false);
-  if(hdiutil_path.empty())
-    {
-    cmCPackLogger(cmCPackLog::LOG_ERROR,
-      "Cannot locate hdiutil command"
-      << std::endl);
-    return 0;
-    }
-  this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path.c_str());
-
-  const std::string setfile_path = cmSystemTools::FindProgram("SetFile",
-    std::vector<std::string>(1, "/Developer/Tools"), false);
-  if(setfile_path.empty())
-    {
-    cmCPackLogger(cmCPackLog::LOG_ERROR,
-      "Cannot locate SetFile command"
-      << std::endl);
-    return 0;
-    }
-  this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path.c_str());
-
-  return this->Superclass::InitializeInternal();
-}
-
-//----------------------------------------------------------------------
-const char* cmCPackBundleGenerator::GetOutputExtension()
-{
-  return ".dmg";
-}
-
 //----------------------------------------------------------------------
 const char* cmCPackBundleGenerator::GetPackagingInstallPrefix()
 {
@@ -316,51 +282,3 @@ int cmCPackBundleGenerator::CompressFiles(const char* outFileName,
 
   return 1;
 }
-
-//----------------------------------------------------------------------
-bool cmCPackBundleGenerator::CopyFile(cmOStringStream& source,
-  cmOStringStream& target)
-{
-  if(!cmSystemTools::CopyFileIfDifferent(
-    source.str().c_str(),
-    target.str().c_str()))
-    {
-    cmCPackLogger(cmCPackLog::LOG_ERROR,
-      "Error copying "
-      << source.str()
-      << " to "
-      << target.str()
-      << std::endl);
-
-    return false;
-    }
-
-  return true;
-}
-
-//----------------------------------------------------------------------
-bool cmCPackBundleGenerator::RunCommand(cmOStringStream& command, 
-  std::string* output)
-{
-  int exit_code = 1;
-
-  bool result = cmSystemTools::RunSingleCommand(
-    command.str().c_str(),
-    output,
-    &exit_code,
-    0,
-    this->GeneratorVerbose,
-    0);
-
-  if(!result || exit_code)
-    {
-    cmCPackLogger(cmCPackLog::LOG_ERROR,
-      "Error executing: "
-      << command.str()
-      << std::endl);
-
-    return false;
-    }
-
-  return true;
-}

+ 2 - 7
Source/CPack/cmCPackBundleGenerator.h

@@ -18,14 +18,14 @@
 #ifndef cmCPackBundleGenerator_h
 #define cmCPackBundleGenerator_h
 
-#include "cmCPackGenerator.h"
+#include "cmCPackDragNDropGenerator.h"
 
 /** \class cmCPackBundleGenerator
  * \brief A generator for OSX bundles
  *
  * Based on Gimp.app
  */
-class cmCPackBundleGenerator : public cmCPackGenerator
+class cmCPackBundleGenerator : public cmCPackDragNDropGenerator
 {
 public:
   cmCPackTypeMacro(cmCPackBundleGenerator, cmCPackGenerator);
@@ -34,15 +34,10 @@ public:
   virtual ~cmCPackBundleGenerator();
 
 protected:
-  virtual int InitializeInternal();
-  virtual const char* GetOutputExtension();
   virtual const char* GetPackagingInstallPrefix();
   int CompressFiles(const char* outFileName, const char* toplevel,
     const std::vector<std::string>& files);
 
-  bool CopyFile(cmOStringStream& source, cmOStringStream& target);
-  bool RunCommand(cmOStringStream& command, std::string* output = 0);
-
   std::string InstallPrefix;
 };
 

+ 253 - 0
Source/CPack/cmCPackDragNDropGenerator.cxx

@@ -0,0 +1,253 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+#include "cmCPackDragNDropGenerator.h"
+#include "cmCPackLog.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+//----------------------------------------------------------------------
+cmCPackDragNDropGenerator::cmCPackDragNDropGenerator()
+{
+}
+
+//----------------------------------------------------------------------
+cmCPackDragNDropGenerator::~cmCPackDragNDropGenerator()
+{
+}
+
+//----------------------------------------------------------------------
+int cmCPackDragNDropGenerator::InitializeInternal()
+{
+  const std::string hdiutil_path = cmSystemTools::FindProgram("hdiutil",
+    std::vector<std::string>(), false);
+  if(hdiutil_path.empty())
+    {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+      "Cannot locate hdiutil command"
+      << std::endl);
+    return 0;
+    }
+  this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path.c_str());
+
+  const std::string setfile_path = cmSystemTools::FindProgram("SetFile",
+    std::vector<std::string>(1, "/Developer/Tools"), false);
+  if(setfile_path.empty())
+    {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+      "Cannot locate SetFile command"
+      << std::endl);
+    return 0;
+    }
+  this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path.c_str());
+
+  return this->Superclass::InitializeInternal();
+}
+
+//----------------------------------------------------------------------
+const char* cmCPackDragNDropGenerator::GetOutputExtension()
+{
+  return ".dmg";
+}
+
+//----------------------------------------------------------------------
+int cmCPackDragNDropGenerator::CompressFiles(const char* outFileName,
+  const char* toplevel, const std::vector<std::string>& files)
+{
+  (void) files;
+
+  // Get optional arguments ...
+  const std::string cpack_package_icon = this->GetOption("CPACK_PACKAGE_ICON") 
+    ? this->GetOption("CPACK_PACKAGE_ICON") : "";
+
+  // The staging directory contains everything that will end-up inside the
+  // final disk image ...
+  cmOStringStream staging;
+  staging << toplevel;
+
+  // Add a symlink to /Applications so users can drag-and-drop the bundle
+  // into it
+  cmOStringStream application_link;
+  application_link << staging.str() << "/Applications";
+  cmSystemTools::CreateSymlink("/Applications",
+    application_link.str().c_str());
+
+  // Optionally add a custom volume icon ...
+  if(!cpack_package_icon.empty())
+    {
+    cmOStringStream package_icon_source;
+    package_icon_source << cpack_package_icon;
+
+    cmOStringStream package_icon_destination;
+    package_icon_destination << staging.str() << "/.VolumeIcon.icns";
+
+    if(!this->CopyFile(package_icon_source, package_icon_destination))
+      {
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+        "Error copying disk volume icon.  "
+                    "Check the value of CPACK_PACKAGE_ICON."
+        << std::endl);
+
+      return 0;
+      }
+    }
+
+  // Create a temporary read-write disk image ...
+  cmOStringStream temp_image;
+  temp_image << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/temp.dmg";
+
+  cmOStringStream temp_image_command;
+  temp_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+  temp_image_command << " create";
+  temp_image_command << " -ov";
+  temp_image_command << " -srcfolder \"" << staging.str() << "\"";
+  temp_image_command << " -volname \""
+    << this->GetOption("CPACK_PACKAGE_FILE_NAME") << "\"";
+  temp_image_command << " -format UDRW";
+  temp_image_command << " \"" << temp_image.str() << "\"";
+
+  if(!this->RunCommand(temp_image_command))
+    {
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+        "Error generating temporary disk image."
+        << std::endl);
+
+    return 0;
+    }
+
+  // Optionally set the custom icon flag for the image ...
+  if(!cpack_package_icon.empty())
+    {
+    cmOStringStream temp_mount;
+
+    cmOStringStream attach_command;
+    attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+    attach_command << " attach";
+    attach_command << " \"" << temp_image.str() << "\"";
+
+    std::string attach_output;
+    if(!this->RunCommand(attach_command, &attach_output))
+      {
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+        "Error attaching temporary disk image."
+        << std::endl);
+
+      return 0;
+      }
+
+    cmsys::RegularExpression mountpoint_regex(".*(/Volumes/[^\n]+)\n.*");
+    mountpoint_regex.find(attach_output.c_str());
+    temp_mount << mountpoint_regex.match(1);
+
+    cmOStringStream 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);
+
+      return 0;
+      }
+
+    cmOStringStream detach_command;
+    detach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+    detach_command << " detach";
+    detach_command << " \"" << temp_mount.str() << "\""; 
+
+    if(!this->RunCommand(detach_command))
+      {
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+        "Error detaching temporary disk image."
+        << std::endl);
+
+      return 0;
+      }
+    }
+
+  // Create the final compressed read-only disk image ...
+  cmOStringStream final_image_command;
+  final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+  final_image_command << " convert \"" << temp_image.str() << "\"";
+  final_image_command << " -format UDZO";
+  final_image_command << " -imagekey";
+  final_image_command << " zlib-level=9";
+  final_image_command << " -o \"" << outFileName << "\"";
+
+  if(!this->RunCommand(final_image_command))
+    {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+      "Error compressing disk image."
+      << std::endl);
+
+    return 0;
+    }
+
+  return 1;
+}
+
+//----------------------------------------------------------------------
+bool cmCPackDragNDropGenerator::CopyFile(cmOStringStream& source,
+  cmOStringStream& target)
+{
+  if(!cmSystemTools::CopyFileIfDifferent(
+    source.str().c_str(),
+    target.str().c_str()))
+    {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+      "Error copying "
+      << source.str()
+      << " to "
+      << target.str()
+      << std::endl);
+
+    return false;
+    }
+
+  return true;
+}
+
+//----------------------------------------------------------------------
+bool cmCPackDragNDropGenerator::RunCommand(cmOStringStream& command,
+  std::string* output)
+{
+  int exit_code = 1;
+
+  bool result = cmSystemTools::RunSingleCommand(
+    command.str().c_str(),
+    output,
+    &exit_code,
+    0,
+    this->GeneratorVerbose,
+    0);
+
+  if(!result || exit_code)
+    {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+      "Error executing: "
+      << command.str()
+      << std::endl);
+
+    return false;
+    }
+
+  return true;
+}

+ 47 - 0
Source/CPack/cmCPackDragNDropGenerator.h

@@ -0,0 +1,47 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc. All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+#ifndef cmCPackDragNDropGenerator_h
+#define cmCPackDragNDropGenerator_h
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackDragNDropGenerator
+ * \brief A generator for OSX drag-n-drop installs
+ */
+class cmCPackDragNDropGenerator : public cmCPackGenerator
+{
+public:
+  cmCPackTypeMacro(cmCPackDragNDropGenerator, cmCPackGenerator);
+
+  cmCPackDragNDropGenerator();
+  virtual ~cmCPackDragNDropGenerator();
+
+protected:
+  virtual int InitializeInternal();
+  virtual const char* GetOutputExtension();
+  int CompressFiles(const char* outFileName, const char* toplevel,
+    const std::vector<std::string>& files);
+
+  bool CopyFile(cmOStringStream& source, cmOStringStream& target);
+  bool RunCommand(cmOStringStream& command, std::string* output = 0);
+
+  std::string InstallPrefix;
+};
+
+#endif
+

+ 3 - 0
Source/CPack/cmCPackGeneratorFactory.cxx

@@ -25,6 +25,7 @@
 #include "cmCPackSTGZGenerator.h"
 #include "cmCPackNSISGenerator.h"
 #ifdef __APPLE__
+#  include "cmCPackDragNDropGenerator.h"
 #  include "cmCPackBundleGenerator.h"
 #  include "cmCPackPackageMakerGenerator.h"
 #  include "cmCPackOSXX11Generator.h"
@@ -67,6 +68,8 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory()
   this->RegisterGenerator("TZ", "Tar Compress compression",
     cmCPackTarCompressGenerator::CreateGenerator);
 #ifdef __APPLE__
+  this->RegisterGenerator("DragNDrop", "Mac OSX Drag And Drop",
+    cmCPackDragNDropGenerator::CreateGenerator);
   this->RegisterGenerator("Bundle", "Mac OSX bundle",
     cmCPackBundleGenerator::CreateGenerator);
   this->RegisterGenerator("PackageMaker", "Mac OSX Package Maker installer",

+ 6 - 0
Tests/CMakeLists.txt

@@ -391,6 +391,11 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel
   endif(WIN32)
 
   IF(CTEST_RUN_CPackComponents)
+    set(CPackComponents_EXTRA_OPTIONS)
+    if(APPLE)
+      set(CPackComponents_EXTRA_OPTIONS -DCPACK_BINARY_DRAGNDROP:BOOL=ON)
+    endif(APPLE)
+
     ADD_TEST(CPackComponents ${CMAKE_CTEST_COMMAND}
       --build-and-test
       "${CMake_SOURCE_DIR}/Tests/CPackComponents"
@@ -403,6 +408,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel
       --build-options
         -DCPACK_BINARY_DEB:BOOL=${CPACK_BINARY_DEB}
         -DCPACK_BINARY_RPM:BOOL=${CPACK_BINARY_RPM}
+        ${CPackComponents_EXTRA_OPTIONS}
       --test-command ${CMAKE_CMAKE_COMMAND}
         "-DCPackComponents_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackComponents"
         -P "${CMake_SOURCE_DIR}/Tests/CPackComponents/VerifyResult.cmake")