| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmCPackOSXX11Generator.h" |
| |
| #include <sstream> |
| |
| #include "cmCPackGenerator.h" |
| #include "cmCPackLog.h" |
| #include "cmGeneratedFileStream.h" |
| #include "cmSystemTools.h" |
| #include "cm_sys_stat.h" |
| |
| cmCPackOSXX11Generator::cmCPackOSXX11Generator() |
| { |
| } |
| |
| cmCPackOSXX11Generator::~cmCPackOSXX11Generator() |
| { |
| } |
| |
| int cmCPackOSXX11Generator::PackageFiles() |
| { |
| // TODO: Use toplevel ? |
| // It is used! Is this an obsolete comment? |
| |
| const char* cpackPackageExecutables = |
| this->GetOption("CPACK_PACKAGE_EXECUTABLES"); |
| if (cpackPackageExecutables) { |
| cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackPackageExecutables: " |
| << cpackPackageExecutables << "." << std::endl); |
| std::ostringstream str; |
| std::ostringstream deleteStr; |
| std::vector<std::string> cpackPackageExecutablesVector; |
| cmSystemTools::ExpandListArgument(cpackPackageExecutables, |
| cpackPackageExecutablesVector); |
| if (cpackPackageExecutablesVector.size() % 2 != 0) { |
| cmCPackLogger( |
| cmCPackLog::LOG_ERROR, |
| "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and " |
| "<icon name>." |
| << std::endl); |
| return 0; |
| } |
| std::vector<std::string>::iterator it; |
| for (it = cpackPackageExecutablesVector.begin(); |
| it != cpackPackageExecutablesVector.end(); ++it) { |
| std::string cpackExecutableName = *it; |
| ++it; |
| this->SetOptionIfNotSet("CPACK_EXECUTABLE_NAME", |
| cpackExecutableName.c_str()); |
| } |
| } |
| |
| // Disk image directories |
| std::string diskImageDirectory = toplevel; |
| std::string diskImageBackgroundImageDir = |
| diskImageDirectory + "/.background"; |
| |
| // App bundle directories |
| std::string packageDirFileName = toplevel; |
| packageDirFileName += "/"; |
| packageDirFileName += this->GetOption("CPACK_PACKAGE_FILE_NAME"); |
| packageDirFileName += ".app"; |
| std::string contentsDirectory = packageDirFileName + "/Contents"; |
| std::string resourcesDirectory = contentsDirectory + "/Resources"; |
| std::string appDirectory = contentsDirectory + "/MacOS"; |
| std::string scriptDirectory = resourcesDirectory + "/Scripts"; |
| std::string resourceFileName = this->GetOption("CPACK_PACKAGE_FILE_NAME"); |
| resourceFileName += ".rsrc"; |
| |
| const char* dir = resourcesDirectory.c_str(); |
| const char* appdir = appDirectory.c_str(); |
| const char* scrDir = scriptDirectory.c_str(); |
| const char* contDir = contentsDirectory.c_str(); |
| const char* rsrcFile = resourceFileName.c_str(); |
| const char* iconFile = this->GetOption("CPACK_PACKAGE_ICON"); |
| if (iconFile) { |
| std::string iconFileName = cmsys::SystemTools::GetFilenameName(iconFile); |
| if (!cmSystemTools::FileExists(iconFile)) { |
| cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find icon file: " |
| << iconFile |
| << ". Please check CPACK_PACKAGE_ICON setting." |
| << std::endl); |
| return 0; |
| } |
| std::string destFileName = resourcesDirectory + "/" + iconFileName; |
| this->ConfigureFile(iconFile, destFileName.c_str(), true); |
| this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str()); |
| } |
| |
| std::string applicationsLinkName = diskImageDirectory + "/Applications"; |
| cmSystemTools::CreateSymlink("/Applications", applicationsLinkName); |
| |
| if (!this->CopyResourcePlistFile("VolumeIcon.icns", diskImageDirectory, |
| ".VolumeIcon.icns", true) || |
| !this->CopyResourcePlistFile("DS_Store", diskImageDirectory, ".DS_Store", |
| true) || |
| !this->CopyResourcePlistFile("background.png", |
| diskImageBackgroundImageDir, |
| "background.png", true) || |
| !this->CopyResourcePlistFile("RuntimeScript", dir) || |
| !this->CopyResourcePlistFile("OSXX11.Info.plist", contDir, |
| "Info.plist") || |
| !this->CopyResourcePlistFile("OSXX11.main.scpt", scrDir, "main.scpt", |
| true) || |
| !this->CopyResourcePlistFile("OSXScriptLauncher.rsrc", dir, rsrcFile, |
| true) || |
| !this->CopyResourcePlistFile("OSXScriptLauncher", appdir, |
| this->GetOption("CPACK_PACKAGE_FILE_NAME"), |
| true)) { |
| cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files" |
| << std::endl); |
| return 0; |
| } |
| |
| // Two of the files need to have execute permission, so ensure they do: |
| std::string runTimeScript = dir; |
| runTimeScript += "/"; |
| runTimeScript += "RuntimeScript"; |
| |
| std::string appScriptName = appdir; |
| appScriptName += "/"; |
| appScriptName += this->GetOption("CPACK_PACKAGE_FILE_NAME"); |
| |
| mode_t mode; |
| if (cmsys::SystemTools::GetPermissions(runTimeScript.c_str(), mode)) { |
| mode |= (S_IXUSR | S_IXGRP | S_IXOTH); |
| cmsys::SystemTools::SetPermissions(runTimeScript.c_str(), mode); |
| cmCPackLogger(cmCPackLog::LOG_OUTPUT, |
| "Setting: " << runTimeScript << " to permission: " << mode |
| << std::endl); |
| } |
| |
| if (cmsys::SystemTools::GetPermissions(appScriptName.c_str(), mode)) { |
| mode |= (S_IXUSR | S_IXGRP | S_IXOTH); |
| cmsys::SystemTools::SetPermissions(appScriptName.c_str(), mode); |
| cmCPackLogger(cmCPackLog::LOG_OUTPUT, |
| "Setting: " << appScriptName << " to permission: " << mode |
| << std::endl); |
| } |
| |
| std::string output; |
| std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); |
| tmpFile += "/hdiutilOutput.log"; |
| std::ostringstream dmgCmd; |
| dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE") |
| << "\" create -ov -fs HFS+ -format UDZO -srcfolder \"" |
| << diskImageDirectory << "\" \"" << packageFileNames[0] << "\""; |
| cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Compress disk image using command: " |
| << dmgCmd.str() << std::endl); |
| // since we get random dashboard failures with this one |
| // try running it more than once |
| int retVal = 1; |
| int numTries = 10; |
| bool res = false; |
| while (numTries > 0) { |
| res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output, |
| &output, &retVal, nullptr, |
| 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() << std::endl |
| << "# Output:" << std::endl |
| << output << std::endl; |
| cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running hdiutil command: " |
| << dmgCmd.str() << std::endl |
| << "Please check " << tmpFile << " for errors" |
| << std::endl); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| int cmCPackOSXX11Generator::InitializeInternal() |
| { |
| cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackOSXX11Generator::Initialize()" |
| << std::endl); |
| std::vector<std::string> path; |
| std::string 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 cmCPackOSXX11Generator::CopyCreateResourceFile(const std::string& 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 ? 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 = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); |
| destFileName += "/Resources/"; |
| destFileName += name + ext; |
| |
| |
| cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: " |
| << (inFileName ? inFileName : "(NULL)") |
| << " to " << destFileName << std::endl); |
| this->ConfigureFile(inFileName, destFileName.c_str()); |
| return true; |
| } |
| */ |
| |
| bool cmCPackOSXX11Generator::CopyResourcePlistFile( |
| const std::string& name, const std::string& dir, |
| const char* outputFileName /* = 0 */, bool copyOnly /* = false */) |
| { |
| 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; |
| } |
| |
| if (!outputFileName) { |
| outputFileName = name.c_str(); |
| } |
| |
| std::string destFileName = dir; |
| destFileName += "/"; |
| destFileName += outputFileName; |
| |
| cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: " |
| << inFileName << " to " << destFileName << std::endl); |
| this->ConfigureFile(inFileName.c_str(), destFileName.c_str(), copyOnly); |
| return true; |
| } |
| |
| const char* cmCPackOSXX11Generator::GetPackagingInstallPrefix() |
| { |
| this->InstallPrefix = "/"; |
| this->InstallPrefix += this->GetOption("CPACK_PACKAGE_FILE_NAME"); |
| this->InstallPrefix += ".app/Contents/Resources"; |
| return this->InstallPrefix.c_str(); |
| } |