Resync.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / CPack / cmCPackNSISGenerator.cxx
blobfcf08bdfad6bf6043148eb5c48986d73f239651d
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCPackNSISGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2008/02/15 15:40:55 $
7 Version: $Revision: 1.31 $
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 =========================================================================*/
18 #include "cmCPackNSISGenerator.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>
29 #include <cmsys/Directory.hxx>
30 #include <cmsys/RegularExpression.hxx>
32 /* NSIS uses different command line syntax on Windows and others */
33 #ifdef _WIN32
34 # define NSIS_OPT "/"
35 #else
36 # define NSIS_OPT "-"
37 #endif
39 //----------------------------------------------------------------------
40 cmCPackNSISGenerator::cmCPackNSISGenerator()
44 //----------------------------------------------------------------------
45 cmCPackNSISGenerator::~cmCPackNSISGenerator()
49 //----------------------------------------------------------------------
50 int cmCPackNSISGenerator::CompressFiles(const char* outFileName,
51 const char* toplevel, const std::vector<std::string>& files)
53 (void)outFileName; // TODO: Fix nsis to force out file name
54 (void)toplevel;
55 std::string nsisInFileName = this->FindTemplate("NSIS.template.in");
56 if ( nsisInFileName.size() == 0 )
58 cmCPackLogger(cmCPackLog::LOG_ERROR,
59 "CPack error: Could not find NSIS installer template file."
60 << std::endl);
61 return false;
63 std::string nsisInInstallOptions
64 = this->FindTemplate("NSIS.InstallOptions.ini.in");
65 if ( nsisInInstallOptions.size() == 0 )
67 cmCPackLogger(cmCPackLog::LOG_ERROR,
68 "CPack error: Could not find NSIS installer options file."
69 << std::endl);
70 return false;
72 std::string nsisFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
73 std::string tmpFile = nsisFileName;
74 tmpFile += "/NSISOutput.log";
75 std::string nsisInstallOptions = nsisFileName + "/NSIS.InstallOptions.ini";
76 nsisFileName += "/project.nsi";
77 cmOStringStream str;
78 std::vector<std::string>::const_iterator it;
79 for ( it = files.begin(); it != files.end(); ++ it )
81 std::string fileN = cmSystemTools::RelativePath(toplevel,
82 it->c_str());
83 cmSystemTools::ReplaceString(fileN, "/", "\\");
84 str << " Delete \"$INSTDIR\\" << fileN.c_str() << "\"" << std::endl;
86 cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Files: "
87 << str.str().c_str() << std::endl);
88 this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str().c_str());
89 std::vector<std::string> dirs;
90 this->GetListOfSubdirectories(toplevel, dirs);
91 std::vector<std::string>::const_iterator sit;
92 cmOStringStream dstr;
93 for ( sit = dirs.begin(); sit != dirs.end(); ++ sit )
95 std::string fileN = cmSystemTools::RelativePath(toplevel,
96 sit->c_str());
97 if ( fileN.empty() )
99 continue;
101 cmSystemTools::ReplaceString(fileN, "/", "\\");
102 dstr << " RMDir \"$INSTDIR\\" << fileN.c_str() << "\"" << std::endl;
104 cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Dirs: "
105 << dstr.str().c_str() << std::endl);
106 this->SetOptionIfNotSet("CPACK_NSIS_DELETE_DIRECTORIES",
107 dstr.str().c_str());
109 cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: " << nsisInFileName
110 << " to " << nsisFileName << std::endl);
111 if(this->IsSet("CPACK_NSIS_MUI_ICON")
112 && this->IsSet("CPACK_NSIS_MUI_UNIICON"))
114 std::string installerIconCode="!define MUI_ICON \"";
115 installerIconCode += this->GetOption("CPACK_NSIS_MUI_ICON");
116 installerIconCode += "\"\n";
117 installerIconCode += "!define MUI_UNICON \"";
118 installerIconCode += this->GetOption("CPACK_NSIS_MUI_UNIICON");
119 installerIconCode += "\"\n";
120 this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_ICON_CODE",
121 installerIconCode.c_str());
123 if(this->IsSet("CPACK_PACKAGE_ICON"))
125 std::string installerIconCode = "!define MUI_HEADERIMAGE_BITMAP \"";
126 installerIconCode += this->GetOption("CPACK_PACKAGE_ICON");
127 installerIconCode += "\"\n";
128 this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_ICON_CODE",
129 installerIconCode.c_str());
131 this->ConfigureFile(nsisInInstallOptions.c_str(),
132 nsisInstallOptions.c_str());
133 this->ConfigureFile(nsisInFileName.c_str(), nsisFileName.c_str());
134 std::string nsisCmd = "\"";
135 nsisCmd += this->GetOption("CPACK_INSTALLER_PROGRAM");
136 nsisCmd += "\" \"" + nsisFileName + "\"";
137 cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << nsisCmd.c_str()
138 << std::endl);
139 std::string output;
140 int retVal = 1;
141 bool res = cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output,
142 &retVal, 0, this->GeneratorVerbose, 0);
143 if ( !res || retVal )
145 cmGeneratedFileStream ofs(tmpFile.c_str());
146 ofs << "# Run command: " << nsisCmd.c_str() << std::endl
147 << "# Output:" << std::endl
148 << output.c_str() << std::endl;
149 cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running NSIS command: "
150 << nsisCmd.c_str() << std::endl
151 << "Please check " << tmpFile.c_str() << " for errors" << std::endl);
152 return 0;
154 return 1;
157 //----------------------------------------------------------------------
158 int cmCPackNSISGenerator::InitializeInternal()
160 if ( cmSystemTools::IsOn(this->GetOption(
161 "CPACK_INCLUDE_TOPLEVEL_DIRECTORY")) )
163 cmCPackLogger(cmCPackLog::LOG_ERROR,
164 "NSIS Generator cannot work with CPACK_INCLUDE_TOPLEVEL_DIRECTORY. "
165 "This option will be ignored."
166 << std::endl);
167 this->SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", 0);
170 cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackNSISGenerator::Initialize()"
171 << std::endl);
172 std::vector<std::string> path;
173 std::string nsisPath;
175 #ifdef _WIN32
176 if ( !cmsys::SystemTools::ReadRegistryValue(
177 "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath) )
179 cmCPackLogger
180 (cmCPackLog::LOG_ERROR,
181 "Cannot find NSIS registry value. This is usually caused by NSIS "
182 "not being installed. Please install NSIS from "
183 "http://nsis.sourceforge.net"
184 << std::endl);
185 return 0;
187 path.push_back(nsisPath);
188 #endif
189 nsisPath = cmSystemTools::FindProgram("makensis", path, false);
190 if ( nsisPath.empty() )
192 cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find NSIS compiler"
193 << std::endl);
194 return 0;
196 std::string nsisCmd = "\"" + nsisPath + "\" " NSIS_OPT "VERSION";
197 cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Test NSIS version: "
198 << nsisCmd.c_str() << std::endl);
199 std::string output;
200 int retVal = 1;
201 bool resS = cmSystemTools::RunSingleCommand(nsisCmd.c_str(),
202 &output, &retVal, 0, this->GeneratorVerbose, 0);
204 cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
205 if ( !resS || retVal || !versionRex.find(output))
207 std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
208 tmpFile += "/NSISOutput.log";
209 cmGeneratedFileStream ofs(tmpFile.c_str());
210 ofs << "# Run command: " << nsisCmd.c_str() << std::endl
211 << "# Output:" << std::endl
212 << output.c_str() << std::endl;
213 cmCPackLogger(cmCPackLog::LOG_ERROR,
214 "Problem checking NSIS version with command: "
215 << nsisCmd.c_str() << std::endl
216 << "Please check " << tmpFile.c_str() << " for errors" << std::endl);
217 return 0;
219 double nsisVersion = atof(versionRex.match(1).c_str());
220 double minNSISVersion = 2.09;
221 cmCPackLogger(cmCPackLog::LOG_DEBUG, "NSIS Version: "
222 << nsisVersion << std::endl);
223 if ( nsisVersion < minNSISVersion )
225 cmCPackLogger(cmCPackLog::LOG_ERROR,
226 "CPack requires NSIS Version 2.09 or greater. NSIS found on the system "
227 "was: "
228 << nsisVersion << std::endl);
229 return 0;
231 this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", nsisPath.c_str());
232 const char* cpackPackageExecutables
233 = this->GetOption("CPACK_PACKAGE_EXECUTABLES");
234 const char* cpackPackageDeskTopLinks
235 = this->GetOption("CPACK_CREATE_DESKTOP_LINKS");
236 std::vector<std::string> cpackPackageDesktopLinksVector;
237 if(cpackPackageDeskTopLinks)
239 cmCPackLogger(cmCPackLog::LOG_DEBUG, "CPACK_CREATE_DESKTOP_LINKS: "
240 << cpackPackageDeskTopLinks << std::endl);
242 cmSystemTools::
243 ExpandListArgument(cpackPackageDeskTopLinks,
244 cpackPackageDesktopLinksVector);
245 for(std::vector<std::string>::iterator i =
246 cpackPackageDesktopLinksVector.begin(); i !=
247 cpackPackageDesktopLinksVector.end(); ++i)
249 cmCPackLogger(cmCPackLog::LOG_DEBUG, "CPACK_CREATE_DESKTOP_LINKS: "
250 << *i << std::endl);
253 else
255 cmCPackLogger(cmCPackLog::LOG_DEBUG, "CPACK_CREATE_DESKTOP_LINKS: "
256 << "not set" << std::endl);
259 if ( cpackPackageExecutables )
261 cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackPackageExecutables: "
262 << cpackPackageExecutables << "." << std::endl);
263 cmOStringStream str;
264 cmOStringStream deleteStr;
265 std::vector<std::string> cpackPackageExecutablesVector;
266 cmSystemTools::ExpandListArgument(cpackPackageExecutables,
267 cpackPackageExecutablesVector);
268 if ( cpackPackageExecutablesVector.size() % 2 != 0 )
270 cmCPackLogger(cmCPackLog::LOG_ERROR,
271 "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
272 "<icon name>." << std::endl);
273 return 0;
275 std::vector<std::string>::iterator it;
276 for ( it = cpackPackageExecutablesVector.begin();
277 it != cpackPackageExecutablesVector.end();
278 ++it )
280 std::string execName = *it;
281 ++ it;
282 std::string linkName = *it;
283 str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\"
284 << linkName << ".lnk\" \"$INSTDIR\\bin\\" << execName << ".exe\""
285 << std::endl;
286 deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
287 << ".lnk\"" << std::endl;
288 // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
289 // if so add a desktop link
290 if(cpackPackageDesktopLinksVector.size() &&
291 std::find(cpackPackageDesktopLinksVector.begin(),
292 cpackPackageDesktopLinksVector.end(),
293 execName)
294 != cpackPackageDesktopLinksVector.end())
296 str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
297 str << " CreateShortCut \"$DESKTOP\\"
298 << linkName << ".lnk\" \"$INSTDIR\\bin\\" << execName << ".exe\""
299 << std::endl;
300 deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
301 deleteStr << " Delete \"$DESKTOP\\" << linkName
302 << ".lnk\"" << std::endl;
305 this->CreateMenuLinks(str, deleteStr);
306 this->SetOptionIfNotSet("CPACK_NSIS_CREATE_ICONS", str.str().c_str());
307 this->SetOptionIfNotSet("CPACK_NSIS_DELETE_ICONS",
308 deleteStr.str().c_str());
310 this->SetOptionIfNotSet("CPACK_NSIS_COMPRESSOR", "lzma");
312 return this->Superclass::InitializeInternal();
315 //----------------------------------------------------------------------
316 void cmCPackNSISGenerator::CreateMenuLinks( cmOStringStream& str,
317 cmOStringStream& deleteStr)
319 const char* cpackMenuLinks
320 = this->GetOption("CPACK_NSIS_MENU_LINKS");
321 if(!cpackMenuLinks)
323 return;
325 cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackMenuLinks: "
326 << cpackMenuLinks << "." << std::endl);
327 std::vector<std::string> cpackMenuLinksVector;
328 cmSystemTools::ExpandListArgument(cpackMenuLinks,
329 cpackMenuLinksVector);
330 if ( cpackMenuLinksVector.size() % 2 != 0 )
332 cmCPackLogger(
333 cmCPackLog::LOG_ERROR,
334 "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
335 "<icon name>." << std::endl);
336 return;
338 std::vector<std::string>::iterator it;
339 for ( it = cpackMenuLinksVector.begin();
340 it != cpackMenuLinksVector.end();
341 ++it )
343 std::string sourceName = *it;
344 bool url = false;
345 if(sourceName.find("http:") == 0)
347 url = true;
349 /* convert / to \\ */
350 if(!url)
352 cmSystemTools::ReplaceString(sourceName, "/", "\\");
354 ++ it;
355 std::string linkName = *it;
356 if(!url)
358 str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\"
359 << linkName << ".lnk\" \"$INSTDIR\\" << sourceName << "\""
360 << std::endl;
361 deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
362 << ".lnk\"" << std::endl;
364 else
366 str << " WriteINIStr \"$SMPROGRAMS\\$STARTMENU_FOLDER\\"
367 << linkName << ".url\" \"InternetShortcut\" \"URL\" \""
368 << sourceName << "\""
369 << std::endl;
370 deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
371 << ".url\"" << std::endl;
373 // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
374 // if so add a desktop link
375 std::string desktop = "CPACK_CREATE_DESKTOP_LINK_";
376 desktop += linkName;
377 if(this->IsSet(desktop.c_str()))
379 str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
380 str << " CreateShortCut \"$DESKTOP\\"
381 << linkName << ".lnk\" \"$INSTDIR\\" << sourceName << "\""
382 << std::endl;
383 deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
384 deleteStr << " Delete \"$DESKTOP\\" << linkName
385 << ".lnk\"" << std::endl;
390 //----------------------------------------------------------------------
391 bool cmCPackNSISGenerator::GetListOfSubdirectories(const char* topdir,
392 std::vector<std::string>& dirs)
394 cmsys::Directory dir;
395 dir.Load(topdir);
396 size_t fileNum;
397 for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum)
399 if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".") &&
400 strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)),".."))
402 cmsys_stl::string fullPath = topdir;
403 fullPath += "/";
404 fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
405 if(cmsys::SystemTools::FileIsDirectory(fullPath.c_str()) &&
406 !cmsys::SystemTools::FileIsSymlink(fullPath.c_str()))
408 if (!this->GetListOfSubdirectories(fullPath.c_str(), dirs))
410 return false;
415 dirs.push_back(topdir);
416 return true;