|
|
@@ -22,6 +22,7 @@
|
|
|
#include "cmSystemTools.h"
|
|
|
#include "cmMakefile.h"
|
|
|
#include "cmGeneratedFileStream.h"
|
|
|
+#include "cmCPackComponentGroup.h"
|
|
|
#include "cmCPackLog.h"
|
|
|
|
|
|
#include <cmsys/SystemTools.hxx>
|
|
|
@@ -38,6 +39,13 @@ cmCPackPackageMakerGenerator::~cmCPackPackageMakerGenerator()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
+//----------------------------------------------------------------------
|
|
|
+bool cmCPackPackageMakerGenerator::SupportsComponentInstallation() const
|
|
|
+{
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------
|
|
|
int cmCPackPackageMakerGenerator::CopyInstallScript(const char* resdir,
|
|
|
const char* script,
|
|
|
const char* name)
|
|
|
@@ -96,23 +104,59 @@ int cmCPackPackageMakerGenerator::CompressFiles(const char* outFileName,
|
|
|
// them executable
|
|
|
if(preflight)
|
|
|
{
|
|
|
- this->CopyInstallScript(resDir.c_str(),
|
|
|
- preflight,
|
|
|
- "preflight");
|
|
|
+ this->CopyInstallScript(resDir.c_str(),
|
|
|
+ preflight,
|
|
|
+ "preflight");
|
|
|
}
|
|
|
if(postflight)
|
|
|
{
|
|
|
- this->CopyInstallScript(resDir.c_str(),
|
|
|
- postflight,
|
|
|
- "postflight");
|
|
|
+ this->CopyInstallScript(resDir.c_str(),
|
|
|
+ postflight,
|
|
|
+ "postflight");
|
|
|
}
|
|
|
if(postupgrade)
|
|
|
{
|
|
|
- this->CopyInstallScript(resDir.c_str(),
|
|
|
- postupgrade,
|
|
|
- "postupgrade");
|
|
|
+ this->CopyInstallScript(resDir.c_str(),
|
|
|
+ postupgrade,
|
|
|
+ "postupgrade");
|
|
|
}
|
|
|
|
|
|
+ if (!this->Components.empty())
|
|
|
+ {
|
|
|
+ // Create the directory where component packages will be installed.
|
|
|
+ std::string basePackageDir = toplevel;
|
|
|
+ basePackageDir += "/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 packages for each component
|
|
|
+ std::map<std::string, cmCPackComponent>::iterator compIt;
|
|
|
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
|
|
|
+ ++compIt)
|
|
|
+ {
|
|
|
+ std::string packageFile = basePackageDir;
|
|
|
+ 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")
|
|
|
|| !this->CopyCreateResourceFile("ReadMe")
|
|
|
|| !this->CopyCreateResourceFile("Welcome")
|
|
|
@@ -126,68 +170,58 @@ int cmCPackPackageMakerGenerator::CompressFiles(const char* outFileName,
|
|
|
|
|
|
std::string packageDirFileName
|
|
|
= this->GetOption("CPACK_TEMPORARY_DIRECTORY");
|
|
|
- packageDirFileName += ".pkg";
|
|
|
+ if (this->Components.empty())
|
|
|
+ {
|
|
|
+ packageDirFileName += ".pkg";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ packageDirFileName += ".mpkg";
|
|
|
+ if (this->PackageMakerVersion == 3.0)
|
|
|
+ {
|
|
|
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
|
+ "PackageMaker 3.0 cannot build component-based installations."
|
|
|
+ << std::endl << "Please use PackageMaker 2.5 instead." << std::endl);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
|
|
|
- tmpFile += "/PackageMakerOutput.log";
|
|
|
cmOStringStream pkgCmd;
|
|
|
pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
|
|
|
- << "\" -build -p \"" << packageDirFileName << "\" -f \""
|
|
|
- << this->GetOption("CPACK_TEMPORARY_DIRECTORY")
|
|
|
- << "\" -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 )
|
|
|
+ << "\" -build -p \"" << packageDirFileName << "\"";
|
|
|
+ if (this->Components.empty())
|
|
|
{
|
|
|
- pkgCmd << " -v";
|
|
|
+ pkgCmd << " -f \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY");
|
|
|
}
|
|
|
- cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << pkgCmd.str().c_str()
|
|
|
- << std::endl);
|
|
|
- std::string output;
|
|
|
- int retVal = 1;
|
|
|
- //bool res = cmSystemTools::RunSingleCommand(pkgCmd.str().c_str(), &output,
|
|
|
- //&retVal, 0, this->GeneratorVerbose, 0);
|
|
|
- bool res = true;
|
|
|
- retVal = system(pkgCmd.str().c_str());
|
|
|
- cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running package maker"
|
|
|
- << std::endl);
|
|
|
- if ( !res || retVal )
|
|
|
+ else
|
|
|
{
|
|
|
- cmGeneratedFileStream ofs(tmpFile.c_str());
|
|
|
- ofs << "# Run command: " << pkgCmd.str().c_str() << std::endl
|
|
|
- << "# Output:" << std::endl
|
|
|
- << output.c_str() << std::endl;
|
|
|
- cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
|
- "Problem running PackageMaker command: " << pkgCmd.str().c_str()
|
|
|
- << std::endl << "Please check " << tmpFile.c_str() << " for errors"
|
|
|
- << std::endl);
|
|
|
- return 0;
|
|
|
+ pkgCmd << " -mi \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY")
|
|
|
+ << "/packages/";
|
|
|
}
|
|
|
- // sometimes the pkgCmd 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(packageDirFileName.c_str()))
|
|
|
+ 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 )
|
|
|
{
|
|
|
- cmSystemTools::Delay(500);
|
|
|
- tries--;
|
|
|
+ pkgCmd << " -v";
|
|
|
}
|
|
|
- if(!cmSystemTools::FileExists(packageDirFileName.c_str()))
|
|
|
+ if (!RunPackageMaker(pkgCmd.str().c_str(), packageDirFileName.c_str()))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (!this->Components.empty())
|
|
|
{
|
|
|
- cmCPackLogger(
|
|
|
- cmCPackLog::LOG_ERROR,
|
|
|
- "Problem running PackageMaker command: " << pkgCmd.str().c_str()
|
|
|
- << std::endl << "Package not created: " << packageDirFileName.c_str()
|
|
|
- << std::endl);
|
|
|
+ WriteDistributionFile(packageDirFileName.c_str());
|
|
|
}
|
|
|
- tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
|
|
|
+
|
|
|
+ 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
|
|
|
<< "\" \"" << outFileName << "\"";
|
|
|
- res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output,
|
|
|
+ std::string output;
|
|
|
+ int retVal = 1;
|
|
|
+ bool res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output,
|
|
|
&retVal, 0, this->GeneratorVerbose, 0);
|
|
|
if ( !res || retVal )
|
|
|
{
|
|
|
@@ -339,8 +373,14 @@ bool cmCPackPackageMakerGenerator::CopyCreateResourceFile(const char* name)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-bool cmCPackPackageMakerGenerator::CopyResourcePlistFile(const char* name)
|
|
|
+bool cmCPackPackageMakerGenerator::CopyResourcePlistFile(const char* name,
|
|
|
+ const char* outName)
|
|
|
{
|
|
|
+ if (!outName)
|
|
|
+ {
|
|
|
+ outName = name;
|
|
|
+ }
|
|
|
+
|
|
|
std::string inFName = "CPack.";
|
|
|
inFName += name;
|
|
|
inFName += ".in";
|
|
|
@@ -354,10 +394,374 @@ bool cmCPackPackageMakerGenerator::CopyResourcePlistFile(const char* name)
|
|
|
|
|
|
std::string destFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
|
|
|
destFileName += "/";
|
|
|
- destFileName += name;
|
|
|
+ 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)
|
|
|
+{
|
|
|
+ std::string packagesDir = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
|
|
|
+ packagesDir += ".dummy";
|
|
|
+ cmOStringStream out;
|
|
|
+ out << cmSystemTools::GetFilenameWithoutLastExtension(packagesDir)
|
|
|
+ << "-" << component.Name << ".pkg";
|
|
|
+ return out.str();
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------
|
|
|
+bool
|
|
|
+cmCPackPackageMakerGenerator::
|
|
|
+GenerateComponentPackage(const char *packageFile,
|
|
|
+ const char *packageDir,
|
|
|
+ const cmCPackComponent& component)
|
|
|
+{
|
|
|
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
|
|
|
+ "- Building component package: " << packageFile << std::endl);
|
|
|
+
|
|
|
+ // Create the description file for this component.
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Run PackageMaker
|
|
|
+ cmOStringStream pkgCmd;
|
|
|
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
|
|
|
+ << "\" -build -p \"" << packageFile << "\""
|
|
|
+ << " -f \"" << packageDir << "\""
|
|
|
+ << "-i \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
|
|
|
+ << "/" << infoFileName << "\""
|
|
|
+ << "-d \"" << descriptionFile << "\"";
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ 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());
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------
|
|
|
+void
|
|
|
+cmCPackPackageMakerGenerator::
|
|
|
+CreateChoiceOutline(const cmCPackComponentGroup& group, cmOStringStream& out)
|
|
|
+{
|
|
|
+ out << "<line choice=\"" << group.Name << "Choice\">" << std::endl;
|
|
|
+ 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 += this->GetOption("CPACK_PACKAGE_VERSION");
|
|
|
+ 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";
|
|
|
+ AddDependencyAttributes(component, out);
|
|
|
+ AddReverseDependencyAttributes(component, 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 += GetPackageName(component);
|
|
|
+
|
|
|
+ // Determine the installed size of the package. To do so, we dig
|
|
|
+ // into the Info.plist file from the generated package to retrieve
|
|
|
+ // this size.
|
|
|
+ int installedSize = 0;
|
|
|
+ std::string infoPlistFile = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
|
|
|
+ infoPlistFile += ".mpkg/";
|
|
|
+ infoPlistFile += relativePackageLocation;
|
|
|
+ infoPlistFile += "/Contents/Info.plist";
|
|
|
+ bool foundFlagInstalledSize = false;
|
|
|
+ std::string line;
|
|
|
+ std::ifstream ifs(infoPlistFile.c_str());
|
|
|
+ while ( cmSystemTools::GetLineFromStream(ifs, line) )
|
|
|
+ {
|
|
|
+ if (foundFlagInstalledSize)
|
|
|
+ {
|
|
|
+ std::string::size_type pos = line.find("<integer>");
|
|
|
+ if (pos == std::string::npos)
|
|
|
+ {
|
|
|
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot parse package size in "
|
|
|
+ << infoPlistFile << std::endl
|
|
|
+ << "String is \"" << line << "\"" << std::endl);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ line.erase(0, pos + 9);
|
|
|
+ pos = line.find("</integer>");
|
|
|
+ if (pos == std::string::npos)
|
|
|
+ {
|
|
|
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot parse package size in "
|
|
|
+ << infoPlistFile << std::endl);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ line.erase(pos, std::string::npos);
|
|
|
+ installedSize = atoi(line.c_str());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ foundFlagInstalledSize = false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ foundFlagInstalledSize
|
|
|
+ = line.find("IFPkgFlagInstalledSize") != std::string::npos;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ out << "<pkg-ref id=\"" << packageId << "\" "
|
|
|
+ << "version=\"" << this->GetOption("CPACK_PACKAGE_VERSION") << "\" "
|
|
|
+ << "installKBytes=\"" << installedSize << "\" "
|
|
|
+ << "auth=\"Admin\" onConclusion=\"None\">"
|
|
|
+ << "file:./" << relativePackageLocation << "</pkg-ref>" << std::endl;
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------
|
|
|
+void
|
|
|
+cmCPackPackageMakerGenerator::
|
|
|
+AddDependencyAttributes(const cmCPackComponent& component, cmOStringStream& out)
|
|
|
+{
|
|
|
+ std::vector<cmCPackComponent *>::const_iterator dependIt;
|
|
|
+ for (dependIt = component.Dependencies.begin();
|
|
|
+ dependIt != component.Dependencies.end();
|
|
|
+ ++dependIt)
|
|
|
+ {
|
|
|
+ out << " && choices['" << (*dependIt)->Name << "Choice'].selected";
|
|
|
+ AddDependencyAttributes(**dependIt, out);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------
|
|
|
+void
|
|
|
+cmCPackPackageMakerGenerator::
|
|
|
+AddReverseDependencyAttributes(const cmCPackComponent& component,
|
|
|
+ cmOStringStream& out)
|
|
|
+{
|
|
|
+ std::vector<cmCPackComponent *>::const_iterator dependIt;
|
|
|
+ for (dependIt = component.ReverseDependencies.begin();
|
|
|
+ dependIt != component.ReverseDependencies.end();
|
|
|
+ ++dependIt)
|
|
|
+ {
|
|
|
+ out << " || choices['" << (*dependIt)->Name << "Choice'].selected";
|
|
|
+ AddReverseDependencyAttributes(**dependIt, out);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------
|
|
|
+std::string cmCPackPackageMakerGenerator::EscapeForXML(std::string str)
|
|
|
+{
|
|
|
+ cmSystemTools::ReplaceString(str, "&", "&");
|
|
|
+ cmSystemTools::ReplaceString(str, "<", "<");
|
|
|
+ cmSystemTools::ReplaceString(str, ">", ">");
|
|
|
+ cmSystemTools::ReplaceString(str, "\"", """);
|
|
|
+ return str;
|
|
|
+}
|