/*============================================================================ CMake - Cross Platform Makefile Generator Copyright 2000-2009 Kitware, Inc., Insight Software Consortium Distributed under the OSI-approved BSD License (the "License"); see accompanying file Copyright.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ #include "cmCPackProductBuildGenerator.h" #include "cmake.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmSystemTools.h" #include "cmMakefile.h" #include "cmGeneratedFileStream.h" #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" #include #include cmCPackProductBuildGenerator::cmCPackProductBuildGenerator() { this->componentPackageMethod = ONE_PACKAGE; } cmCPackProductBuildGenerator::~cmCPackProductBuildGenerator() { } int cmCPackProductBuildGenerator::PackageFiles() { // TODO: Use toplevel // It is used! Is this an obsolete comment? std::string packageDirFileName = this->GetOption("CPACK_TEMPORARY_DIRECTORY"); // Create the directory where component packages will be built. std::string basePackageDir = packageDirFileName; basePackageDir += "/Contents/Packages"; if (!cmsys::SystemTools::MakeDirectory(basePackageDir.c_str())) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem creating component packages directory: " << basePackageDir << std::endl); return 0; } if (!this->Components.empty()) { std::map::iterator compIt; for (compIt = this->Components.begin(); compIt != this->Components.end(); ++compIt) { std::string packageDir = toplevel; packageDir += '/'; packageDir += compIt->first; if (!this->GenerateComponentPackage(basePackageDir, GetPackageName(compIt->second), packageDir, &compIt->second)) { return 0; } } } else { if(!this->GenerateComponentPackage(basePackageDir, this->GetOption("CPACK_PACKAGE_NAME"), toplevel, NULL)) { return 0; } } // Copy or create all of the resource files we need. std::string resDir = packageDirFileName + "/Contents"; if ( !this->CopyCreateResourceFile("License", resDir.c_str()) || !this->CopyCreateResourceFile("ReadMe", resDir.c_str()) || !this->CopyCreateResourceFile("Welcome", resDir.c_str())) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files" << std::endl); return 0; } // combine package(s) into a distribution WriteDistributionFile(packageDirFileName.c_str()); std::ostringstream pkgCmd; std::string version = this->GetOption("CPACK_PACKAGE_VERSION"); std::string productbuild = this->GetOption("CPACK_COMMAND_PRODUCTBUILD"); pkgCmd << productbuild << " --distribution \"" << packageDirFileName << "/Contents/distribution.dist\"" << " --package-path \"" << packageDirFileName << "/Contents/Packages" << "\"" << " --resources \"" << resDir << "\"" << " --version \"" << version << "\"" << " \"" << packageFileNames[0] << "\""; // Run ProductBuild return RunProductBuild(pkgCmd.str()); } int cmCPackProductBuildGenerator::InitializeInternal() { this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/Applications"); std::vector no_paths; std::string program = cmSystemTools::FindProgram("pkgbuild", no_paths, false); if (program.empty()) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find pkgbuild executable" << std::endl); return 0; } this->SetOptionIfNotSet("CPACK_COMMAND_PKGBUILD", program.c_str()); program = cmSystemTools::FindProgram("productbuild", no_paths, false); if (program.empty()) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find productbuild executable" << std::endl); return 0; } this->SetOptionIfNotSet("CPACK_COMMAND_PRODUCTBUILD", program.c_str()); return this->Superclass::InitializeInternal(); } bool cmCPackProductBuildGenerator::RunProductBuild( const std::string& command) { std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); tmpFile += "/ProductBuildOutput.log"; cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl); std::string output, error_output; int retVal = 1; bool res = cmSystemTools::RunSingleCommand(command.c_str(), &output, &error_output, &retVal, 0, this->GeneratorVerbose, 0); cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command" << std::endl); if ( !res || retVal ) { cmGeneratedFileStream ofs(tmpFile.c_str()); ofs << "# Run command: " << command << std::endl << "# Output:" << std::endl << output << std::endl; cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running command: " << command << std::endl << "Please check " << tmpFile << " for errors" << std::endl); return false; } return true; } bool cmCPackProductBuildGenerator::GenerateComponentPackage( const std::string& packageFileDir, const std::string& packageFileName, const std::string& packageDir, const cmCPackComponent* component) { std::string packageFile = packageFileDir; packageFile += '/'; packageFile += packageFileName; cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Building component package: " << packageFile << std::endl); const char* comp_name = component ? component->Name.c_str() : NULL; const char* preflight = this->GetComponentScript("PREFLIGHT", comp_name); const char* postflight = this->GetComponentScript("POSTFLIGHT", comp_name); std::string resDir = packageFileDir; if(component) { resDir += "/"; resDir += component->Name; } std::string scriptDir = resDir + "/scripts"; if ( !cmsys::SystemTools::MakeDirectory(scriptDir.c_str())) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem creating installer directory: " << scriptDir << std::endl); return 0; } // if preflight, postflight, or postupgrade are set // then copy them into the script directory and make // them executable if(preflight) { this->CopyInstallScript(scriptDir.c_str(), preflight, "preinstall"); } if(postflight) { this->CopyInstallScript(scriptDir.c_str(), postflight, "postinstall"); } // The command that will be used to run ProductBuild std::ostringstream pkgCmd; std::string pkgId = "com."; pkgId += this->GetOption("CPACK_PACKAGE_VENDOR"); pkgId += '.'; pkgId += this->GetOption("CPACK_PACKAGE_NAME"); if(component) { pkgId += '.'; pkgId += component->Name; } std::string version = this->GetOption("CPACK_PACKAGE_VERSION"); std::string pkgbuild = this->GetOption("CPACK_COMMAND_PKGBUILD"); pkgCmd << pkgbuild << " --root \"" << packageDir << "\"" << " --identifier \"" << pkgId << "\"" << " --scripts \"" << scriptDir << "\"" << " --version \"" << version << "\"" << " --install-location \"/\"" << " \"" << packageFile << "\""; // Run ProductBuild return RunProductBuild(pkgCmd.str()); } const char* cmCPackProductBuildGenerator::GetComponentScript( const char* script, const char* component_name) { std::string scriptname = std::string("CPACK_") + script + "_"; if(component_name) { scriptname += cmSystemTools::UpperCase(component_name); scriptname += "_"; } scriptname += "SCRIPT"; return this->GetOption(scriptname); }