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 <anthraxx@archlinux.org>
This commit is contained in:
Levente Polyak 2024-01-05 19:23:52 +01:00
parent 0e538cf498
commit d0dc0e1a32
No known key found for this signature in database
GPG Key ID: FC1B547C8D8172C8
7 changed files with 135 additions and 20 deletions

View File

@ -67,7 +67,6 @@ Component: pkgctl db remove
- arch-install-scripts - arch-install-scripts
- awk - awk
- bash - bash
- bats
- binutils - binutils
- coreutils - coreutils
- diffutils - diffutils
@ -87,6 +86,10 @@ Component: pkgctl db remove
- mercurial - mercurial
- subversion - subversion
### Optional Dependencies
- bats (pretty printing)
### Development Dependencies ### Development Dependencies
- asciidoc - asciidoc

View File

@ -9,6 +9,8 @@ source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-tags.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh
# shellcheck source=src/lib/valid-inspect.sh # shellcheck source=src/lib/valid-inspect.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/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} _binary_arch=${DEVTOOLS_VALID_ARCHES[*]:0:-1}
_colors=(never always auto) _colors=(never always auto)
@ -333,11 +335,15 @@ _pkgctl_repo_web_opts() { _filedir -d; }
_pkgctl_search_args=( _pkgctl_search_args=(
--json
--no-default-filter --no-default-filter
--json
-F --format
-N --no-line-number
-h --help -h --help
) )
_pkgctl_search_opts() { :; } _pkgctl_search_opts() { :; }
_pkgctl_search_args__format_opts() { _devtools_completions_search_format; }
_pkgctl_search_args_F_opts() { _devtools_completions_search_format; }
_pkgctl_diff_args=( _pkgctl_diff_args=(
@ -391,6 +397,9 @@ _devtools_completions_protocol() {
_devtools_completions_inspect() { _devtools_completions_inspect() {
mapfile -t COMPREPLY < <(compgen -W "${DEVTOOLS_VALID_INSPECT_MODES[*]}" -- "$cur") 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() { __devtools_complete() {
local service=$1 local service=$1

View File

@ -9,6 +9,8 @@ source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-tags.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh
# shellcheck source=src/lib/valid-inspect.sh # shellcheck source=src/lib/valid-inspect.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/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} _binary_arch=${DEVTOOLS_VALID_ARCHES[*]:0:-1}
_colors=(never always auto) _colors=(never always auto)
@ -140,8 +142,10 @@ _pkgctl_repo_web_args=(
) )
_pkgctl_search_args=( _pkgctl_search_args=(
'--json[Enable printing results in JSON]'
'--no-default-filter[Do not apply default filter (like -path:keys/pgp/*.asc)]' '--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]' '(-h --help)'{-h,--help}'[Display usage]'
'1:query' '1:query'
) )

View File

@ -20,7 +20,7 @@ use glob matching.
Available filters for the blobs scope: path, extension Available filters for the blobs scope: path, extension
Every usage of the search command must be authenticated. Consult the 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. status.
Search Tips Search Tips
@ -41,14 +41,27 @@ Search Tips
Options Options
------- -------
*--json*:: *-h, --help*::
Enable printing results in JSON Show a help text
Filter Options
--------------
*--no-default-filter*:: *--no-default-filter*::
Do not apply default filter (like -path:keys/pgp/*.asc) Do not apply default filter (like -path:keys/pgp/*.asc)
*-h, --help*:: Output Options
Show a help text --------------
*--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 See Also
-------- --------

View File

@ -33,9 +33,11 @@ export PKGBASE_MAINTAINER_URL=https://archlinux.org/packages/pkgbase-maintainer
# check if messages are to be printed using color # check if messages are to be printed using color
if [[ -t 2 && "$TERM" != dumb ]] || [[ ${DEVTOOLS_COLOR} == always ]]; then if [[ -t 2 && "$TERM" != dumb ]] || [[ ${DEVTOOLS_COLOR} == always ]]; then
colorize colorize
PURPLE="$(tput setaf 5)"
DARK_GREEN="$(tput setaf 2)"
else else
# shellcheck disable=2034 # shellcheck disable=2034
declare -gr ALL_OFF='' BOLD='' BLUE='' GREEN='' RED='' YELLOW='' declare -gr ALL_OFF='' BOLD='' BLUE='' GREEN='' RED='' YELLOW='' PURPLE=''
fi fi
stat_busy() { stat_busy() {

View File

@ -12,7 +12,10 @@ source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/cache.sh source "${_DEVTOOLS_LIBRARY_DIR}"/lib/cache.sh
# shellcheck source=src/lib/api/gitlab.sh # shellcheck source=src/lib/api/gitlab.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/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 source /usr/share/makepkg/util/message.sh
set -eo pipefail set -eo pipefail
@ -48,16 +51,33 @@ pkgctl_search_usage() {
! Merge request !23456 ! Merge request !23456
OPTIONS OPTIONS
--json Enable printing results in JSON -h, --help Show this help text
--no-default-filter Do not apply default filter (like -path:keys/pgp/*.asc)
-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 EXAMPLES
$ ${COMMAND} linux $ ${COMMAND} linux
$ ${COMMAND} '"pytest -v" +PYTHONPATH' $ ${COMMAND} --json '"pytest -v" +PYTHONPATH'
_EOF_ _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() { pkgctl_search() {
if (( $# < 1 )); then if (( $# < 1 )); then
pkgctl_search_usage pkgctl_search_usage
@ -66,15 +86,17 @@ pkgctl_search() {
# options # options
local search local search
local formatter=pretty local output_format=
local use_default_filter=1 local use_default_filter=1
local line_numbers=1
# variables # variables
local bats_style="header,grid"
local default_filter="-path:keys/pgp/*.asc" local default_filter="-path:keys/pgp/*.asc"
local graphql_lookup_batch=200 local graphql_lookup_batch=200
local output result query entries from until length 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 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 while (( $# )); do
case $1 in case $1 in
@ -82,14 +104,28 @@ pkgctl_search() {
pkgctl_search_usage pkgctl_search_usage
exit 0 exit 0
;; ;;
--json)
formatter=json
shift
;;
--no-default-filter) --no-default-filter)
use_default_filter=0 use_default_filter=0
shift shift
;; ;;
--json)
pkgctl_search_check_option_group_format "$1" "${output_format}"
output_format=json
shift
;;
-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
;;
--) --)
shift shift
break break
@ -114,16 +150,35 @@ pkgctl_search() {
search+=" ${default_filter}" search+=" ${default_filter}"
fi 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" stat_busy "Querying gitlab search api"
output=$(gitlab_api_search "${search}") output=$(gitlab_api_search "${search}")
stat_done stat_done
# collect project ids whose name needs to be looked up
project_name_cache_file=$(get_cache_file gitlab/project_id_to_name) project_name_cache_file=$(get_cache_file gitlab/project_id_to_name)
lock 11 "${project_name_cache_file}" "Locking project name cache" lock 11 "${project_name_cache_file}" "Locking project name cache"
mapfile -t project_ids < <( mapfile -t project_ids < <(
jq --raw-output '[.[].project_id] | unique[]' <<< "${output}" | \ jq --raw-output '[.[].project_id] | unique[]' <<< "${output}" | \
grep --invert-match --file <(awk '{ print $1 }' < "${project_name_cache_file}" )) grep --invert-match --file <(awk '{ print $1 }' < "${project_name_cache_file}" ))
# look up project names
stat_busy "Querying project names" stat_busy "Querying project names"
local entries="${#project_ids[@]}" local entries="${#project_ids[@]}"
local until=0 local until=0
@ -171,7 +226,7 @@ pkgctl_search() {
lock_close 11 lock_close 11
# output mode JSON # output mode JSON
if [[ ${formatter} == json ]]; then if [[ ${output_format} == json ]]; then
jq --from-file <( jq --from-file <(
for project_id in $(jq '.[].project_id' <<< "${output}"); do for project_id in $(jq '.[].project_id' <<< "${output}"); do
project_name=${project_name_lookup[${project_id}]} project_name=${project_name_lookup[${project_id}]}
@ -197,6 +252,23 @@ pkgctl_search() {
unset "data[${#data[@]}-1]" unset "data[${#data[@]}-1]"
fi 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 # prepend empty lines to match startline
if (( startline > 1 )); then if (( startline > 1 )); then
mapfile -t data < <( mapfile -t data < <(
@ -210,6 +282,7 @@ pkgctl_search() {
--line-range "${startline}:" \ --line-range "${startline}:" \
--paging=never \ --paging=never \
--force-colorization \ --force-colorization \
--style "${bats_style}" \
--map-syntax "PKGBUILD:Bourne Again Shell (bash)" \ --map-syntax "PKGBUILD:Bourne Again Shell (bash)" \
--map-syntax ".SRCINFO:INI" \ --map-syntax ".SRCINFO:INI" \
--map-syntax "*install:Bourne Again Shell (bash)" \ --map-syntax "*install:Bourne Again Shell (bash)" \

11
src/lib/valid-search.sh Normal file
View File

@ -0,0 +1,11 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
:
# shellcheck disable=2034
valid_search_output_format=(
pretty
plain
json
)