BashCompletion.cmake 4.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. # A wrapper around pkg-config-provided and cmake-provided bash completion that
  2. # will have dynamic behavior at INSTALL() time to allow both root-level
  3. # INSTALL() as well as user-level INSTALL().
  4. #
  5. # See also https://github.com/scop/bash-completion
  6. #
  7. # Copyright (c) 2018, Tres Finocchiaro, <tres.finocchiaro@gmail.com>
  8. # Redistribution and use is allowed according to the terms of the BSD license.
  9. # For details see the accompanying COPYING-CMAKE-SCRIPTS file.
  10. #
  11. # Usage:
  12. # INCLUDE(BashCompletion)
  13. # BASHCOMP_INSTALL(foo)
  14. # ... where "foo" is a shell script adjacent to the CMakeLists.txt
  15. #
  16. # How it determines BASHCOMP_PKG_PATH, in order:
  17. # 1. Uses BASHCOMP_PKG_PATH if already set (e.g. -DBASHCOMP_PKG_PATH=...)
  18. # a. If not, uses pkg-config's PKG_CHECK_MODULES to determine path
  19. # b. Fallback to cmake's FIND_PACKAGE(bash-completion) path
  20. # c. Fallback to hard-coded /usr/share/bash-completion/completions
  21. # 2. Final fallback to ${CMAKE_INSTALL_PREFIX}/share/bash-completion/completions if
  22. # detected path is unwritable.
  23. # - Windows does not support bash completion
  24. # - macOS support should eventually be added for Homebrew (TODO)
  25. IF(WIN32)
  26. MESSAGE(STATUS "Bash competion is not supported on this platform.")
  27. ELSEIF(APPLE)
  28. MESSAGE(STATUS "Bash completion is not yet implemented for this platform.")
  29. ELSE()
  30. INCLUDE(FindUnixCommands)
  31. # Honor manual override if provided
  32. IF(NOT BASHCOMP_PKG_PATH)
  33. # First, use pkg-config, which is the most reliable
  34. FIND_PACKAGE(PkgConfig QUIET)
  35. IF(PKGCONFIG_FOUND)
  36. PKG_CHECK_MODULES(BASH_COMPLETION bash-completion)
  37. PKG_GET_VARIABLE(BASHCOMP_PKG_PATH bash-completion completionsdir)
  38. ELSE()
  39. # Second, use cmake (preferred but less common)
  40. FIND_PACKAGE(bash-completion QUIET)
  41. IF(BASH_COMPLETION_FOUND)
  42. SET(BASHCOMP_PKG_PATH "${BASH_COMPLETION_COMPLETIONSDIR}")
  43. ENDIF()
  44. ENDIF()
  45. # Third, use a hard-coded fallback value
  46. IF("${BASHCOMP_PKG_PATH}" STREQUAL "")
  47. SET(BASHCOMP_PKG_PATH "/usr/share/bash-completion/completions")
  48. ENDIF()
  49. ENDIF()
  50. # Always provide a fallback for non-root INSTALL()
  51. SET(BASHCOMP_USER_PATH "${CMAKE_INSTALL_PREFIX}/share/bash-completion/completions")
  52. # Cmake doesn't allow easy use of conditional logic at INSTALL() time
  53. # this is a problem because ${BASHCOMP_PKG_PATH} may not be writable and we
  54. # need sane fallback behavior for bundled INSTALL() (e.g. .AppImage, etc).
  55. #
  56. # The reason this can't be detected by cmake is that it's fairly common to
  57. # run "cmake" as a one user (i.e. non-root) and "make install" as another user
  58. # (i.e. root).
  59. #
  60. # - Creates a script called "install_${SCRIPT_NAME}_completion.sh" into the
  61. # working binary directory and invokes this script at install.
  62. # - Script handles INSTALL()-time conditional logic for sane ballback behavior
  63. # when ${BASHCOMP_PKG_PATH} is unwritable (i.e. non-root); Something cmake
  64. # can't handle on its own at INSTALL() time)
  65. MACRO(BASHCOMP_INSTALL SCRIPT_NAME)
  66. # A shell script for wrapping conditionl logic
  67. SET(BASHCOMP_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_${SCRIPT_NAME}_completion.sh")
  68. FILE(WRITE ${BASHCOMP_SCRIPT} "\
  69. #!${BASH}\n\
  70. set -e\n\
  71. if [ -w \"${BASHCOMP_PKG_PATH}\" ]; then\n\
  72. BASHCOMP_PKG_PATH=\"${BASHCOMP_PKG_PATH}\"\n\
  73. else \n\
  74. BASHCOMP_PKG_PATH=\"\$DESTDIR${BASHCOMP_USER_PATH}\"\n\
  75. fi\n\
  76. echo -e \"\\nInstalling bash completion...\\n\"\n\
  77. mkdir -p \"\$BASHCOMP_PKG_PATH\"\n\
  78. cp \"${CMAKE_CURRENT_SOURCE_DIR}/${SCRIPT_NAME}\" \"\$BASHCOMP_PKG_PATH\"\n\
  79. chmod a+r \"\$BASHCOMP_PKG_PATH/${SCRIPT_NAME}\"\n\
  80. echo -e \"Bash completion for ${SCRIPT_NAME} has been installed to \$BASHCOMP_PKG_PATH/${SCRIPT_NAME}\"\n\
  81. ")
  82. INSTALL(CODE "EXECUTE_PROCESS(COMMAND chmod u+x \"install_${SCRIPT_NAME}_completion.sh\" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )")
  83. INSTALL(CODE "EXECUTE_PROCESS(COMMAND \"./install_${SCRIPT_NAME}_completion.sh\" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )")
  84. MESSAGE(STATUS "Bash completion script for ${SCRIPT_NAME} will be installed to ${BASHCOMP_PKG_PATH} or fallback to ${BASHCOMP_USER_PATH} if unwritable.")
  85. ENDMACRO()
  86. ENDIF()