/*========================================================================= 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 "cmCPackPackageMakerGenerator.h" #include "cmake.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmSystemTools.h" #include "cmMakefile.h" #include "cmGeneratedFileStream.h" #include "cmCPackLog.h" #include #include //---------------------------------------------------------------------- cmCPackPackageMakerGenerator::cmCPackPackageMakerGenerator() { this->PackageMakerVersion = 0; } //---------------------------------------------------------------------- cmCPackPackageMakerGenerator::~cmCPackPackageMakerGenerator() { } //---------------------------------------------------------------------- int cmCPackPackageMakerGenerator::CompressFiles(const char* outFileName, const char* toplevel, const std::vector& files) { (void) files; // TODO: Fix api to not need files. (void) toplevel; // TODO: Use toplevel // Create directory structure std::string resDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); resDir += "/Resources"; std::string preflightDirName = resDir + "/PreFlight"; std::string postflightDirName = resDir + "/PostFlight"; if ( !cmsys::SystemTools::MakeDirectory(preflightDirName.c_str()) || !cmsys::SystemTools::MakeDirectory(postflightDirName.c_str()) ) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem creating installer directories: " << preflightDirName.c_str() << " and " << postflightDirName.c_str() << std::endl); return 0; } if ( !this->CopyCreateResourceFile("License") || !this->CopyCreateResourceFile("ReadMe") || !this->CopyCreateResourceFile("Welcome") || !this->CopyResourcePlistFile("Info.plist") || !this->CopyResourcePlistFile("Description.plist") ) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files" << std::endl); return 0; } std::string packageDirFileName = this->GetOption("CPACK_TEMPORARY_DIRECTORY"); packageDirFileName += ".pkg"; 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 ) { pkgCmd << " -v"; } 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 ) { 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; } 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, &retVal, 0, this->GeneratorVerbose, 0); 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); std::vector 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("CFBundleShortVersionString"); cmsys::RegularExpression rexVersion("([0-9]+.[0-9.]+)"); 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 ) { 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); 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) { 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 << ".rtf, " << name << ".html, or " << name << ".txt file" << std::endl); return false; } if ( !cmSystemTools::FileExists(inFileName) ) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find " << name << " 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 = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); destFileName += "/Resources/"; destFileName += name + ext; cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: " << inFileName << " to " << destFileName.c_str() << std::endl); this->ConfigureFile(inFileName, destFileName.c_str()); return true; } bool cmCPackPackageMakerGenerator::CopyResourcePlistFile(const char* 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 += name; 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; }