Переглянути джерело

productbuild: Add new productbuild cpack generator.

This cpack generator basically replaces the obsolete PackageMaker generator.
Clinton Stimpson 12 роки тому
батько
коміт
2e3c67d1b6

+ 1 - 0
Help/manual/cmake-modules.7.rst

@@ -60,6 +60,7 @@ All Modules
    /module/CPackIFW
    /module/CPackNSIS
    /module/CPackPackageMaker
+   /module/CPackProductBuild
    /module/CPackRPM
    /module/CPack
    /module/CPackWIX

+ 1 - 0
Help/module/CPackProductBuild.rst

@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CPackProductBuild.cmake

+ 3 - 0
Modules/CPack.cmake

@@ -455,6 +455,7 @@ if(NOT CPACK_GENERATOR)
         option(CPACK_BINARY_DRAGNDROP    "Enable to build OSX Drag And Drop package" OFF)
         option(CPACK_BINARY_OSXX11       "Enable to build OSX X11 packages"      OFF)
         option(CPACK_BINARY_PACKAGEMAKER "Enable to build PackageMaker packages" OFF)
+        option(CPACK_BINARY_PRODUCTBUILD "Enable to build productbuild packages" OFF)
       else()
         option(CPACK_BINARY_TZ  "Enable to build TZ packages"     ON)
       endif()
@@ -483,6 +484,7 @@ if(NOT CPACK_GENERATOR)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_NSIS         NSIS)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_OSXX11       OSXX11)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_PACKAGEMAKER PackageMaker)
+  cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_PRODUCTBUILD productbuild)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_RPM          RPM)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_STGZ         STGZ)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_TBZ2         TBZ2)
@@ -531,6 +533,7 @@ mark_as_advanced(
   CPACK_BINARY_NSIS
   CPACK_BINARY_OSXX11
   CPACK_BINARY_PACKAGEMAKER
+  CPACK_BINARY_PRODUCTBUILD
   CPACK_BINARY_RPM
   CPACK_BINARY_STGZ
   CPACK_BINARY_TBZ2

+ 38 - 0
Modules/CPackProductBuild.cmake

@@ -0,0 +1,38 @@
+#.rst:
+# CPackProductBuild
+# -----------------
+#
+# productbuild CPack generator (Mac OS X).
+#
+# Variables specific to CPack productbuild generator
+# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+#
+# The following variable is specific to installers built on Mac
+# OS X using productbuild:
+#
+# .. variable:: CPACK_COMMAND_PRODUCTBUILD
+#
+#  Path to the productbuild(1) command used to generate a product archive for
+#  the OS X Installer or Mac App Store.  This variable can be used to override
+#  the automatically detected command (or specify its location if the
+#  auto-detection fails to find it.)
+#
+# .. variable:: CPACK_COMMAND_PKGBUILD
+#
+#  Path to the pkgbuild(1) command used to generate an OS X component package
+#  on OS X.  This variable can be used to override the automatically detected
+#  command (or specify its location if the auto-detection fails to find it.)
+#
+
+#=============================================================================
+# Copyright 2006-2012 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)

+ 1 - 0
Source/CMakeLists.txt

@@ -719,6 +719,7 @@ if(APPLE)
     CPack/cmCPackOSXX11Generator.cxx
     CPack/cmCPackPKGGenerator.cxx
     CPack/cmCPackPackageMakerGenerator.cxx
+    CPack/cmCPackProductBuildGenerator.cxx
     )
 endif()
 

+ 5 - 0
Source/CPack/cmCPackGeneratorFactory.cxx

@@ -28,6 +28,7 @@
 #include "cmCPackDragNDropGenerator.h"
 #include "cmCPackOSXX11Generator.h"
 #include "cmCPackPackageMakerGenerator.h"
+#include "cmCPackProductBuildGenerator.h"
 #endif
 
 #ifdef __CYGWIN__
@@ -122,6 +123,10 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory()
     this->RegisterGenerator("OSXX11", "Mac OSX X11 bundle",
                             cmCPackOSXX11Generator::CreateGenerator);
   }
+  if (cmCPackProductBuildGenerator::CanGenerate()) {
+    this->RegisterGenerator("productbuild", "Mac OSX pkg",
+      cmCPackProductBuildGenerator::CreateGenerator);
+  }
 #endif
 #if !defined(_WIN32) && !defined(__QNXNTO__) && !defined(__BEOS__) &&         \
   !defined(__HAIKU__)

+ 0 - 1
Source/CPack/cmCPackPKGGenerator.cxx

@@ -41,7 +41,6 @@ int cmCPackPKGGenerator::InitializeInternal()
 {
   cmCPackLogger(cmCPackLog::LOG_DEBUG,
                 "cmCPackPKGGenerator::Initialize()" << std::endl);
-  this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
 
   return this->Superclass::InitializeInternal();
 }

+ 2 - 0
Source/CPack/cmCPackPackageMakerGenerator.cxx

@@ -329,6 +329,8 @@ int cmCPackPackageMakerGenerator::PackageFiles()
 
 int cmCPackPackageMakerGenerator::InitializeInternal()
 {
+  this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+
   // Starting with Xcode 4.3, PackageMaker is a separate app, and you
   // can put it anywhere you want. So... use a variable for its location.
   // People who put it in unexpected places can use the variable to tell

+ 260 - 0
Source/CPack/cmCPackProductBuildGenerator.cxx

@@ -0,0 +1,260 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmCPackProductBuildGenerator.h"
+
+#include "cmake.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmSystemTools.h"
+#include "cmMakefile.h"
+#include "cmGeneratedFileStream.h"
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+
+#include <cmsys/SystemTools.hxx>
+#include <cmsys/Glob.hxx>
+
+cmCPackProductBuildGenerator::cmCPackProductBuildGenerator()
+{
+  this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackProductBuildGenerator::~cmCPackProductBuildGenerator()
+{
+}
+
+int cmCPackProductBuildGenerator::PackageFiles()
+{
+  // TODO: Use toplevel
+  //       It is used! Is this an obsolete comment?
+
+  std::string packageDirFileName
+    = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+
+  // Create the directory where component packages will be built.
+  std::string basePackageDir = packageDirFileName;
+  basePackageDir += "/Contents/Packages";
+  if (!cmsys::SystemTools::MakeDirectory(basePackageDir.c_str()))
+  {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+                  "Problem creating component packages directory: "
+                  << basePackageDir.c_str() << std::endl);
+    return 0;
+  }
+
+  if (!this->Components.empty())
+    {
+    std::map<std::string, cmCPackComponent>::iterator compIt;
+    for (compIt = this->Components.begin(); compIt != this->Components.end();
+         ++compIt)
+      {
+      std::string packageDir = toplevel;
+      packageDir += '/';
+      packageDir += compIt->first;
+      if (!this->GenerateComponentPackage(basePackageDir,
+                                          GetPackageName(compIt->second),
+                                          packageDir,
+                                          &compIt->second))
+        {
+        return 0;
+        }
+      }
+    }
+  else
+  {
+    if(!this->GenerateComponentPackage(basePackageDir,
+                                       this->GetOption("CPACK_PACKAGE_NAME"),
+                                       toplevel, NULL))
+    {
+      return 0;
+    }
+  }
+
+  // Copy or create all of the resource files we need.
+  std::string resDir = packageDirFileName + "/Contents";
+  if ( !this->CopyCreateResourceFile("License", resDir.c_str())
+      || !this->CopyCreateResourceFile("ReadMe", resDir.c_str())
+      || !this->CopyCreateResourceFile("Welcome", resDir.c_str()))
+  {
+    cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
+                  << std::endl);
+    return 0;
+  }
+
+  // combine package(s) into a distribution
+  WriteDistributionFile(packageDirFileName.c_str());
+  std::ostringstream pkgCmd;
+
+  std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
+  std::string productbuild = this->GetOption("CPACK_COMMAND_PRODUCTBUILD");
+
+  pkgCmd << productbuild
+  << " --distribution \"" << packageDirFileName
+    << "/Contents/distribution.dist\""
+  << " --package-path \"" << packageDirFileName << "/Contents/Packages" << "\""
+  << " --resources \"" << resDir << "\""
+  << " --version \"" << version << "\""
+  << " \"" << packageFileNames[0] << "\"";
+
+  // Run ProductBuild
+  return RunProductBuild(pkgCmd.str());
+}
+
+int cmCPackProductBuildGenerator::InitializeInternal()
+{
+  this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/Applications");
+
+  std::vector<std::string> no_paths;
+  std::string program =
+    cmSystemTools::FindProgram("pkgbuild", no_paths, false);
+  if (program.empty()) {
+    cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find pkgbuild executable"
+                    << std::endl);
+    return 0;
+  }
+  this->SetOptionIfNotSet("CPACK_COMMAND_PKGBUILD", program.c_str());
+
+
+  program = cmSystemTools::FindProgram("productbuild", no_paths, false);
+  if (program.empty()) {
+    cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find productbuild executable"
+                    << std::endl);
+    return 0;
+  }
+  this->SetOptionIfNotSet("CPACK_COMMAND_PRODUCTBUILD", program.c_str());
+
+  return this->Superclass::InitializeInternal();
+}
+
+
+bool cmCPackProductBuildGenerator::RunProductBuild(
+  const std::string& command)
+{
+  std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+  tmpFile += "/ProductBuildOutput.log";
+
+  cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl);
+  std::string output, error_output;
+  int retVal = 1;
+  bool res = cmSystemTools::RunSingleCommand(command.c_str(),
+    &output, &error_output, &retVal, 0, this->GeneratorVerbose, 0);
+  cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command"
+    << std::endl);
+  if ( !res || retVal )
+    {
+    cmGeneratedFileStream ofs(tmpFile.c_str());
+    ofs << "# Run command: " << command << std::endl
+      << "# Output:" << std::endl
+      << output.c_str() << std::endl;
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+      "Problem running command: " << command
+      << std::endl << "Please check " << tmpFile.c_str() << " for errors"
+      << std::endl);
+    return false;
+    }
+  return true;
+}
+
+bool cmCPackProductBuildGenerator::GenerateComponentPackage(
+  const std::string& packageFileDir,
+  const std::string& packageFileName,
+  const std::string& packageDir,
+  const cmCPackComponent* component)
+{
+  std::string packageFile = packageFileDir;
+  packageFile += '/';
+  packageFile += packageFileName;
+
+  cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+                "-   Building component package: " <<
+                packageFile << std::endl);
+
+  const char* comp_name = component ? component->Name.c_str() : NULL;
+
+  const char* preflight = this->GetComponentScript("PREFLIGHT", comp_name);
+  const char* postflight = this->GetComponentScript("POSTFLIGHT", comp_name);
+
+  std::string resDir = packageFileDir;
+  if(component)
+  {
+    resDir += "/";
+    resDir += component->Name;
+  }
+  std::string scriptDir = resDir + "/scripts";
+
+  if ( !cmsys::SystemTools::MakeDirectory(scriptDir.c_str()))
+  {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+                  "Problem creating installer directory: "
+                  << scriptDir.c_str() << std::endl);
+    return 0;
+  }
+
+  // if preflight, postflight, or postupgrade are set
+  // then copy them into the script directory and make
+  // them executable
+  if(preflight)
+  {
+    this->CopyInstallScript(scriptDir.c_str(),
+                            preflight,
+                            "preinstall");
+  }
+  if(postflight)
+  {
+    this->CopyInstallScript(scriptDir.c_str(),
+                            postflight,
+                            "postinstall");
+  }
+
+
+  // The command that will be used to run ProductBuild
+  std::ostringstream pkgCmd;
+
+  std::string pkgId = "com.";
+  pkgId += this->GetOption("CPACK_PACKAGE_VENDOR");
+  pkgId += '.';
+  pkgId += this->GetOption("CPACK_PACKAGE_NAME");
+  if(component)
+    {
+    pkgId += '.';
+    pkgId += component->Name;
+    }
+
+  std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
+  std::string pkgbuild = this->GetOption("CPACK_COMMAND_PKGBUILD");
+
+  pkgCmd << pkgbuild
+         << " --root \"" << packageDir << "\""
+         << " --identifier \"" << pkgId << "\""
+         << " --scripts \"" << scriptDir << "\""
+         << " --version \"" << version << "\""
+         << " --install-location \"/\""
+         << " \"" << packageFile << "\"";
+
+  // Run ProductBuild
+  return RunProductBuild(pkgCmd.str());
+}
+
+const char* cmCPackProductBuildGenerator::GetComponentScript(
+  const char* script,
+  const char* component_name)
+{
+  std::string scriptname = std::string("CPACK_") + script + "_";
+  if(component_name)
+  {
+    scriptname += cmSystemTools::UpperCase(component_name);
+    scriptname += "_";
+  }
+  scriptname += "SCRIPT";
+
+  return this->GetOption(scriptname);
+}

+ 60 - 0
Source/CPack/cmCPackProductBuildGenerator.h

@@ -0,0 +1,60 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc.
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackProductBuildGenerator_h
+#define cmCPackProductBuildGenerator_h
+
+
+#include "cmCPackPKGGenerator.h"
+
+class cmCPackComponent;
+
+/** \class cmCPackProductBuildGenerator
+ * \brief A generator for ProductBuild files
+ *
+ */
+class cmCPackProductBuildGenerator : public cmCPackPKGGenerator
+{
+public:
+  cmCPackTypeMacro(cmCPackProductBuildGenerator, cmCPackPKGGenerator);
+
+  /**
+   * Construct generator
+   */
+  cmCPackProductBuildGenerator();
+  virtual ~cmCPackProductBuildGenerator();
+
+protected:
+  virtual int InitializeInternal();
+  int PackageFiles();
+  virtual const char* GetOutputExtension() { return ".pkg"; }
+
+  // Run ProductBuild with the given command line, which will (if
+  // successful) produce the given package file. Returns true if
+  // ProductBuild succeeds, false otherwise.
+  bool RunProductBuild(const std::string& command);
+
+  // Generate a package in the file packageFile for the given
+  // component.  All of the files within this component are stored in
+  // the directory packageDir. Returns true if successful, false
+  // otherwise.
+  bool GenerateComponentPackage(const std::string& packageFileDir,
+                                const std::string& packageFileName,
+                                const std::string& packageDir,
+                                const cmCPackComponent* component);
+
+  const char* GetComponentScript(const char* script,
+                                 const char* script_component);
+
+};
+
+#endif

+ 11 - 0
Tests/CMakeLists.txt

@@ -951,6 +951,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
     set(CPackComponents_BUILD_OPTIONS)
     if(APPLE)
       set(CPackComponents_BUILD_OPTIONS -DCPACK_BINARY_DRAGNDROP:BOOL=ON)
+      if(CMake_TEST_XCODE_VERSION VERSION_GREATER "4.6")
+        set(CPackComponents_BUILD_OPTIONS ${CPackComponents_BUILD_OPTIONS}
+          -DCPACK_BINARY_PRODUCTBUILD:BOOL=ON)
+      endif()
     endif()
     if(NSIS_MAKENSIS_EXECUTABLE)
       set(CPackComponents_BUILD_OPTIONS ${CPackComponents_BUILD_OPTIONS}
@@ -995,6 +999,9 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
     list(APPEND ACTIVE_CPACK_GENERATORS "ZIP")
     if(APPLE)
       list(APPEND ACTIVE_CPACK_GENERATORS "DragNDrop")
+      if(CMake_TEST_XCODE_VERSION VERSION_GREATER "4.6")
+        list(APPEND ACTIVE_CPACK_GENERATORS "productbuild")
+      endif()
     endif()
 
     # set up list of component packaging ways
@@ -1105,6 +1112,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
     set(CPackComponents_BUILD_OPTIONS)
     if(APPLE)
       set(CPackComponents_BUILD_OPTIONS -DCPACK_BINARY_DRAGNDROP:BOOL=ON)
+      if(CMake_TEST_XCODE_VERSION VERSION_GREATER "4.6")
+        set(CPackComponents_BUILD_OPTIONS ${CPackComponents_BUILD_OPTIONS}
+          -DCPACK_BINARY_PRODUCTBUILD:BOOL=ON)
+      endif()
     endif()
     if(NOT NSIS_MAKENSIS_EXECUTABLE)
       set(CPackComponents_BUILD_OPTIONS ${CPackComponents_BUILD_OPTIONS}