1# Copyright 2006-2008 The FLWOR Foundation. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15# Utility routines to package a local SVN working copy's changes into 16# a single file, and for applying that file to a fresh SVN enlistment 17# elsewhere. 18 19 20MACRO (FIND_PREREQS) 21 # Definitely need svn here. 22 FIND_PROGRAM(SVN_EXECUTABLE svn DOC "subversion command line client") 23 IF(NOT SVN_EXECUTABLE) 24 MESSAGE (FATAL_ERROR "Subversion is required; not found") 25 ENDIF(NOT SVN_EXECUTABLE) 26 SET (svn "${SVN_EXECUTABLE}") 27 28 # create path to execute zorba 29 SET(ZORBA_EXE "${ZORBA_BUILD_DIR}/bin/zorba") 30 IF (WIN32) 31 SET(ZORBA_EXE "${ZORBA_EXE}.bat") 32 ENDIF (WIN32) 33 IF (NOT EXISTS ${ZORBA_EXE}) 34 MESSAGE (FATAL_ERROR "Zorba is required; not found. Specify -DZORBA_BUILD_DIR to point to your build directory if necessary. (${ZORBA_EXE})") 35 ENDIF (NOT EXISTS ${ZORBA_EXE}) 36 EXECUTE_PROCESS (COMMAND "${ZORBA_EXE}" --omit-xml-declaration 37 --query "1+1" OUTPUT_VARIABLE ignored RESULT_VARIABLE result) 38 IF (result) 39 MESSAGE (FATAL_ERROR "Zorba is not functional. Specify -DZORBA_BUILD_DIR to point to your build directory if necessary. (${ZORBA_EXE})") 40 ENDIF (result) 41ENDMACRO (FIND_PREREQS) 42 43 44# Utility routine: given svn-status.xml file and a changelist (may be 45# ""), return a list of files which match any specified status. 46MACRO (get_files_with_status filelist svnstatusxml changelist) 47 # Which element to look at? 48 if ("${changelist}" STREQUAL "") 49 set (elem "target") 50 else ("${changelist}" STREQUAL "") 51 set (elem "changelist[@name=\"${changelist}\"]") 52 endif ("${changelist}" STREQUAL "") 53 54 # Which statuses to look at? 55 set (whereclause "") 56 set (prefix "where") 57 foreach (status ${ARGN}) 58 set (whereclause "${whereclause}${prefix} $status eq \"${status}\"") 59 set (prefix " or") 60 endforeach (status ${ARGN}) 61 62 # BUG: if the query below has new lines you will get a Zorba syntax error on Windows 63 set (query "fn:string-join(for $entry in status/${elem}/entry let $status := data($entry/wc-status/@item) ${whereclause} return $entry/@path, ';')") 64 # Set "filelist" to result 65 execute_process (COMMAND "${ZORBA_EXE}" --omit-xml-declaration 66 --query "${query}" --context-item "${svnstatusxml}" 67 OUTPUT_VARIABLE "${filelist}") 68ENDMACRO (get_files_with_status) 69 70 71# Args: 72# srcdir: root of local SVN working copy with changes to package 73# tmpdir: directory to hold temp files 74# changelist: svn changelist to package (may be "" to package all changes) 75# resultfile: Full path to changes.tgz file to create 76# 77# Note that this function will NOT create any output file if there are no 78# svn changes in the given srcdir. 79macro (svn_package srcdir tmpdir changelist resultfile) 80 find_prereqs () 81 82 # Canonicalize srcdir 83 get_filename_component (abssrcdir "${srcdir}" ABSOLUTE) 84 85 # Start by making our working directory 86 set (chgdir "${tmpdir}/changes") 87 file (MAKE_DIRECTORY "${chgdir}") 88 89 # Write out the "svn info" and "svn status" information 90 execute_process (COMMAND "${svn}" --xml info "${abssrcdir}" 91 OUTPUT_FILE "${chgdir}/svn-info.xml") 92 execute_process (COMMAND "${svn}" --xml status "${abssrcdir}" 93 OUTPUT_FILE "${chgdir}/svn-status.xml") 94 95 # Also save the named of the changelist for the remote queue to use 96 file (WRITE "${chgdir}/changelist" "${changelist}") 97 98 # Check to see whether there are any changes to package 99 get_files_with_status (chgfiles "${chgdir}/svn-status.xml" "${changelist}" 100 added modified deleted) 101 if (chgfiles) 102 # Pick out path names for added and modified files in the 103 # specified changelist, or from the default changelist (<target> 104 # element) if no changelist specified 105 get_files_with_status (copyfiles "${chgdir}/svn-status.xml" "${changelist}" 106 added modified) 107 108 # Copy each modified or added file to a corresponding place in the 109 # directory hierarchy of the changes directory. Skip directories. 110 file (MAKE_DIRECTORY "${chgdir}/files") 111 foreach (filepath ${copyfiles}) 112 if (NOT IS_DIRECTORY "${filepath}") 113 file (TO_CMAKE_PATH "${filepath}" filepath) 114 file (RELATIVE_PATH relpath "${abssrcdir}" "${filepath}") 115 get_filename_component (reldir "${relpath}" PATH) 116 file (MAKE_DIRECTORY "${chgdir}/files/${reldir}") 117 message ("Copying ${filepath} to ${chgdir}/files/${reldir}..") 118 execute_process (COMMAND "${CMAKE_COMMAND}" -E copy 119 "${filepath}" "${chgdir}/files/${reldir}") 120 endif (NOT IS_DIRECTORY "${filepath}") 121 endforeach (filepath) 122 123 # Package up changes/ directory 124 execute_process (COMMAND "${CMAKE_COMMAND}" -E tar czf 125 "${resultfile}" "changes" 126 WORKING_DIRECTORY "${tmpdir}") 127 endif (chgfiles) 128 file (REMOVE_RECURSE "${chgdir}") 129endmacro (svn_package) 130 131 132# Args: 133# changefile - a changes.tgz file from package_svn 134# outdir - directory to check out SVN into and apply changes - see below 135# tmpdir - directory to temporarily unpack changefile into 136# logfile - file to append log messages into 137# result_var - if the variable named by "result_var" is non-zero or contains 138# a message after svn_unpackage() returns, an error was encountered 139# resultdir_var - the variable named by "resultdir_var" will be set to 140# the path the package was unpackaged into 141# 142# Regarding "outdir": svn_unpackage() will place the results into a 143# subdir of outdir. If there is already a subdir of outdir that is an 144# svn checkout of the same URL, it will unpackage into that 145# directory. Otherwise, it will create a new subdir with the basename 146# of "changefile" minus the .tgz extension. 147function (svn_unpackage changefile outdir tmpdir logfile result_var 148 resultdir_var) 149 find_prereqs () 150 151 # Unpack changes.tgz into working dir 152 execute_process (COMMAND "${CMAKE_COMMAND}" -E tar xzf "${changefile}" 153 WORKING_DIRECTORY "${tmpdir}") 154 set (chgdir "${tmpdir}/changes") 155 156 # De-Windows all text files - this also is currently Linux-specific 157 # and depends on "dos2unix" existing. 158 file (GLOB_RECURSE textfiles 159 "${chgdir}/*.c" "${chgdir}/*.cpp" "${chgdir}/*.cxx" 160 "${chgdir}/*.h" "${chgdir}/*.hpp" "${chgdir}/*.hxx" 161 "${chgdir}/*.txt" "${chgdir}/*.cmake" "${chgdir}/*.conf" 162 "${chgdir}/*.xml" "${chgdir}/*.xq" "${chgdir}/*.txt" 163 "${chgdir}/*.res" "${chgdir}/*.spec" "${chgdir}/*.xqlib") 164 foreach (textfile ${textfiles}) 165 execute_process (COMMAND dos2unix -k "${textfile}") 166 endforeach (textfile) 167 168 # Determine SVN URL and revision 169 execute_process (COMMAND "${ZORBA_EXE}" --omit-xml-declaration 170 --query "data(info/entry/@revision)" 171 --context-item "${chgdir}/svn-info.xml" 172 OUTPUT_VARIABLE svnrev) 173 execute_process (COMMAND "${ZORBA_EXE}" --omit-xml-declaration 174 --query "data(info/entry/url)" 175 --context-item "${chgdir}/svn-info.xml" 176 OUTPUT_VARIABLE svnroot) 177 # Special hack: Sourceforge has two URLs for everything, one http: and 178 # one https:. The remote queue checks out via http:, so we have to 179 # tweak the unpackaged URL here if it's https:. 180 if ("${svnroot}" MATCHES "^https:.*sourceforge.net") 181 string (REPLACE "https:" "http:" svnroot "${svnroot}") 182 endif ("${svnroot}" MATCHES "^https:.*sourceforge.net") 183 file (APPEND "${logfile}" "Checking out/updating from ${svnroot}...\n") 184 185 # Look through outdir for a subdir matching svnroot. 186 set (svndir) 187 file (GLOB subdirs "${outdir}/*") 188 foreach (subdir ${subdirs}) 189 execute_process (COMMAND "${svn}" info --xml "${subdir}" 190 OUTPUT_FILE "${tmpdir}/tmpinfo.xml" ERROR_VARIABLE ignored 191 RESULT_VARIABLE result) 192 if (NOT result) 193 execute_process (COMMAND "${ZORBA_EXE}" --omit-xml-declaration 194 --query "data(info/entry/url)" 195 --context-item "${tmpdir}/tmpinfo.xml" 196 OUTPUT_VARIABLE subdir_svnroot) 197 file (REMOVE "${tmpdir}/tmpinfo.xml") 198 if (subdir_svnroot STREQUAL svnroot) 199 set (svndir "${subdir}") 200 break () 201 endif (subdir_svnroot STREQUAL svnroot) 202 endif (NOT result) 203 endforeach (subdir) 204 if (NOT svndir) 205 # No matching URL found; use basename of input file 206 get_filename_component (basename "${changesfile}" NAME_WE) 207 set (svndir "${outdir}/${basename}") 208 endif (NOT svndir) 209 file (APPEND "${logfile}" "..outputting to ${svndir}\n") 210 set (${resultdir_var} "${svndir}" PARENT_SCOPE) 211 212 execute_process (COMMAND "${svn}" checkout 213 -r "${svnrev}" "${svnroot}" "${svndir}" 214 OUTPUT_VARIABLE svnlog ERROR_VARIABLE svnlog) 215 file (APPEND "${logfile}" ${svnlog}) 216 217 # Copy modified/added files on top of svn directory 218 file (APPEND "${logfile}" "Copying added/modified files...\n") 219 execute_process (COMMAND "${CMAKE_COMMAND}" -E copy_directory 220 "${chgdir}/files" "${svndir}") 221 file (APPEND "${logfile}" "Done copying.\n") 222 223 # Modified files are already all set. Process svn-status.xml to 224 # delete any files which were deleted on client's svn, as named in 225 # the client's changelist. 226 file (READ "${chgdir}/changelist" changelist) 227 get_files_with_status (deletefiles 228 "${chgdir}/svn-status.xml" "${changelist}" deleted) 229 execute_process (COMMAND "${ZORBA_EXE}" --omit-xml-declaration 230 --query "data(info/entry/@path)" 231 --context-item "${chgdir}/svn-info.xml" 232 OUTPUT_VARIABLE clientroot) 233 # clientroot and the filepaths below are absolute paths from the 234 # client, which might be Windows-style paths with drive letters. The 235 # following is a horrific hack which lets us get the remote path 236 # component no matter which platform they came from. (Note: This 237 # only works on Linux, which is the platform the remote queue runs 238 # on. If we ever have a Windows remote queue machine, this will 239 # die.) 240 # 1. Stick a leading / on them, so Linux thinks they're absolute. 241 # 2. Convert to "CMake paths", which have forward-slashes. 242 # 3. Do relative_path as normal. 243 file (TO_CMAKE_PATH "/${clientroot}" clientroot) 244 foreach (filepath ${deletefiles}) 245 file (TO_CMAKE_PATH "/${filepath}" filepath) 246 file (RELATIVE_PATH relpath "${clientroot}" "${filepath}") 247 execute_process (COMMAND "${svn}" delete "${svndir}/${relpath}" 248 OUTPUT_VARIABLE output ERROR_VARIABLE output RESULT_VARIABLE result) 249 file (APPEND "${logfile}" "${output}") 250 if (result) 251 set (${result_var} ${result} PARENT_SCOPE) 252 return () 253 endif () 254 endforeach (filepath ${deletefiles}) 255 256 # Now add any new files, using the local output of "svn status" to 257 # find "unversioned" files. (We could read the svn-status.xml from 258 # the changes file, but when it is based on a changelist, it won't 259 # include directories to add.) 260 execute_process (COMMAND "${svn}" --xml status "${svndir}" 261 OUTPUT_FILE "${chgdir}/svn-status.xml") 262 get_files_with_status (addfiles "${chgdir}/svn-status.xml" "" unversioned) 263 foreach (filepath ${addfiles}) 264 execute_process (COMMAND "${svn}" add "${filepath}" 265 OUTPUT_VARIABLE output ERROR_VARIABLE output RESULT_VARIABLE result) 266 file (APPEND "${logfile}" "${output}") 267 if (result) 268 set (${result_var} ${result} PARENT_SCOPE) 269 return () 270 endif () 271 endforeach (filepath ${addfiles}) 272 273 # Remove temporary unpackaged workingset 274 file (REMOVE_RECURSE "${chgdir}") 275 276endfunction (svn_unpackage) 277