Skip to content

Commit

Permalink
ENH: Add CMake infrastructure for fetching Remote modules.
Browse files Browse the repository at this point in the history
A new function is created, itk_fetch_module, that will fetch remote modules
given the module name, description, repository URL, and version.  The list of
modules compatible with the current version of ITK are kept in
Modules/Remote/*.remote.cmake.  Contributed modules can be added to this list by
community members
(all Remote modules should have a working nightly dashboard submission and a
corresponding Insight Journal article).

A remote module listing will result in a CMake configuration
Fetch_${module_name} that defaults to OFF.  If turned ON, the repository will be
downloaded at configuration time, and the module will be available for
configuration and building.

Change-Id: Ic2d770dc9d214f1365e0812c32e6bc90f48db7ea
  • Loading branch information
thewtex committed Apr 27, 2012
1 parent 4efb9b4 commit 05480a2
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 3 deletions.
150 changes: 150 additions & 0 deletions CMake/ITKModuleRemote.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Function to fetch remote modules.

# Helper to perform the initial git clone and checkout.
function(_git_clone git_executable git_repository git_tag module_dir)
execute_process(
COMMAND "${git_executable}" clone "${git_repository}" "${module_dir}"
RESULT_VARIABLE error_code
OUTPUT_QUIET
ERROR_QUIET
)
if(error_code)
message(FATAL_ERROR "Failed to clone repository: '${git_repository}'")
endif()

execute_process(
COMMAND "${git_executable}" checkout ${git_tag}
WORKING_DIRECTORY "${module_dir}"
RESULT_VARIABLE error_code
OUTPUT_QUIET
ERROR_QUIET
)
if(error_code)
message(FATAL_ERROR "Failed to checkout tag: '${git_tag}'")
endif()

execute_process(
COMMAND "${git_executable}" submodule init
WORKING_DIRECTORY "${module_dir}"
RESULT_VARIABLE error_code
)
if(error_code)
message(FATAL_ERROR "Failed to init submodules in: '${module_dir}'")
endif()

execute_process(
COMMAND "${git_executable}" submodule update --recursive
WORKING_DIRECTORY "${module_dir}"
RESULT_VARIABLE error_code
)
if(error_code)
message(FATAL_ERROR "Failed to update submodules in: '${module_dir}'")
endif()
endfunction()

# Helper to perform a git update. Checks the current Git revision against the
# desired revision and only performs a fetch and checkout if needed.
function(_git_update git_executable git_repository git_tag module_dir)
execute_process(
COMMAND "${git_executable}" rev-parse --verify ${git_tag}
WORKING_DIRECTORY "${module_dir}"
RESULT_VARIABLE error_code
OUTPUT_VARIABLE tag_hash
)
if(error_code)
message(FATAL_ERROR "Failed to get the hash for tag '${module_dir}'")
endif()
execute_process(
COMMAND "${git_executable}" rev-parse --verify HEAD
WORKING_DIRECTORY "${module_dir}"
RESULT_VARIABLE error_code
OUTPUT_VARIABLE head_hash
)
if(error_code)
message(FATAL_ERROR "Failed to get the hash for ${git_repository} HEAD")
endif()

# Is the hash checkout out that we want?
if(NOT ("${tag_hash}" STREQUAL "${head_hash}"))
execute_process(
COMMAND "${git_executable}" fetch
WORKING_DIRECTORY "${module_dir}"
RESULT_VARIABLE error_code
)
if(error_code)
message(FATAL_ERROR "Failed to fetch repository '${git_repository}'")
endif()

execute_process(
COMMAND "${git_executable}" checkout ${git_tag}
WORKING_DIRECTORY "${module_dir}"
RESULT_VARIABLE error_code
)
if(error_code)
message(FATAL_ERROR "Failed to checkout tag: '${git_tag}'")
endif()

execute_process(
COMMAND "${git_executable}" submodule update --recursive
WORKING_DIRECTORY "${module_dir}"
RESULT_VARIABLE error_code
)
if(error_code)
message(FATAL_ERROR "Failed to update submodules in: '${module_dir}'")
endif()
endif()
endfunction()

# Helper function to fetch a module stored in a Git repository.
# Git fetches are only performed when required.
function(_fetch_with_git git_executable git_repository git_tag module_dir)
if("${git_tag}" STREQUAL "" OR "${git_repository}" STREQUAL "")
message(FATAL_ERROR "Tag or repository for git checkout should not be empty.")
endif()

# If we don't have a clone yet.
if(NOT EXISTS "${module_dir}")
_git_clone("${git_executable}" "${git_repository}" "${git_tag}" "${module_dir}")
else() # We already have a clone, but we need to check that it has the right revision.
_git_update("${git_executable}" "${git_repository}" "${git_tag}" "${module_dir}")
endif()
endfunction(_fetch_with_git)

# Fetch a remote module.
#
# A new CMake option is created, Fetch_${module_name}, which defaults to OFF.
# Once set to ON, the module is downloaded into the Remote module group, and an
# option to build the module will be available on the next CMake configuration.
#
# A module name and description are required. The description will show up in
# the CMake user interface.
#
# The following options are currently supported:
# [GIT_REPOSITORY url] # URL of git repo
# [GIT_TAG tag] # Git branch name, commit id or tag
function(itk_fetch_module _name _description)
option(Fetch_${_name} "${_description}" OFF)
mark_as_advanced(Fetch_${_name})
if(Fetch_${_name})
include(CMakeParseArguments)
cmake_parse_arguments(_fetch_options "" "GIT_REPOSITORY;GIT_TAG" "" ${ARGN})
find_package(Git)
if(NOT GIT_EXECUTABLE)
message(FATAL_ERROR "error: could not find git for clone of ${_name}")
endif()
execute_process(
COMMAND "${GIT_EXECUTABLE}" --version
OUTPUT_VARIABLE ov
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REGEX REPLACE "^git version (.+)$" "\\1" _version "${ov}")
if("${_version}" VERSION_LESS 1.6.6)
message(FATAL_ERROR "Git version 1.6.6 or later is required.")
endif()
_fetch_with_git("${GIT_EXECUTABLE}"
"${_fetch_options_GIT_REPOSITORY}"
"${_fetch_options_GIT_TAG}"
"${ITK_SOURCE_DIR}/Modules/Remote/${_name}"
)
endif()
endfunction()
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,8 @@ if(BUILD_TESTING)
add_subdirectory(Utilities/InstallTest)
endif()

add_subdirectory(Modules/Remote)

#-----------------------------------------------------------------------------
# The subdirectories added below this line should use only the public
# interface with find_package(ITK). Set ITK_DIR to use this ITK build.
Expand Down
3 changes: 0 additions & 3 deletions Modules/External/readme.txt

This file was deleted.

4 changes: 4 additions & 0 deletions Modules/Remote/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*
!*.remote.cmake
!CMakeLists.txt
!README.txt
7 changes: 7 additions & 0 deletions Modules/Remote/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Functions to fetch remote modules.
include(ITKModuleRemote)

file(GLOB remotes "*.remote.cmake")
foreach(remote_module ${remotes})
include(${remote_module})
endforeach()
11 changes: 11 additions & 0 deletions Modules/Remote/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
This directory is a place-holder for all remote modules distributed outside ITK's
main repository. Remote modules share the same directory structure as modules
in the main repository. They will be picked up by the configuration system and
entered into the build after they are downloaded into this directory.

Modules can be easily downloaded and accessible to the community by listing the
module in the current directory. For more information on adding a new module to
the list of new modules, see the page that describes the policy and procedures
for adding a new module:

http://www.itk.org/Wiki/ITK/Policy_and_Procedures_for_Adding_Remote_Modules

0 comments on commit 05480a2

Please sign in to comment.