From d0dc0e1a32d6ed9b166eca777f7fb7071c4c2df1 Mon Sep 17 00:00:00 2001 From: Levente Polyak Date: Fri, 5 Jan 2024 19:23:52 +0100 Subject: feat(search): add optional plain output formatting This allows to run the search command without bats, which is not used in the default pretty output format. Component: pkgctl search Signed-off-by: Levente Polyak --- README.md | 5 +- contrib/completion/bash/devtools.in | 11 ++++- contrib/completion/zsh/_devtools.in | 6 ++- doc/man/pkgctl-search.1.asciidoc | 23 +++++++-- src/lib/common.sh | 4 +- src/lib/search.sh | 93 +++++++++++++++++++++++++++++++++---- src/lib/valid-search.sh | 11 +++++ 7 files changed, 134 insertions(+), 19 deletions(-) create mode 100644 src/lib/valid-search.sh diff --git a/README.md b/README.md index 6c36a37..ca761db 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,6 @@ Component: pkgctl db remove - arch-install-scripts - awk - bash -- bats - binutils - coreutils - diffutils @@ -87,6 +86,10 @@ Component: pkgctl db remove - mercurial - subversion +### Optional Dependencies + +- bats (pretty printing) + ### Development Dependencies - asciidoc diff --git a/contrib/completion/bash/devtools.in b/contrib/completion/bash/devtools.in index 155bb7e..4c7b73a 100644 --- a/contrib/completion/bash/devtools.in +++ b/contrib/completion/bash/devtools.in @@ -9,6 +9,8 @@ source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-tags.sh source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh # shellcheck source=src/lib/valid-inspect.sh source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-inspect.sh +# shellcheck source=src/lib/valid-search.sh +source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-search.sh _binary_arch=${DEVTOOLS_VALID_ARCHES[*]:0:-1} _colors=(never always auto) @@ -333,11 +335,15 @@ _pkgctl_repo_web_opts() { _filedir -d; } _pkgctl_search_args=( - --json --no-default-filter + --json + -F --format + -N --no-line-number -h --help ) _pkgctl_search_opts() { :; } +_pkgctl_search_args__format_opts() { _devtools_completions_search_format; } +_pkgctl_search_args_F_opts() { _devtools_completions_search_format; } _pkgctl_diff_args=( @@ -391,6 +397,9 @@ _devtools_completions_protocol() { _devtools_completions_inspect() { mapfile -t COMPREPLY < <(compgen -W "${DEVTOOLS_VALID_INSPECT_MODES[*]}" -- "$cur") } +_devtools_completions_search_format() { + mapfile -t COMPREPLY < <(compgen -W "${valid_search_output_format[*]}" -- "$cur") +} __devtools_complete() { local service=$1 diff --git a/contrib/completion/zsh/_devtools.in b/contrib/completion/zsh/_devtools.in index 120b47a..448fbed 100644 --- a/contrib/completion/zsh/_devtools.in +++ b/contrib/completion/zsh/_devtools.in @@ -9,6 +9,8 @@ source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-tags.sh source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh # shellcheck source=src/lib/valid-inspect.sh source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-inspect.sh +# shellcheck source=src/lib/valid-search.sh +source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-search.sh _binary_arch=${DEVTOOLS_VALID_ARCHES[*]:0:-1} _colors=(never always auto) @@ -140,8 +142,10 @@ _pkgctl_repo_web_args=( ) _pkgctl_search_args=( - '--json[Enable printing results in JSON]' '--no-default-filter[Do not apply default filter (like -path:keys/pgp/*.asc)]' + '--json[Enable printing results in JSON]' + '(-F --format)'{-F,--format}"[Controls the formatting of the results]:format:($valid_search_output_format[*])" + '(-N --no-line-number)'{-N,--no-line-number}"[Don't show line numbers when formatting results]" '(-h --help)'{-h,--help}'[Display usage]' '1:query' ) diff --git a/doc/man/pkgctl-search.1.asciidoc b/doc/man/pkgctl-search.1.asciidoc index fb79b88..8172b00 100644 --- a/doc/man/pkgctl-search.1.asciidoc +++ b/doc/man/pkgctl-search.1.asciidoc @@ -20,7 +20,7 @@ use glob matching. Available filters for the blobs scope: path, extension Every usage of the search command must be authenticated. Consult the -'pkgctl auth' command to authenticate with GitLab or view the authentication +`'pkgctl auth'` command to authenticate with GitLab or view the authentication status. Search Tips @@ -41,14 +41,27 @@ Search Tips Options ------- -*--json*:: - Enable printing results in JSON +*-h, --help*:: + Show a help text + +Filter Options +-------------- *--no-default-filter*:: Do not apply default filter (like -path:keys/pgp/*.asc) -*-h, --help*:: - Show a help text +Output Options +-------------- + +*--json*:: + Enable printing in JSON; Shorthand for `'--format json'` + +*-F, --format* 'FORMAT':: + Controls the formatting of the results; `FORMAT` is `'pretty'`, `'plain'`, + or `'json'` (default `pretty`) + +*-N, --no-line-number*:: + Don't show line numbers when formatting results See Also -------- diff --git a/src/lib/common.sh b/src/lib/common.sh index 29b0343..17b91bc 100644 --- a/src/lib/common.sh +++ b/src/lib/common.sh @@ -33,9 +33,11 @@ export PKGBASE_MAINTAINER_URL=https://archlinux.org/packages/pkgbase-maintainer # check if messages are to be printed using color if [[ -t 2 && "$TERM" != dumb ]] || [[ ${DEVTOOLS_COLOR} == always ]]; then colorize + PURPLE="$(tput setaf 5)" + DARK_GREEN="$(tput setaf 2)" else # shellcheck disable=2034 - declare -gr ALL_OFF='' BOLD='' BLUE='' GREEN='' RED='' YELLOW='' + declare -gr ALL_OFF='' BOLD='' BLUE='' GREEN='' RED='' YELLOW='' PURPLE='' fi stat_busy() { diff --git a/src/lib/search.sh b/src/lib/search.sh index cf64db3..862af25 100644 --- a/src/lib/search.sh +++ b/src/lib/search.sh @@ -12,7 +12,10 @@ source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh source "${_DEVTOOLS_LIBRARY_DIR}"/lib/cache.sh # shellcheck source=src/lib/api/gitlab.sh source "${_DEVTOOLS_LIBRARY_DIR}"/lib/api/gitlab.sh +# shellcheck source=src/lib/valid-search.sh +source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-search.sh +source /usr/share/makepkg/util/util.sh source /usr/share/makepkg/util/message.sh set -eo pipefail @@ -48,16 +51,33 @@ pkgctl_search_usage() { ! Merge request !23456 OPTIONS - --json Enable printing results in JSON - --no-default-filter Do not apply default filter (like -path:keys/pgp/*.asc) - -h, --help Show this help text + -h, --help Show this help text + + FILTER OPTIONS + --no-default-filter Do not apply default filter (like -path:keys/pgp/*.asc) + + OUTPUT OPTIONS + --json Enable printing in JSON; Shorthand for '--format json' + -F, --format FORMAT Controls the formatting of the results; FORMAT is 'pretty', + 'plain', or 'json' (default: pretty) + -N, --no-line-number Don't show line numbers when formatting results EXAMPLES $ ${COMMAND} linux - $ ${COMMAND} '"pytest -v" +PYTHONPATH' + $ ${COMMAND} --json '"pytest -v" +PYTHONPATH' _EOF_ } +pkgctl_search_check_option_group_format() { + local option=$1 + local output_format=$2 + if [[ -n ${output_format} ]]; then + die "The argument '%s' cannot be used with one or more of the other specified arguments" "${option}" + exit 1 + fi + return 0 +} + pkgctl_search() { if (( $# < 1 )); then pkgctl_search_usage @@ -66,15 +86,17 @@ pkgctl_search() { # options local search - local formatter=pretty + local output_format= local use_default_filter=1 + local line_numbers=1 # variables + local bats_style="header,grid" local default_filter="-path:keys/pgp/*.asc" local graphql_lookup_batch=200 local output result query entries from until length local project_name_cache_file project_name_lookup project_ids project_id project_name project_slice - local mapping_output path startline data + local mapping_output path startline currentline data line while (( $# )); do case $1 in @@ -82,12 +104,26 @@ pkgctl_search() { pkgctl_search_usage exit 0 ;; + --no-default-filter) + use_default_filter=0 + shift + ;; --json) - formatter=json + pkgctl_search_check_option_group_format "$1" "${output_format}" + output_format=json shift ;; - --no-default-filter) - use_default_filter=0 + -F|--format) + (( $# <= 1 )) && die "missing argument for %s" "$1" + pkgctl_search_check_option_group_format "$1" "${output_format}" + output_format="${2}" + if ! in_array "${output_format}" "${valid_search_output_format[@]}"; then + die "Unknown output format: %s" "${output_format}" + fi + shift 2 + ;; + -N|--no-line-number) + line_numbers=0 shift ;; --) @@ -114,16 +150,35 @@ pkgctl_search() { search+=" ${default_filter}" fi + # assign default output format + if [[ -z ${output_format} ]]; then + output_format=pretty + fi + + # check for optional dependencies + if [[ ${output_format} == pretty ]] && ! command -v bats &>/dev/null; then + warning "Failed to find optional dependency 'bats': falling back to plain output" + output_format=plain + fi + + # populate line numbers option + if (( line_numbers )); then + bats_style="numbers,${bats_style}" + fi + + # call the gitlab search API stat_busy "Querying gitlab search api" output=$(gitlab_api_search "${search}") stat_done + # collect project ids whose name needs to be looked up project_name_cache_file=$(get_cache_file gitlab/project_id_to_name) lock 11 "${project_name_cache_file}" "Locking project name cache" mapfile -t project_ids < <( jq --raw-output '[.[].project_id] | unique[]' <<< "${output}" | \ grep --invert-match --file <(awk '{ print $1 }' < "${project_name_cache_file}" )) + # look up project names stat_busy "Querying project names" local entries="${#project_ids[@]}" local until=0 @@ -171,7 +226,7 @@ pkgctl_search() { lock_close 11 # output mode JSON - if [[ ${formatter} == json ]]; then + if [[ ${output_format} == json ]]; then jq --from-file <( for project_id in $(jq '.[].project_id' <<< "${output}"); do project_name=${project_name_lookup[${project_id}]} @@ -197,6 +252,23 @@ pkgctl_search() { unset "data[${#data[@]}-1]" fi + # output mode plain + if [[ ${output_format} == plain ]]; then + printf "%s%s%s\n" "${PURPLE}" "${project_name}/${path}" "${ALL_OFF}" + + currentline=${startline} + for line in "${data[@]}"; do + if (( line_numbers )); then + line="${DARK_GREEN}${currentline}${ALL_OFF}: ${line}" + currentline=$(( currentline + 1 )) + fi + printf "%s\n" "${line}" + done + printf "\n" + + continue + fi + # prepend empty lines to match startline if (( startline > 1 )); then mapfile -t data < <( @@ -210,6 +282,7 @@ pkgctl_search() { --line-range "${startline}:" \ --paging=never \ --force-colorization \ + --style "${bats_style}" \ --map-syntax "PKGBUILD:Bourne Again Shell (bash)" \ --map-syntax ".SRCINFO:INI" \ --map-syntax "*install:Bourne Again Shell (bash)" \ diff --git a/src/lib/valid-search.sh b/src/lib/valid-search.sh new file mode 100644 index 0000000..43799a5 --- /dev/null +++ b/src/lib/valid-search.sh @@ -0,0 +1,11 @@ +#!/hint/bash +# +# SPDX-License-Identifier: GPL-3.0-or-later +: + +# shellcheck disable=2034 +valid_search_output_format=( + pretty + plain + json +) -- cgit v1.2.3-54-g00ecf