cmCPackIFWPackage.cxx 22 KB

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