@@ -55,6 +55,8 @@ libdir_relative ?= $(libdir_relative_temp)
prefix ?= /usr/local
man_dir ?= $(prefix)/share/man
man_dir_SQ = '$(subst ','\'',$(man_dir))'
+completion_dir ?= $(prefix)/share/bash-completion/completions
+completion_dir_SQ = '$(subst ','\'',$(completion_dir))'
libdir ?= $(prefix)/$(libdir_relative)
libdir_SQ = '$(subst ','\'',$(libdir))'
includedir_relative ?= include/tracefs
@@ -86,9 +88,6 @@ else
PREF_DEFINED := 0
endif
-etcdir ?= /etc
-etcdir_SQ = '$(subst ','\'',$(etcdir))'
-
export man_dir man_dir_SQ html_install html_install_SQ INSTALL
export img_install img_install_SQ
export DESTDIR DESTDIR_SQ
@@ -100,8 +99,6 @@ HELP_DIR = -DHELP_DIR=$(html_install)
HELP_DIR_SQ = '$(subst ','\'',$(HELP_DIR))'
#' emacs highlighting gets confused by the above escaped quote.
-BASH_COMPLETE_DIR ?= $(etcdir)/bash_completion.d
-
# copy a bit from Linux kbuild
ifeq ("$(origin V)", "command line")
@@ -300,7 +297,10 @@ install_libs: libs install_pkgconfig
$(Q)$(call do_install,$(src)/include/tracefs.h,$(includedir_SQ),644)
$(Q)$(call install_ld_config)
-install: install_libs
+install_bash_completion: force
+ $(Q)$(call do_install_data,$(src)/src/tracefs_sql.bash,$(completion_dir))
+
+install: install_libs install_bash_completion
install_pkgconfig: $(PKG_CONFIG_FILE)
$(Q)$(call , $(PKG_CONFIG_FILE)) \
@@ -21,6 +21,7 @@ threads_dep = dependency('threads', required: true)
cunit_dep = dependency('cunit', required : false)
prefixdir = get_option('prefix')
+datadir = join_paths(prefixdir, get_option('datadir'))
bindir = join_paths(prefixdir, get_option('bindir'))
mandir = join_paths(prefixdir, get_option('mandir'))
htmldir = join_paths(prefixdir, get_option('htmldir'))
@@ -187,6 +187,14 @@ define do_install
$(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR_SQ)$2'
endef
+define do_install_data
+ $(print_install) \
+ if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
+ fi; \
+ $(INSTALL) -m 644 $1 '$(DESTDIR_SQ)$2'
+endef
+
define do_install_pkgconfig_file
if [ -n "${pkgconfig_dir}" ]; then \
$(call do_install,$(PKG_CONFIG_FILE),$(pkgconfig_dir),644); \
@@ -63,3 +63,7 @@ pkg.generate(
libtracefs_dep = declare_dependency(
include_directories: ['.'],
link_with: libtracefs)
+
+install_data(
+ 'tracefs_sql.bash',
+ install_dir: datadir + '/bash-completion/completions')
new file mode 100644
@@ -0,0 +1,366 @@
+make_small() {
+ local w=$1
+
+ echo $w | tr A-Z a-z
+}
+
+prev_keyword() {
+ local i=$1
+ shift
+ local words=("$@")
+
+ while [ $i -gt 0 ]; do
+ let i=$i-1
+ local w=$(make_small ${words[$i]})
+
+ case $w in
+ select)
+ echo "select"
+ return
+ ;;
+ from)
+ echo "from"
+ return
+ ;;
+ as)
+ echo "as"
+ return
+ ;;
+ on)
+ echo "on"
+ return
+ ;;
+ join)
+ echo "join"
+ return
+ ;;
+ where)
+ echo "where"
+ return
+ ;;
+ *)
+ if [ "$w" != "${w%%,}" ]; then
+ echo ","
+ return
+ fi
+ if [ "$w" != "${w%%=}" ]; then
+ echo "="
+ return
+ fi
+ if [ "$w" != "${w%%&}" ]; then
+ echo "&"
+ return
+ fi
+ ;;
+ esac
+ done
+ echo ""
+}
+
+prev_command() {
+ local i=$1
+ shift
+ local words=("$@")
+
+ while [ $i -gt 0 ]; do
+ let i=$i-1
+ local w=$(make_small ${words[$i]})
+
+ case $w in
+ select)
+ echo "select"
+ return
+ ;;
+ from)
+ echo "from"
+ return
+ ;;
+ on)
+ echo "on"
+ return
+ ;;
+ join)
+ echo "join"
+ return
+ ;;
+ where)
+ echo "where"
+ return
+ ;;
+ esac
+ done
+ echo ""
+}
+
+add_vars() {
+ local words=("$@")
+
+ local i=$COMP_CWORD
+
+ local event=""
+
+ let found_from=0
+ let found_as=0
+
+ while [ $i -gt 0 ]; do
+ let i=$i-1
+ local w=$(make_small ${words[$i]})
+
+ case $w in
+ "from")
+ let found_from=1
+ ;;
+ "as")
+ # Do not add the event itself if it was used by name
+ if [ $found_as -eq 0 ]; then
+ event=${words[$i-1]};
+ fi
+ let found_as=1
+ ;;
+ *)
+ if [ $found_from -eq 1 ]; then
+ start=$(echo $w | sed -e 's/\.[^\.]*$//')
+ if [ "$start" != "$w" -a "$start" == "${start%%\.*}" -a \
+ "$start" != "$event" ]; then
+ echo -n "$start "
+ fi
+ fi
+ ;;
+ esac
+ done
+}
+
+add_options() {
+ local cur="$1"
+ local list="$2"
+
+ COMPREPLY=( $(compgen -W "${list}" -- "${cur}") )
+}
+
+print_fields() {
+ local event=$1
+ local var=$2
+ local extra=$3
+
+ local list=$(trace-cmd list -e "^${event/\./:}\$" -F | cut -d';' -f1 | sed -ne 's/\t.*:.* \(.*\)/\1/p' |sed -e 's/\[.*\]//')
+
+ for field in $list $extra; do
+ if [ -z "$var" ]; then
+ echo "$event.$field"
+ else
+ echo "$var.$field"
+ fi
+ done
+}
+
+__list_events() {
+ local cur=$1
+
+ local list=$(trace-cmd list -e "$cur")
+ local prefix=${cur%%:*}
+ if [ -z "$cur" -o "$cur" != "$prefix" ]; then
+ echo "${list}"
+ else
+ local events=$(for e in $list; do echo ${e/*:/}; done | sort -u)
+ local systems=$(for s in $list; do echo ${s/:*/:}; done | sort -u)
+
+ echo "${events} ${systems}"
+ fi
+}
+
+select_options() {
+ local cur=$1
+ local extra=$2
+ local list=$(__list_events "${cur/\./:}" | sed -e 's/:/./g')
+ local select_list=" TIMESTAMP_DELTA TIMESTAMP_DELTA_USECS $extra"
+ local select_fields=" TIMESTAMP TIMESTAMP_USECS STACKTRACE COMM"
+ add_options "$cur" "$list $select_list"
+ local cnt=${#COMPREPLY[@]}
+ if [ $cnt -eq 1 ]; then
+ local comp=${COMPREPLY[0]}
+ local w=$(compgen -W "$select_list" -- "$comp" )
+ if [ -z "$w" ]; then
+ COMPREPLY=("$comp.")
+ compopt -o nospace
+ fi
+ elif [ $cnt -eq 0 ]; then
+ local w=$(echo $cur | sed -e 's/\.[^\.]*$//')
+ list=$(print_fields $w "" "$select_fields")
+ COMPREPLY=( $(compgen -W "${list}" -- "${cur}") )
+ fi
+}
+
+check_as() {
+ local words=("$@")
+
+ last_key=$(prev_keyword $COMP_CWORD ${words[@]})
+ if [ "$last_key" != "as" ]; then
+ echo -n "AS"
+ fi
+}
+
+on_list() {
+ local type=$1
+ shift
+ local words=("$@")
+
+ local i=$COMP_CWORD
+
+ local var=""
+
+ while [ $i -gt 0 ]; do
+ let i=$i-1
+ local w=$(make_small ${words[$i]})
+ case $w in
+ "from"|"join")
+ if [ $w == $type ]; then
+ print_fields ${words[$i+1]} "$var"
+ return
+ fi
+ var=""
+ ;;
+ as)
+ var=${words[$i+1]}
+ ;;
+ esac
+ done
+}
+
+update_completion() {
+ local cur=$1
+ shift
+ local words=("$@")
+
+ if [ ${#COMPREPLY[@]} -gt 0 ]; then
+ return
+ fi
+
+ for w in ${words[@]}; do
+ if [ "$w" != "${w##$cur}" ]; then
+ COMPREPLY=("$w")
+ return
+ fi
+ done
+}
+
+# return 0 if it was handled, otherwise return 1
+tracefs_sql_completion()
+{
+ local prev=$1
+ local cur=$2
+ shift 2
+ local words=("$@")
+
+ if [ "$cur" != "${cur%%,}" ]; then
+ COMPREPLY=("$cur")
+ return 0
+ fi
+
+ local p=$(make_small $prev)
+
+ if [ "$p" != "${p%%,}" ]; then
+ p=$(prev_command $COMP_CWORD ${words[@]})
+ fi
+
+ case "$p" in
+ "select")
+ select_options "$cur"
+ ;;
+ "on")
+ list=$(on_list "from" ${words[@]})
+ add_options "$cur" "$list"
+ ;;
+ "where")
+ flist=$(on_list "from" ${words[@]})
+ jlist=$(on_list "join" ${words[@]})
+ add_options "$cur" "$flist $jlist"
+ ;;
+ "as")
+ local last_cmd=$(prev_command $COMP_CWORD ${words[@]})
+ case $last_cmd in
+ "select")
+ if [ ! -z "$cur" ]; then
+ COMPREPLY=("$cur" "$cur,")
+ fi
+ ;;
+ "from"|"join")
+ list=$(add_vars ${words[@]})
+ if [ ! -z "$list" ]; then
+ add_options "$cur" "$list"
+ fi
+ ;;
+ esac
+ ;;
+ "from"|"join")
+ local list=$(trace-cmd list -e "${cur/\./:}" | tr : .)
+ local prefix=${cur/\./}
+ if [ -z "$cur" -o "$cur" != "$prefix" ]; then
+ COMPREPLY=( $(compgen -W "${list}" -- "${cur}") )
+ else
+ local events=$(for e in $list; do echo ${e/*\./}; done | sort -u)
+ local systems=$(for s in $list; do echo ${s/\.*/.}; done | sort -u)
+
+ COMPREPLY=( $(compgen -W "all ${events} ${systems}" -- "${cur}") )
+ fi
+ ;;
+ # TIMESTAMP_DELTA must be labeled
+ "timestamp_delta"|"timestamp_delta_usecs")
+ COMPREPLY=( $(compgen -W "AS" -- "${cur}") )
+ update_completion "$cur" "as"
+ ;;
+ *)
+ local last_cmd=$(prev_command $COMP_CWORD ${words[@]})
+ local list=$(check_as ${words[@]})
+ local alist=""
+ if [ ! -z "$list" ]; then
+ alist="as"
+ fi
+ case $last_cmd in
+ "select")
+ if [ "$cur" != "${cur%%,}" ]; then
+ select_options "$cur" "$list"
+ else
+ add_options "$cur" "FROM , $list"
+ update_completion "$cur" from $alist
+ fi
+ ;;
+ "from")
+ add_options "$cur" "JOIN $list"
+ update_completion "$cur" join $alist
+ ;;
+ "join")
+ add_options "$cur" "ON $list"
+ update_completion "$cur" on $alist
+ ;;
+ "on")
+ if [ "$cur" != "${cur%%=}" ]; then
+ COMPREPLY=("")
+ else
+ last_key=$(prev_keyword $COMP_CWORD ${words[@]})
+ if [ "$last_key" == "=" ]; then
+ if [ $prev == "=" ]; then
+ list=$(on_list "join" ${words[@]})
+ add_options "$cur" "$list"
+ else
+ add_options "$cur" "WHERE"
+ update_completion "$cur" where
+ fi
+ else
+ add_options "$cur" "="
+ fi
+ fi
+ ;;
+ "where")
+ if [ "$cur" != "${cur%%[=&]}" ]; then
+ COMPREPLY=("")
+ else
+ add_options "$cur" "== != &"
+ fi
+ ;;
+ *)
+ return 1
+ esac
+ ;;
+ esac
+ return 0
+}