| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941 | /*============================================================================  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 "cmCPackPackageMakerGenerator.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>//----------------------------------------------------------------------cmCPackPackageMakerGenerator::cmCPackPackageMakerGenerator(){  this->PackageMakerVersion = 0.0;  this->PackageCompatibilityVersion = 10.4;}//----------------------------------------------------------------------cmCPackPackageMakerGenerator::~cmCPackPackageMakerGenerator(){}//----------------------------------------------------------------------bool cmCPackPackageMakerGenerator::SupportsComponentInstallation() const{  return this->PackageCompatibilityVersion >= 10.4;}//----------------------------------------------------------------------int cmCPackPackageMakerGenerator::CopyInstallScript(const char* resdir,                                                    const char* script,                                                    const char* name){  std::string dst = resdir;  dst += "/";  dst += name;  cmSystemTools::CopyFileAlways(script, dst.c_str());  cmSystemTools::SetPermissions(dst.c_str(),0777);  cmCPackLogger(cmCPackLog::LOG_VERBOSE,                "copy script : " << script << "\ninto " << dst.c_str() <<                 std::endl);  return 1;}//----------------------------------------------------------------------int cmCPackPackageMakerGenerator::PackageFiles(){  // TODO: Use toplevel  //       It is used! Is this an obsolete comment?  std::string resDir; // Where this package's resources will go.  std::string packageDirFileName    = this->GetOption("CPACK_TEMPORARY_DIRECTORY");  if (this->Components.empty())    {    packageDirFileName += ".pkg";    resDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");    resDir += "/Resources";    }  else    {    packageDirFileName += ".mpkg";    if ( !cmsys::SystemTools::MakeDirectory(packageDirFileName.c_str()))      {      cmCPackLogger(cmCPackLog::LOG_ERROR,                    "unable to create package directory "                     << packageDirFileName << std::endl);        return 0;      }    resDir = packageDirFileName;    resDir += "/Contents";    if ( !cmsys::SystemTools::MakeDirectory(resDir.c_str()))      {      cmCPackLogger(cmCPackLog::LOG_ERROR,                    "unable to create package subdirectory " << resDir                     << std::endl);        return 0;      }    resDir += "/Resources";    if ( !cmsys::SystemTools::MakeDirectory(resDir.c_str()))      {      cmCPackLogger(cmCPackLog::LOG_ERROR,                    "unable to create package subdirectory " << resDir                     << std::endl);        return 0;      }    resDir += "/en.lproj";    }  // Create directory structure  std::string preflightDirName = resDir + "/PreFlight";  std::string postflightDirName = resDir + "/PostFlight";  const char* preflight = this->GetOption("CPACK_PREFLIGHT_SCRIPT");  const char* postflight = this->GetOption("CPACK_POSTFLIGHT_SCRIPT");  const char* postupgrade = this->GetOption("CPACK_POSTUPGRADE_SCRIPT");  // if preflight or postflight scripts not there create directories  // of the same name, I think this makes it work  if(!preflight)    {    if ( !cmsys::SystemTools::MakeDirectory(preflightDirName.c_str()))      {      cmCPackLogger(cmCPackLog::LOG_ERROR,                    "Problem creating installer directory: "                    << preflightDirName.c_str() << std::endl);      return 0;      }    }  if(!postflight)    {    if ( !cmsys::SystemTools::MakeDirectory(postflightDirName.c_str()))      {      cmCPackLogger(cmCPackLog::LOG_ERROR,                    "Problem creating installer directory: "                    << postflightDirName.c_str() << std::endl);      return 0;      }    }  // if preflight, postflight, or postupgrade are set   // then copy them into the resource directory and make  // them executable  if(preflight)    {    this->CopyInstallScript(resDir.c_str(),                            preflight,                            "preflight");    }  if(postflight)    {    this->CopyInstallScript(resDir.c_str(),                            postflight,                            "postflight");    }  if(postupgrade)    {    this->CopyInstallScript(resDir.c_str(),                            postupgrade,                            "postupgrade");    }  if (!this->Components.empty())    {    // 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;      }    // Create the directory where downloaded component packages will    // be placed.    const char* userUploadDirectory =      this->GetOption("CPACK_UPLOAD_DIRECTORY");    std::string uploadDirectory;    if (userUploadDirectory && *userUploadDirectory)      {      uploadDirectory = userUploadDirectory;      }    else      {      uploadDirectory= this->GetOption("CPACK_PACKAGE_DIRECTORY");      uploadDirectory += "/CPackUploads";      }    // Create packages for each component    bool warnedAboutDownloadCompatibility = false;    std::map<std::string, cmCPackComponent>::iterator compIt;    for (compIt = this->Components.begin(); compIt != this->Components.end();         ++compIt)      {      std::string packageFile;      if (compIt->second.IsDownloaded)        {        if (this->PackageCompatibilityVersion >= 10.5 &&            this->PackageMakerVersion >= 3.0)          {          // Build this package within the upload directory.          packageFile = uploadDirectory;          if(!cmSystemTools::FileExists(uploadDirectory.c_str()))            {            if (!cmSystemTools::MakeDirectory(uploadDirectory.c_str()))              {              cmCPackLogger(cmCPackLog::LOG_ERROR,                            "Unable to create package upload directory "                             << uploadDirectory << std::endl);              return 0;              }            }          }        else if (!warnedAboutDownloadCompatibility)          {          if (this->PackageCompatibilityVersion < 10.5)            {            cmCPackLogger(              cmCPackLog::LOG_WARNING,              "CPack warning: please set CPACK_OSX_PACKAGE_VERSION to 10.5 "              "or greater enable downloaded packages. CPack will build a "              "non-downloaded package."              << std::endl);            }          if (this->PackageMakerVersion < 3)            {            cmCPackLogger(cmCPackLog::LOG_WARNING,                        "CPack warning: unable to build downloaded "                          "packages with PackageMaker versions prior "                          "to 3.0. CPack will build a non-downloaded package."                          << std::endl);            }          warnedAboutDownloadCompatibility = true;          }        }      if (packageFile.empty())        {        // Build this package within the overall distribution        // metapackage.        packageFile = basePackageDir;        // We're not downloading this component, even if the user        // requested it.        compIt->second.IsDownloaded = false;        }      packageFile += '/';      packageFile += GetPackageName(compIt->second);      std::string packageDir = toplevel;      packageDir += '/';      packageDir += compIt->first;      if (!this->GenerateComponentPackage(packageFile.c_str(),                                           packageDir.c_str(),                                          compIt->second))        {        return 0;        }      }    }  this->SetOption("CPACK_MODULE_VERSION_SUFFIX", "");  // Copy or create all of the resource files we need.  if ( !this->CopyCreateResourceFile("License", resDir.c_str())       || !this->CopyCreateResourceFile("ReadMe", resDir.c_str())       || !this->CopyCreateResourceFile("Welcome", resDir.c_str())       || !this->CopyResourcePlistFile("Info.plist")       || !this->CopyResourcePlistFile("Description.plist") )    {    cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"      << std::endl);    return 0;    }  if (this->Components.empty())    {    // Use PackageMaker to build the package.    cmOStringStream pkgCmd;    pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")           << "\" -build -p \"" << packageDirFileName << "\"";    if (this->Components.empty())      {      pkgCmd << " -f \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY");      }    else      {      pkgCmd << " -mi \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY")             << "/packages/";      }    pkgCmd << "\" -r \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")           << "/Resources\" -i \""           << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")            << "/Info.plist\" -d \""           << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")           << "/Description.plist\"";    if ( this->PackageMakerVersion > 2.0 )      {      pkgCmd << " -v";      }    if (!RunPackageMaker(pkgCmd.str().c_str(), packageDirFileName.c_str()))      return 0;    }  else    {    // We have built the package in place. Generate the    // distribution.dist file to describe it for the installer.    WriteDistributionFile(packageDirFileName.c_str());    }  std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");  tmpFile += "/hdiutilOutput.log";  cmOStringStream dmgCmd;  dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")    << "\" create -ov -format UDZO -srcfolder \"" << packageDirFileName    << "\" \"" << packageFileNames[0] << "\"";  std::string output;  int retVal = 1;  int numTries = 10;  bool res = false;  while(numTries > 0)    {    res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output,                                          &retVal, 0, this->GeneratorVerbose,                                           0);    if ( res && !retVal )      {      numTries = -1;      break;      }    cmSystemTools::Delay(500);    numTries--;    }  if ( !res || retVal )    {    cmGeneratedFileStream ofs(tmpFile.c_str());    ofs << "# Run command: " << dmgCmd.str().c_str() << std::endl      << "# Output:" << std::endl      << output.c_str() << std::endl;    cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running hdiutil command: "      << dmgCmd.str().c_str() << std::endl      << "Please check " << tmpFile.c_str() << " for errors" << std::endl);    return 0;    }  return 1;}//----------------------------------------------------------------------int cmCPackPackageMakerGenerator::InitializeInternal(){  cmCPackLogger(cmCPackLog::LOG_DEBUG,    "cmCPackPackageMakerGenerator::Initialize()" << std::endl);  this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");  std::vector<std::string> path;  std::string pkgPath    = "/Developer/Applications/Utilities/PackageMaker.app/Contents";  std::string versionFile = pkgPath + "/version.plist";  if ( !cmSystemTools::FileExists(versionFile.c_str()) )    {    pkgPath = "/Developer/Applications/PackageMaker.app/Contents";    std::string newVersionFile = pkgPath + "/version.plist";    if ( !cmSystemTools::FileExists(newVersionFile.c_str()) )      {      cmCPackLogger(cmCPackLog::LOG_ERROR,        "Cannot find PackageMaker compiler version file: "        << versionFile.c_str() << " or " << newVersionFile.c_str()        << std::endl);      return 0;      }    versionFile = newVersionFile;    }  std::ifstream ifs(versionFile.c_str());  if ( !ifs )    {    cmCPackLogger(cmCPackLog::LOG_ERROR,      "Cannot open PackageMaker compiler version file" << std::endl);    return 0;    }  // Check the PackageMaker version  cmsys::RegularExpression rexKey("<key>CFBundleShortVersionString</key>");  cmsys::RegularExpression rexVersion("<string>([0-9]+.[0-9.]+)</string>");  std::string line;  bool foundKey = false;  while ( cmSystemTools::GetLineFromStream(ifs, line) )    {    if ( rexKey.find(line) )      {      foundKey = true;      break;      }    }  if ( !foundKey )    {    cmCPackLogger(cmCPackLog::LOG_ERROR,      "Cannot find CFBundleShortVersionString in the PackageMaker compiler "      "version file" << std::endl);    return 0;    }  if ( !cmSystemTools::GetLineFromStream(ifs, line) ||    !rexVersion.find(line) )    {    cmCPackLogger(cmCPackLog::LOG_ERROR,      "Problem reading the PackageMaker compiler version file: "      << versionFile.c_str() << std::endl);    return 0;    }  this->PackageMakerVersion = atof(rexVersion.match(1).c_str());  if ( this->PackageMakerVersion < 1.0 )    {    cmCPackLogger(cmCPackLog::LOG_ERROR, "Require PackageMaker 1.0 or higher"      << std::endl);    return 0;    }  cmCPackLogger(cmCPackLog::LOG_DEBUG, "PackageMaker version is: "    << this->PackageMakerVersion << std::endl);  // Determine the package compatibility version. If it wasn't  // specified by the user, we define it based on which features the  // user requested.  const char *packageCompat = this->GetOption("CPACK_OSX_PACKAGE_VERSION");  if (packageCompat && *packageCompat)    {    this->PackageCompatibilityVersion = atof(packageCompat);      }  else if (this->GetOption("CPACK_DOWNLOAD_SITE"))    {    this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.5");    this->PackageCompatibilityVersion = 10.5;    }  else if (this->GetOption("CPACK_COMPONENTS_ALL"))    {    this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.4");    this->PackageCompatibilityVersion = 10.4;    }  else    {    this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.3");    this->PackageCompatibilityVersion = 10.3;    }  pkgPath += "/MacOS";  path.push_back(pkgPath);  pkgPath = cmSystemTools::FindProgram("PackageMaker", path, false);  if ( pkgPath.empty() )    {    cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find PackageMaker compiler"      << std::endl);    return 0;    }  this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath.c_str());  pkgPath = cmSystemTools::FindProgram("hdiutil", path, false);  if ( pkgPath.empty() )    {    cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find hdiutil compiler"      << std::endl);    return 0;    }  this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",                           pkgPath.c_str());  return this->Superclass::InitializeInternal();}//----------------------------------------------------------------------bool cmCPackPackageMakerGenerator::CopyCreateResourceFile(const char* name,                                                          const char* dirName){  std::string uname = cmSystemTools::UpperCase(name);  std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;  const char* inFileName = this->GetOption(cpackVar.c_str());  if ( !inFileName )    {    cmCPackLogger(cmCPackLog::LOG_ERROR, "CPack option: " << cpackVar.c_str()                  << " not specified. It should point to "                   << (name ? name : "(NULL)")                  << ".rtf, " << name                  << ".html, or " << name << ".txt file" << std::endl);    return false;    }  if ( !cmSystemTools::FileExists(inFileName) )    {    cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find "                   << (name ? name : "(NULL)")                  << " resource file: " << inFileName << std::endl);    return false;    }  std::string ext = cmSystemTools::GetFilenameLastExtension(inFileName);  if ( ext != ".rtfd" && ext != ".rtf" && ext != ".html" && ext != ".txt" )    {    cmCPackLogger(cmCPackLog::LOG_ERROR, "Bad file extension specified: "      << ext << ". Currently only .rtfd, .rtf, .html, and .txt files allowed."      << std::endl);    return false;    }  std::string destFileName = dirName;  destFileName += '/';  destFileName += name + ext;  // Set this so that distribution.dist gets the right name (without  // the path).  this->SetOption(("CPACK_RESOURCE_FILE_" + uname + "_NOPATH").c_str(),                  (name + ext).c_str());  cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "                 << (inFileName ? inFileName : "(NULL)")                << " to " << destFileName.c_str() << std::endl);  this->ConfigureFile(inFileName, destFileName.c_str());  return true;}bool cmCPackPackageMakerGenerator::CopyResourcePlistFile(const char* name,                                                         const char* outName){  if (!outName)    {    outName = name;    }  std::string inFName = "CPack.";  inFName += name;  inFName += ".in";  std::string inFileName = this->FindTemplate(inFName.c_str());  if ( inFileName.empty() )    {    cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find input file: "      << inFName << std::endl);    return false;    }  std::string destFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");  destFileName += "/";  destFileName += outName;  cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "    << inFileName.c_str() << " to " << destFileName.c_str() << std::endl);  this->ConfigureFile(inFileName.c_str(), destFileName.c_str());  return true;}//----------------------------------------------------------------------bool cmCPackPackageMakerGenerator::RunPackageMaker(const char *command,                                                   const char *packageFile){  std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");  tmpFile += "/PackageMakerOutput.log";  cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl);  std::string output;  int retVal = 1;  bool res = cmSystemTools::RunSingleCommand(command, &output, &retVal, 0,                                              this->GeneratorVerbose, 0);  cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running package maker"    << 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 PackageMaker command: " << command      << std::endl << "Please check " << tmpFile.c_str() << " for errors"      << std::endl);    return false;    }  // sometimes the command finishes but the directory is not yet  // created, so try 10 times to see if it shows up  int tries = 10;  while(tries > 0 &&         !cmSystemTools::FileExists(packageFile))    {    cmSystemTools::Delay(500);    tries--;    }  if(!cmSystemTools::FileExists(packageFile))    {    cmCPackLogger(      cmCPackLog::LOG_ERROR,      "Problem running PackageMaker command: " << command      << std::endl << "Package not created: " << packageFile      << std::endl);    return false;    }  return true;}//----------------------------------------------------------------------std::string cmCPackPackageMakerGenerator::GetPackageName(const cmCPackComponent& component){  if (component.ArchiveFile.empty())    {    std::string packagesDir = this->GetOption("CPACK_TEMPORARY_DIRECTORY");    packagesDir += ".dummy";    cmOStringStream out;    out << cmSystemTools::GetFilenameWithoutLastExtension(packagesDir)        << "-" << component.Name << ".pkg";    return out.str();    }  else    {    return component.ArchiveFile + ".pkg";    }}//----------------------------------------------------------------------boolcmCPackPackageMakerGenerator::GenerateComponentPackage(const char *packageFile,                         const char *packageDir,                         const cmCPackComponent& component){  cmCPackLogger(cmCPackLog::LOG_OUTPUT,                "-   Building component package: " <<                packageFile << std::endl);  // The command that will be used to run PackageMaker  cmOStringStream pkgCmd;  if (this->PackageCompatibilityVersion < 10.5 ||       this->PackageMakerVersion < 3.0)    {    // Create Description.plist and Info.plist files for normal Mac OS    // X packages, which work on Mac OS X 10.3 and newer.    std::string descriptionFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");    descriptionFile += '/' + component.Name + "-Description.plist";    std::ofstream out(descriptionFile.c_str());    out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl        << "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\""        << "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" << std::endl        << "<plist version=\"1.4\">" << std::endl        << "<dict>" << std::endl        << "  <key>IFPkgDescriptionTitle</key>" << std::endl        << "  <string>" << component.DisplayName << "</string>" << std::endl        << "  <key>IFPkgDescriptionVersion</key>" << std::endl        << "  <string>" << this->GetOption("CPACK_PACKAGE_VERSION")         << "</string>" << std::endl        << "  <key>IFPkgDescriptionDescription</key>" << std::endl        << "  <string>" + this->EscapeForXML(component.Description)         << "</string>" << std::endl        << "</dict>" << std::endl        << "</plist>" << std::endl;    out.close();    // Create the Info.plist file for this component    std::string moduleVersionSuffix = ".";    moduleVersionSuffix += component.Name;    this->SetOption("CPACK_MODULE_VERSION_SUFFIX",                     moduleVersionSuffix.c_str());    std::string infoFileName = component.Name;    infoFileName += "-Info.plist";    if (!this->CopyResourcePlistFile("Info.plist", infoFileName.c_str()))      {      return false;      }    pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")           << "\" -build -p \"" << packageFile << "\""           << " -f \"" << packageDir << "\""           << " -i \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")            << "/" << infoFileName << "\""           << " -d \"" << descriptionFile << "\"";     }  else    {    // Create a "flat" package on Mac OS X 10.5 and newer. Flat    // packages are stored in a single file, rather than a directory    // like normal packages, and can be downloaded by the installer    // on-the-fly in Mac OS X 10.5 or newer. Thus, we need to create    // flat packages when the packages will be downloaded on the fly.    std::string pkgId = "com.";    pkgId += this->GetOption("CPACK_PACKAGE_VENDOR");    pkgId += '.';    pkgId += this->GetOption("CPACK_PACKAGE_NAME");    pkgId += '.';    pkgId += component.Name;    pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")           << "\" --root \"" << packageDir << "\""           << " --id " << pkgId           << " --target " << this->GetOption("CPACK_OSX_PACKAGE_VERSION")           << " --out \"" << packageFile << "\"";    }  // Run PackageMaker    return RunPackageMaker(pkgCmd.str().c_str(), packageFile);}//----------------------------------------------------------------------void cmCPackPackageMakerGenerator::WriteDistributionFile(const char* metapackageFile){  std::string distributionTemplate     = this->FindTemplate("CPack.distribution.dist.in");  if ( distributionTemplate.empty() )    {    cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find input file: "      << distributionTemplate << std::endl);    return;    }  std::string distributionFile = metapackageFile;  distributionFile += "/Contents/distribution.dist";  // Create the choice outline, which provides a tree-based view of  // the components in their groups.  cmOStringStream choiceOut;  choiceOut << "<choices-outline>" << std::endl;  // Emit the outline for the groups  std::map<std::string, cmCPackComponentGroup>::iterator groupIt;  for (groupIt = this->ComponentGroups.begin();        groupIt != this->ComponentGroups.end();        ++groupIt)    {    if (groupIt->second.ParentGroup == 0)      {      CreateChoiceOutline(groupIt->second, choiceOut);      }    }  // Emit the outline for the non-grouped components  std::map<std::string, cmCPackComponent>::iterator compIt;  for (compIt = this->Components.begin(); compIt != this->Components.end();       ++compIt)    {    if (!compIt->second.Group)      {      choiceOut << "<line choice=\"" << compIt->first << "Choice\"></line>"                << std::endl;      }    }  choiceOut << "</choices-outline>" << std::endl;  // Create the actual choices  for (groupIt = this->ComponentGroups.begin();        groupIt != this->ComponentGroups.end();        ++groupIt)    {    CreateChoice(groupIt->second, choiceOut);    }  for (compIt = this->Components.begin(); compIt != this->Components.end();       ++compIt)    {    CreateChoice(compIt->second, choiceOut);    }  this->SetOption("CPACK_PACKAGEMAKER_CHOICES", choiceOut.str().c_str());  // Create the distribution.dist file in the metapackage to turn it  // into a distribution package.  this->ConfigureFile(distributionTemplate.c_str(),                       distributionFile.c_str());}//----------------------------------------------------------------------voidcmCPackPackageMakerGenerator::CreateChoiceOutline(const cmCPackComponentGroup& group, cmOStringStream& out){  out << "<line choice=\"" << group.Name << "Choice\">" << std::endl;  std::vector<cmCPackComponentGroup*>::const_iterator groupIt;  for (groupIt = group.Subgroups.begin(); groupIt != group.Subgroups.end();       ++groupIt)    {    CreateChoiceOutline(**groupIt, out);    }  std::vector<cmCPackComponent*>::const_iterator compIt;  for (compIt = group.Components.begin(); compIt != group.Components.end();       ++compIt)    {    out << "  <line choice=\"" << (*compIt)->Name << "Choice\"></line>"        << std::endl;    }  out << "</line>" << std::endl;}//----------------------------------------------------------------------void cmCPackPackageMakerGenerator::CreateChoice(const cmCPackComponentGroup& group,                                           cmOStringStream& out){  out << "<choice id=\"" << group.Name << "Choice\" "       << "title=\"" << group.DisplayName << "\" "      << "start_selected=\"true\" "       << "start_enabled=\"true\" "      << "start_visible=\"true\" ";  if (!group.Description.empty())    {    out << "description=\"" << EscapeForXML(group.Description)        << "\"";    }  out << "></choice>" << std::endl;}//----------------------------------------------------------------------void cmCPackPackageMakerGenerator::CreateChoice(const cmCPackComponent& component,                                           cmOStringStream& out){  std::string packageId = "com.";  packageId += this->GetOption("CPACK_PACKAGE_VENDOR");  packageId += '.';   packageId += this->GetOption("CPACK_PACKAGE_NAME");  packageId += '.';  packageId += component.Name;  out << "<choice id=\"" << component.Name << "Choice\" "       << "title=\"" << component.DisplayName << "\" "      << "start_selected=\""       << (component.IsDisabledByDefault &&           !component.IsRequired? "false" : "true")      << "\" "      << "start_enabled=\""      << (component.IsRequired? "false" : "true")      << "\" "      << "start_visible=\"" << (component.IsHidden? "false" : "true") << "\" ";  if (!component.Description.empty())    {    out << "description=\"" << EscapeForXML(component.Description)        << "\" ";    }  if (!component.Dependencies.empty() ||      !component.ReverseDependencies.empty())    {    // The "selected" expression is evaluated each time any choice is    // selected, for all choices *except* the one that the user    // selected. A component is marked selected if it has been    // selected (my.choice.selected in Javascript) and all of the    // components it depends on have been selected (transitively) or    // if any of the components that depend on it have been selected    // (transitively). Assume that we have components A, B, C, D, and    // E, where each component depends on the previous component (B    // depends on A, C depends on B, D depends on C, and E depends on    // D). The expression we build for the component C will be    //   my.choice.selected && B && A || D || E    // This way, selecting C will automatically select everything it depends    // on (B and A), while selecting something that depends on C--either D    // or E--will automatically cause C to get selected.    out << "selected=\"my.choice.selected";    std::set<const cmCPackComponent *> visited;    AddDependencyAttributes(component, visited, out);    visited.clear();    AddReverseDependencyAttributes(component, visited, out);    out << "\"";    }  out << ">" << std::endl;  out << "  <pkg-ref id=\"" << packageId << "\"></pkg-ref>" << std::endl;  out << "</choice>" << std::endl;  // Create a description of the package associated with this  // component.  std::string relativePackageLocation = "Contents/Packages/";  relativePackageLocation += this->GetPackageName(component);  // Determine the installed size of the package.  std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");  dirName += '/';  dirName += component.Name;  unsigned long installedSize     = component.GetInstalledSizeInKbytes(dirName.c_str());  out << "<pkg-ref id=\"" << packageId << "\" "      << "version=\"" << this->GetOption("CPACK_PACKAGE_VERSION") << "\" "      << "installKBytes=\"" << installedSize << "\" "      << "auth=\"Admin\" onConclusion=\"None\">";  if (component.IsDownloaded)    {    out << this->GetOption("CPACK_DOWNLOAD_SITE")         << this->GetPackageName(component);    }  else    {    out << "file:./" << relativePackageLocation;    }  out << "</pkg-ref>" << std::endl;}//----------------------------------------------------------------------void cmCPackPackageMakerGenerator::AddDependencyAttributes(const cmCPackComponent& component,                         std::set<const cmCPackComponent *>& visited,                        cmOStringStream& out){  if (visited.find(&component) != visited.end())    {    return;    }  visited.insert(&component);  std::vector<cmCPackComponent *>::const_iterator dependIt;  for (dependIt = component.Dependencies.begin();       dependIt != component.Dependencies.end();       ++dependIt)    {    out << " && choices['" <<       (*dependIt)->Name << "Choice'].selected";    AddDependencyAttributes(**dependIt, visited, out);    }}//----------------------------------------------------------------------void cmCPackPackageMakerGenerator::AddReverseDependencyAttributes(const cmCPackComponent& component,                                std::set<const cmCPackComponent *>& visited,                               cmOStringStream& out){  if (visited.find(&component) != visited.end())    {    return;    }  visited.insert(&component);  std::vector<cmCPackComponent *>::const_iterator dependIt;  for (dependIt = component.ReverseDependencies.begin();       dependIt != component.ReverseDependencies.end();       ++dependIt)    {    out << " || choices['" << (*dependIt)->Name << "Choice'].selected";    AddReverseDependencyAttributes(**dependIt, visited, out);    }}//----------------------------------------------------------------------std::string cmCPackPackageMakerGenerator::EscapeForXML(std::string str){  cmSystemTools::ReplaceString(str, "&", "&");  cmSystemTools::ReplaceString(str, "<", "<");  cmSystemTools::ReplaceString(str, ">", ">");  cmSystemTools::ReplaceString(str, "\"", """);  return str;}
 |