Pārlūkot izejas kodu

ENH: Apply patch for feature request #7170. Thanks to Tim Shead for contributing...

David Cole 17 gadi atpakaļ
vecāks
revīzija
79e255a7d3

+ 3 - 1
Modules/CPack.cmake

@@ -114,6 +114,7 @@ if(NOT CPACK_GENERATOR)
       option(CPACK_BINARY_CYGWIN "Enable to build Cygwin binary packages" ON)
     else(CYGWIN)
       if(APPLE)
+        option(CPACK_BINARY_BUNDLE       "Enable to build OSX bundles"      OFF)
         option(CPACK_BINARY_PACKAGEMAKER "Enable to build PackageMaker packages" ON)
         option(CPACK_BINARY_OSXX11       "Enable to build OSX X11 packages"      OFF)
       else(APPLE)
@@ -131,6 +132,7 @@ if(NOT CPACK_GENERATOR)
     option(CPACK_BINARY_ZIP  "Enable to build ZIP packages" ON)
   endif(UNIX)
   
+  cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_BUNDLE       Bundle)
   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)
@@ -171,7 +173,7 @@ endif(NOT CPACK_SOURCE_GENERATOR)
 mark_as_advanced(CPACK_BINARY_CYGWIN CPACK_BINARY_PACKAGEMAKER CPACK_BINARY_OSXX11
                  CPACK_BINARY_STGZ   CPACK_BINARY_TGZ          CPACK_BINARY_TBZ2 
                  CPACK_BINARY_DEB    CPACK_BINARY_RPM          CPACK_BINARY_TZ     
-                 CPACK_BINARY_NSIS CPACK_BINARY_ZIP 
+                 CPACK_BINARY_NSIS CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE
                  CPACK_SOURCE_CYGWIN CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ 
                  CPACK_SOURCE_TZ CPACK_SOURCE_ZIP)
 

+ 1 - 0
Source/CMakeLists.txt

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

+ 319 - 0
Source/CPack/cmCPackBundleGenerator.cxx

@@ -0,0 +1,319 @@
+/*=========================================================================
+
+  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 "cmCPackBundleGenerator.h"
+#include "cmCPackLog.h"
+#include "cmSystemTools.h"
+
+//----------------------------------------------------------------------
+cmCPackBundleGenerator::cmCPackBundleGenerator()
+{
+}
+
+//----------------------------------------------------------------------
+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()
+{
+  this->InstallPrefix = "/";
+  this->InstallPrefix += this->GetOption("CPACK_BUNDLE_NAME");
+  this->InstallPrefix += ".app/Contents/Resources";
+
+  return this->InstallPrefix.c_str();
+}
+
+//----------------------------------------------------------------------
+int cmCPackBundleGenerator::CompressFiles(const char* outFileName,
+  const char* toplevel, const std::vector<std::string>& files)
+{
+  // The staging directory contains everything that will end-up inside the
+  // final disk image ...
+  cmOStringStream staging;
+  staging << toplevel;
+
+  cmOStringStream contents;
+  contents << staging.str() << "/" << this->GetOption("CPACK_BUNDLE_NAME")
+    << ".app/" << "Contents";
+
+  cmOStringStream application;
+  application << contents.str() << "/" << "MacOS";
+
+  cmOStringStream resources;
+  resources << contents.str() << "/" << "Resources";
+
+  // Install a user-provided bundle metadata file ...
+  if(this->GetOption("CPACK_BUNDLE_PLIST"))
+    {
+    cmOStringStream plist_source;
+    plist_source << this->GetOption("CPACK_BUNDLE_PLIST");
+
+    cmOStringStream plist_target;
+    plist_target << contents.str() << "/" << "Info.plist";
+
+    if(!this->CopyFile(plist_source, plist_target))
+      {
+      return 0;
+      }
+    }
+
+  // Install a user-provided bundle icon ...
+  if(this->GetOption("CPACK_BUNDLE_ICON"))
+    {
+    cmOStringStream icon_source;
+    icon_source << this->GetOption("CPACK_BUNDLE_ICON");
+
+    cmOStringStream icon_target;
+    icon_target << resources.str() << "/"
+      << this->GetOption("CPACK_BUNDLE_NAME") << ".icns";
+
+    if(!this->CopyFile(icon_source, icon_target))
+      {
+      return 0;
+      }
+    }
+
+  // Install a user-provided startup command (could be an executable or a
+  // script) ...
+  if(this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND"))
+    {
+    cmOStringStream command_source;
+    command_source << this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND");
+
+    cmOStringStream command_target;
+    command_target << application.str() << "/"
+      << this->GetOption("CPACK_BUNDLE_NAME");
+
+    if(!this->CopyFile(command_source, command_target))
+      {
+      return 0;
+      }
+
+    cmSystemTools::SetPermissions(command_target.str().c_str(), 0777);
+    }
+
+  // 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(this->GetOption("CPACK_PACKAGE_ICON"))
+    {
+    cmOStringStream package_icon_source;
+    package_icon_source << this->GetOption("CPACK_PACKAGE_ICON");
+
+    cmOStringStream package_icon_destination;
+    package_icon_destination << staging.str() << "/.VolumeIcon.icns";
+
+    if(!this->CopyFile(package_icon_source, package_icon_destination))
+      {
+      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))
+    {
+    return 0;
+    }
+
+  // Optionally set the custom icon flag for the image ...
+  if(this->GetOption("CPACK_PACKAGE_ICON"))
+    {
+    cmOStringStream temp_mount;
+    temp_mount << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/mnt";
+    cmSystemTools::MakeDirectory(temp_mount.str().c_str());
+
+    cmOStringStream attach_command;
+    attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+    attach_command << " attach";
+    attach_command << " -mountpoint \"" << temp_mount.str() << "\"";
+    attach_command << " \"" << temp_image.str() << "\"";
+
+    if(!this->RunCommand(attach_command))
+      {
+      return 0;
+      }
+
+    cmOStringStream setfile_command;
+    setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
+    setfile_command << " -a C";
+    setfile_command << " \"" << temp_mount.str() << "\"";
+
+    if(!this->RunCommand(setfile_command))
+      {
+      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))
+      {
+      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))
+    {
+    return 0;
+    }
+
+/*
+  // Disk image directories
+  std::string diskImageDirectory = toplevel;
+  std::string diskImageBackgroundImageDir = diskImageDirectory
+    + "/.background";
+
+  // App bundle directories
+  std::string packageDirFileName = toplevel;
+  packageDirFileName += "/";
+  packageDirFileName += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+  packageDirFileName += ".app";
+  std::string contentsDirectory = packageDirFileName + "/Contents";
+  std::string resourcesDirectory = contentsDirectory + "/Resources";
+  std::string appDirectory = contentsDirectory + "/MacOS";
+
+  const char* dir = resourcesDirectory.c_str();
+  const char* appdir = appDirectory.c_str();
+  const char* contDir = contentsDirectory.c_str();
+  const char* iconFile = this->GetOption("CPACK_PACKAGE_ICON");
+  if ( iconFile )
+    {
+    std::string iconFileName = cmsys::SystemTools::GetFilenameName(iconFile);
+    if ( !cmSystemTools::FileExists(iconFile) )
+      {
+      cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find icon file: "
+        << iconFile << ". Please check CPACK_PACKAGE_ICON setting."
+        << std::endl);
+      return 0;
+      }
+    std::string destFileName = resourcesDirectory + "/" + iconFileName;
+    this->ConfigureFile(iconFile, destFileName.c_str(), true);
+    this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str());
+    }
+
+  if (
+    !this->CopyResourcePlistFile("VolumeIcon.icns", 
+                                 diskImageDirectory.c_str(),
+                                 ".VolumeIcon.icns", true ) ||
+    !this->CopyResourcePlistFile("DS_Store", diskImageDirectory.c_str(),
+      ".DS_Store", true ) ||
+    !this->CopyResourcePlistFile("background.png",
+      diskImageBackgroundImageDir.c_str(), "background.png", true ) ||
+    !this->CopyResourcePlistFile("RuntimeScript", dir) ||
+    !this->CopyResourcePlistFile("Bundle.Info.plist", contDir,
+      "Info.plist" ) ||
+    !this->CopyResourcePlistFile("OSXScriptLauncher", appdir, 
+      this->GetOption("CPACK_PACKAGE_FILE_NAME"), true)
+  )
+    {
+    cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
+      << std::endl);
+    return 0;
+    }
+*/
+
+  return 1;
+}
+
+//----------------------------------------------------------------------
+bool cmCPackBundleGenerator::CopyFile(cmOStringStream& source,
+  cmOStringStream& target)
+{
+  return cmSystemTools::CopyFileIfDifferent(source.str().c_str(),
+    target.str().c_str());
+}
+
+//----------------------------------------------------------------------
+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, "Problem running command: "
+      << command.str().c_str() << std::endl);
+    return false;
+    }
+
+  return true;
+}

+ 49 - 0
Source/CPack/cmCPackBundleGenerator.h

@@ -0,0 +1,49 @@
+/*=========================================================================
+
+  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 cmCPackBundleGenerator_h
+#define cmCPackBundleGenerator_h
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackBundleGenerator
+ * \brief A generator for OSX bundles
+ *
+ * Based on Gimp.app
+ */
+class cmCPackBundleGenerator : public cmCPackGenerator
+{
+public:
+  cmCPackTypeMacro(cmCPackBundleGenerator, cmCPackGenerator);
+
+  cmCPackBundleGenerator();
+  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 InstallPrefix;
+};
+
+#endif

+ 3 - 0
Source/CPack/cmCPackGeneratorFactory.cxx

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