1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCPackPackageMakerGenerator.cxx,v $
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"
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
,
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
);
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"
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 )
93 cmCPackLogger(cmCPackLog::LOG_VERBOSE
, "Execute: " << pkgCmd
.str().c_str()
97 //bool res = cmSystemTools::RunSingleCommand(pkgCmd.str().c_str(), &output,
98 //&retVal, 0, this->GeneratorVerbose, 0);
100 retVal
= system(pkgCmd
.str().c_str());
101 cmCPackLogger(cmCPackLog::LOG_VERBOSE
, "Done running package maker"
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"
115 // sometimes the pkgCmd finishes but the directory is not yet
116 // created, so try 10 times to see if it shows up
119 !cmSystemTools::FileExists(packageDirFileName
.c_str()))
121 cmSystemTools::Delay(500);
124 if(!cmSystemTools::FileExists(packageDirFileName
.c_str()))
127 cmCPackLog::LOG_ERROR
,
128 "Problem running PackageMaker command: " << pkgCmd
.str().c_str()
129 << std::endl
<< "Package not created: " << packageDirFileName
.c_str()
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
);
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
;
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()
177 versionFile
= newVersionFile
;
179 std::ifstream
ifs(versionFile
.c_str());
182 cmCPackLogger(cmCPackLog::LOG_ERROR
,
183 "Cannot open PackageMaker compiler version file" << std::endl
);
186 // Check the PackageMaker version
187 cmsys::RegularExpression
rexKey("<key>CFBundleShortVersionString</key>");
188 cmsys::RegularExpression
rexVersion("<string>([0-9]+.[0-9.]+)</string>");
190 bool foundKey
= false;
191 while ( cmSystemTools::GetLineFromStream(ifs
, line
) )
193 if ( rexKey
.find(line
) )
201 cmCPackLogger(cmCPackLog::LOG_ERROR
,
202 "Cannot find CFBundleShortVersionString in the PackageMaker compiler "
203 "version file" << std::endl
);
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
);
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"
221 cmCPackLogger(cmCPackLog::LOG_DEBUG
, "PackageMaker version is: "
222 << this->PackageMakerVersion
<< std::endl
);
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"
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"
241 this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
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());
255 cmCPackLogger(cmCPackLog::LOG_ERROR
, "CPack option: " << cpackVar
.c_str()
256 << " not specified. It should point to "
257 << (name
? name
: "(NULL)")
259 << ".html, or " << name
<< ".txt file" << std::endl
);
262 if ( !cmSystemTools::FileExists(inFileName
) )
264 cmCPackLogger(cmCPackLog::LOG_ERROR
, "Cannot find "
265 << (name
? name
: "(NULL)")
266 << " resource file: " << inFileName
<< std::endl
);
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."
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());
290 bool cmCPackPackageMakerGenerator::CopyResourcePlistFile(const char* name
)
292 std::string inFName
= "CPack.";
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
);
303 std::string destFileName
= this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
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());