From 48b79061e38c4aea37de97a47020ef535f9ab75f Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 24 Jan 2013 14:09:39 -0500 Subject: [PATCH 1/3] ENH: ExternalData: Partly generalize hash algo/ext handling Use private global variables _ExternalData_REGEX_(ALGO|EXT) to match the possible hash algorithm names and extensions in regular expressions. Note that we cannot yet use "file()" instead of "cmake -E md5sum" to compute hashes because it requires CMake >= 2.8.7. Therefore we also cannot yet allow other hash algorithms. Leave a TODO comment. Change-Id: I9e569432833fa9b754ba62b192179c783d4a6ebf --- CMake/ExternalData.cmake | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/CMake/ExternalData.cmake b/CMake/ExternalData.cmake index efcc56364e0..ca7a01326a4 100644 --- a/CMake/ExternalData.cmake +++ b/CMake/ExternalData.cmake @@ -282,18 +282,19 @@ endfunction() #----------------------------------------------------------------------------- # Private helper interface +set(_ExternalData_REGEX_ALGO "MD5") +set(_ExternalData_REGEX_EXT "md5") set(_ExternalData_SELF "${CMAKE_CURRENT_LIST_FILE}") get_filename_component(_ExternalData_SELF_DIR "${_ExternalData_SELF}" PATH) function(_ExternalData_compute_hash var_hash algo file) - if("${algo}" STREQUAL "MD5") - # TODO: Errors + if("${algo}" MATCHES "^${_ExternalData_REGEX_ALGO}$") + # TODO: Require CMake 2.8.7 to support other hashes with file(${algo} ...) execute_process(COMMAND "${CMAKE_COMMAND}" -E md5sum "${file}" OUTPUT_VARIABLE output) string(SUBSTRING "${output}" 0 32 hash) set("${var_hash}" "${hash}" PARENT_SCOPE) else() - # TODO: Other hashes. message(FATAL_ERROR "Hash algorithm ${algo} unimplemented.") endif() endfunction() @@ -322,7 +323,7 @@ function(_ExternalData_atomic_write file content) endfunction() function(_ExternalData_link_content name var_ext) - if("${ExternalData_LINK_CONTENT}" MATCHES "^(MD5)$") + if("${ExternalData_LINK_CONTENT}" MATCHES "^(${_ExternalData_REGEX_ALGO})$") set(algo "${ExternalData_LINK_CONTENT}") else() message(FATAL_ERROR @@ -332,7 +333,7 @@ function(_ExternalData_link_content name var_ext) _ExternalData_compute_hash(hash "${algo}" "${name}") get_filename_component(dir "${name}" PATH) set(staged "${dir}/.ExternalData_${algo}_${hash}") - set(ext ".md5") + string(TOLOWER ".${algo}" ext) _ExternalData_atomic_write("${name}${ext}" "${hash}\n") file(RENAME "${name}" "${staged}") set("${var_ext}" "${ext}" PARENT_SCOPE) @@ -561,7 +562,7 @@ endmacro() function(_ExternalData_arg_find_files pattern regex) file(GLOB globbed RELATIVE "${top_src}" "${top_src}/${pattern}*") foreach(entry IN LISTS globbed) - if("x${entry}" MATCHES "^x(.*)(\\.md5)$") + if("x${entry}" MATCHES "^x(.*)(\\.(${_ExternalData_REGEX_EXT}))$") set(relname "${CMAKE_MATCH_1}") set(alg "${CMAKE_MATCH_2}") else() @@ -748,8 +749,8 @@ if("${ExternalData_ACTION}" STREQUAL "fetch") file(READ "${name}${ext}" hash) string(STRIP "${hash}" hash) - if("${ext}" STREQUAL ".md5") - set(algo "MD5") + if("${ext}" MATCHES "^\\.(${_ExternalData_REGEX_EXT})$") + string(TOUPPER "${CMAKE_MATCH_1}" algo) else() message(FATAL_ERROR "Unknown hash algorithm extension \"${ext}\"") endif() From d42c3abd3b9579d9d1d968ebb05ea856b22388c3 Mon Sep 17 00:00:00 2001 From: Brad King Date: Sun, 3 Feb 2013 11:49:47 -0500 Subject: [PATCH 2/3] ENH: ExternalData: Attach download rules to content links in IDEs Each data file to be created in the build tree corresponds one-to-one with a raw file or content link in the source tree. Use the MAIN_DEPENDENCY of add_custom_command to attach the build rule to the source tree file. This looks much nicer in the IDE project file browser and avoids ".rule" files. Change-Id: Id8c5043be9baad39701522a074b24bc6a48ce233 --- CMake/ExternalData.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMake/ExternalData.cmake b/CMake/ExternalData.cmake index ca7a01326a4..622a6f714e9 100644 --- a/CMake/ExternalData.cmake +++ b/CMake/ExternalData.cmake @@ -207,7 +207,7 @@ function(ExternalData_add_target target) -DExternalData_ACTION=local -DExternalData_CONFIG=${config} -P ${_ExternalData_SELF} - DEPENDS "${name}" + MAIN_DEPENDENCY "${name}" ) list(APPEND files "${file}") endif() @@ -238,7 +238,7 @@ function(ExternalData_add_target target) -DExternalData_CONFIG=${config} -P ${_ExternalData_SELF} # Update whenever the object hash changes. - DEPENDS "${name}${ext}" + MAIN_DEPENDENCY "${name}${ext}" ) list(APPEND files "${file}${stamp}") endif() From 5a11039b1cbd5c22e9217c3d67f8bf855cb6e8c7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 12 Mar 2013 15:40:37 -0400 Subject: [PATCH 3/3] ENH: ExternalData: Preserve escaped semicolons during argument expansion The CMake language implicitly flattens lists so a ";" in a list element must be escaped with a backslash. List expansion removes backslashes escaping semicolons to leave raw semicolons in the values. Teach ExternalData_Add_Test and ExternalData_Expand_Arguments to re-escape semicolons found in list elements so the resulting argument lists work as if constructed directly by the set() command. For example: ExternalData_Add_Test(Data NAME test1 COMMAND ... "a\\;b") ExternalData_Expand_Arguments(Data args2 "c\\;d") add_test(NAME test2 COMMAND ... ${args2}) should be equivalent to set(args1 "a\\;b") add_test(NAME test1 COMMAND ... ${args1}) set(args2 "c\\;d") add_test(NAME test2 COMMAND ... ${args2}) which is equivalent to add_test(NAME test1 COMMAND ... "a;b") add_test(NAME test2 COMMAND ... "c;d") Note that it is not possible to make ExternalData_Add_Test act exactly like add_test when quoted arguments contain semicolons because the CMake language flattens lists when constructing function ARGN values. This re-escape approach at least allows test arguments to have semicolons. While at it, teach ExternalData APIs to not transform "DATA{...;...}" arguments because the contained semicolons are non-sensical. Change-Id: I6ebd1e6a21a6621491343b0e85bf1502a3ae19f6 Suggested-by: Jean-Christophe Fillion-Robin --- CMake/ExternalData.cmake | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/CMake/ExternalData.cmake b/CMake/ExternalData.cmake index 622a6f714e9..b215c88283b 100644 --- a/CMake/ExternalData.cmake +++ b/CMake/ExternalData.cmake @@ -172,7 +172,8 @@ #============================================================================= function(ExternalData_add_test target) - ExternalData_expand_arguments("${target}" testArgs ${ARGN}) + # Expand all arguments as a single string to preserve escaped semicolons. + ExternalData_expand_arguments("${target}" testArgs "${ARGN}") add_test(${testArgs}) endfunction() @@ -250,13 +251,17 @@ endfunction() function(ExternalData_expand_arguments target outArgsVar) # Replace DATA{} references with real arguments. - set(data_regex "DATA{([^{}\r\n]*)}") + set(data_regex "DATA{([^;{}\r\n]*)}") set(other_regex "([^D]|D[^A]|DA[^T]|DAT[^A]|DATA[^{])+|.") set(outArgs "") + # This list expansion un-escapes semicolons in list element values so we + # must re-escape them below anywhere a new list expansion will occur. foreach(arg IN LISTS ARGN) if("x${arg}" MATCHES "${data_regex}") + # Re-escape in-value semicolons before expansion in foreach below. + string(REPLACE ";" "\\;" tmp "${arg}") # Split argument into DATA{}-pieces and other pieces. - string(REGEX MATCHALL "${data_regex}|${other_regex}" pieces "${arg}") + string(REGEX MATCHALL "${data_regex}|${other_regex}" pieces "${tmp}") # Compose output argument with DATA{}-pieces replaced. set(outArg "") foreach(piece IN LISTS pieces) @@ -270,11 +275,13 @@ function(ExternalData_expand_arguments target outArgsVar) set(outArg "${outArg}${piece}") endif() endforeach() - list(APPEND outArgs "${outArg}") else() # No replacements needed in this argument. - list(APPEND outArgs "${arg}") + set(outArg "${arg}") endif() + # Re-escape in-value semicolons in resulting list. + string(REPLACE ";" "\\;" outArg "${outArg}") + list(APPEND outArgs "${outArg}") endforeach() set("${outArgsVar}" "${outArgs}" PARENT_SCOPE) endfunction()