diff options
author | David Cole <david.cole@kitware.com> | 2008-07-09 17:38:56 (GMT) |
---|---|---|
committer | David Cole <david.cole@kitware.com> | 2008-07-09 17:38:56 (GMT) |
commit | 71f61636b6abfe5f243374b5575019098418b4c6 (patch) | |
tree | d6ca84ec6701ed19ae98b8dfbeb321aafa81495e /Source/CPack | |
parent | 3366e6c2cd8bb2d9e30d2deb5637c840d52221a3 (diff) | |
download | CMake-71f61636b6abfe5f243374b5575019098418b4c6.zip CMake-71f61636b6abfe5f243374b5575019098418b4c6.tar.gz CMake-71f61636b6abfe5f243374b5575019098418b4c6.tar.bz2 |
ENH: One more patch from Doug Gregor including PackageMaker functionality for componentized-for-the-end-user and download-some-bit-on-demand installers.
Diffstat (limited to 'Source/CPack')
-rw-r--r-- | Source/CPack/cmCPackComponentGroup.cxx | 49 | ||||
-rw-r--r-- | Source/CPack/cmCPackComponentGroup.h | 14 | ||||
-rw-r--r-- | Source/CPack/cmCPackPackageMakerGenerator.cxx | 289 | ||||
-rw-r--r-- | Source/CPack/cmCPackPackageMakerGenerator.h | 1 |
4 files changed, 254 insertions, 99 deletions
diff --git a/Source/CPack/cmCPackComponentGroup.cxx b/Source/CPack/cmCPackComponentGroup.cxx new file mode 100644 index 0000000..63ad9d7 --- /dev/null +++ b/Source/CPack/cmCPackComponentGroup.cxx @@ -0,0 +1,49 @@ +/*========================================================================= + + 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 "cmCPackComponentGroup.h" +#include "cmSystemTools.h" +#include <vector> +#include <string> + +//---------------------------------------------------------------------- +unsigned long cmCPackComponent::GetInstalledSize(const char* installDir) const +{ + if (this->TotalSize != 0) + { + return this->TotalSize; + } + + std::vector<std::string>::const_iterator fileIt; + for (fileIt = this->Files.begin(); fileIt != this->Files.end(); ++fileIt) + { + std::string path = installDir; + path += '/'; + path += *fileIt; + this->TotalSize += cmSystemTools::FileLength(path.c_str()); + } + + return this->TotalSize; +} + +//---------------------------------------------------------------------- +unsigned long +cmCPackComponent::GetInstalledSizeInKbytes(const char* installDir) const +{ + unsigned long result = (GetInstalledSize(installDir) + 512) / 1024; + return result? result : 1; +} diff --git a/Source/CPack/cmCPackComponentGroup.h b/Source/CPack/cmCPackComponentGroup.h index d080a87..e17b1b7 100644 --- a/Source/CPack/cmCPackComponentGroup.h +++ b/Source/CPack/cmCPackComponentGroup.h @@ -49,7 +49,7 @@ public: class cmCPackComponent { public: - cmCPackComponent() : Group(0) { } + cmCPackComponent() : Group(0), TotalSize(0) { } /// The name of the component (used to reference the component). std::string Name; @@ -95,6 +95,18 @@ public: /// The list of installed directories that are part of this component. std::vector<std::string> Directories; + + /// Get the total installed size of all of the files in this + /// component, in bytes. installDir is the directory into which the + /// component was installed. + unsigned long GetInstalledSize(const char* installDir) const; + + /// Identical to GetInstalledSize, but returns the result in + /// kilobytes. + unsigned long GetInstalledSizeInKbytes(const char* installDir) const; + + private: + mutable unsigned long TotalSize; }; /** \class cmCPackComponentGroup diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx index a156971..d35e764 100644 --- a/Source/CPack/cmCPackPackageMakerGenerator.cxx +++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx @@ -32,6 +32,7 @@ cmCPackPackageMakerGenerator::cmCPackPackageMakerGenerator() { this->PackageMakerVersion = 0.0; + this->PackageCompatibilityVersion = 10.4; } //---------------------------------------------------------------------- @@ -42,7 +43,7 @@ cmCPackPackageMakerGenerator::~cmCPackPackageMakerGenerator() //---------------------------------------------------------------------- bool cmCPackPackageMakerGenerator::SupportsComponentInstallation() const { - return true; + return this->PackageCompatibilityVersion >= 10.4; } //---------------------------------------------------------------------- @@ -165,7 +166,7 @@ int cmCPackPackageMakerGenerator::CompressFiles(const char* outFileName, if (!this->Components.empty()) { - // Create the directory where component packages will be installed. + // Create the directory where component packages will be built. std::string basePackageDir = packageDirFileName; basePackageDir += "/Contents/Packages"; if (!cmsys::SystemTools::MakeDirectory(basePackageDir.c_str())) @@ -176,12 +177,78 @@ int cmCPackPackageMakerGenerator::CompressFiles(const char* outFileName, 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 = basePackageDir; + 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); @@ -229,7 +296,7 @@ int cmCPackPackageMakerGenerator::CompressFiles(const char* outFileName, << "/Resources\" -i \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/Info.plist\" -d \"" - << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") + << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/Description.plist\""; if ( this->PackageMakerVersion > 2.0 ) { @@ -339,6 +406,30 @@ int cmCPackPackageMakerGenerator::InitializeInternal() 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); @@ -491,12 +582,19 @@ bool cmCPackPackageMakerGenerator::RunPackageMaker(const char *command, 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(); + 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"; + } } //---------------------------------------------------------------------- @@ -509,46 +607,74 @@ GenerateComponentPackage(const char *packageFile, 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())) + // 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 { - return false; + // 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 - 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); } @@ -670,8 +796,6 @@ cmCPackPackageMakerGenerator::CreateChoice(const cmCPackComponent& component, packageId += '.'; packageId += this->GetOption("CPACK_PACKAGE_NAME"); packageId += '.'; - packageId += this->GetOption("CPACK_PACKAGE_VERSION"); - packageId += '.'; packageId += component.Name; out << "<choice id=\"" << component.Name << "Choice\" " @@ -716,60 +840,29 @@ cmCPackPackageMakerGenerator::CreateChoice(const cmCPackComponent& component, // 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; - } - } - + 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\">" - << "file:./" << relativePackageLocation << "</pkg-ref>" << std::endl; + << "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; } //---------------------------------------------------------------------- diff --git a/Source/CPack/cmCPackPackageMakerGenerator.h b/Source/CPack/cmCPackPackageMakerGenerator.h index 37f8f0e..228e099 100644 --- a/Source/CPack/cmCPackPackageMakerGenerator.h +++ b/Source/CPack/cmCPackPackageMakerGenerator.h @@ -116,6 +116,7 @@ protected: std::string EscapeForXML(std::string str); double PackageMakerVersion; + double PackageCompatibilityVersion; }; #endif |