resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmGlobVerificationManager.cxx
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 "cmGlobVerificationManager.h"
4
5 #include <sstream>
6
7 #include "cmsys/FStream.hxx"
8
9 #include "cmGeneratedFileStream.h"
10 #include "cmListFileCache.h"
11 #include "cmMessageType.h"
12 #include "cmMessenger.h"
13 #include "cmStringAlgorithms.h"
14 #include "cmSystemTools.h"
15 #include "cmVersion.h"
16
17 bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path,
18                                                        cmMessenger* messenger)
19 {
20   if (this->Cache.empty()) {
21     return true;
22   }
23
24   std::string scriptFile = cmStrCat(path, "/CMakeFiles");
25   std::string stampFile = scriptFile;
26   cmSystemTools::MakeDirectory(scriptFile);
27   scriptFile += "/VerifyGlobs.cmake";
28   stampFile += "/cmake.verify_globs";
29   cmGeneratedFileStream verifyScriptFile(scriptFile);
30   verifyScriptFile.SetCopyIfDifferent(true);
31   if (!verifyScriptFile) {
32     cmSystemTools::Error("Unable to open verification script file for save. " +
33                          scriptFile);
34     cmSystemTools::ReportLastSystemError("");
35     return false;
36   }
37
38   verifyScriptFile << std::boolalpha;
39   verifyScriptFile << "# CMAKE generated file: DO NOT EDIT!\n"
40                    << "# Generated by CMake Version "
41                    << cmVersion::GetMajorVersion() << "."
42                    << cmVersion::GetMinorVersion() << "\n";
43
44   verifyScriptFile << "cmake_policy(SET CMP0009 NEW)\n";
45
46   for (auto const& i : this->Cache) {
47     CacheEntryKey k = std::get<0>(i);
48     CacheEntryValue v = std::get<1>(i);
49
50     if (!v.Initialized) {
51       continue;
52     }
53
54     verifyScriptFile << "\n";
55
56     for (auto const& bt : v.Backtraces) {
57       verifyScriptFile << "# " << std::get<0>(bt);
58       messenger->PrintBacktraceTitle(verifyScriptFile, std::get<1>(bt));
59       verifyScriptFile << "\n";
60     }
61
62     k.PrintGlobCommand(verifyScriptFile, "NEW_GLOB");
63     verifyScriptFile << "\n";
64
65     verifyScriptFile << "set(OLD_GLOB\n";
66     for (const std::string& file : v.Files) {
67       verifyScriptFile << "  \"" << file << "\"\n";
68     }
69     verifyScriptFile << "  )\n";
70
71     verifyScriptFile << "if(NOT \"${NEW_GLOB}\" STREQUAL \"${OLD_GLOB}\")\n"
72                      << "  message(\"-- GLOB mismatch!\")\n"
73                      << "  file(TOUCH_NOCREATE \"" << stampFile << "\")\n"
74                      << "endif()\n";
75   }
76   verifyScriptFile.Close();
77
78   cmsys::ofstream verifyStampFile(stampFile.c_str());
79   if (!verifyStampFile) {
80     cmSystemTools::Error("Unable to open verification stamp file for write. " +
81                          stampFile);
82     return false;
83   }
84   verifyStampFile << "# This file is generated by CMake for checking of the "
85                      "VerifyGlobs.cmake file\n";
86   this->VerifyScript = scriptFile;
87   this->VerifyStamp = stampFile;
88   return true;
89 }
90
91 bool cmGlobVerificationManager::DoWriteVerifyTarget() const
92 {
93   return !this->VerifyScript.empty() && !this->VerifyStamp.empty();
94 }
95
96 bool cmGlobVerificationManager::CacheEntryKey::operator<(
97   const CacheEntryKey& r) const
98 {
99   if (this->Recurse < r.Recurse) {
100     return true;
101   }
102   if (this->Recurse > r.Recurse) {
103     return false;
104   }
105   if (this->ListDirectories < r.ListDirectories) {
106     return true;
107   }
108   if (this->ListDirectories > r.ListDirectories) {
109     return false;
110   }
111   if (this->FollowSymlinks < r.FollowSymlinks) {
112     return true;
113   }
114   if (this->FollowSymlinks > r.FollowSymlinks) {
115     return false;
116   }
117   if (this->Relative < r.Relative) {
118     return true;
119   }
120   if (this->Relative > r.Relative) {
121     return false;
122   }
123   if (this->Expression < r.Expression) {
124     return true;
125   }
126   if (this->Expression > r.Expression) {
127     return false;
128   }
129   return false;
130 }
131
132 void cmGlobVerificationManager::CacheEntryKey::PrintGlobCommand(
133   std::ostream& out, const std::string& cmdVar)
134 {
135   out << "file(GLOB" << (this->Recurse ? "_RECURSE " : " ");
136   out << cmdVar << " ";
137   if (this->Recurse && this->FollowSymlinks) {
138     out << "FOLLOW_SYMLINKS ";
139   }
140   out << "LIST_DIRECTORIES " << this->ListDirectories << " ";
141   if (!this->Relative.empty()) {
142     out << "RELATIVE \"" << this->Relative << "\" ";
143   }
144   out << "\"" << this->Expression << "\")";
145 }
146
147 void cmGlobVerificationManager::AddCacheEntry(
148   const bool recurse, const bool listDirectories, const bool followSymlinks,
149   const std::string& relative, const std::string& expression,
150   const std::vector<std::string>& files, const std::string& variable,
151   const cmListFileBacktrace& backtrace, cmMessenger* messenger)
152 {
153   CacheEntryKey key = CacheEntryKey(recurse, listDirectories, followSymlinks,
154                                     relative, expression);
155   CacheEntryValue& value = this->Cache[key];
156   if (!value.Initialized) {
157     value.Files = files;
158     value.Initialized = true;
159     value.Backtraces.emplace_back(variable, backtrace);
160   } else if (value.Initialized && value.Files != files) {
161     std::ostringstream message;
162     message << std::boolalpha;
163     message << "The glob expression\n ";
164     key.PrintGlobCommand(message, variable);
165     message << "\nwas already present in the glob cache but the directory "
166                "contents have changed during the configuration run.\n";
167     message << "Matching glob expressions:";
168     for (auto const& bt : value.Backtraces) {
169       message << "\n  " << std::get<0>(bt);
170       messenger->PrintBacktraceTitle(message, std::get<1>(bt));
171     }
172     messenger->IssueMessage(MessageType::FATAL_ERROR, message.str(),
173                             backtrace);
174   } else {
175     value.Backtraces.emplace_back(variable, backtrace);
176   }
177 }
178
179 void cmGlobVerificationManager::Reset()
180 {
181   this->Cache.clear();
182   this->VerifyScript.clear();
183   this->VerifyStamp.clear();
184 }