Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Tests / CTestUpdateCommon.cmake
1 #-----------------------------------------------------------------------------
2 # Function to run a child process and report output only on error.
3 function(run_child)
4   execute_process(${ARGN}
5     RESULT_VARIABLE FAILED
6     OUTPUT_VARIABLE OUTPUT
7     ERROR_VARIABLE OUTPUT
8     OUTPUT_STRIP_TRAILING_WHITESPACE
9     ERROR_STRIP_TRAILING_WHITESPACE
10     )
11   if(FAILED)
12     string(REPLACE "\n" "\n  " OUTPUT "${OUTPUT}")
13     message(FATAL_ERROR "Child failed (${FAILED}), output is\n  ${OUTPUT}\n"
14       "Command = [${ARGN}]\n")
15   endif()
16
17   # Pass output back up to the parent scope for possible further inspection.
18   set(OUTPUT "${OUTPUT}" PARENT_SCOPE)
19 endfunction()
20
21 #-----------------------------------------------------------------------------
22 # Function to find the Update.xml file and check for expected entries.
23 function(check_updates build)
24   # Find the Update.xml file for the given build tree
25   set(PATTERN ${TOP}/${build}/Testing/*/Update.xml)
26   file(GLOB UPDATE_XML_FILE RELATIVE ${TOP} ${PATTERN})
27   string(REGEX REPLACE "//Update.xml$" "/Update.xml"
28     UPDATE_XML_FILE "${UPDATE_XML_FILE}"
29     )
30   if(NOT UPDATE_XML_FILE)
31     message(FATAL_ERROR "Cannot find Update.xml with pattern\n  ${PATTERN}")
32   endif()
33   message(" found ${UPDATE_XML_FILE}")
34
35   set(max_update_xml_size 16384)
36
37   # Read entries from the Update.xml file
38   set(types "Updated|Modified|Conflicting")
39   file(STRINGS ${TOP}/${UPDATE_XML_FILE} UPDATE_XML_ENTRIES
40     REGEX "<(${types}|FullName)>"
41     LIMIT_INPUT ${max_update_xml_size}
42     )
43
44   string(REGEX REPLACE
45     "[ \t]*<(${types})>[ \t]*;[ \t]*<FullName>([^<]*)</FullName>"
46     "\\1{\\2}" UPDATE_XML_ENTRIES "${UPDATE_XML_ENTRIES}")
47
48   # If specified, remove the given prefix from the files in Update.xml.
49   # Some VCS systems, like Perforce, return absolute locations
50   if(DEFINED REPOSITORY_FILE_PREFIX)
51     string(REPLACE
52       "${REPOSITORY_FILE_PREFIX}" ""
53       UPDATE_XML_ENTRIES "${UPDATE_XML_ENTRIES}")
54   endif()
55
56   # Compare expected and actual entries
57   set(EXTRA "${UPDATE_XML_ENTRIES}")
58   list(REMOVE_ITEM EXTRA ${ARGN} ${UPDATE_EXTRA} ${UPDATE_MAYBE})
59   set(MISSING "${ARGN}" ${UPDATE_EXTRA})
60   if(NOT "" STREQUAL "${UPDATE_XML_ENTRIES}")
61     list(REMOVE_ITEM MISSING ${UPDATE_XML_ENTRIES})
62   endif()
63
64   if(NOT UPDATE_NOT_GLOBAL)
65     set(rev_elements Revision PriorRevision ${UPDATE_GLOBAL_ELEMENTS})
66     string(REPLACE ";" "|" rev_regex "${rev_elements}")
67     set(rev_regex "^\t<(${rev_regex})>[^<\n]+</(${rev_regex})>$")
68     file(STRINGS ${TOP}/${UPDATE_XML_FILE} UPDATE_XML_REVISIONS
69       REGEX "${rev_regex}"
70       LIMIT_INPUT ${max_update_xml_size}
71       )
72     foreach(r IN LISTS UPDATE_XML_REVISIONS)
73       string(REGEX REPLACE "${rev_regex}" "\\1" element "${r}")
74       set(element_${element} 1)
75     endforeach()
76     foreach(element IN LISTS rev_elements)
77       if(NOT element_${element})
78         list(APPEND MISSING "global <${element}> element")
79       endif()
80     endforeach()
81   endif()
82
83   # Report the result
84   set(MSG "")
85   if(MISSING)
86     # List the missing entries
87     string(APPEND MSG "Update.xml is missing expected entries:\n")
88     foreach(f IN LISTS MISSING)
89       string(APPEND MSG "  ${f}\n")
90     endforeach()
91   else()
92     # Success
93     message(" no entries missing from Update.xml")
94   endif()
95
96   # Report the result
97   if(EXTRA)
98     # List the extra entries
99     string(APPEND MSG "Update.xml has extra unexpected entries:\n")
100     foreach(f IN LISTS EXTRA)
101       string(APPEND MSG "  ${f}\n")
102     endforeach()
103   else()
104     # Success
105     message(" no extra entries in Update.xml")
106   endif()
107
108   if(MSG)
109     # Provide the log file
110     file(GLOB UPDATE_LOG_FILE
111       ${TOP}/${build}/Testing/Temporary/LastUpdate*.log)
112     if(UPDATE_LOG_FILE)
113       file(READ ${UPDATE_LOG_FILE} UPDATE_LOG LIMIT ${max_update_xml_size})
114       string(REPLACE "\n" "\n  " UPDATE_LOG "${UPDATE_LOG}")
115       string(APPEND MSG "Update log:\n  ${UPDATE_LOG}")
116     else()
117       string(APPEND MSG "No update log found!")
118     endif()
119
120     # Display the error message
121     message(FATAL_ERROR "${MSG}")
122   endif()
123 endfunction()
124
125 #-----------------------------------------------------------------------------
126 # Function to create initial content.
127 function(create_content dir)
128   file(MAKE_DIRECTORY ${TOP}/${dir})
129
130   # An example CTest project configuration file.
131   file(WRITE ${TOP}/${dir}/CTestConfig.cmake
132     "# CTest Configuration File
133 set(CTEST_NIGHTLY_START_TIME \"21:00:00 EDT\")
134 ")
135
136   # Some other files.
137   file(WRITE ${TOP}/${dir}/foo.txt "foo\n")
138   file(WRITE ${TOP}/${dir}/bar.txt "bar\n")
139 endfunction()
140
141 #-----------------------------------------------------------------------------
142 # Function to update content.
143 function(update_content dir added_var removed_var dirs_var)
144   file(APPEND ${TOP}/${dir}/foo.txt "foo line 2\n")
145   file(WRITE ${TOP}/${dir}/zot.txt "zot\n")
146   file(REMOVE ${TOP}/${dir}/bar.txt)
147   file(MAKE_DIRECTORY ${TOP}/${dir}/subdir)
148   file(WRITE ${TOP}/${dir}/subdir/foo.txt "foo\n")
149   file(WRITE ${TOP}/${dir}/subdir/bar.txt "bar\n")
150   set(${dirs_var} subdir PARENT_SCOPE)
151   set(${added_var} zot.txt subdir/foo.txt subdir/bar.txt PARENT_SCOPE)
152   set(${removed_var} bar.txt PARENT_SCOPE)
153 endfunction()
154
155 #-----------------------------------------------------------------------------
156 # Function to change existing files
157 function(change_content dir)
158   file(APPEND ${TOP}/${dir}/foo.txt "foo line 3\n")
159   file(APPEND ${TOP}/${dir}/subdir/foo.txt "foo line 2\n")
160 endfunction()
161
162 #-----------------------------------------------------------------------------
163 # Function to create local modifications before update
164 function(modify_content dir)
165   file(APPEND ${TOP}/${dir}/CTestConfig.cmake "# local modification\n")
166 endfunction()
167
168 #-----------------------------------------------------------------------------
169 # Function to write CTestConfiguration.ini content.
170 function(create_build_tree src_dir bin_dir)
171   file(MAKE_DIRECTORY ${TOP}/${bin_dir})
172   file(WRITE ${TOP}/${bin_dir}/CTestConfiguration.ini
173     "# CTest Configuration File
174 SourceDirectory: ${TOP}/${src_dir}
175 BuildDirectory: ${TOP}/${bin_dir}
176 Site: test.site
177 BuildName: user-test
178 ")
179 endfunction()
180
181 #-----------------------------------------------------------------------------
182 # Function to write the dashboard test script.
183 function(create_dashboard_script bin_dir custom_text)
184   if (NOT ctest_update_check)
185     set(ctest_update_check [[
186 if(ret LESS 0)
187   message(FATAL_ERROR "ctest_update failed with ${ret}")
188 endif()
189 ]])
190   endif()
191
192   # Write the dashboard script.
193   file(WRITE ${TOP}/${bin_dir}.cmake
194     "# CTest Dashboard Script
195 set(CTEST_DASHBOARD_ROOT \"${TOP}\")
196 set(CTEST_SITE test.site)
197 set(CTEST_BUILD_NAME dash-test)
198 set(CTEST_SOURCE_DIRECTORY \${CTEST_DASHBOARD_ROOT}/dash-source)
199 set(CTEST_BINARY_DIRECTORY \${CTEST_DASHBOARD_ROOT}/${bin_dir})
200 ${custom_text}
201 # Start a dashboard and run the update step
202 ctest_start(Experimental)
203 ctest_update(SOURCE \${CTEST_SOURCE_DIRECTORY} RETURN_VALUE ret ${ctest_update_args})
204 ${ctest_update_check}")
205 endfunction()
206
207 #-----------------------------------------------------------------------------
208 # Function to run the dashboard through the command line
209 function(run_dashboard_command_line bin_dir)
210   run_child(
211     WORKING_DIRECTORY ${TOP}/${bin_dir}
212     COMMAND ${CMAKE_CTEST_COMMAND} -M Experimental -T Start -T Update
213     )
214
215   # Verify the updates reported by CTest.
216   list(APPEND UPDATE_MAYBE Updated{subdir})
217   set(_modified Modified{CTestConfig.cmake})
218   if(UPDATE_NO_MODIFIED)
219     set(_modified "")
220   endif()
221   check_updates(${bin_dir}
222     Updated{foo.txt}
223     Updated{bar.txt}
224     Updated{zot.txt}
225     Updated{subdir/foo.txt}
226     Updated{subdir/bar.txt}
227     ${_modified}
228     )
229 endfunction()
230
231 #-----------------------------------------------------------------------------
232 # Function to find the Update.xml file and make sure
233 # it only has the Revision in it and no updates
234 function(check_no_update bin_dir)
235   set(PATTERN ${TOP}/${bin_dir}/Testing/*/Update.xml)
236   file(GLOB UPDATE_XML_FILE RELATIVE ${TOP} ${PATTERN})
237   string(REGEX REPLACE "//Update.xml$" "/Update.xml"
238     UPDATE_XML_FILE "${UPDATE_XML_FILE}")
239   message(" found ${UPDATE_XML_FILE}")
240   set(rev_regex "Revision|PriorRevision")
241   file(STRINGS ${TOP}/${UPDATE_XML_FILE} UPDATE_XML_REVISIONS
242     REGEX "^\t<(${rev_regex})>[^<\n]+</(${rev_regex})>$"
243     )
244   set(found_revisons FALSE)
245   foreach(r IN LISTS UPDATE_XML_REVISIONS)
246     if("${r}" MATCHES "PriorRevision")
247       message(FATAL_ERROR "Found PriorRevision in no update test")
248     endif()
249     if("${r}" MATCHES "<Revision>")
250       set(found_revisons TRUE)
251     endif()
252   endforeach()
253   if(found_revisons)
254     message(" found <Revision> in no update test")
255   else()
256     message(FATAL_ERROR " missing <Revision> in no update test")
257   endif()
258 endfunction()
259
260 #-----------------------------------------------------------------------------
261 # Function to find the Update.xml file and make sure
262 # it only has the UpdateReturnStatus failure message and no updates.
263 function(check_fail_update bin_dir)
264   set(PATTERN ${TOP}/${bin_dir}/Testing/*/Update.xml)
265   file(GLOB UPDATE_XML_FILE RELATIVE ${TOP} ${PATTERN})
266   string(REGEX REPLACE "//Update.xml$" "/Update.xml"
267     UPDATE_XML_FILE "${UPDATE_XML_FILE}")
268   message(" found ${UPDATE_XML_FILE}")
269   file(STRINGS ${TOP}/${UPDATE_XML_FILE} UPDATE_XML_STATUS
270     REGEX "^\t<UpdateReturnStatus>[^<\n]+"
271     )
272   if(UPDATE_XML_STATUS MATCHES "Update command failed")
273     message(" correctly found 'Update command failed'")
274   else()
275     message(FATAL_ERROR " missing 'Update command failed'")
276   endif()
277 endfunction()
278
279 #-----------------------------------------------------------------------------
280 # Function to run the dashboard through a script
281 function(run_dashboard_script bin_dir)
282   run_child(
283     WORKING_DIRECTORY ${TOP}
284     COMMAND ${CMAKE_CTEST_COMMAND} -S ${bin_dir}.cmake -V
285     )
286
287   # Verify the updates reported by CTest.
288   list(APPEND UPDATE_MAYBE Updated{subdir} Updated{CTestConfig.cmake})
289   if(NO_UPDATE)
290     check_no_update(${bin_dir})
291   elseif(FAIL_UPDATE)
292     check_fail_update(${bin_dir})
293   else()
294     check_updates(${bin_dir}
295       Updated{foo.txt}
296       Updated{bar.txt}
297       Updated{zot.txt}
298       Updated{subdir/foo.txt}
299       Updated{subdir/bar.txt}
300       )
301   endif()
302
303   # Pass console output up to the parent, in case they'd like to inspect it.
304   set(OUTPUT "${OUTPUT}" PARENT_SCOPE)
305 endfunction()
306
307 #-----------------------------------------------------------------------------
308 # Function to initialize the testing directory.
309 function(init_testing)
310   file(REMOVE_RECURSE ${TOP})
311   file(MAKE_DIRECTORY ${TOP})
312 endfunction()