1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCPackPackageMakerGenerator.cxx,v $
6 Date: $Date: 2008/02/19 19:26:19 $
7 Version: $Revision: 1.23 $
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"
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 int cmCPackPackageMakerGenerator::CopyInstallScript(const char* resdir
,
45 std::string dst
= resdir
;
48 cmSystemTools::CopyFileAlways(script
, dst
.c_str());
49 cmSystemTools::SetPermissions(dst
.c_str(),0777);
50 cmCPackLogger(cmCPackLog::LOG_VERBOSE
,
51 "copy script : " << script
<< "\ninto " << dst
.c_str() <<
57 //----------------------------------------------------------------------
58 int cmCPackPackageMakerGenerator::CompressFiles(const char* outFileName
,
60 const std::vector
<std::string
>& files
)
62 (void) files
; // TODO: Fix api to not need files.
63 (void) toplevel
; // TODO: Use toplevel
64 // Create directory structure
65 std::string resDir
= this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
66 resDir
+= "/Resources";
67 std::string preflightDirName
= resDir
+ "/PreFlight";
68 std::string postflightDirName
= resDir
+ "/PostFlight";
69 const char* preflight
= this->GetOption("CPACK_PREFLIGHT_SCRIPT");
70 const char* postflight
= this->GetOption("CPACK_POSTFLIGHT_SCRIPT");
71 const char* postupgrade
= this->GetOption("CPACK_POSTUPGRADE_SCRIPT");
72 // if preflight or postflight scripts not there create directories
73 // of the same name, I think this makes it work
76 if ( !cmsys::SystemTools::MakeDirectory(preflightDirName
.c_str()))
78 cmCPackLogger(cmCPackLog::LOG_ERROR
,
79 "Problem creating installer directory: "
80 << preflightDirName
.c_str() << std::endl
);
86 if ( !cmsys::SystemTools::MakeDirectory(postflightDirName
.c_str()))
88 cmCPackLogger(cmCPackLog::LOG_ERROR
,
89 "Problem creating installer directory: "
90 << postflightDirName
.c_str() << std::endl
);
94 // if preflight, postflight, or postupgrade are set
95 // then copy them into the resource directory and make
99 this->CopyInstallScript(resDir
.c_str(),
105 this->CopyInstallScript(resDir
.c_str(),
111 this->CopyInstallScript(resDir
.c_str(),
116 if ( !this->CopyCreateResourceFile("License")
117 || !this->CopyCreateResourceFile("ReadMe")
118 || !this->CopyCreateResourceFile("Welcome")
119 || !this->CopyResourcePlistFile("Info.plist")
120 || !this->CopyResourcePlistFile("Description.plist") )
122 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Problem copying the resource files"
127 std::string packageDirFileName
128 = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
129 packageDirFileName
+= ".pkg";
131 std::string tmpFile
= this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
132 tmpFile
+= "/PackageMakerOutput.log";
133 cmOStringStream pkgCmd
;
134 pkgCmd
<< "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
135 << "\" -build -p \"" << packageDirFileName
<< "\" -f \""
136 << this->GetOption("CPACK_TEMPORARY_DIRECTORY")
137 << "\" -r \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
138 << "/Resources\" -i \""
139 << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/Info.plist\" -d \""
140 << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/Description.plist\"";
141 if ( this->PackageMakerVersion
> 2.0 )
145 cmCPackLogger(cmCPackLog::LOG_VERBOSE
, "Execute: " << pkgCmd
.str().c_str()
149 //bool res = cmSystemTools::RunSingleCommand(pkgCmd.str().c_str(), &output,
150 //&retVal, 0, this->GeneratorVerbose, 0);
152 retVal
= system(pkgCmd
.str().c_str());
153 cmCPackLogger(cmCPackLog::LOG_VERBOSE
, "Done running package maker"
155 if ( !res
|| retVal
)
157 cmGeneratedFileStream
ofs(tmpFile
.c_str());
158 ofs
<< "# Run command: " << pkgCmd
.str().c_str() << std::endl
159 << "# Output:" << std::endl
160 << output
.c_str() << std::endl
;
161 cmCPackLogger(cmCPackLog::LOG_ERROR
,
162 "Problem running PackageMaker command: " << pkgCmd
.str().c_str()
163 << std::endl
<< "Please check " << tmpFile
.c_str() << " for errors"
167 // sometimes the pkgCmd finishes but the directory is not yet
168 // created, so try 10 times to see if it shows up
171 !cmSystemTools::FileExists(packageDirFileName
.c_str()))
173 cmSystemTools::Delay(500);
176 if(!cmSystemTools::FileExists(packageDirFileName
.c_str()))
179 cmCPackLog::LOG_ERROR
,
180 "Problem running PackageMaker command: " << pkgCmd
.str().c_str()
181 << std::endl
<< "Package not created: " << packageDirFileName
.c_str()
184 tmpFile
= this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
185 tmpFile
+= "/hdiutilOutput.log";
186 cmOStringStream dmgCmd
;
187 dmgCmd
<< "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")
188 << "\" create -ov -format UDZO -srcfolder \"" << packageDirFileName
189 << "\" \"" << outFileName
<< "\"";
190 res
= cmSystemTools::RunSingleCommand(dmgCmd
.str().c_str(), &output
,
191 &retVal
, 0, this->GeneratorVerbose
, 0);
192 if ( !res
|| retVal
)
194 cmGeneratedFileStream
ofs(tmpFile
.c_str());
195 ofs
<< "# Run command: " << dmgCmd
.str().c_str() << std::endl
196 << "# Output:" << std::endl
197 << output
.c_str() << std::endl
;
198 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Problem running hdiutil command: "
199 << dmgCmd
.str().c_str() << std::endl
200 << "Please check " << tmpFile
.c_str() << " for errors" << std::endl
);
207 //----------------------------------------------------------------------
208 int cmCPackPackageMakerGenerator::InitializeInternal()
210 cmCPackLogger(cmCPackLog::LOG_DEBUG
,
211 "cmCPackPackageMakerGenerator::Initialize()" << std::endl
);
212 this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
213 std::vector
<std::string
> path
;
215 = "/Developer/Applications/Utilities/PackageMaker.app/Contents";
216 std::string versionFile
= pkgPath
+ "/version.plist";
217 if ( !cmSystemTools::FileExists(versionFile
.c_str()) )
219 pkgPath
= "/Developer/Applications/PackageMaker.app/Contents";
220 std::string newVersionFile
= pkgPath
+ "/version.plist";
221 if ( !cmSystemTools::FileExists(newVersionFile
.c_str()) )
223 cmCPackLogger(cmCPackLog::LOG_ERROR
,
224 "Cannot find PackageMaker compiler version file: "
225 << versionFile
.c_str() << " or " << newVersionFile
.c_str()
229 versionFile
= newVersionFile
;
231 std::ifstream
ifs(versionFile
.c_str());
234 cmCPackLogger(cmCPackLog::LOG_ERROR
,
235 "Cannot open PackageMaker compiler version file" << std::endl
);
238 // Check the PackageMaker version
239 cmsys::RegularExpression
rexKey("<key>CFBundleShortVersionString</key>");
240 cmsys::RegularExpression
rexVersion("<string>([0-9]+.[0-9.]+)</string>");
242 bool foundKey
= false;
243 while ( cmSystemTools::GetLineFromStream(ifs
, line
) )
245 if ( rexKey
.find(line
) )
253 cmCPackLogger(cmCPackLog::LOG_ERROR
,
254 "Cannot find CFBundleShortVersionString in the PackageMaker compiler "
255 "version file" << std::endl
);
258 if ( !cmSystemTools::GetLineFromStream(ifs
, line
) ||
259 !rexVersion
.find(line
) )
261 cmCPackLogger(cmCPackLog::LOG_ERROR
,
262 "Problem reading the PackageMaker compiler version file: "
263 << versionFile
.c_str() << std::endl
);
266 this->PackageMakerVersion
= atof(rexVersion
.match(1).c_str());
267 if ( this->PackageMakerVersion
< 1.0 )
269 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Require PackageMaker 1.0 or higher"
273 cmCPackLogger(cmCPackLog::LOG_DEBUG
, "PackageMaker version is: "
274 << this->PackageMakerVersion
<< std::endl
);
277 path
.push_back(pkgPath
);
278 pkgPath
= cmSystemTools::FindProgram("PackageMaker", path
, false);
279 if ( pkgPath
.empty() )
281 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Cannot find PackageMaker compiler"
285 this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath
.c_str());
286 pkgPath
= cmSystemTools::FindProgram("hdiutil", path
, false);
287 if ( pkgPath
.empty() )
289 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Cannot find hdiutil compiler"
293 this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
296 return this->Superclass::InitializeInternal();
299 //----------------------------------------------------------------------
300 bool cmCPackPackageMakerGenerator::CopyCreateResourceFile(const char* name
)
302 std::string uname
= cmSystemTools::UpperCase(name
);
303 std::string cpackVar
= "CPACK_RESOURCE_FILE_" + uname
;
304 const char* inFileName
= this->GetOption(cpackVar
.c_str());
307 cmCPackLogger(cmCPackLog::LOG_ERROR
, "CPack option: " << cpackVar
.c_str()
308 << " not specified. It should point to "
309 << (name
? name
: "(NULL)")
311 << ".html, or " << name
<< ".txt file" << std::endl
);
314 if ( !cmSystemTools::FileExists(inFileName
) )
316 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Cannot find "
317 << (name
? name
: "(NULL)")
318 << " resource file: " << inFileName
<< std::endl
);
321 std::string ext
= cmSystemTools::GetFilenameLastExtension(inFileName
);
322 if ( ext
!= ".rtfd" && ext
!= ".rtf" && ext
!= ".html" && ext
!= ".txt" )
324 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Bad file extension specified: "
325 << ext
<< ". Currently only .rtfd, .rtf, .html, and .txt files allowed."
330 std::string destFileName
= this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
331 destFileName
+= "/Resources/";
332 destFileName
+= name
+ ext
;
335 cmCPackLogger(cmCPackLog::LOG_VERBOSE
, "Configure file: "
336 << (inFileName
? inFileName
: "(NULL)")
337 << " to " << destFileName
.c_str() << std::endl
);
338 this->ConfigureFile(inFileName
, destFileName
.c_str());
342 bool cmCPackPackageMakerGenerator::CopyResourcePlistFile(const char* name
)
344 std::string inFName
= "CPack.";
347 std::string inFileName
= this->FindTemplate(inFName
.c_str());
348 if ( inFileName
.empty() )
350 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Cannot find input file: "
351 << inFName
<< std::endl
);
355 std::string destFileName
= this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
357 destFileName
+= name
;
359 cmCPackLogger(cmCPackLog::LOG_VERBOSE
, "Configure file: "
360 << inFileName
.c_str() << " to " << destFileName
.c_str() << std::endl
);
361 this->ConfigureFile(inFileName
.c_str(), destFileName
.c_str());