Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Source / cmMessageCommand.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 "cmMessageCommand.h"
4
5 #include <cassert>
6 #include <utility>
7
8 #include <cm/string_view>
9 #include <cmext/string_view>
10
11 #include "cmExecutionStatus.h"
12 #include "cmMakefile.h"
13 #include "cmMessageType.h"
14 #include "cmMessenger.h"
15 #include "cmRange.h"
16 #include "cmStringAlgorithms.h"
17 #include "cmSystemTools.h"
18 #include "cmake.h"
19
20 namespace {
21
22 enum class CheckingType
23 {
24   UNDEFINED,
25   CHECK_START,
26   CHECK_PASS,
27   CHECK_FAIL
28 };
29
30 std::string IndentText(std::string text, cmMakefile& mf)
31 {
32   auto indent =
33     cmJoin(cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT")), "");
34
35   const auto showContext = mf.GetCMakeInstance()->GetShowLogContext() ||
36     mf.IsOn("CMAKE_MESSAGE_CONTEXT_SHOW");
37   if (showContext) {
38     auto context = cmJoin(
39       cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT")), ".");
40     if (!context.empty()) {
41       indent.insert(0u, cmStrCat("["_s, context, "] "_s));
42     }
43   }
44
45   if (!indent.empty()) {
46     cmSystemTools::ReplaceString(text, "\n", "\n" + indent);
47     text.insert(0u, indent);
48   }
49   return text;
50 }
51
52 void ReportCheckResult(cm::string_view what, std::string result,
53                        cmMakefile& mf)
54 {
55   if (mf.GetCMakeInstance()->HasCheckInProgress()) {
56     auto text = mf.GetCMakeInstance()->GetTopCheckInProgressMessage() + " - " +
57       std::move(result);
58     mf.DisplayStatus(IndentText(std::move(text), mf), -1);
59   } else {
60     mf.GetMessenger()->DisplayMessage(
61       MessageType::AUTHOR_WARNING,
62       cmStrCat("Ignored "_s, what, " without CHECK_START"_s),
63       mf.GetBacktrace());
64   }
65 }
66
67 } // anonymous namespace
68
69 // cmLibraryCommand
70 bool cmMessageCommand(std::vector<std::string> const& args,
71                       cmExecutionStatus& status)
72 {
73   if (args.empty()) {
74     status.SetError("called with incorrect number of arguments");
75     return false;
76   }
77
78   auto& mf = status.GetMakefile();
79
80   auto i = args.cbegin();
81
82   auto type = MessageType::MESSAGE;
83   auto fatal = false;
84   auto level = Message::LogLevel::LOG_UNDEFINED;
85   auto checkingType = CheckingType::UNDEFINED;
86   if (*i == "SEND_ERROR") {
87     type = MessageType::FATAL_ERROR;
88     level = Message::LogLevel::LOG_ERROR;
89     ++i;
90   } else if (*i == "FATAL_ERROR") {
91     fatal = true;
92     type = MessageType::FATAL_ERROR;
93     level = Message::LogLevel::LOG_ERROR;
94     ++i;
95   } else if (*i == "WARNING") {
96     type = MessageType::WARNING;
97     level = Message::LogLevel::LOG_WARNING;
98     ++i;
99   } else if (*i == "AUTHOR_WARNING") {
100     if (mf.IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
101         !mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
102       fatal = true;
103       type = MessageType::AUTHOR_ERROR;
104       level = Message::LogLevel::LOG_ERROR;
105     } else if (!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
106       type = MessageType::AUTHOR_WARNING;
107       level = Message::LogLevel::LOG_WARNING;
108     } else {
109       return true;
110     }
111     ++i;
112   } else if (*i == "CHECK_START") {
113     level = Message::LogLevel::LOG_STATUS;
114     checkingType = CheckingType::CHECK_START;
115     ++i;
116   } else if (*i == "CHECK_PASS") {
117     level = Message::LogLevel::LOG_STATUS;
118     checkingType = CheckingType::CHECK_PASS;
119     ++i;
120   } else if (*i == "CHECK_FAIL") {
121     level = Message::LogLevel::LOG_STATUS;
122     checkingType = CheckingType::CHECK_FAIL;
123     ++i;
124   } else if (*i == "STATUS") {
125     level = Message::LogLevel::LOG_STATUS;
126     ++i;
127   } else if (*i == "VERBOSE") {
128     level = Message::LogLevel::LOG_VERBOSE;
129     ++i;
130   } else if (*i == "DEBUG") {
131     level = Message::LogLevel::LOG_DEBUG;
132     ++i;
133   } else if (*i == "TRACE") {
134     level = Message::LogLevel::LOG_TRACE;
135     ++i;
136   } else if (*i == "DEPRECATION") {
137     if (mf.IsOn("CMAKE_ERROR_DEPRECATED")) {
138       fatal = true;
139       type = MessageType::DEPRECATION_ERROR;
140       level = Message::LogLevel::LOG_ERROR;
141     } else if (!mf.IsSet("CMAKE_WARN_DEPRECATED") ||
142                mf.IsOn("CMAKE_WARN_DEPRECATED")) {
143       type = MessageType::DEPRECATION_WARNING;
144       level = Message::LogLevel::LOG_WARNING;
145     } else {
146       return true;
147     }
148     ++i;
149   } else if (*i == "NOTICE") {
150     // `NOTICE` message type is going to be output to stderr
151     level = Message::LogLevel::LOG_NOTICE;
152     ++i;
153   } else {
154     // Messages w/o any type are `NOTICE`s
155     level = Message::LogLevel::LOG_NOTICE;
156   }
157   assert("Message log level expected to be set" &&
158          level != Message::LogLevel::LOG_UNDEFINED);
159
160   Message::LogLevel desiredLevel = mf.GetCurrentLogLevel();
161
162   if (desiredLevel < level) {
163     // Suppress the message
164     return true;
165   }
166
167   auto message = cmJoin(cmMakeRange(i, args.cend()), "");
168
169   switch (level) {
170     case Message::LogLevel::LOG_ERROR:
171     case Message::LogLevel::LOG_WARNING:
172       // we've overridden the message type, above, so display it directly
173       mf.GetMessenger()->DisplayMessage(type, message, mf.GetBacktrace());
174       break;
175
176     case Message::LogLevel::LOG_NOTICE:
177       cmSystemTools::Message(IndentText(message, mf));
178       break;
179
180     case Message::LogLevel::LOG_STATUS:
181       switch (checkingType) {
182         case CheckingType::CHECK_START:
183           mf.DisplayStatus(IndentText(message, mf), -1);
184           mf.GetCMakeInstance()->PushCheckInProgressMessage(message);
185           break;
186
187         case CheckingType::CHECK_PASS:
188           ReportCheckResult("CHECK_PASS"_s, message, mf);
189           break;
190
191         case CheckingType::CHECK_FAIL:
192           ReportCheckResult("CHECK_FAIL"_s, message, mf);
193           break;
194
195         default:
196           mf.DisplayStatus(IndentText(message, mf), -1);
197           break;
198       }
199       break;
200
201     case Message::LogLevel::LOG_VERBOSE:
202     case Message::LogLevel::LOG_DEBUG:
203     case Message::LogLevel::LOG_TRACE:
204       mf.DisplayStatus(IndentText(message, mf), -1);
205       break;
206
207     default:
208       assert("Unexpected log level! Review the `cmMessageCommand.cxx`." &&
209              false);
210       break;
211   }
212
213   if (fatal) {
214     cmSystemTools::SetFatalErrorOccurred();
215   }
216   return true;
217 }