| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 | /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying   file Copyright.txt or https://cmake.org/licensing for details.  */#include "cmCPackPKGGenerator.h"#include <vector>#include "cmCPackComponentGroup.h"#include "cmCPackGenerator.h"#include "cmCPackLog.h"#include "cmSystemTools.h"#include "cmXMLWriter.h"cmCPackPKGGenerator::cmCPackPKGGenerator(){  this->componentPackageMethod = ONE_PACKAGE;}cmCPackPKGGenerator::~cmCPackPKGGenerator(){}bool cmCPackPKGGenerator::SupportsComponentInstallation() const{  return true;}int cmCPackPKGGenerator::InitializeInternal(){  cmCPackLogger(cmCPackLog::LOG_DEBUG,                "cmCPackPKGGenerator::Initialize()" << std::endl);  return this->Superclass::InitializeInternal();}std::string cmCPackPKGGenerator::GetPackageName(  const cmCPackComponent& component){  if (component.ArchiveFile.empty()) {    std::string packagesDir = this->GetOption("CPACK_TEMPORARY_DIRECTORY");    packagesDir += ".dummy";    std::ostringstream out;    out << cmSystemTools::GetFilenameWithoutLastExtension(packagesDir) << "-"        << component.Name << ".pkg";    return out.str();  }  return component.ArchiveFile + ".pkg";}void cmCPackPKGGenerator::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.  std::ostringstream choiceOut;  cmXMLWriter xout(choiceOut, 1);  xout.StartElement("choices-outline");  // 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 == nullptr) {      CreateChoiceOutline(groupIt->second, xout);    }  }  // 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) {      xout.StartElement("line");      xout.Attribute("choice", compIt->first + "Choice");      xout.Content(""); // Avoid self-closing tag.      xout.EndElement();    }  }  if (!this->PostFlightComponent.Name.empty()) {    xout.StartElement("line");    xout.Attribute("choice", PostFlightComponent.Name + "Choice");    xout.Content(""); // Avoid self-closing tag.    xout.EndElement();  }  xout.EndElement(); // choices-outline>  // Create the actual choices  for (groupIt = this->ComponentGroups.begin();       groupIt != this->ComponentGroups.end(); ++groupIt) {    CreateChoice(groupIt->second, xout);  }  for (compIt = this->Components.begin(); compIt != this->Components.end();       ++compIt) {    CreateChoice(compIt->second, xout);  }  if (!this->PostFlightComponent.Name.empty()) {    CreateChoice(PostFlightComponent, xout);  }  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());}void cmCPackPKGGenerator::CreateChoiceOutline(  const cmCPackComponentGroup& group, cmXMLWriter& xout){  xout.StartElement("line");  xout.Attribute("choice", group.Name + "Choice");  std::vector<cmCPackComponentGroup*>::const_iterator groupIt;  for (groupIt = group.Subgroups.begin(); groupIt != group.Subgroups.end();       ++groupIt) {    CreateChoiceOutline(**groupIt, xout);  }  std::vector<cmCPackComponent*>::const_iterator compIt;  for (compIt = group.Components.begin(); compIt != group.Components.end();       ++compIt) {    xout.StartElement("line");    xout.Attribute("choice", (*compIt)->Name + "Choice");    xout.Content(""); // Avoid self-closing tag.    xout.EndElement();  }  xout.EndElement();}void cmCPackPKGGenerator::CreateChoice(const cmCPackComponentGroup& group,                                       cmXMLWriter& xout){  xout.StartElement("choice");  xout.Attribute("id", group.Name + "Choice");  xout.Attribute("title", group.DisplayName);  xout.Attribute("start_selected", "true");  xout.Attribute("start_enabled", "true");  xout.Attribute("start_visible", "true");  if (!group.Description.empty()) {    xout.Attribute("description", group.Description);  }  xout.EndElement();}void cmCPackPKGGenerator::CreateChoice(const cmCPackComponent& component,                                       cmXMLWriter& xout){  std::string packageId = "com.";  packageId += this->GetOption("CPACK_PACKAGE_VENDOR");  packageId += '.';  packageId += this->GetOption("CPACK_PACKAGE_NAME");  packageId += '.';  packageId += component.Name;  xout.StartElement("choice");  xout.Attribute("id", component.Name + "Choice");  xout.Attribute("title", component.DisplayName);  xout.Attribute(    "start_selected",    component.IsDisabledByDefault && !component.IsRequired ? "false" : "true");  xout.Attribute("start_enabled", component.IsRequired ? "false" : "true");  xout.Attribute("start_visible", component.IsHidden ? "false" : "true");  if (!component.Description.empty()) {    xout.Attribute("description", 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.    std::ostringstream selected("my.choice.selected", std::ios_base::ate);    std::set<const cmCPackComponent*> visited;    AddDependencyAttributes(component, visited, selected);    visited.clear();    AddReverseDependencyAttributes(component, visited, selected);    xout.Attribute("selected", selected.str());  }  xout.StartElement("pkg-ref");  xout.Attribute("id", packageId);  xout.EndElement(); // pkg-ref  xout.EndElement(); // choice  // 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;  dirName += this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");  unsigned long installedSize = component.GetInstalledSizeInKbytes(dirName);  xout.StartElement("pkg-ref");  xout.Attribute("id", packageId);  xout.Attribute("version", this->GetOption("CPACK_PACKAGE_VERSION"));  xout.Attribute("installKBytes", installedSize);  xout.Attribute("auth", "Admin");  xout.Attribute("onConclusion", "None");  if (component.IsDownloaded) {    xout.Content(this->GetOption("CPACK_DOWNLOAD_SITE"));    xout.Content(this->GetPackageName(component));  } else {    xout.Content("file:./");    xout.Content(relativePackageLocation);  }  xout.EndElement(); // pkg-ref}void cmCPackPKGGenerator::AddDependencyAttributes(  const cmCPackComponent& component,  std::set<const cmCPackComponent*>& visited, std::ostringstream& 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 cmCPackPKGGenerator::AddReverseDependencyAttributes(  const cmCPackComponent& component,  std::set<const cmCPackComponent*>& visited, std::ostringstream& 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);  }}bool cmCPackPKGGenerator::CopyCreateResourceFile(const std::string& name,                                                 const std::string& dirName){  std::string uname = cmSystemTools::UpperCase(name);  std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;  const char* inFileName = this->GetOption(cpackVar);  if (!inFileName) {    cmCPackLogger(cmCPackLog::LOG_ERROR,                  "CPack option: " << cpackVar.c_str()                                   << " not specified. It should point to "                                   << (!name.empty() ? name : "<empty>")                                   << ".rtf, " << name << ".html, or " << name                                   << ".txt file" << std::endl);    return false;  }  if (!cmSystemTools::FileExists(inFileName)) {    cmCPackLogger(cmCPackLog::LOG_ERROR,                  "Cannot find " << (!name.empty() ? name : "<empty>")                                 << " 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",                  (name + ext).c_str());  cmCPackLogger(cmCPackLog::LOG_VERBOSE,                "Configure file: " << (inFileName ? inFileName : "(NULL)")                                   << " to " << destFileName << std::endl);  this->ConfigureFile(inFileName, destFileName.c_str());  return true;}bool cmCPackPKGGenerator::CopyResourcePlistFile(const std::string& name,                                                const char* outName){  if (!outName) {    outName = name.c_str();  }  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 << " to " << destFileName                                   << std::endl);  this->ConfigureFile(inFileName.c_str(), destFileName.c_str());  return true;}int cmCPackPKGGenerator::CopyInstallScript(const std::string& resdir,                                           const std::string& script,                                           const std::string& name){  std::string dst = resdir;  dst += "/";  dst += name;  cmSystemTools::CopyFileAlways(script, dst);  cmSystemTools::SetPermissions(dst.c_str(), 0777);  cmCPackLogger(cmCPackLog::LOG_VERBOSE,                "copy script : " << script << "\ninto " << dst << std::endl);  return 1;}
 |