cmSourceGroupCommand.cxx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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 "cmSourceGroupCommand.h"
  4. #include <set>
  5. #include <sstream>
  6. #include <stddef.h>
  7. #include "cmMakefile.h"
  8. #include "cmSourceGroup.h"
  9. #include "cmSystemTools.h"
  10. namespace {
  11. const size_t RootIndex = 1;
  12. const size_t FilesWithoutPrefixKeywordIndex = 2;
  13. const size_t FilesWithPrefixKeywordIndex = 4;
  14. const size_t PrefixKeywordIdex = 2;
  15. std::vector<std::string> tokenizePath(const std::string& path)
  16. {
  17. return cmSystemTools::tokenize(path, "\\/");
  18. }
  19. std::string getFullFilePath(const std::string& currentPath,
  20. const std::string& path)
  21. {
  22. std::string fullPath = path;
  23. if (!cmSystemTools::FileIsFullPath(path.c_str())) {
  24. fullPath = currentPath;
  25. fullPath += "/";
  26. fullPath += path;
  27. }
  28. return cmSystemTools::CollapseFullPath(fullPath);
  29. }
  30. std::set<std::string> getSourceGroupFilesPaths(
  31. const std::string& currentPath, const std::string& root,
  32. const std::vector<std::string>& files)
  33. {
  34. std::set<std::string> ret;
  35. const std::string::size_type rootLength = root.length();
  36. for (size_t i = 0; i < files.size(); ++i) {
  37. const std::string fullPath = getFullFilePath(currentPath, files[i]);
  38. ret.insert(fullPath.substr(rootLength + 1)); // +1 to also omnit last '/'
  39. }
  40. return ret;
  41. }
  42. cmSourceGroup* addSourceGroup(const std::vector<std::string>& tokenizedPath,
  43. cmMakefile& makefile)
  44. {
  45. cmSourceGroup* sg;
  46. sg = makefile.GetSourceGroup(tokenizedPath);
  47. if (!sg) {
  48. makefile.AddSourceGroup(tokenizedPath);
  49. sg = makefile.GetSourceGroup(tokenizedPath);
  50. if (!sg) {
  51. return CM_NULLPTR;
  52. }
  53. }
  54. return sg;
  55. }
  56. bool addFilesToItsSourceGroups(const std::set<std::string>& sgFilesPaths,
  57. const std::string& prefix, cmMakefile& makefile,
  58. std::string& errorMsg)
  59. {
  60. cmSourceGroup* sg;
  61. for (std::set<std::string>::const_iterator it = sgFilesPaths.begin();
  62. it != sgFilesPaths.end(); ++it) {
  63. std::vector<std::string> tokenizedPath;
  64. if (!prefix.empty()) {
  65. tokenizedPath = tokenizePath(prefix + '/' + *it);
  66. } else {
  67. tokenizedPath = tokenizePath(*it);
  68. }
  69. if (tokenizedPath.size() > 1) {
  70. tokenizedPath.pop_back();
  71. sg = addSourceGroup(tokenizedPath, makefile);
  72. if (!sg) {
  73. errorMsg = "Could not create source group for file: " + *it;
  74. return false;
  75. }
  76. const std::string fullPath =
  77. getFullFilePath(makefile.GetCurrentSourceDirectory(), *it);
  78. sg->AddGroupFile(fullPath);
  79. }
  80. }
  81. return true;
  82. }
  83. }
  84. class cmExecutionStatus;
  85. // cmSourceGroupCommand
  86. bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args,
  87. cmExecutionStatus&)
  88. {
  89. if (args.empty()) {
  90. this->SetError("called with incorrect number of arguments");
  91. return false;
  92. }
  93. if (args[0] == "TREE") {
  94. std::string error;
  95. if (!processTree(args, error)) {
  96. this->SetError(error);
  97. return false;
  98. }
  99. return true;
  100. }
  101. std::string delimiter = "\\";
  102. if (this->Makefile->GetDefinition("SOURCE_GROUP_DELIMITER")) {
  103. delimiter = this->Makefile->GetDefinition("SOURCE_GROUP_DELIMITER");
  104. }
  105. std::vector<std::string> folders =
  106. cmSystemTools::tokenize(args[0], delimiter);
  107. cmSourceGroup* sg = CM_NULLPTR;
  108. sg = this->Makefile->GetSourceGroup(folders);
  109. if (!sg) {
  110. this->Makefile->AddSourceGroup(folders);
  111. sg = this->Makefile->GetSourceGroup(folders);
  112. }
  113. if (!sg) {
  114. this->SetError("Could not create or find source group");
  115. return false;
  116. }
  117. // If only two arguments are given, the pre-1.8 version of the
  118. // command is being invoked.
  119. if (args.size() == 2 && args[1] != "FILES") {
  120. sg->SetGroupRegex(args[1].c_str());
  121. return true;
  122. }
  123. // Process arguments.
  124. bool doingFiles = false;
  125. for (unsigned int i = 1; i < args.size(); ++i) {
  126. if (args[i] == "REGULAR_EXPRESSION") {
  127. // Next argument must specify the regex.
  128. if (i + 1 < args.size()) {
  129. ++i;
  130. sg->SetGroupRegex(args[i].c_str());
  131. } else {
  132. this->SetError("REGULAR_EXPRESSION argument given without a regex.");
  133. return false;
  134. }
  135. doingFiles = false;
  136. } else if (args[i] == "FILES") {
  137. // Next arguments will specify files.
  138. doingFiles = true;
  139. } else if (doingFiles) {
  140. // Convert name to full path and add to the group's list.
  141. std::string src = args[i];
  142. if (!cmSystemTools::FileIsFullPath(src.c_str())) {
  143. src = this->Makefile->GetCurrentSourceDirectory();
  144. src += "/";
  145. src += args[i];
  146. }
  147. src = cmSystemTools::CollapseFullPath(src);
  148. sg->AddGroupFile(src);
  149. } else {
  150. std::ostringstream err;
  151. err << "Unknown argument \"" << args[i] << "\". "
  152. << "Perhaps the FILES keyword is missing.\n";
  153. this->SetError(err.str());
  154. return false;
  155. }
  156. }
  157. return true;
  158. }
  159. bool cmSourceGroupCommand::checkTreeArgumentsPreconditions(
  160. const std::vector<std::string>& args, std::string& errorMsg) const
  161. {
  162. if (args.size() == 1) {
  163. errorMsg = "TREE argument given without a root.";
  164. return false;
  165. }
  166. if (args.size() < 3) {
  167. errorMsg = "Missing FILES arguments.";
  168. return false;
  169. }
  170. if (args[FilesWithoutPrefixKeywordIndex] != "FILES" &&
  171. args[PrefixKeywordIdex] != "PREFIX") {
  172. errorMsg = "Unknown argument \"" + args[2] +
  173. "\". Perhaps the FILES keyword is missing.\n";
  174. return false;
  175. }
  176. if (args[PrefixKeywordIdex] == "PREFIX" &&
  177. (args.size() < 5 || args[FilesWithPrefixKeywordIndex] != "FILES")) {
  178. errorMsg = "Missing FILES arguments.";
  179. return false;
  180. }
  181. return true;
  182. }
  183. bool cmSourceGroupCommand::processTree(const std::vector<std::string>& args,
  184. std::string& errorMsg)
  185. {
  186. if (!checkTreeArgumentsPreconditions(args, errorMsg)) {
  187. return false;
  188. }
  189. const std::string root = cmSystemTools::CollapseFullPath(args[RootIndex]);
  190. std::string prefix;
  191. size_t filesBegin = FilesWithoutPrefixKeywordIndex + 1;
  192. if (args[PrefixKeywordIdex] == "PREFIX") {
  193. prefix = args[PrefixKeywordIdex + 1];
  194. filesBegin = FilesWithPrefixKeywordIndex + 1;
  195. }
  196. const std::vector<std::string> filesVector(args.begin() + filesBegin,
  197. args.end());
  198. std::set<std::string> sourceGroupPaths = getSourceGroupFilesPaths(
  199. this->Makefile->GetCurrentSourceDirectory(), root, filesVector);
  200. addFilesToItsSourceGroups(sourceGroupPaths, prefix, *(this->Makefile),
  201. errorMsg);
  202. if (!errorMsg.empty()) {
  203. this->SetError(errorMsg);
  204. return false;
  205. }
  206. return true;
  207. }