BASIS  version 1.2.3 (revision 2104)
BasisUpdate.cmake
Go to the documentation of this file.
00001 ##############################################################################
00002 # @file  BasisUpdate.cmake
00003 # @brief Implements automatic file udpate feature (deprecated).
00004 #
00005 # @note The automatic file update works well and the implementation is fine.
00006 #       However, its use became more and more obsolete during the enhancement
00007 #       of BASIS and the development of a more advanced project tool
00008 #       (basisproject.py). Moreover, the update of project files during the
00009 #       configuration of the build system was controversy.
00010 #
00011 # This file provides functions which implement the automatic file update
00012 # of project files from the corresponding template files which they were
00013 # instantiated from. Instead of the need to manually copy files and/or parts
00014 # of files from the updated project template to each project that was
00015 # instantiated from this particular template, the projects themselves check
00016 # for the availibility of updated template files during the configure step
00017 # of CMake and apply the updates if possible and desired by the user.
00018 # The automatic file update mechanism can be configured to have the user decide
00019 # for each or all files whether an available update may be applied or not.
00020 # Further, updates will only be applied if it is guaranteed that these changes
00021 # can be easily reverted.
00022 #
00023 # The automatic file update feature is only enabled when
00024 #
00025 # 1. The option @c BASIS_UPDATE, which is added by this module, is enabled.
00026 #
00027 # 2. @c BASIS_TEMPLATE_URL is a valid URL to the local root directory or
00028 #    repository root directory of the BASIS project template, respectively,
00029 #    Note that local directories must be prefixed by "file://".
00030 #
00031 # 3. The Python interpreter "python" was found and thus the variable
00032 #    @c PYTHON_EXECUTABLE is set.
00033 #
00034 # 4. The script used to merge the content of the template with the existing
00035 #    project files has to be in the same directory as this CMake module.
00036 #
00037 # 5. The project itself has to be under revision control, in particular,
00038 #    a valid Subversion working copy. This is required to ensure that changes
00039 #    applied during the automatic file udpate can be reverted.
00040 #
00041 # When this module is included, it adds the advanced option @c BASIS_UPDATE_AUTO
00042 # which is @c ON by default. If @c BASIS_UPDATE_AUTO is @c ON, files are updated
00043 # automatically without interacting with the user to get confirmation for file
00044 # update. If a project file contains local modifications or is not under
00045 # revision control, the udpate will not be performed automatically in any case.
00046 # Moreover, files which are listed with their path relative to the project
00047 # source directory in @c BASIS_UPDATE_EXCLUDE are excluded from the automatic file
00048 # update.
00049 #
00050 # Copyright (c) 2011, 2012 University of Pennsylvania. All rights reserved.<br />
00051 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.
00052 #
00053 # Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00054 #
00055 # @ingroup CMakeTools
00056 ##############################################################################
00057 
00058 if (__BASIS_UPDATE_INCLUDED)
00059   return ()
00060 else ()
00061   set (__BASIS_UPDATE_INCLUDED TRUE)
00062 endif ()
00063 
00064 
00065 # ============================================================================
00066 # options
00067 # ============================================================================
00068 
00069 ## @brief Enable/Disable update of files.
00070 option (BASIS_UPDATE "Whether the automatic file update is enabled" "ON")
00071 ## @brief Enable/Disable automatic non-interactive update of files.
00072 option (BASIS_UPDATE_AUTO "Whether files may be updated automatically without confirmation" "ON")
00073 
00074 mark_as_advanced (BASIS_UPDATE)
00075 mark_as_advanced (BASIS_UPDATE_AUTO)
00076 
00077 # ============================================================================
00078 # required modules
00079 # ============================================================================
00080 
00081 include ("${CMAKE_CURRENT_LIST_DIR}/CommonTools.cmake")
00082 include ("${CMAKE_CURRENT_LIST_DIR}/RevisionTools.cmake")
00083 
00084 # ============================================================================
00085 # required commands
00086 # ============================================================================
00087 
00088 ## @brief Script used to perform the update of a file.
00089 set (BASIS_UPDATE_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/updatefile.py")
00090 
00091 # ============================================================================
00092 # initialization
00093 # ============================================================================
00094 
00095 ##############################################################################
00096 # @brief Initialize file update and update files already scheduled for update.
00097 #
00098 # This function has to be called before any basis_update() call. It performs
00099 # the update of files already scheduled for updated during a previous CMake
00100 # configure step and for which the user choose to update them by invoking the
00101 # function basis_update_files(). Note that files are only udpated here if the
00102 # interactive mode is enabled or if there are files which could not be updated
00103 # automatically by the last execution of basis_update_finalize(). Otherwise,
00104 # no files are updated by this function. Afterwards the update system is
00105 # initialized for another iteration of CMake's configure step.
00106 #
00107 # Example:
00108 #
00109 # @code
00110 # basis_update_initialize ()
00111 # basis_update (CTestConfig.cmake)
00112 # basis_update_finalize ()
00113 # @endcode
00114 #
00115 # @sa basis_update()
00116 # @sa basis_update_finalize()
00117 # @sa basis_update_files()
00118 #
00119 # @returns Sets @c BASIS_UPDATE_INITIALIZED to indicate the the automatic
00120 #          file update feature has been initialized.
00121 
00122 function (basis_update_initialize)
00123   # initialize only if not done already
00124   if (BASIS_UPDATE_INITIALIZED)
00125     return ()
00126   endif ()
00127 
00128   mark_as_advanced (BASIS_UPDATE_SCRIPT)
00129 
00130   # check BASIS_TEMPLATE_URL
00131   set (BASIS_TEMPLATE_URL_VALID 0)
00132 
00133   if (BASIS_TEMPLATE_URL MATCHES "file://.*")
00134     string (REGEX REPLACE "file://" "" TMP "${BASIS_TEMPLATE_URL}")
00135     if (IS_DIRECTORY "${TMP}")
00136       set (BASIS_TEMPLATE_URL_VALID 1)
00137     endif ()
00138   elseif (BASIS_TEMPLATE_URL MATCHES "http.*://.*")
00139     basis_svn_get_revision (${BASIS_TEMPLATE_URL} REV)
00140     if (REV)
00141       set (BASIS_TEMPLATE_URL_VALID 1)
00142     endif ()
00143   endif ()
00144  
00145   # --------------------------------------------------------------------------
00146   # update enabled
00147   # --------------------------------------------------------------------------
00148 
00149   if (
00150         BASIS_UPDATE             # 1. update is enabled
00151     AND BASIS_TEMPLATE_URL_VALID # 2. valid template root dir
00152     AND PYTHON_EXECUTABLE         # 3. python interpreter found
00153     AND BASIS_UPDATE_SCRIPT      # 4. update script found
00154     AND PROJECT_REVISION         # 5. project is under revision control
00155   )
00156 
00157     # update files which were not updated during last configure run. Instead,
00158     # CMake variables where added which enabled the user to specify the files
00159     # which should be udpated
00160     basis_update_files ()
00161 
00162   # --------------------------------------------------------------------------
00163   # update disabled
00164   # --------------------------------------------------------------------------
00165 
00166   else ()
00167 
00168     if (BASIS_UPDATE)
00169       message ("File update not feasible.")
00170 
00171       if (BASIS_VERBOSE)
00172         message ("Variables related to (automatic) file update:
00173 
00174   BASIS_UPDATE        : ${BASIS_UPDATE}
00175   BASIS_UPDATE_AUTO   : ${BASIS_UPDATE_AUTO}
00176   PYTHON_EXECUTABLE    : ${PYTHON_EXECUTABLE}
00177   BASIS_UPDATE_SCRIPT : ${BASIS_UPDATE_SCRIPT}
00178   BASIS_TEMPLATE_URL  : ${BASIS_TEMPLATE_URL}
00179   PROJECT_REVISION    : ${PROJECT_REVISION}
00180 ")
00181       endif ()
00182 
00183       if (NOT PYTHON_EXECUTABLE)
00184         message ("=> Python interpreter not found.")
00185       endif ()
00186       if (NOT BASIS_UPDATE_SCRIPT)
00187         message ("=> File update script not found.")
00188       endif ()
00189       if (NOT BASIS_TEMPLATE_URL_VALID)
00190         message ("=> Invalid BASIS_TEMPLATE_URL path.")
00191       endif()
00192       if (NOT PROJECT_REVISION)
00193         message ("=> Project is not under revision control.")
00194       endif ()
00195 
00196       message ("Setting BASIS_UPDATE to OFF.")
00197       set (BASIS_UPDATE "OFF" CACHE BOOL "Whether the automatic file update is enabled" FORCE)
00198     endif ()
00199  
00200   endif ()
00201 
00202   # DO NOT cache this variable
00203   set (BASIS_UPDATE_INITIALIZED 1)
00204 endfunction ()
00205 
00206 # ============================================================================
00207 # update
00208 # ============================================================================
00209 
00210 ##############################################################################
00211 # @brief Checks for availibility of update and adds files for which an
00212 #        updated template exists to BASIS_UPDATE_FILES.
00213 #
00214 # This function retrieves a copy of the latest revision of the corresponding
00215 # template file of the project template from which this project was
00216 # instantiated and caches it in the binary tree. If a cached copy is already
00217 # available, the cached copy is used. Then, it checks whether the template
00218 # contains any updated compared to the current project file, ignoring the
00219 # content of customizable sections. If an udpate is available, the file
00220 # is added to BASIS_UPDATE_FILE. The updates will be applied by either
00221 # basis_update_initialize() if the interactive mode is enabled or by
00222 # basis_update_finalize().
00223 #
00224 # Files which are listed with their path relative to the project source
00225 # directory in BASIS_UPDATE_EXCLUDE are excluded from the automatic file
00226 # update and will hence be skipped by this function.
00227 #
00228 # @sa basis_update_initialize()
00229 # @sa basis_update_finalize()
00230 #
00231 # @param [in] FILENAME Name of project file in current source directory.
00232 #
00233 # @returns Nothing.
00234 
00235 function (basis_update FILENAME)
00236   if (NOT BASIS_UPDATE)
00237     return ()
00238   endif ()
00239 
00240   # absolute path of project file
00241   set (CUR "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}")
00242 
00243   # get path of file relative to project source directory
00244   file (RELATIVE_PATH REL "${PROJECT_SOURCE_DIR}" "${CUR}")
00245 
00246   # must be AFTER REL was set
00247   if (BASIS_VERBOSE)
00248     message (STATUS "Checking for update of file '${REL}'...")
00249   endif ()
00250 
00251   # skip file if excluded from file update
00252   if (BASIS_UPDATE_EXCLUDE)
00253     list (FIND BASIS_UPDATE_EXCLUDE "${CUR}" IDX)
00254     if (IDX EQUAL -1)
00255       list (FIND BASIS_UPDATE_EXCLUDE "${REL}" IDX)
00256     endif ()
00257     if (NOT IDX EQUAL -1)
00258       if (BASIS_VERBOSE)
00259         message (STATUS "Checking for update of file '${REL}'... - excluded")
00260       endif ()
00261       return ()
00262     endif ()
00263   endif ()
00264 
00265   # skip file if it is not under revision control
00266   if (EXISTS "${CUR}")
00267     basis_svn_get_last_changed_revision ("${CUR}" CURREV)
00268 
00269     if (CURREV EQUAL 0)
00270       if (BASIS_VERBOSE)
00271         message (STATUS "Checking for update of file '${REL}'... - file unversioned")
00272       endif ()
00273 
00274       return ()
00275     endif ()
00276   endif ()
00277 
00278   # retrieve template file
00279   basis_update_cached_template ("${REL}" TMP)             # file name of cached template file
00280   basis_update_template        ("${REL}" "${TMP}" RETVAL) # update cached template file
00281 
00282   if (NOT RETVAL)
00283     message (STATUS "Checking for update of file '${REL}'... - template missing")
00284     return ()
00285   endif ()
00286 
00287   # get currently cached list of files in BASIS_UPDATE_FILES
00288   set (FILES ${BASIS_UPDATE_FILES})
00289 
00290   # --------------------------------------------------------------------------
00291   # check if update of existing project file is available
00292   # --------------------------------------------------------------------------
00293 
00294   if (EXISTS "${CUR}")
00295     execute_process (
00296       COMMAND
00297         "${PYTHON_EXECUTABLE}" "${BASIS_UPDATE_SCRIPT}" -i "${CUR}" -t "${TMP}"
00298       RESULT_VARIABLE
00299         RETVAL
00300       OUTPUT_QUIET
00301       ERROR_QUIET
00302     )
00303 
00304     if (RETVAL EQUAL 0)
00305       list (APPEND FILES "${REL}")
00306     elseif (RETVAL EQUAL 2)
00307 
00308       if (FILES)
00309         list (REMOVE_ITEM FILES "${REL}")
00310       endif ()
00311 
00312       basis_update_option ("${REL}" OPT)
00313 
00314       if (DEFINED ${OPT})
00315         set (${OPT} "" CACHE INTERNAL "Unused option." FORCE)
00316       endif ()
00317     endif ()
00318 
00319     if (BASIS_VERBOSE)
00320       if (RETVAL EQUAL 0)
00321         message (STATUS "Checking for update of file '${REL}'... - update available")
00322       elseif (RETVAL EQUAL 2)
00323         message (STATUS "Checking for update of file '${REL}'... - up-to-date")
00324       else ()
00325         message (STATUS "Checking for update of file '${REL}'... - failed")
00326       endif ()
00327     endif ()
00328 
00329   # --------------------------------------------------------------------------
00330   # new files added to template
00331   # --------------------------------------------------------------------------
00332 
00333   else ()
00334 
00335     list (APPEND FILES "${REL}")
00336 
00337     if (BASIS_VERBOSE)
00338       message (STATUS "Checking for update of file '${REL}'... - file missing")
00339     endif ()
00340 
00341   endif ()
00342 
00343   # update cached variable BASIS_UPDATE_FILES
00344   set (BASIS_UPDATE_FILES ${FILES} CACHE INTERNAL "Files to be updated." FORCE)
00345 endfunction ()
00346 
00347 # ============================================================================
00348 # finalization
00349 # ============================================================================
00350 
00351 ##############################################################################
00352 # @brief Adds file update options for user interaction or performs
00353 #        file update immediately if quiet update enabled.
00354 #
00355 # @sa basis_update()
00356 # @sa basis_update_initialize()
00357 # @sa basis_update_finalize()
00358 #
00359 # @returns Nothing.
00360 
00361 function (basis_update_finalize)
00362   if (NOT BASIS_UPDATE)
00363     return ()
00364   endif ()
00365 
00366   set (FILES ${BASIS_UPDATE_FILES})
00367 
00368   if (FILES)
00369     list (REMOVE_DUPLICATES FILES)
00370   endif ()
00371 
00372   # iterate over files added by basis_update ()
00373   foreach (REL ${FILES})
00374 
00375     # absolute path of project file
00376     set (CUR "${PROJECT_SOURCE_DIR}/${REL}")
00377 
00378     # name of cached template file
00379     basis_update_cached_template ("${REL}" TMP)
00380 
00381     # ------------------------------------------------------------------------
00382     # project file exists
00383     # ------------------------------------------------------------------------
00384 
00385     if (EXISTS "${CUR}")
00386 
00387       # check if it is under revision control and whether it has local modifications
00388       if (EXISTS "${CUR}")
00389         basis_svn_get_last_changed_revision (${CUR} CURREV)
00390         basis_svn_status                    (${CUR} CURSTATUS)
00391       endif ()
00392 
00393       basis_update_option ("${REL}" OPT) # name of file update option
00394 
00395       # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00396       # quietly update file w/o user interaction
00397       # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00398 
00399       if (
00400             BASIS_UPDATE_AUTO          # 1. option BASIS_UPDATE_AUTO is ON
00401         AND CURREV GREATER 0           # 2. project file is under revision control
00402         AND "${CURSTATUS}" STREQUAL "" # 3. project file has no local modifications
00403       )
00404         if (BASIS_VERBOSE)
00405           message (STATUS "Updating file '${REL}'...")
00406         endif ()
00407 
00408         execute_process (
00409           COMMAND
00410             "${PYTHON_EXECUTABLE}" "${BASIS_UPDATE_SCRIPT}" -f -i "${CUR}" -t "${TMP}" -o "${CUR}"
00411           RESULT_VARIABLE
00412             RETVAL
00413           OUTPUT_QUIET
00414           ERROR_QUIET
00415         )
00416 
00417         if (RETVAL EQUAL 0 OR RETVAL EQUAL 2)
00418           list (REMOVE_ITEM FILES "${REL}")
00419           set (${OPT} "" CACHE INTERNAL "Unused option." FORCE)
00420         endif ()
00421 
00422         if (RETVAL EQUAL 0)
00423           message ("Updated file '${REL}'")
00424         elseif (NOT RETVAL EQUAL 2)
00425           message ("Failed to update file '${REL}'")
00426         endif ()
00427 
00428         if (BASIS_VERBOSE)
00429           if (RETVAL EQUAL 0)
00430             message (STATUS "Updating file '${REL}'... - done")
00431           elseif (RETVAL EQUAL 2)
00432             message (STATUS "Updating file '${REL}'... - up-to-date")
00433           else ()
00434             message (STATUS "Updating file '${REL}'... - failed")
00435           endif ()
00436         endif ()
00437 
00438       # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00439       # add file update option (if not present yet)
00440       # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00441 
00442       else ()
00443 
00444         if ("${${OPT}}" STREQUAL "")
00445           # add option which user can modify to force update of file
00446           set (${OPT} "OFF" CACHE BOOL "Whether file '${REL}' should be updated." FORCE)
00447           # add BASIS_UPDATE_ALL option if not present
00448           if ("${UPDATE_ALL}" STREQUAL "")
00449             set (UPDATE_ALL "OFF" CACHE BOOL "Whether all files should be updated." FORCE)
00450           endif ()
00451         endif ()
00452 
00453         # inform user that file update is available
00454         message ("Update of file '${REL}' available.\nSet UPDATE_ALL or ${OPT} to ON if changes should be applied.")
00455 
00456       endif ()
00457 
00458     # ----------------------------------------------------------------------
00459     # project file non existent
00460     # ----------------------------------------------------------------------
00461 
00462     else ()
00463 
00464       if (BASIS_VERBOSE)
00465         message (STATUS "Adding file '${REL}'...")
00466       endif ()
00467 
00468       configure_file ("${TMP}" "${CUR}" COPYONLY)
00469 
00470       list (REMOVE_ITEM FILES "${REL}")
00471       set (${OPT} "" CACHE INTERNAL "Unused option." FORCE)
00472 
00473       message ("Added file '${REL}'. Do not forget to add it to the repository!")
00474 
00475       if (BASIS_VERBOSE)
00476         message (STATUS "Adding file '${REL}'... - done")
00477       endif ()
00478 
00479     endif ()
00480 
00481   endforeach ()
00482 
00483   if (NOT FILES)
00484     set (UPDATE_ALL "" CACHE INTERNAL "Unused option." FORCE)
00485   endif ()
00486 
00487   set (BASIS_UPDATE_FILES ${FILES} CACHE INTERNAL "Files to be updated." FORCE)
00488 endfunction ()
00489 
00490 # ============================================================================
00491 # helpers
00492 # ============================================================================
00493 
00494 # ----------------------------------------------------------------------------
00495 # common helpers
00496 # ----------------------------------------------------------------------------
00497 
00498 ##############################################################################
00499 # @brief Get name of file update option.
00500 #
00501 # The CMake variable name returned by this function is used as file update
00502 # option which enables the user to select which files should be udpated.
00503 #
00504 # @sa basis_update_finalize()
00505 # @sa basis_update_files()
00506 #
00507 # @param [in]  REL         Path of project file relative to project source directory.
00508 # @param [out] OPTION_NAME Name of file update option.
00509 #
00510 # @returns Sets @p OPTION_NAME to the name of the CMake option variable.
00511 
00512 function (basis_update_option REL OPTION_NAME)
00513   set (TMP "${REL}")
00514   string (REGEX REPLACE "\\.|\\\\|/|-" "_" TMP ${TMP})
00515   set (${OPTION_NAME} "UPDATE_${TMP}" PARENT_SCOPE)
00516 endfunction ()
00517 
00518 ##############################################################################
00519 # @brief Get filename of cached template file.
00520 #
00521 # @param [in]  REL      Path of project file relative to project source directory.
00522 # @param [out] TEMPLATE Absolute path of cached template file in binary tree
00523 #                       of project.
00524 #
00525 # @returns Sets @p TEMPLATE to the full path of the updated template file.
00526 
00527 function (basis_update_cached_template REL TEMPLATE)
00528   # URL of template file
00529   set (SRC "${BASIS_TEMPLATE_URL}/${REL}")
00530 
00531   # get revision of template file. If no revision number can be determined,
00532   # we either did not find the svn client or the file referenced by SRC
00533   # is not a repository. However, if it is a working copy, we will still
00534   # get a revision number. Thus, we then need to check if SRC is a URL
00535   # starting with 'https://sbia-svn' or not (see below).
00536   basis_svn_get_last_changed_revision ("${SRC}" REV)
00537 
00538   if (REV GREATER 0)
00539     basis_svn_status ("${SRC}" STATUS)
00540     if (NOT "${STATUS}" STREQUAL "")
00541       set (REV "0") # under revision control, but locally modified
00542     endif ()
00543   else ()
00544     set (REV "-") # not under revision control (or non-existent)
00545   endif ()
00546 
00547   # file name of cached template file in binary tree of project
00548   set (${TEMPLATE} "${PROJECT_BINARY_DIR}/${REL}.rev${REV}" PARENT_SCOPE)
00549 endfunction ()
00550 
00551 # ----------------------------------------------------------------------------
00552 # update helpers
00553 # ----------------------------------------------------------------------------
00554 
00555 ##############################################################################
00556 # @brief Removes cached template files from binary tree.
00557 #
00558 # This function is used by basis_update_template() to remove cached template
00559 # copies of a particular file in the binary tree when no longer needed.
00560 #
00561 # @sa basis_update_template()
00562 #
00563 # @param [in] REL  Path of the project file whose template copies shall be
00564 #                  removed relative to the project's source directory.
00565 # @param [in] ARGN Absolute paths of cached template files to preserve.
00566 #
00567 # @returns Nothing.
00568 
00569 function (basis_update_clear REL)
00570   # collect all cached template files
00571   file (GLOB FILES "${PROJECT_BINARY_DIR}/${REL}.rev*")
00572   # remove files which are to be preserved
00573   if (FILES)
00574     foreach (ARG ${ARGN})
00575       list (REMOVE_ITEM FILES ${ARG})
00576     endforeach ()
00577   endif ()
00578   # remove files
00579   if (FILES)
00580     file (REMOVE ${FILES})
00581   endif ()
00582 endfunction ()
00583 
00584 ##############################################################################
00585 # @brief Retrieves latest revision of template file.
00586 #
00587 # @param [in]  REL      Path of project/template file relative to project source tree.
00588 # @param [in]  TEMPLATE Absolute path of cached template file in binary tree of project.
00589 # @param [out] RETVAL   Boolean variable which indicates success or failure.
00590 #
00591 # @returns Sets @p RETVAL either to 1 or 0 whether or not the update was
00592 #          successful or not, respectively.
00593 
00594 function (basis_update_template REL TEMPLATE RETVAL)
00595 
00596   # URL of template file
00597   set (SRC "${BASIS_TEMPLATE_URL}/${REL}")
00598 
00599   # if template file is not under revision control or has local modifications
00600   # we cannot use caching as there is no unique revision number assigned
00601   if (TEMPLATE MATCHES ".*\\.rev[0|-]")
00602 
00603     # remove previously exported/downloaded template files
00604     basis_update_clear ("${REL}")
00605 
00606     # download template file from non-revision controlled template
00607     file (DOWNLOAD "${SRC}" "${TEMPLATE}" TIMEOUT 30 STATUS RET)
00608     list (GET RET 0 RET)
00609 
00610   # if cached file not available, retrieve it from repository or working copy
00611   elseif (NOT EXISTS "${TEMPLATE}")
00612 
00613     # remove previously exported/downloaded revisions
00614     basis_update_clear ("${REL}")
00615 
00616     # if template URL is SVN repository, export file using SVN client
00617     if ("${SRC}" MATCHES "^https://sbia-svn.*")
00618       execute_process (
00619         COMMAND         "${Subversion_SVN_EXECUTABLE}" export "${SRC}" "${TEMPLATE}"
00620         TIMEOUT         30
00621         RESULT_VARIABLE RET
00622         OUTPUT_QUIET
00623         ERROR_QUIET
00624       )
00625     # otherwise, download file
00626     else ()
00627       file (DOWNLOAD "${SRC}" "${TEMPLATE}" TIMEOUT 30 STATUS RET)
00628       list (GET RET 0 RET)
00629     endif ()
00630   else ()
00631     basis_update_clear ("${REL}" "${TEMPLATE}")
00632     set (RET 0)
00633   endif ()
00634 
00635   # return value
00636   if (RET EQUAL 0)
00637     set (${RETVAL} 1 PARENT_SCOPE)
00638   else ()
00639     set (${RETVAL} 0 PARENT_SCOPE)
00640   endif ()
00641 endfunction ()
00642 
00643 ##############################################################################
00644 # @brief Update files listed in BASIS_UPDATE_FILES for which file
00645 #        update option exists and is ON or UPDATE_ALL is ON.
00646 #
00647 # This function attempts to update all files in BASIS_UPDATE_FILES
00648 # whose file update option is ON. If the option UPDATE_ALL is ON,
00649 # the file update options of individual files are ignored and all files
00650 # are updated. It is called by basis_update_initialize().
00651 #
00652 # The list BASIS_UPDATE_FILES is populated by the function basis_update()
00653 # and the file update options for the listed files are added by
00654 # basis_update_finalize() if BASIS_UPDATE_QUIET is OFF. Otherwise,
00655 # the files are updated directly by basis_update_finalize() if possible.
00656 #
00657 # @sa basis_update_initialize()
00658 # @sa basis_update_finalize()
00659 #
00660 # @returns Nothing.
00661 
00662 function (basis_update_files)
00663   if (NOT BASIS_UPDATE)
00664     return ()
00665   endif ()
00666 
00667   set (FILES ${BASIS_UPDATE_FILES})
00668 
00669   if (FILES)
00670     list (REMOVE_DUPLICATES FILES)
00671   endif ()
00672 
00673   foreach (REL ${FILES})
00674 
00675     # absolute path of project file
00676     set (CUR "${PROJECT_SOURCE_DIR}/${REL}")
00677 
00678     # if project file exists, check if it is under revision control and
00679     # whether it has local modifications
00680     if (EXISTS "${CUR}")
00681       basis_svn_status (${CUR} CURSTATUS)
00682     else ()
00683       set (CURSTATUS "")
00684     endif ()
00685 
00686     # get name of cached template file
00687     basis_update_cached_template ("${REL}" TMP)
00688 
00689     # if cached template file exists...
00690     if (EXISTS "${TMP}")
00691  
00692       basis_update_option ("${REL}" OPT) # name of file update option
00693 
00694       # ...and file update option is ON
00695       if ("${${OPT}}" STREQUAL "ON" OR "${UPDATE_ALL}" STREQUAL "ON")
00696 
00697         if (BASIS_VERBOSE)
00698           message (STATUS "Updating file '${REL}'...")
00699         endif ()
00700 
00701         # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00702         # project file has local modifications
00703         # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00704 
00705         if (NOT "${CURSTATUS}" STREQUAL "")
00706 
00707           message ("File '${REL}' has local modifications. Modifications must be committed or reverted before file can be updated.")
00708 
00709           if ("${${OPT}}" STREQUAL "ON")
00710             message ("Setting ${OPT} to OFF.")
00711             set (${OPT} "OFF" CACHE BOOL "Whether file '${REL}' should be updated." FORCE)
00712           endif ()
00713 
00714           if (BASIS_VERBOSE)
00715             message (STATUS "Updating file '${REL}'... - failed")
00716           endif ()
00717 
00718         # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00719         # project file has NO local modifications
00720         # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00721 
00722         else ()
00723 
00724           execute_process (
00725             COMMAND
00726               "${PYTHON_EXECUTABLE}" "${BASIS_UPDATE_SCRIPT}" -f -i "${CUR}" -t "${TMP}" -o "${CUR}"
00727             RESULT_VARIABLE
00728               RETVAL
00729             OUTPUT_QUIET
00730             ERROR_QUIET
00731           )
00732 
00733           if (RETVAL EQUAL 0 OR RETVAL EQUAL 2)
00734             list (REMOVE_ITEM FILES "${REL}")
00735             set (${OPT} "" CACHE INTERNAL "Unused option." FORCE)
00736           endif ()
00737 
00738           if (RETVAL EQUAL 0)
00739             message ("Updated file '${REL}'")
00740           elseif (NOT RETVAL EQUAL 2)
00741             message ("Failed to update file '${REL}'")
00742           endif ()
00743 
00744           if (BASIS_VERBOSE)
00745             if (RETVAL EQUAL 0)
00746               message (STATUS "Updating file '${REL}'... - done")
00747             elseif (RETVAL EQUAL 2)
00748               message (STATUS "Updating file '${REL}'... - up-to-date")
00749             else ()
00750               message (STATUS "Updating file '${REL}'... - failed")
00751             endif ()
00752           endif ()
00753   
00754         endif ()
00755       endif ()
00756     endif ()
00757 
00758   endforeach ()
00759 
00760   set (BASIS_UPDATE_FILES ${FILES} CACHE INTERNAL "Files to be updated." FORCE)
00761 
00762   # reset option UPDATE_ALL
00763   if (FILES)
00764     if ("${UPDATE_ALL}" STREQUAL "ON")
00765       message ("Setting UPDATE_ALL to OFF.")
00766       set (UPDATE_ALL "OFF" CACHE BOOL "Whether all files should be updated." FORCE)
00767     endif ()
00768   else ()
00769     set (UPDATE_ALL "" CACHE INTERNAL "Unused option." FORCE)
00770   endif ()
00771 endfunction ()