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().
5 # See also https://github.com/scop/bash-completion
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.
12 # INCLUDE(BashCompletion)
13 # BASHCOMP_INSTALL(foo)
14 # ... where "foo" is a shell script adjacent to the CMakeLists.txt
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.
24 # - Windows does not support bash completion
25 # - macOS support should eventually be added for Homebrew (TODO)
27 MESSAGE(STATUS "Bash completion is not supported on this platform.")
29 MESSAGE(STATUS "Bash completion is not yet implemented for this platform.")
31 INCLUDE(FindUnixCommands)
32 # Honor manual override if provided
33 IF(NOT BASHCOMP_PKG_PATH)
34 # First, use pkg-config, which is the most reliable
35 FIND_PACKAGE(PkgConfig QUIET)
37 PKG_CHECK_MODULES(BASH_COMPLETION bash-completion)
38 PKG_GET_VARIABLE(BASHCOMP_PKG_PATH bash-completion completionsdir)
40 # Second, use cmake (preferred but less common)
41 FIND_PACKAGE(bash-completion QUIET)
42 IF(BASH_COMPLETION_FOUND)
43 SET(BASHCOMP_PKG_PATH "${BASH_COMPLETION_COMPLETIONSDIR}")
47 # Third, use a hard-coded fallback value
48 IF("${BASHCOMP_PKG_PATH}" STREQUAL "")
49 SET(BASHCOMP_PKG_PATH "/usr/share/bash-completion/completions")
53 # Always provide a fallback for non-root INSTALL()
54 SET(BASHCOMP_USER_PATH "${CMAKE_INSTALL_PREFIX}/share/bash-completion/completions")
56 # Cmake doesn't allow easy use of conditional logic at INSTALL() time
57 # this is a problem because ${BASHCOMP_PKG_PATH} may not be writable and we
58 # need sane fallback behavior for bundled INSTALL() (e.g. .AppImage, etc).
60 # The reason this can't be detected by cmake is that it's fairly common to
61 # run "cmake" as a one user (i.e. non-root) and "make install" as another user
64 # - Creates a script called "install_${SCRIPT_NAME}_completion.sh" into the
65 # working binary directory and invokes this script at install.
66 # - Script handles INSTALL()-time conditional logic for sane ballback behavior
67 # when ${BASHCOMP_PKG_PATH} is unwritable (i.e. non-root); Something cmake
68 # can't handle on its own at INSTALL() time)
69 MACRO(BASHCOMP_INSTALL SCRIPT_NAME)
70 # A shell script for wrapping conditionl logic
71 SET(BASHCOMP_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_${SCRIPT_NAME}_completion.sh")
73 FILE(WRITE ${BASHCOMP_SCRIPT} "\
76 BASHCOMP_PKG_PATH=\"${BASHCOMP_USER_PATH}\"\n\
77 if [ -n \"${BASHCOMP_PKG_PATH}\" ]; then\n\
78 BASHCOMP_PKG_PATH=\"${BASHCOMP_PKG_PATH}\"\n\
80 echo -e \"\\nInstalling bash completion...\\n\"\n\
81 mkdir -p \"\${DESTDIR}/$BASHCOMP_PKG_PATH\"\n\
82 cp \"${CMAKE_CURRENT_BINARY_DIR}/${SCRIPT_NAME}\" \"\${DESTDIR}/$BASHCOMP_PKG_PATH\"\n\
83 chmod a+r \"\${DESTDIR}/$BASHCOMP_PKG_PATH/${SCRIPT_NAME}\"\n\
84 echo -e \"Bash completion for ${SCRIPT_NAME} has been installed to \${DESTDIR}/$BASHCOMP_PKG_PATH/${SCRIPT_NAME}\"\n\
86 INSTALL(CODE "EXECUTE_PROCESS(COMMAND chmod u+x \"install_${SCRIPT_NAME}_completion.sh\" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )")
87 INSTALL(CODE "EXECUTE_PROCESS(COMMAND \"./install_${SCRIPT_NAME}_completion.sh\" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )")
89 MESSAGE(STATUS "Bash completion script for ${SCRIPT_NAME} will be installed to ${DESTDIR}/${BASHCOMP_PKG_PATH} or fallback to ${BASHCOMP_USER_PATH} if unwritable.")