cmSourceGroupCommand.cxx 6.6 KB

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