ENH: keep cleaning up Tcl/Tk modules
[cmake.git] / Source / CPack / cmCPackPackageMakerGenerator.cxx
blob7def0363c9659f18708c00e2ebce6ab271ee6e81
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCPackPackageMakerGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2007-12-17 20:27:30 $
7 Version: $Revision: 1.22 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmCPackPackageMakerGenerator.h"
19 #include "cmake.h"
20 #include "cmGlobalGenerator.h"
21 #include "cmLocalGenerator.h"
22 #include "cmSystemTools.h"
23 #include "cmMakefile.h"
24 #include "cmGeneratedFileStream.h"
25 #include "cmCPackLog.h"
27 #include <cmsys/SystemTools.hxx>
28 #include <cmsys/Glob.hxx>
30 //----------------------------------------------------------------------
31 cmCPackPackageMakerGenerator::cmCPackPackageMakerGenerator()
33 this->PackageMakerVersion = 0.0;
36 //----------------------------------------------------------------------
37 cmCPackPackageMakerGenerator::~cmCPackPackageMakerGenerator()
41 //----------------------------------------------------------------------
42 int cmCPackPackageMakerGenerator::CompressFiles(const char* outFileName,
43 const char* toplevel,
44 const std::vector<std::string>& files)
46 (void) files; // TODO: Fix api to not need files.
47 (void) toplevel; // TODO: Use toplevel
48 // Create directory structure
49 std::string resDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
50 resDir += "/Resources";
51 std::string preflightDirName = resDir + "/PreFlight";
52 std::string postflightDirName = resDir + "/PostFlight";
54 if ( !cmsys::SystemTools::MakeDirectory(preflightDirName.c_str())
55 || !cmsys::SystemTools::MakeDirectory(postflightDirName.c_str()) )
57 cmCPackLogger(cmCPackLog::LOG_ERROR,
58 "Problem creating installer directories: "
59 << preflightDirName.c_str() << " and "
60 << postflightDirName.c_str() << std::endl);
61 return 0;
64 if ( !this->CopyCreateResourceFile("License")
65 || !this->CopyCreateResourceFile("ReadMe")
66 || !this->CopyCreateResourceFile("Welcome")
67 || !this->CopyResourcePlistFile("Info.plist")
68 || !this->CopyResourcePlistFile("Description.plist") )
70 cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
71 << std::endl);
72 return 0;
75 std::string packageDirFileName
76 = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
77 packageDirFileName += ".pkg";
79 std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
80 tmpFile += "/PackageMakerOutput.log";
81 cmOStringStream pkgCmd;
82 pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
83 << "\" -build -p \"" << packageDirFileName << "\" -f \""
84 << this->GetOption("CPACK_TEMPORARY_DIRECTORY")
85 << "\" -r \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
86 << "/Resources\" -i \""
87 << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/Info.plist\" -d \""
88 << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/Description.plist\"";
89 if ( this->PackageMakerVersion > 2.0 )
91 pkgCmd << " -v";
93 cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << pkgCmd.str().c_str()
94 << std::endl);
95 std::string output;
96 int retVal = 1;
97 //bool res = cmSystemTools::RunSingleCommand(pkgCmd.str().c_str(), &output,
98 //&retVal, 0, this->GeneratorVerbose, 0);
99 bool res = true;
100 retVal = system(pkgCmd.str().c_str());
101 cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running package maker"
102 << std::endl);
103 if ( !res || retVal )
105 cmGeneratedFileStream ofs(tmpFile.c_str());
106 ofs << "# Run command: " << pkgCmd.str().c_str() << std::endl
107 << "# Output:" << std::endl
108 << output.c_str() << std::endl;
109 cmCPackLogger(cmCPackLog::LOG_ERROR,
110 "Problem running PackageMaker command: " << pkgCmd.str().c_str()
111 << std::endl << "Please check " << tmpFile.c_str() << " for errors"
112 << std::endl);
113 return 0;
115 // sometimes the pkgCmd finishes but the directory is not yet
116 // created, so try 10 times to see if it shows up
117 int tries = 10;
118 while(tries > 0 &&
119 !cmSystemTools::FileExists(packageDirFileName.c_str()))
121 cmSystemTools::Delay(500);
122 tries--;
124 if(!cmSystemTools::FileExists(packageDirFileName.c_str()))
126 cmCPackLogger(
127 cmCPackLog::LOG_ERROR,
128 "Problem running PackageMaker command: " << pkgCmd.str().c_str()
129 << std::endl << "Package not created: " << packageDirFileName.c_str()
130 << std::endl);
132 tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
133 tmpFile += "/hdiutilOutput.log";
134 cmOStringStream dmgCmd;
135 dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")
136 << "\" create -ov -format UDZO -srcfolder \"" << packageDirFileName
137 << "\" \"" << outFileName << "\"";
138 res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output,
139 &retVal, 0, this->GeneratorVerbose, 0);
140 if ( !res || retVal )
142 cmGeneratedFileStream ofs(tmpFile.c_str());
143 ofs << "# Run command: " << dmgCmd.str().c_str() << std::endl
144 << "# Output:" << std::endl
145 << output.c_str() << std::endl;
146 cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running hdiutil command: "
147 << dmgCmd.str().c_str() << std::endl
148 << "Please check " << tmpFile.c_str() << " for errors" << std::endl);
149 return 0;
152 return 1;
155 //----------------------------------------------------------------------
156 int cmCPackPackageMakerGenerator::InitializeInternal()
158 cmCPackLogger(cmCPackLog::LOG_DEBUG,
159 "cmCPackPackageMakerGenerator::Initialize()" << std::endl);
160 this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
161 std::vector<std::string> path;
162 std::string pkgPath
163 = "/Developer/Applications/Utilities/PackageMaker.app/Contents";
164 std::string versionFile = pkgPath + "/version.plist";
165 if ( !cmSystemTools::FileExists(versionFile.c_str()) )
167 pkgPath = "/Developer/Applications/PackageMaker.app/Contents";
168 std::string newVersionFile = pkgPath + "/version.plist";
169 if ( !cmSystemTools::FileExists(newVersionFile.c_str()) )
171 cmCPackLogger(cmCPackLog::LOG_ERROR,
172 "Cannot find PackageMaker compiler version file: "
173 << versionFile.c_str() << " or " << newVersionFile.c_str()
174 << std::endl);
175 return 0;
177 versionFile = newVersionFile;
179 std::ifstream ifs(versionFile.c_str());
180 if ( !ifs )
182 cmCPackLogger(cmCPackLog::LOG_ERROR,
183 "Cannot open PackageMaker compiler version file" << std::endl);
184 return 0;
186 // Check the PackageMaker version
187 cmsys::RegularExpression rexKey("<key>CFBundleShortVersionString</key>");
188 cmsys::RegularExpression rexVersion("<string>([0-9]+.[0-9.]+)</string>");
189 std::string line;
190 bool foundKey = false;
191 while ( cmSystemTools::GetLineFromStream(ifs, line) )
193 if ( rexKey.find(line) )
195 foundKey = true;
196 break;
199 if ( !foundKey )
201 cmCPackLogger(cmCPackLog::LOG_ERROR,
202 "Cannot find CFBundleShortVersionString in the PackageMaker compiler "
203 "version file" << std::endl);
204 return 0;
206 if ( !cmSystemTools::GetLineFromStream(ifs, line) ||
207 !rexVersion.find(line) )
209 cmCPackLogger(cmCPackLog::LOG_ERROR,
210 "Problem reading the PackageMaker compiler version file: "
211 << versionFile.c_str() << std::endl);
212 return 0;
214 this->PackageMakerVersion = atof(rexVersion.match(1).c_str());
215 if ( this->PackageMakerVersion < 1.0 )
217 cmCPackLogger(cmCPackLog::LOG_ERROR, "Require PackageMaker 1.0 or higher"
218 << std::endl);
219 return 0;
221 cmCPackLogger(cmCPackLog::LOG_DEBUG, "PackageMaker version is: "
222 << this->PackageMakerVersion << std::endl);
224 pkgPath += "/MacOS";
225 path.push_back(pkgPath);
226 pkgPath = cmSystemTools::FindProgram("PackageMaker", path, false);
227 if ( pkgPath.empty() )
229 cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find PackageMaker compiler"
230 << std::endl);
231 return 0;
233 this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath.c_str());
234 pkgPath = cmSystemTools::FindProgram("hdiutil", path, false);
235 if ( pkgPath.empty() )
237 cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find hdiutil compiler"
238 << std::endl);
239 return 0;
241 this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
242 pkgPath.c_str());
244 return this->Superclass::InitializeInternal();
247 //----------------------------------------------------------------------
248 bool cmCPackPackageMakerGenerator::CopyCreateResourceFile(const char* name)
250 std::string uname = cmSystemTools::UpperCase(name);
251 std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;
252 const char* inFileName = this->GetOption(cpackVar.c_str());
253 if ( !inFileName )
255 cmCPackLogger(cmCPackLog::LOG_ERROR, "CPack option: " << cpackVar.c_str()
256 << " not specified. It should point to "
257 << (name ? name : "(NULL)")
258 << ".rtf, " << name
259 << ".html, or " << name << ".txt file" << std::endl);
260 return false;
262 if ( !cmSystemTools::FileExists(inFileName) )
264 cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find "
265 << (name ? name : "(NULL)")
266 << " resource file: " << inFileName << std::endl);
267 return false;
269 std::string ext = cmSystemTools::GetFilenameLastExtension(inFileName);
270 if ( ext != ".rtfd" && ext != ".rtf" && ext != ".html" && ext != ".txt" )
272 cmCPackLogger(cmCPackLog::LOG_ERROR, "Bad file extension specified: "
273 << ext << ". Currently only .rtfd, .rtf, .html, and .txt files allowed."
274 << std::endl);
275 return false;
278 std::string destFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
279 destFileName += "/Resources/";
280 destFileName += name + ext;
283 cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
284 << (inFileName ? inFileName : "(NULL)")
285 << " to " << destFileName.c_str() << std::endl);
286 this->ConfigureFile(inFileName, destFileName.c_str());
287 return true;
290 bool cmCPackPackageMakerGenerator::CopyResourcePlistFile(const char* name)
292 std::string inFName = "CPack.";
293 inFName += name;
294 inFName += ".in";
295 std::string inFileName = this->FindTemplate(inFName.c_str());
296 if ( inFileName.empty() )
298 cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find input file: "
299 << inFName << std::endl);
300 return false;
303 std::string destFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
304 destFileName += "/";
305 destFileName += name;
307 cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
308 << inFileName.c_str() << " to " << destFileName.c_str() << std::endl);
309 this->ConfigureFile(inFileName.c_str(), destFileName.c_str());
310 return true;