cmCPackIFWPackage.cxx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmCPackIFWPackage.h"
  4. #include <cstddef>
  5. #include <map>
  6. #include <sstream>
  7. #include <utility>
  8. #include <cm/string_view>
  9. #include "cmCPackComponentGroup.h"
  10. #include "cmCPackIFWCommon.h"
  11. #include "cmCPackIFWGenerator.h"
  12. #include "cmCPackIFWInstaller.h"
  13. #include "cmCPackLog.h" // IWYU pragma: keep
  14. #include "cmGeneratedFileStream.h"
  15. #include "cmList.h"
  16. #include "cmStringAlgorithms.h"
  17. #include "cmSystemTools.h"
  18. #include "cmTimestamp.h"
  19. #include "cmValue.h"
  20. #include "cmXMLWriter.h"
  21. //---------------------------------------------------------- CompareStruct ---
  22. cmCPackIFWPackage::CompareStruct::CompareStruct()
  23. : Type(cmCPackIFWPackage::CompareNone)
  24. {
  25. }
  26. //------------------------------------------------------- DependenceStruct ---
  27. cmCPackIFWPackage::DependenceStruct::DependenceStruct() = default;
  28. cmCPackIFWPackage::DependenceStruct::DependenceStruct(
  29. const std::string& dependence)
  30. {
  31. // Preferred format is name and version are separated by a colon (:), but
  32. // note that this is only supported with QtIFW 3.1 or later. Backward
  33. // compatibility allows a hyphen (-) as a separator instead, but names then
  34. // cannot contain a hyphen.
  35. size_t pos;
  36. if ((pos = dependence.find(':')) == std::string::npos) {
  37. pos = dependence.find('-');
  38. }
  39. if (pos != std::string::npos) {
  40. this->Name = dependence.substr(0, pos);
  41. ++pos;
  42. if (pos == dependence.size()) {
  43. // Nothing after the separator. Treat this as no version constraint.
  44. return;
  45. }
  46. const auto versionPart =
  47. cm::string_view(dependence.data() + pos, dependence.size() - pos);
  48. if (cmHasLiteralPrefix(versionPart, "<=")) {
  49. this->Compare.Type = cmCPackIFWPackage::CompareLessOrEqual;
  50. this->Compare.Value = std::string(versionPart.substr(2));
  51. } else if (cmHasLiteralPrefix(versionPart, ">=")) {
  52. this->Compare.Type = cmCPackIFWPackage::CompareGreaterOrEqual;
  53. this->Compare.Value = std::string(versionPart.substr(2));
  54. } else if (cmHasPrefix(versionPart, '<')) {
  55. this->Compare.Type = cmCPackIFWPackage::CompareLess;
  56. this->Compare.Value = std::string(versionPart.substr(1));
  57. } else if (cmHasPrefix(versionPart, '=')) {
  58. this->Compare.Type = cmCPackIFWPackage::CompareEqual;
  59. this->Compare.Value = std::string(versionPart.substr(1));
  60. } else if (cmHasPrefix(versionPart, '>')) {
  61. this->Compare.Type = cmCPackIFWPackage::CompareGreater;
  62. this->Compare.Value = std::string(versionPart.substr(1));
  63. } else {
  64. // We found no operator but a version specification is still expected to
  65. // follow. The default behavior is to treat this the same as =. We
  66. // explicitly record that as our type (it simplifies our logic a little
  67. // and is also clearer).
  68. this->Compare.Type = cmCPackIFWPackage::CompareEqual;
  69. this->Compare.Value = std::string(versionPart);
  70. }
  71. } else {
  72. this->Name = dependence;
  73. }
  74. }
  75. std::string cmCPackIFWPackage::DependenceStruct::NameWithCompare() const
  76. {
  77. std::string result = this->Name;
  78. if (this->Name.find('-') != std::string::npos) {
  79. // When a name contains a hyphen, we must use a colon after the name to
  80. // prevent the hyphen from being parsed by QtIFW as the separator between
  81. // the name and the version. Note that a colon is only supported with
  82. // QtIFW 3.1 or later.
  83. result += ":";
  84. } else if (this->Compare.Type != cmCPackIFWPackage::CompareNone ||
  85. !this->Compare.Value.empty()) {
  86. // No hyphen in the name and we know a version part will follow. Use a
  87. // hyphen as a separator since this works for all QtIFW versions.
  88. result += "-";
  89. }
  90. if (this->Compare.Type == cmCPackIFWPackage::CompareLessOrEqual) {
  91. result += "<=";
  92. } else if (this->Compare.Type == cmCPackIFWPackage::CompareGreaterOrEqual) {
  93. result += ">=";
  94. } else if (this->Compare.Type == cmCPackIFWPackage::CompareLess) {
  95. result += "<";
  96. } else if (this->Compare.Type == cmCPackIFWPackage::CompareEqual) {
  97. result += "=";
  98. } else if (this->Compare.Type == cmCPackIFWPackage::CompareGreater) {
  99. result += ">";
  100. }
  101. result += this->Compare.Value;
  102. return result;
  103. }
  104. //------------------------------------------------------ cmCPackIFWPackage ---
  105. cmCPackIFWPackage::cmCPackIFWPackage()
  106. : Installer(nullptr)
  107. {
  108. }
  109. std::string cmCPackIFWPackage::GetComponentName(cmCPackComponent* component)
  110. {
  111. if (!component) {
  112. return "";
  113. }
  114. cmValue option =
  115. this->GetOption("CPACK_IFW_COMPONENT_" +
  116. cmsys::SystemTools::UpperCase(component->Name) + "_NAME");
  117. return option ? *option : component->Name;
  118. }
  119. void cmCPackIFWPackage::DefaultConfiguration()
  120. {
  121. this->DisplayName.clear();
  122. this->Description.clear();
  123. this->Version.clear();
  124. this->ReleaseDate.clear();
  125. this->Script.clear();
  126. this->Licenses.clear();
  127. this->UserInterfaces.clear();
  128. this->Translations.clear();
  129. this->SortingPriority.clear();
  130. this->UpdateText.clear();
  131. this->Default.clear();
  132. this->Essential.clear();
  133. this->Virtual.clear();
  134. this->ForcedInstallation.clear();
  135. this->RequiresAdminRights.clear();
  136. }
  137. // Default configuration (all in one package)
  138. int cmCPackIFWPackage::ConfigureFromOptions()
  139. {
  140. // Restore default configuration
  141. this->DefaultConfiguration();
  142. // Name
  143. this->Name = this->Generator->GetRootPackageName();
  144. // Display name
  145. if (cmValue option = this->GetOption("CPACK_PACKAGE_NAME")) {
  146. this->DisplayName[""] = *option;
  147. } else {
  148. this->DisplayName[""] = "Your package";
  149. }
  150. // Description
  151. if (cmValue option = this->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
  152. this->Description[""] = *option;
  153. } else {
  154. this->Description[""] = "Your package description";
  155. }
  156. // Version
  157. if (cmValue option = this->GetOption("CPACK_PACKAGE_VERSION")) {
  158. this->Version = *option;
  159. } else {
  160. this->Version = "1.0.0";
  161. }
  162. this->ForcedInstallation = "true";
  163. return 1;
  164. }
  165. int cmCPackIFWPackage::ConfigureFromComponent(cmCPackComponent* component)
  166. {
  167. if (!component) {
  168. return 0;
  169. }
  170. // Restore default configuration
  171. this->DefaultConfiguration();
  172. std::string prefix = "CPACK_IFW_COMPONENT_" +
  173. cmsys::SystemTools::UpperCase(component->Name) + "_";
  174. // Display name
  175. this->DisplayName[""] = component->DisplayName;
  176. // Description
  177. this->Description[""] = component->Description;
  178. // Version
  179. if (cmValue optVERSION = this->GetOption(prefix + "VERSION")) {
  180. this->Version = *optVERSION;
  181. } else if (cmValue optPACKAGE_VERSION =
  182. this->GetOption("CPACK_PACKAGE_VERSION")) {
  183. this->Version = *optPACKAGE_VERSION;
  184. } else {
  185. this->Version = "1.0.0";
  186. }
  187. // Script
  188. if (cmValue option = this->GetOption(prefix + "SCRIPT")) {
  189. this->Script = *option;
  190. }
  191. // User interfaces
  192. if (cmValue option = this->GetOption(prefix + "USER_INTERFACES")) {
  193. this->UserInterfaces.clear();
  194. cmExpandList(option, this->UserInterfaces);
  195. }
  196. // CMake dependencies
  197. if (!component->Dependencies.empty()) {
  198. for (cmCPackComponent* dep : component->Dependencies) {
  199. this->Dependencies.insert(this->Generator->ComponentPackages[dep]);
  200. }
  201. }
  202. // Licenses
  203. if (cmValue option = this->GetOption(prefix + "LICENSES")) {
  204. this->Licenses.clear();
  205. cmExpandList(option, this->Licenses);
  206. if (this->Licenses.size() % 2 != 0) {
  207. cmCPackIFWLogger(
  208. WARNING,
  209. prefix << "LICENSES"
  210. << " should contain pairs of <display_name> and <file_path>."
  211. << std::endl);
  212. this->Licenses.clear();
  213. }
  214. }
  215. // Priority
  216. if (cmValue option = this->GetOption(prefix + "PRIORITY")) {
  217. this->SortingPriority = *option;
  218. cmCPackIFWLogger(
  219. WARNING,
  220. "The \"PRIORITY\" option is set "
  221. << "for component \"" << component->Name << "\", but there option is "
  222. << "deprecated. Please use \"SORTING_PRIORITY\" option instead."
  223. << std::endl);
  224. }
  225. // Default
  226. this->Default = component->IsDisabledByDefault ? "false" : "true";
  227. // Essential
  228. if (this->IsOn(prefix + "ESSENTIAL")) {
  229. this->Essential = "true";
  230. }
  231. // Virtual
  232. this->Virtual = component->IsHidden ? "true" : "";
  233. // ForcedInstallation
  234. this->ForcedInstallation = component->IsRequired ? "true" : "false";
  235. return this->ConfigureFromPrefix(prefix);
  236. }
  237. int cmCPackIFWPackage::ConfigureFromGroup(cmCPackComponentGroup* group)
  238. {
  239. if (!group) {
  240. return 0;
  241. }
  242. // Restore default configuration
  243. this->DefaultConfiguration();
  244. std::string prefix = "CPACK_IFW_COMPONENT_GROUP_" +
  245. cmsys::SystemTools::UpperCase(group->Name) + "_";
  246. this->DisplayName[""] = group->DisplayName;
  247. this->Description[""] = group->Description;
  248. // Version
  249. if (cmValue optVERSION = this->GetOption(prefix + "VERSION")) {
  250. this->Version = *optVERSION;
  251. } else if (cmValue optPACKAGE_VERSION =
  252. this->GetOption("CPACK_PACKAGE_VERSION")) {
  253. this->Version = *optPACKAGE_VERSION;
  254. } else {
  255. this->Version = "1.0.0";
  256. }
  257. // Script
  258. if (cmValue option = this->GetOption(prefix + "SCRIPT")) {
  259. this->Script = *option;
  260. }
  261. // User interfaces
  262. if (cmValue option = this->GetOption(prefix + "USER_INTERFACES")) {
  263. this->UserInterfaces.clear();
  264. cmExpandList(option, this->UserInterfaces);
  265. }
  266. // Licenses
  267. if (cmValue option = this->GetOption(prefix + "LICENSES")) {
  268. this->Licenses.clear();
  269. cmExpandList(option, this->Licenses);
  270. if (this->Licenses.size() % 2 != 0) {
  271. cmCPackIFWLogger(
  272. WARNING,
  273. prefix << "LICENSES"
  274. << " should contain pairs of <display_name> and <file_path>."
  275. << std::endl);
  276. this->Licenses.clear();
  277. }
  278. }
  279. // Priority
  280. if (cmValue option = this->GetOption(prefix + "PRIORITY")) {
  281. this->SortingPriority = *option;
  282. cmCPackIFWLogger(
  283. WARNING,
  284. "The \"PRIORITY\" option is set "
  285. << "for component group \"" << group->Name
  286. << "\", but there option is "
  287. << "deprecated. Please use \"SORTING_PRIORITY\" option instead."
  288. << std::endl);
  289. }
  290. return this->ConfigureFromPrefix(prefix);
  291. }
  292. int cmCPackIFWPackage::ConfigureFromGroup(const std::string& groupName)
  293. {
  294. // Group configuration
  295. cmCPackComponentGroup group;
  296. std::string prefix =
  297. "CPACK_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(groupName) + "_";
  298. if (cmValue option = this->GetOption(prefix + "DISPLAY_NAME")) {
  299. group.DisplayName = *option;
  300. } else {
  301. group.DisplayName = group.Name;
  302. }
  303. if (cmValue option = this->GetOption(prefix + "DESCRIPTION")) {
  304. group.Description = *option;
  305. }
  306. group.IsBold = this->IsOn(prefix + "BOLD_TITLE");
  307. group.IsExpandedByDefault = this->IsOn(prefix + "EXPANDED");
  308. // Package configuration
  309. group.Name = groupName;
  310. if (this->Generator) {
  311. this->Name = this->Generator->GetGroupPackageName(&group);
  312. } else {
  313. this->Name = group.Name;
  314. }
  315. return this->ConfigureFromGroup(&group);
  316. }
  317. // Common options for components and groups
  318. int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
  319. {
  320. // Temporary variable for full option name
  321. std::string option;
  322. // Display name
  323. option = prefix + "DISPLAY_NAME";
  324. if (this->IsSetToEmpty(option)) {
  325. this->DisplayName.clear();
  326. } else if (cmValue value = this->GetOption(option)) {
  327. cmCPackIFWPackage::ExpandListArgument(*value, this->DisplayName);
  328. }
  329. // Description
  330. option = prefix + "DESCRIPTION";
  331. if (this->IsSetToEmpty(option)) {
  332. this->Description.clear();
  333. } else if (cmValue value = this->GetOption(option)) {
  334. cmCPackIFWPackage::ExpandListArgument(*value, this->Description);
  335. }
  336. // Release date
  337. option = prefix + "RELEASE_DATE";
  338. if (this->IsSetToEmpty(option)) {
  339. this->ReleaseDate.clear();
  340. } else if (cmValue value = this->GetOption(option)) {
  341. this->ReleaseDate = *value;
  342. }
  343. // Sorting priority
  344. option = prefix + "SORTING_PRIORITY";
  345. if (this->IsSetToEmpty(option)) {
  346. this->SortingPriority.clear();
  347. } else if (cmValue value = this->GetOption(option)) {
  348. this->SortingPriority = *value;
  349. }
  350. // Update text
  351. option = prefix + "UPDATE_TEXT";
  352. if (this->IsSetToEmpty(option)) {
  353. this->UpdateText.clear();
  354. } else if (cmValue value = this->GetOption(option)) {
  355. this->UpdateText = *value;
  356. }
  357. // Translations
  358. option = prefix + "TRANSLATIONS";
  359. if (this->IsSetToEmpty(option)) {
  360. this->Translations.clear();
  361. } else if (cmValue value = this->GetOption(option)) {
  362. this->Translations.clear();
  363. cmExpandList(value, this->Translations);
  364. }
  365. // QtIFW dependencies
  366. std::vector<std::string> deps;
  367. option = prefix + "DEPENDS";
  368. if (cmValue value = this->GetOption(option)) {
  369. cmExpandList(value, deps);
  370. }
  371. option = prefix + "DEPENDENCIES";
  372. if (cmValue value = this->GetOption(option)) {
  373. cmExpandList(value, deps);
  374. }
  375. for (std::string const& d : deps) {
  376. DependenceStruct dep(d);
  377. if (this->Generator->Packages.count(dep.Name)) {
  378. cmCPackIFWPackage& depPkg = this->Generator->Packages[dep.Name];
  379. dep.Name = depPkg.Name;
  380. }
  381. bool hasDep = this->Generator->DependentPackages.count(dep.Name) > 0;
  382. DependenceStruct& depRef = this->Generator->DependentPackages[dep.Name];
  383. if (!hasDep) {
  384. depRef = dep;
  385. }
  386. this->AlienDependencies.insert(&depRef);
  387. }
  388. // Automatic dependency on
  389. option = prefix + "AUTO_DEPEND_ON";
  390. if (this->IsSetToEmpty(option)) {
  391. this->AlienAutoDependOn.clear();
  392. } else if (cmValue value = this->GetOption(option)) {
  393. cmList depsOn{ value };
  394. for (std::string const& d : depsOn) {
  395. DependenceStruct dep(d);
  396. if (this->Generator->Packages.count(dep.Name)) {
  397. cmCPackIFWPackage& depPkg = this->Generator->Packages[dep.Name];
  398. dep.Name = depPkg.Name;
  399. }
  400. bool hasDep = this->Generator->DependentPackages.count(dep.Name) > 0;
  401. DependenceStruct& depRef = this->Generator->DependentPackages[dep.Name];
  402. if (!hasDep) {
  403. depRef = dep;
  404. }
  405. this->AlienAutoDependOn.insert(&depRef);
  406. }
  407. }
  408. // Visibility
  409. option = prefix + "VIRTUAL";
  410. if (this->IsSetToEmpty(option)) {
  411. this->Virtual.clear();
  412. } else if (this->IsOn(option)) {
  413. this->Virtual = "true";
  414. }
  415. // Default selection
  416. option = prefix + "DEFAULT";
  417. if (this->IsSetToEmpty(option)) {
  418. this->Default.clear();
  419. } else if (cmValue value = this->GetOption(option)) {
  420. std::string lowerValue = cmsys::SystemTools::LowerCase(*value);
  421. if (lowerValue == "true") {
  422. this->Default = "true";
  423. } else if (lowerValue == "false") {
  424. this->Default = "false";
  425. } else if (lowerValue == "script") {
  426. this->Default = "script";
  427. } else {
  428. this->Default = *value;
  429. }
  430. }
  431. // Forsed installation
  432. option = prefix + "FORCED_INSTALLATION";
  433. if (this->IsSetToEmpty(option)) {
  434. this->ForcedInstallation.clear();
  435. } else if (this->IsOn(option)) {
  436. this->ForcedInstallation = "true";
  437. } else if (this->IsSetToOff(option)) {
  438. this->ForcedInstallation = "false";
  439. }
  440. // Replaces
  441. option = prefix + "REPLACES";
  442. if (this->IsSetToEmpty(option)) {
  443. this->Replaces.clear();
  444. } else if (cmValue value = this->GetOption(option)) {
  445. this->Replaces.clear();
  446. cmExpandList(value, this->Replaces);
  447. }
  448. // Requires admin rights
  449. option = prefix + "REQUIRES_ADMIN_RIGHTS";
  450. if (this->IsSetToEmpty(option)) {
  451. this->RequiresAdminRights.clear();
  452. } else if (this->IsOn(option)) {
  453. this->RequiresAdminRights = "true";
  454. } else if (this->IsSetToOff(option)) {
  455. this->RequiresAdminRights = "false";
  456. }
  457. // Checkable
  458. option = prefix + "CHECKABLE";
  459. if (this->IsSetToEmpty(option)) {
  460. this->Checkable.clear();
  461. } else if (this->IsOn(option)) {
  462. this->Checkable = "true";
  463. } else if (this->IsSetToOff(option)) {
  464. this->Checkable = "false";
  465. }
  466. return 1;
  467. }
  468. void cmCPackIFWPackage::GeneratePackageFile()
  469. {
  470. // Lazy directory initialization
  471. if (this->Directory.empty()) {
  472. if (this->Installer) {
  473. this->Directory = this->Installer->Directory + "/packages/" + this->Name;
  474. } else if (this->Generator) {
  475. this->Directory = this->Generator->toplevel + "/packages/" + this->Name;
  476. }
  477. }
  478. // Output stream
  479. cmGeneratedFileStream fout(this->Directory + "/meta/package.xml");
  480. cmXMLWriter xout(fout);
  481. xout.StartDocument();
  482. this->WriteGeneratedByToStrim(xout);
  483. xout.StartElement("Package");
  484. // DisplayName (with translations)
  485. for (auto const& dn : this->DisplayName) {
  486. xout.StartElement("DisplayName");
  487. if (!dn.first.empty()) {
  488. xout.Attribute("xml:lang", dn.first);
  489. }
  490. xout.Content(dn.second);
  491. xout.EndElement();
  492. }
  493. // Description (with translations)
  494. for (auto const& d : this->Description) {
  495. xout.StartElement("Description");
  496. if (!d.first.empty()) {
  497. xout.Attribute("xml:lang", d.first);
  498. }
  499. xout.Content(d.second);
  500. xout.EndElement();
  501. }
  502. // Update text
  503. if (!this->UpdateText.empty()) {
  504. xout.Element("UpdateText", this->UpdateText);
  505. }
  506. xout.Element("Name", this->Name);
  507. xout.Element("Version", this->Version);
  508. if (!this->ReleaseDate.empty()) {
  509. xout.Element("ReleaseDate", this->ReleaseDate);
  510. } else {
  511. xout.Element("ReleaseDate", cmTimestamp().CurrentTime("%Y-%m-%d", true));
  512. }
  513. // Script (copy to meta dir)
  514. if (!this->Script.empty()) {
  515. std::string name = cmSystemTools::GetFilenameName(this->Script);
  516. std::string path = this->Directory + "/meta/" + name;
  517. cmsys::SystemTools::CopyFileIfDifferent(this->Script, path);
  518. xout.Element("Script", name);
  519. }
  520. // User Interfaces (copy to meta dir)
  521. std::vector<std::string> userInterfaces = this->UserInterfaces;
  522. for (std::string& userInterface : userInterfaces) {
  523. std::string name = cmSystemTools::GetFilenameName(userInterface);
  524. std::string path = this->Directory + "/meta/" + name;
  525. cmsys::SystemTools::CopyFileIfDifferent(userInterface, path);
  526. userInterface = name;
  527. }
  528. if (!userInterfaces.empty()) {
  529. xout.StartElement("UserInterfaces");
  530. for (std::string const& userInterface : userInterfaces) {
  531. xout.Element("UserInterface", userInterface);
  532. }
  533. xout.EndElement();
  534. }
  535. // Translations (copy to meta dir)
  536. std::vector<std::string> translations = this->Translations;
  537. for (std::string& translation : translations) {
  538. std::string name = cmSystemTools::GetFilenameName(translation);
  539. std::string path = this->Directory + "/meta/" + name;
  540. cmsys::SystemTools::CopyFileIfDifferent(translation, path);
  541. translation = name;
  542. }
  543. if (!translations.empty()) {
  544. xout.StartElement("Translations");
  545. for (std::string const& translation : translations) {
  546. xout.Element("Translation", translation);
  547. }
  548. xout.EndElement();
  549. }
  550. // Dependencies
  551. const bool hyphensInNamesUnsupported = this->Generator &&
  552. !this->Generator->FrameworkVersion.empty() && this->IsVersionLess("3.1");
  553. bool warnUnsupportedNames = false;
  554. std::set<DependenceStruct> compDepSet;
  555. for (DependenceStruct* ad : this->AlienDependencies) {
  556. compDepSet.insert(*ad);
  557. }
  558. for (cmCPackIFWPackage* d : this->Dependencies) {
  559. compDepSet.insert(DependenceStruct(d->Name));
  560. }
  561. // Write dependencies
  562. if (!compDepSet.empty()) {
  563. std::ostringstream dependencies;
  564. auto it = compDepSet.begin();
  565. warnUnsupportedNames |=
  566. hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
  567. dependencies << it->NameWithCompare();
  568. ++it;
  569. while (it != compDepSet.end()) {
  570. warnUnsupportedNames |=
  571. hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
  572. dependencies << "," << it->NameWithCompare();
  573. ++it;
  574. }
  575. xout.Element("Dependencies", dependencies.str());
  576. }
  577. // Automatic dependency on
  578. std::set<DependenceStruct> compAutoDepSet;
  579. for (DependenceStruct* aad : this->AlienAutoDependOn) {
  580. compAutoDepSet.insert(*aad);
  581. }
  582. // Write automatic dependency on
  583. if (!compAutoDepSet.empty()) {
  584. std::ostringstream dependencies;
  585. auto it = compAutoDepSet.begin();
  586. warnUnsupportedNames |=
  587. hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
  588. dependencies << it->NameWithCompare();
  589. ++it;
  590. while (it != compAutoDepSet.end()) {
  591. warnUnsupportedNames |=
  592. hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
  593. dependencies << "," << it->NameWithCompare();
  594. ++it;
  595. }
  596. xout.Element("AutoDependOn", dependencies.str());
  597. }
  598. if (warnUnsupportedNames) {
  599. cmCPackIFWLogger(
  600. WARNING,
  601. "The dependencies for component \""
  602. << this->Name << "\" specify names that contain hyphens. "
  603. << "This requires QtIFW 3.1 or later, but you are using version "
  604. << this->Generator->FrameworkVersion << std::endl);
  605. }
  606. // Licenses (copy to meta dir)
  607. std::vector<std::string> licenses = this->Licenses;
  608. for (size_t i = 1; i < licenses.size(); i += 2) {
  609. std::string name = cmSystemTools::GetFilenameName(licenses[i]);
  610. std::string path = this->Directory + "/meta/" + name;
  611. cmsys::SystemTools::CopyFileIfDifferent(licenses[i], path);
  612. licenses[i] = name;
  613. }
  614. if (!licenses.empty()) {
  615. xout.StartElement("Licenses");
  616. for (size_t i = 0; i < licenses.size(); i += 2) {
  617. xout.StartElement("License");
  618. xout.Attribute("name", licenses[i]);
  619. xout.Attribute("file", licenses[i + 1]);
  620. xout.EndElement();
  621. }
  622. xout.EndElement();
  623. }
  624. if (!this->ForcedInstallation.empty()) {
  625. xout.Element("ForcedInstallation", this->ForcedInstallation);
  626. }
  627. // Replaces
  628. if (!this->Replaces.empty()) {
  629. std::ostringstream replaces;
  630. auto it = this->Replaces.begin();
  631. replaces << *it;
  632. ++it;
  633. while (it != this->Replaces.end()) {
  634. replaces << "," << *it;
  635. ++it;
  636. }
  637. xout.Element("Replaces", replaces.str());
  638. }
  639. if (!this->RequiresAdminRights.empty()) {
  640. xout.Element("RequiresAdminRights", this->RequiresAdminRights);
  641. }
  642. if (!this->Virtual.empty()) {
  643. xout.Element("Virtual", this->Virtual);
  644. } else if (!this->Default.empty()) {
  645. xout.Element("Default", this->Default);
  646. }
  647. // Essential
  648. if (!this->Essential.empty()) {
  649. xout.Element("Essential", this->Essential);
  650. }
  651. // Priority
  652. if (!this->SortingPriority.empty()) {
  653. xout.Element("SortingPriority", this->SortingPriority);
  654. }
  655. // Checkable
  656. if (!this->Checkable.empty()) {
  657. xout.Element("Checkable", this->Checkable);
  658. }
  659. xout.EndElement();
  660. xout.EndDocument();
  661. }