| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040 |
- /*============================================================================
- 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 "cmCPackPackageMakerGenerator.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 <cmsys/SystemTools.hxx>
- #include <cmsys/Glob.hxx>
- #include <cmsys/FStream.hxx>
- //----------------------------------------------------------------------
- cmCPackPackageMakerGenerator::cmCPackPackageMakerGenerator()
- {
- this->PackageMakerVersion = 0.0;
- this->PackageCompatibilityVersion = 10.4;
- }
- //----------------------------------------------------------------------
- cmCPackPackageMakerGenerator::~cmCPackPackageMakerGenerator()
- {
- }
- //----------------------------------------------------------------------
- bool cmCPackPackageMakerGenerator::SupportsComponentInstallation() const
- {
- return this->PackageCompatibilityVersion >= 10.4;
- }
- //----------------------------------------------------------------------
- int cmCPackPackageMakerGenerator::CopyInstallScript(const char* resdir,
- const char* script,
- const char* name)
- {
- std::string dst = resdir;
- dst += "/";
- dst += name;
- cmSystemTools::CopyFileAlways(script, dst.c_str());
- cmSystemTools::SetPermissions(dst.c_str(),0777);
- cmCPackLogger(cmCPackLog::LOG_VERBOSE,
- "copy script : " << script << "\ninto " << dst.c_str() <<
- std::endl);
- return 1;
- }
- //----------------------------------------------------------------------
- int cmCPackPackageMakerGenerator::PackageFiles()
- {
- // TODO: Use toplevel
- // It is used! Is this an obsolete comment?
- std::string resDir; // Where this package's resources will go.
- std::string packageDirFileName
- = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
- if (this->Components.empty())
- {
- packageDirFileName += ".pkg";
- resDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
- resDir += "/Resources";
- }
- else
- {
- packageDirFileName += ".mpkg";
- if ( !cmsys::SystemTools::MakeDirectory(packageDirFileName.c_str()))
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "unable to create package directory "
- << packageDirFileName << std::endl);
- return 0;
- }
- resDir = packageDirFileName;
- resDir += "/Contents";
- if ( !cmsys::SystemTools::MakeDirectory(resDir.c_str()))
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "unable to create package subdirectory " << resDir
- << std::endl);
- return 0;
- }
- resDir += "/Resources";
- if ( !cmsys::SystemTools::MakeDirectory(resDir.c_str()))
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "unable to create package subdirectory " << resDir
- << std::endl);
- return 0;
- }
- resDir += "/en.lproj";
- }
- const char* preflight = this->GetOption("CPACK_PREFLIGHT_SCRIPT");
- const char* postflight = this->GetOption("CPACK_POSTFLIGHT_SCRIPT");
- const char* postupgrade = this->GetOption("CPACK_POSTUPGRADE_SCRIPT");
- if(this->Components.empty())
- {
- // Create directory structure
- std::string preflightDirName = resDir + "/PreFlight";
- std::string postflightDirName = resDir + "/PostFlight";
- // if preflight or postflight scripts not there create directories
- // of the same name, I think this makes it work
- if(!preflight)
- {
- if ( !cmsys::SystemTools::MakeDirectory(preflightDirName.c_str()))
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Problem creating installer directory: "
- << preflightDirName.c_str() << std::endl);
- return 0;
- }
- }
- if(!postflight)
- {
- if ( !cmsys::SystemTools::MakeDirectory(postflightDirName.c_str()))
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Problem creating installer directory: "
- << postflightDirName.c_str() << std::endl);
- return 0;
- }
- }
- // if preflight, postflight, or postupgrade are set
- // then copy them into the resource directory and make
- // them executable
- if(preflight)
- {
- this->CopyInstallScript(resDir.c_str(),
- preflight,
- "preflight");
- }
- if(postflight)
- {
- this->CopyInstallScript(resDir.c_str(),
- postflight,
- "postflight");
- }
- if(postupgrade)
- {
- this->CopyInstallScript(resDir.c_str(),
- postupgrade,
- "postupgrade");
- }
- }
- else if(postflight)
- {
- // create a postflight component to house the script
- this->PostFlightComponent.Name = "PostFlight";
- this->PostFlightComponent.DisplayName = "PostFlight";
- this->PostFlightComponent.Description = "PostFlight";
- this->PostFlightComponent.IsHidden = true;
- // empty directory for pkg contents
- std::string packageDir = toplevel + "/" + PostFlightComponent.Name;
- if (!cmsys::SystemTools::MakeDirectory(packageDir.c_str()))
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Problem creating component packages directory: "
- << packageDir.c_str() << std::endl);
- return 0;
- }
- // create package
- std::string packageFileDir = packageDirFileName + "/Contents/Packages/";
- if (!cmsys::SystemTools::MakeDirectory(packageFileDir.c_str()))
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Problem creating component PostFlight Packages directory: "
- << packageFileDir.c_str() << std::endl);
- return 0;
- }
- std::string packageFile = packageFileDir +
- this->GetPackageName(PostFlightComponent);
- if (!this->GenerateComponentPackage(packageFile.c_str(),
- packageDir.c_str(),
- PostFlightComponent))
- {
- return 0;
- }
- // copy postflight script into resource directory of .pkg
- std::string resourceDir = packageFile + "/Contents/Resources";
- this->CopyInstallScript(resourceDir.c_str(),
- postflight,
- "postflight");
- }
- if (!this->Components.empty())
- {
- // 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.c_str() << std::endl);
- 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;
- 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);
- 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", resDir.c_str())
- || !this->CopyCreateResourceFile("ReadMe", resDir.c_str())
- || !this->CopyCreateResourceFile("Welcome", resDir.c_str())
- || !this->CopyResourcePlistFile("Info.plist")
- || !this->CopyResourcePlistFile("Description.plist") )
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
- << std::endl);
- return 0;
- }
- if (this->Components.empty())
- {
- // Use PackageMaker to build the package.
- cmOStringStream pkgCmd;
- pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
- << "\" -build -p \"" << packageDirFileName << "\"";
- if (this->Components.empty())
- {
- pkgCmd << " -f \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY");
- }
- else
- {
- pkgCmd << " -mi \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY")
- << "/packages/";
- }
- 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 )
- {
- pkgCmd << " -v";
- }
- if (!RunPackageMaker(pkgCmd.str().c_str(), packageDirFileName.c_str()))
- return 0;
- }
- else
- {
- // We have built the package in place. Generate the
- // distribution.dist file to describe it for the installer.
- WriteDistributionFile(packageDirFileName.c_str());
- }
- 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
- << "\" \"" << packageFileNames[0] << "\"";
- std::string output;
- int retVal = 1;
- int numTries = 10;
- bool res = false;
- while(numTries > 0)
- {
- res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output,
- &retVal, 0, 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().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);
- this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
- // Starting with Xcode 4.3, PackageMaker is a separate app, and you
- // can put it anywhere you want. So... use a variable for its location.
- // People who put it in unexpected places can use the variable to tell
- // us where it is.
- //
- // Use the following locations, in "most recent installation" order,
- // to search for the PackageMaker app. Assume people who copy it into
- // the new Xcode 4.3 app in "/Applications" will copy it into the nested
- // Applications folder inside the Xcode bundle itself. Or directly in
- // the "/Applications" directory.
- //
- // If found, save result in the CPACK_INSTALLER_PROGRAM variable.
- std::vector<std::string> paths;
- paths.push_back(
- "/Applications/Xcode.app/Contents/Applications"
- "/PackageMaker.app/Contents/MacOS");
- paths.push_back(
- "/Applications/Utilities"
- "/PackageMaker.app/Contents/MacOS");
- paths.push_back(
- "/Applications"
- "/PackageMaker.app/Contents/MacOS");
- paths.push_back(
- "/Developer/Applications/Utilities"
- "/PackageMaker.app/Contents/MacOS");
- paths.push_back(
- "/Developer/Applications"
- "/PackageMaker.app/Contents/MacOS");
- std::string pkgPath;
- const char *inst_program = this->GetOption("CPACK_INSTALLER_PROGRAM");
- if (inst_program && *inst_program)
- {
- pkgPath = inst_program;
- }
- else
- {
- pkgPath = cmSystemTools::FindProgram("PackageMaker", paths, false);
- if ( pkgPath.empty() )
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find PackageMaker compiler"
- << std::endl);
- return 0;
- }
- this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath.c_str());
- }
- // Get path to the real PackageMaker, not a symlink:
- pkgPath = cmSystemTools::GetRealPath(pkgPath.c_str());
- // Up from there to find the version.plist file in the "Contents" dir:
- std::string contents_dir;
- contents_dir = cmSystemTools::GetFilenamePath(pkgPath);
- contents_dir = cmSystemTools::GetFilenamePath(contents_dir);
- std::string versionFile = contents_dir + "/version.plist";
- if ( !cmSystemTools::FileExists(versionFile.c_str()) )
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Cannot find PackageMaker compiler version file: "
- << versionFile.c_str()
- << std::endl);
- return 0;
- }
- cmsys::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("<key>CFBundleShortVersionString</key>");
- cmsys::RegularExpression rexVersion("<string>([0-9]+.[0-9.]+)</string>");
- 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.0 )
- {
- 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);
- // 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;
- }
- std::vector<std::string> no_paths;
- pkgPath = cmSystemTools::FindProgram("hdiutil", no_paths, 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 std::string& name,
- const std::string& dirName)
- {
- 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.empty() ? name : "<empty>")
- << ".rtf, " << name
- << ".html, or " << name << ".txt file" << std::endl);
- return false;
- }
- if ( !cmSystemTools::FileExists(inFileName) )
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find "
- << (!name.empty() ? name : "<empty>")
- << " 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 = dirName;
- destFileName += '/';
- destFileName += name + ext;
- // Set this so that distribution.dist gets the right name (without
- // the path).
- this->SetOption(("CPACK_RESOURCE_FILE_" + uname + "_NOPATH").c_str(),
- (name + ext).c_str());
- cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
- << (inFileName ? inFileName : "(NULL)")
- << " to " << destFileName.c_str() << std::endl);
- this->ConfigureFile(inFileName, destFileName.c_str());
- return true;
- }
- bool cmCPackPackageMakerGenerator::CopyResourcePlistFile(const char* name,
- const char* outName)
- {
- if (!outName)
- {
- outName = 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 += 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)
- {
- 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";
- }
- }
- //----------------------------------------------------------------------
- bool
- cmCPackPackageMakerGenerator::
- GenerateComponentPackage(const char *packageFile,
- const char *packageDir,
- const cmCPackComponent& component)
- {
- cmCPackLogger(cmCPackLog::LOG_OUTPUT,
- "- Building component package: " <<
- packageFile << std::endl);
- // 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";
- cmsys::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
- {
- // 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
- 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)
- {
- if (groupIt->second.ParentGroup == 0)
- {
- 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;
- }
- }
- if(!this->PostFlightComponent.Name.empty())
- {
- choiceOut << "<line choice=\"" << PostFlightComponent.Name
- << "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);
- }
- if(!this->PostFlightComponent.Name.empty())
- {
- CreateChoice(PostFlightComponent, 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<cmCPackComponentGroup*>::const_iterator groupIt;
- for (groupIt = group.Subgroups.begin(); groupIt != group.Subgroups.end();
- ++groupIt)
- {
- CreateChoiceOutline(**groupIt, out);
- }
- 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 += 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";
- std::set<const cmCPackComponent *> visited;
- AddDependencyAttributes(component, visited, out);
- visited.clear();
- AddReverseDependencyAttributes(component, visited, 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 += 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\">";
- if (component.IsDownloaded)
- {
- out << this->GetOption("CPACK_DOWNLOAD_SITE")
- << this->GetPackageName(component);
- }
- else
- {
- out << "file:./" << relativePackageLocation;
- }
- out << "</pkg-ref>" << std::endl;
- }
- //----------------------------------------------------------------------
- void
- cmCPackPackageMakerGenerator::
- AddDependencyAttributes(const cmCPackComponent& component,
- std::set<const cmCPackComponent *>& visited,
- cmOStringStream& out)
- {
- if (visited.find(&component) != visited.end())
- {
- return;
- }
- visited.insert(&component);
- std::vector<cmCPackComponent *>::const_iterator dependIt;
- for (dependIt = component.Dependencies.begin();
- dependIt != component.Dependencies.end();
- ++dependIt)
- {
- out << " && choices['" <<
- (*dependIt)->Name << "Choice'].selected";
- AddDependencyAttributes(**dependIt, visited, out);
- }
- }
- //----------------------------------------------------------------------
- void
- cmCPackPackageMakerGenerator::
- AddReverseDependencyAttributes(const cmCPackComponent& component,
- std::set<const cmCPackComponent *>& visited,
- cmOStringStream& out)
- {
- if (visited.find(&component) != visited.end())
- {
- return;
- }
- visited.insert(&component);
- std::vector<cmCPackComponent *>::const_iterator dependIt;
- for (dependIt = component.ReverseDependencies.begin();
- dependIt != component.ReverseDependencies.end();
- ++dependIt)
- {
- out << " || choices['" << (*dependIt)->Name << "Choice'].selected";
- AddReverseDependencyAttributes(**dependIt, visited, out);
- }
- }
- //----------------------------------------------------------------------
- std::string cmCPackPackageMakerGenerator::EscapeForXML(std::string str)
- {
- cmSystemTools::ReplaceString(str, "&", "&");
- cmSystemTools::ReplaceString(str, "<", "<");
- cmSystemTools::ReplaceString(str, ">", ">");
- cmSystemTools::ReplaceString(str, "\"", """);
- return str;
- }
|