1##============================================================================ 2## Copyright (c) Kitware, Inc. 3## All rights reserved. 4## See LICENSE.txt for details. 5## 6## This software is distributed WITHOUT ANY WARRANTY; without even 7## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 8## PURPOSE. See the above copyright notice for more information. 9##============================================================================ 10 11## This CMake script checks source files for the appropriate VTKM copyright 12## statement, which is stored in VTKm_SOURCE_DIR/CMake/VTKmCopyrightStatement.txt. 13## To run this script, execute CMake as follows: 14## 15## cmake -DVTKm_SOURCE_DIR=<VTKm_SOURCE_DIR> -P <VTKm_SOURCE_DIR>/CMake/VTKMCheckCopyright.cmake 16## 17 18set(FILES_TO_CHECK 19 *.txt 20 *.cmake 21 *.h 22 *.h.in 23 *.cxx 24 *.cu 25 ) 26 27set(EXCEPTIONS 28 LICENSE.txt 29 README.txt 30 ) 31 32if (NOT VTKm_SOURCE_DIR) 33 message(SEND_ERROR "VTKm_SOURCE_DIR not defined.") 34endif (NOT VTKm_SOURCE_DIR) 35 36set(copyright_file ${VTKm_SOURCE_DIR}/CMake/VTKmCopyrightStatement.txt) 37 38if (NOT EXISTS ${copyright_file}) 39 message(SEND_ERROR "Cannot find VTKMCopyrightStatement.txt.") 40endif (NOT EXISTS ${copyright_file}) 41 42set(license_file ${VTKm_SOURCE_DIR}/LICENSE.txt) 43 44if (NOT EXISTS ${license_file}) 45 message(SEND_ERROR "Cannot find LICENSE.txt.") 46endif (NOT EXISTS ${license_file}) 47 48# Get a list of third party files (with different copyrights) from the 49# license file. 50file(STRINGS ${license_file} license_lines) 51list(FIND 52 license_lines 53 "- - - - - - - - - - - - - - - - - - - - - - - - do not remove this line" 54 separator_index 55 ) 56math(EXPR begin_index "${separator_index} + 1") 57list(LENGTH license_lines license_file_length) 58math(EXPR end_index "${license_file_length} - 1") 59foreach (index RANGE ${begin_index} ${end_index}) 60 list(GET license_lines ${index} tpl_file) 61 set(EXCEPTIONS ${EXCEPTIONS} ${tpl_file}) 62endforeach(index) 63# if the build directory is in the source directory, exclude generated build 64# files 65find_path(BUILD_DIR CMakeCache.txt .) 66get_filename_component(abs_build_dir ${BUILD_DIR} ABSOLUTE) 67get_filename_component(build_dir_name ${abs_build_dir} NAME) 68set(EXCEPTIONS ${EXCEPTIONS} ${build_dir_name}/*) 69message("Copyright Check Exceptions: ${EXCEPTIONS}") 70 71# Gets the current year (if possible). 72function (get_year var) 73 string(TIMESTAMP result "%Y") 74 set(${var} "${result}" PARENT_SCOPE) 75endfunction (get_year) 76 77set(copyright_file_year 2014) 78get_year(current_year) 79 80# Escapes ';' characters (list delimiters) and splits the given string into 81# a list of its lines without newlines. 82function (list_of_lines var string) 83 string(REGEX REPLACE ";" "\\\\;" conditioned_string "${string}") 84 string(REGEX REPLACE "\n" ";" conditioned_string "${conditioned_string}") 85 set(${var} "${conditioned_string}" PARENT_SCOPE) 86endfunction (list_of_lines) 87 88# Read in copyright statement file. 89file(READ ${copyright_file} COPYRIGHT_STATEMENT) 90 91# Remove trailing whitespace and ending lines. They are sometimes hard to 92# see or remove in editors. 93string(REGEX REPLACE "[ \t]*\n" "\n" COPYRIGHT_STATEMENT "${COPYRIGHT_STATEMENT}") 94string(REGEX REPLACE "\n+$" "" COPYRIGHT_STATEMENT "${COPYRIGHT_STATEMENT}") 95 96# Get a list of lines in the copyright statement. 97list_of_lines(COPYRIGHT_LINE_LIST "${COPYRIGHT_STATEMENT}") 98 99# Comment regular expression characters that we want to match literally. 100string(REPLACE "." "\\." COPYRIGHT_LINE_LIST "${COPYRIGHT_LINE_LIST}") 101string(REPLACE "(" "\\(" COPYRIGHT_LINE_LIST "${COPYRIGHT_LINE_LIST}") 102string(REPLACE ")" "\\)" COPYRIGHT_LINE_LIST "${COPYRIGHT_LINE_LIST}") 103 104# Introduce regular expression for years we want to be generic. 105string(REPLACE 106 "${copyright_file_year}" 107 "20[0-9][0-9]" 108 COPYRIGHT_LINE_LIST 109 "${COPYRIGHT_LINE_LIST}" 110 ) 111 112# Replace year in COPYRIGHT_STATEMENT with current year. 113string(REPLACE 114 "${copyright_file_year}" 115 "${current_year}" 116 COPYRIGHT_STATEMENT 117 "${COPYRIGHT_STATEMENT}" 118 ) 119 120# Print an error concerning the missing copyright in the given file. 121function(missing_copyright filename comment_prefix) 122 message("${filename} does not have the appropriate copyright statement:\n") 123 124 # Condition the copyright statement 125 string(REPLACE 126 "\n" 127 "\n${comment_prefix} " 128 comment_copyright 129 "${COPYRIGHT_STATEMENT}" 130 ) 131 set(comment_copyright "${comment_prefix} ${comment_copyright}") 132 string(REPLACE 133 "\n${comment_prefix} \n" 134 "\n${comment_prefix}\n" 135 comment_copyright 136 "${comment_copyright}" 137 ) 138 139 message("${comment_prefix}=============================================================================") 140 message("${comment_prefix}") 141 message("${comment_copyright}") 142 message("${comment_prefix}") 143 message("${comment_prefix}=============================================================================\n") 144 message(SEND_ERROR 145 "Please add the previous statement to the beginning of ${filename}" 146 ) 147endfunction(missing_copyright) 148 149# Get an appropriate beginning line comment for the given filename. 150function(get_comment_prefix var filename) 151 get_filename_component(base "${filename}" NAME_WE) 152 get_filename_component(extension "${filename}" EXT) 153 if (extension STREQUAL ".cmake") 154 set(${var} "##" PARENT_SCOPE) 155 elseif (base STREQUAL "CMakeLists" AND extension STREQUAL ".txt") 156 set(${var} "##" PARENT_SCOPE) 157 elseif (extension STREQUAL ".txt") 158 set(${var} "" PARENT_SCOPE) 159 elseif (extension STREQUAL ".h" OR extension STREQUAL ".h.in" OR extension STREQUAL ".cxx" OR extension STREQUAL ".cu") 160 set(${var} "//" PARENT_SCOPE) 161 elseif (extension STREQUAL ".worklet") 162 set(${var} "//" PARENT_SCOPE) 163 else (extension STREQUAL ".cmake") 164 message(SEND_ERROR "Could not identify file type of ${filename}.") 165 endif (extension STREQUAL ".cmake") 166endfunction(get_comment_prefix) 167 168# Check the given file for the appropriate copyright statement. 169function(check_copyright filename) 170 171 get_comment_prefix(comment_prefix "${filename}") 172 173 # Read in the first 2000 characters of the file and split into lines. 174 # This is roughly equivalent to the file STRINGS command except that we 175 # also escape semicolons (list separators) in the input, which the file 176 # STRINGS command does not currently do. 177 file(READ "${filename}" header_contents LIMIT 2000) 178 list_of_lines(header_lines "${header_contents}") 179 180 set(printed) 181 # Check each copyright line. 182 foreach (copyright_line IN LISTS COPYRIGHT_LINE_LIST) 183 set(match) 184 # My original algorithm tried to check the order by removing items from 185 # header_lines as they were encountered. Unfortunately, CMake 2.8's 186 # list REMOVE_AT command removed the escaping on the ; in one of the 187 # header_line's items and cause the compare to fail. 188 foreach (header_line IN LISTS header_lines) 189 if (copyright_line) 190 string(REGEX MATCH 191 "^${comment_prefix}[ \t]*${copyright_line}[ \t]*$" 192 match 193 "${header_line}" 194 ) 195 else (copyright_line) 196 if (NOT header_line) 197 set(match TRUE) 198 endif (NOT header_line) 199 endif (copyright_line) 200 if (match) 201 break() 202 endif (match) 203 endforeach (header_line) 204 if (NOT match AND NOT printed) 205 message(STATUS "Could not find match for `${copyright_line}'") 206 missing_copyright("${filename}" "${comment_prefix}") 207 set(printed TRUE) 208 endif (NOT match AND NOT printed) 209 endforeach (copyright_line) 210endfunction(check_copyright) 211 212foreach (glob_expression ${FILES_TO_CHECK}) 213 file(GLOB_RECURSE file_list 214 RELATIVE "${VTKm_SOURCE_DIR}" 215 "${VTKm_SOURCE_DIR}/${glob_expression}" 216 ) 217 218 foreach (file ${file_list}) 219 set(skip) 220 foreach(exception ${EXCEPTIONS}) 221 if(file MATCHES "^${exception}(/.*)?$") 222 # This file is an exception 223 set(skip TRUE) 224 endif(file MATCHES "^${exception}(/.*)?$") 225 endforeach(exception) 226 227 if (NOT skip) 228 check_copyright("${VTKm_SOURCE_DIR}/${file}") 229 endif (NOT skip) 230 endforeach (file) 231endforeach (glob_expression) 232