15 aururl="https://aur.archlinux.org/"
16 pacman_config="/etc/pacman.conf"
19 # https://github.com/FascodeNet/alterlinux/blob/dev/tools/msg.sh の変数名にアンダーバーを追加し関数化
21 local OPTIND OPTARG arg
23 local _appname="msg.sh"
24 local _bash_debug=false
28 local _msg_type="info"
30 local _label_space="7"
32 local _customized_label=false
33 local _customized_label_color=false
35 local _noappname=false
37 local _output="stdout"
40 echo "usage ${0} [option] [type] [message]"
42 echo "Display a message with a colored app name and message type label"
45 echo " info General message"
46 echo " warn Warning message"
47 echo " error Error message"
48 echo " debug Debug message"
50 echo " General options:"
51 echo " -a [name] Specify the app name"
52 echo " -c [character] Specify the character to adjust the label"
53 echo " -l [label] Specify the label."
54 echo " -n | --nocolor No output colored output"
55 echo " -o [option] Specify echo options"
56 echo " -r [color] Specify the color of label"
57 echo " -s [number] Specifies the label space."
58 echo " -x | --bash-debug Enables output bash debugging"
59 echo " -h | --help This help message"
61 echo " --nolabel Do not output label"
62 echo " --noappname Do not output app name"
63 echo " --noadjust Do not adjust the width of the label"
66 while getopts "a:c:l:no:r:s:xh-:" arg; do
72 _adjust_chr="${OPTARG}"
75 _customized_label=true
76 _msg_label="${OPTARG}"
82 _echo_opts="${OPTARG}"
85 _customized_label_color=true
117 _label_space="${OPTARG}"
158 shift $((OPTIND - 1))
183 # You can specify multiple decorations with ;.
184 # 0 => All attributs off (ノーマル)
186 # 4 => Underscore (下線)
188 # 7 => Reverse video on (色反転)
195 [[ "${_customized_label_color}" = false ]] && _labelcolor="32"
196 [[ "${_customized_label}" = false ]] && _msg_label="Info"
202 [[ "${_customized_label_color}" = false ]] && _labelcolor="33"
203 [[ "${_customized_label}" = false ]] && _msg_label="Warning"
209 [[ "${_customized_label_color}" = false ]] && _labelcolor="35"
210 [[ "${_customized_label}" = false ]] && _msg_label="Debug"
216 [[ "${_customized_label_color}" = false ]] && _labelcolor="31"
217 [[ "${_customized_label}" = false ]] && _msg_label="Error"
221 echo "Please specify the message type" >&2
225 echo "Unknown message type" >&2
230 _word_count="${#_msg_label}"
235 if [[ "${_nolabel}" = false ]]; then
236 if [[ "${_noadjust}" = false ]]; then
237 for __time in $( seq 1 $(( ${_label_space} - ${_word_count})) ); do
238 echo -ne "${_adjust_chr}"
241 if [[ "${_nocolor}" = false ]]; then
242 echo -ne "\e[$([[ -v _backcolor ]] && echo -n "${_backcolor}"; [[ -v _labelcolor ]] && echo -n ";${_labelcolor}"; [[ -v _decotypes ]] && echo -n ";${_decotypes}")m${_msg_label}\e[m "
244 echo -ne "${_msg_label} "
250 if [[ "${_noappname}" = false ]]; then
251 if [[ "${_nocolor}" = false ]]; then
252 echo -ne "\e[36m[${_appname}]\e[m "
254 echo -ne "[${_appname}] "
259 for _count in $(seq "1" "$(echo -ne "${_message}\n" | wc -l)"); do
260 _echo_message=$(echo -ne "${_message}\n" |head -n "${_count}" | tail -n 1 )
261 _full_message="$(echo_appname)$(echo_type)${_echo_message}"
264 echo ${_echo_opts} "${_full_message}" >&1
267 echo ${_echo_opts} "${_full_message}" >&2
270 echo ${_echo_opts} "${_full_message}" > ${_output}
276 # Show an INFO message
279 local _msg_opts="-a WFA"
280 if [[ "${1}" = "-n" ]]; then
281 _msg_opts="${_msg_opts} -o -n"
284 [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
285 [[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
286 msg ${_msg_opts} info "${1}"
289 # Show an Warning message
292 local _msg_opts="-a WFA"
293 if [[ "${1}" = "-n" ]]; then
294 _msg_opts="${_msg_opts} -o -n"
297 [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
298 [[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
299 msg ${_msg_opts} warn "${1}"
302 # Show an debug message
305 if [[ "${debug}" = true ]]; then
306 local _msg_opts="-a WFA"
307 if [[ "${1}" = "-n" ]]; then
308 _msg_opts="${_msg_opts} -o -n"
311 [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
312 [[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
313 msg ${_msg_opts} debug "${1}"
317 # Show an ERROR message then exit with status
319 # $2: exit code number (with 0 does not exit)
321 local _msg_opts="-a WFA"
322 if [[ "${1}" = "-n" ]]; then
323 _msg_opts="${_msg_opts} -o -n"
326 [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
327 [[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
328 msg ${_msg_opts} error "${1}"
329 if [[ -n "${2:-}" ]]; then
335 # Delete the file if it exists.
336 # For directories, rm -rf is used.
337 # If the file does not exist, skip it.
338 # remove <file> <file> ...
340 local _list=($(echo "$@")) _file
341 for _file in "${_list[@]}"; do
342 msg_debug "Removing ${_file}"
343 if [[ -f "${_file}" ]]; then
345 elif [[ -d "${_file}" ]]; then
352 local _pacman_help=false
358 echo "wfa <operation> [...]"
361 echo "wfa {-h --help}"
362 echo "wfa {-V --version}"
363 #echo "wfa {-D --database} <options> <package(s)>"
364 #echo "wfa {-F --files} [options] [package(s)]"
365 echo "wfa {-Q --query} [options] [package(s)]"
366 echo "wfa {-R --remove} [options] <package(s)>"
367 echo "wfa {-S --sync} [options] [package(s)]"
368 #echo "wfa {-T --deptest} [options] [package(s)]"
369 #echo "wfa {-U --upgrade} [options] <file(s)>"
372 local _wfa_usage_sync
374 echo "usage: wfa {-S --sync} [options] [package(s)]"
376 echo " -b, --dbpath <path> set an alternate database location"
377 echo " --config <path> set an alternate configuration file"
378 echo " --noconfirm do not ask for any confirmation"
382 if [[ "${operation}" = "none" ]]; then
384 elif [[ "${_pacman_help}" = true ]]; then
385 pacman -h --${operation}
386 elif [[ "$(type -t "_wfa_usage_${operation}" )" = "function" ]]; then
387 _wfa_usage_${operation}
389 msg_error "Undefined operation." 1
394 if [[ "${operation}" = "none" ]]; then
396 add_args pacman "--${operation}"
398 msg_error "only one operation may be used at a time" 1
403 if (( ${UID} == 0 )); then
411 run_sudo pacman ${pacman_args} ${@}
415 # https://github.com/FascodeNet/aptpac/blob/master/aptpac のADD_OPTION関数を参考
416 # Usage: add_args [pacman/makepkg] <args1> <args2>...
424 _args_array=(${makepkg_args})
426 makepkg_args=${_args_array[@]}
427 msg_debug "MAKEPKG ARGS: ${makepkg_args}"
431 _args_array=(${pacman_args})
433 pacman_args=${_args_array[@]}
434 msg_debug "PACMAN ARGS: ${pacman_args}"
439 # 引数で指定されたパッケージがAUR以外の場所に存在しない場合にのみ正常終了します(AURのパッケージの場合に正常終了)
440 check_aur_package() {
441 local _package="${1}"
442 # 参考: https://qiita.com/Hayao0819/items/a8740a17301fafa2fdab
443 if [[ -z "$(pacman -Ssq "${_package}" 2>/dev/null | grep -o ".*${_package}$")" ]]; then
452 # 引数で指定されたパッケージが既にインストールされている場合は正常終了します。
453 check_installed_package() {
454 local _package="${1}"
455 if pacman -Qq "${_package}" 2> /dev/null 1>&2; then
463 local _user_config_dir
464 if [[ -v XDG_CONFIG_HOME ]]; then
465 _user_config_dir="${XDG_CONFIG_HOME}"
467 _use_config_dir="${HOME}/.config"
469 if [[ -f "${_use_config_dir}/user-dirs.dirs" ]]; then
470 source "${_use_config_dir}/user-dirs.dirs"
472 if [[ -v XDG_CACHE_HOME ]]; then
473 echo -n "${XDG_CACHE_HOME}"
476 echo -n "${HOME}/.cache"
481 # Usage: get_srcinfo_data <path> <var>
484 local _srcinfo="${1}" _ver="${2}"
485 local _srcinfo_json=$(python << EOF
486 from srcinfo.parse import parse_srcinfo; import json
490 parsed, errors = parse_srcinfo(text)
491 print(json.dumps(parsed))
494 echo "${_srcinfo_json}" | jq -r .${2}
499 local _srcinfo="${1}"
502 if [[ ! -f "${_srcinfo}" ]]; then
503 msg_error ".SRCINFO does not exist."
505 for _pkg in $(cat "${_srcinfo}" | grep "${_var} = " | cut -d ' ' -f "3"); do
508 echo -n "${_output[@]}"
512 # AURからパッケージをビルドしてインストールします
513 # 現在1つのパッケージしか指定できません
514 install_aur_package() {
515 local _package="${1}"
518 if [[ ! -v wfa_cache_dir ]]; then
519 wfa_cache_dir="$(get_cache_dir)/wfa"
521 mkdir -p "${wfa_cache_dir}/archive"
522 mkdir -p "${wfa_cache_dir}/build/${_package}"
525 local _aur_json=$(curl -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name&arg=${_package}" | jq -r)
526 if (( "$(echo "${_aur_json}" | jq -r ".resultcount")" == 0 )); then
527 msg_error "Could not find all required packages:\n ${_package}" 1
530 local _found_packages="$(echo "${_aur_json}" | jq -r --tab '.results[].Name')"
531 #msg_debug "Found package: $(echo ${_found_packages} | tr '\n' ' ')"
533 if [[ -n "$(echo "${_found_packages}" | grep -x "${_package}" )" ]]; then
534 msg_debug "Select a package ${_package} with an exact name match"
536 msg_error "No package with an exact name match was found." 1
540 msg_info "Download PKGBUILD of ${_package}"
541 _aur_json=$(echo "${_aur_json}" | jq -r ".results[] | select(.Name == \"${_package}\")" )
542 local _aur_snapshot_url="${aururl%/}$(echo "${_aur_json}" | jq -r ".URLPath")"
543 local _aur_version="$(echo "${_aur_json}" | jq -r ".Version")"
544 msg_debug "Get PKGBUILD from ${_aur_snapshot_url}"
546 local _pkgbuild_archive_path="${wfa_cache_dir}/archive/${_package}-${_aur_version}"
547 local _download_pkgbuild=true
548 if [[ -f "${_pkgbuild_archive_path}" ]]; then
549 msg_warn "PKGBUILD has already been downloaded."
550 msg_warn -n "Do you want to overwrite and download? [n] :"
552 if [[ "${noconfirm}" = true ]]; then
558 case "${_yes_or_no}" in
559 "y" | "Y" | "yes" | "Yes" | "YES" ) _download_pkgbuild=true ;;
560 * ) _download_pkgbuild=false ;;
563 if [[ "${_download_pkgbuild}" = true ]]; then
564 remove "${_pkgbuild_archive_path}"
565 curl -L -C - -f -o "${_pkgbuild_archive_path}" "${_aur_snapshot_url}"
569 msg_info "Unpacking the tarball of PKGBUILD ..."
570 tar -xv -f "${_pkgbuild_archive_path}" -C "${wfa_cache_dir}/build/" 2>/dev/null 1>&2
573 local _build_dir="${wfa_cache_dir}/build/${_package}"
574 if [[ ! -f "${_build_dir}/.SRCINFO" ]]; then
575 msg_warn ".SRCINFO was not found.\nGenerate it using makepkg."
576 makepkg -p "${_build_dir}/PKGBUILD" --printsrcinfo > "${_build_dir}/.SRCINFO"
579 local _makedepends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" "makedepends")"
580 local _depends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" "depends")"
581 local _conflicts="$(get_srcinfo_data "${_build_dir}/.SRCINFO" "conflicts")"
582 msg_debug "makedepends: ${_makedepends}"
583 msg_debug "depends: ${_depends}"
584 msg_debug "conflicts: ${_conflicts}"
588 local _pkg _conflicts_found=false
589 for _pkg in ${_conflicts[@]}; do
590 if pacman -Qq "${_pkg}" 2>/dev/null 1>&2 ; then
591 _conflicts_found=true
592 msg_error "${_package} is colliding with ${_pkg}"
595 if [[ ! "$(pacman -Qq "${_package}")" = "${_package}" ]]; then
596 msg_error "${_package} is colliding with $(pacman -Qq "${_package}")"
597 _conflicts_found=true
599 if [[ "${_conflicts_found}" = true ]]; then
600 msg_error "A conflict was found." 1
605 msg_info "Install dependent packages..."
606 local _force_aur="${force_aur}"
608 install_package "${_depends}"
609 force_aur="${_force_aur}"
614 if [[ -d "${_build_dir}/src" ]]; then
615 msg_info "Found ${_build_dir}/src"
616 msg_info "Packages to cleanBuild? [n] :"
619 if [[ "${noconfirm}" = true ]]; then
625 case "${_yes_or_no}" in
626 "y" | "Y" | "yes" | "Yes" | "YES" ) add_args makepkg "--clean" ;;
631 add_args makepkg "-p '${_build_dir}/PKGBUILD'"
632 makepkg ${makepkg_args}
636 operation_version() {
637 # Pyalpmからlibalpmの値を取得
638 # 参考: https://pyalpm.readthedocs.io/en/latest/pyalpm/pyalpm.html
639 local _libalpm_version="$(python3 -c 'import pyalpm; print(pyalpm.alpmversion())')"
640 local _pacman_version="$(pacman -Q pacman | cut -d ' ' -f 2)"
641 echo "wfa v${wfa_version} - pacman v${_pacman_version} - libalpm v${_libalpm_version}"
645 run_pacman "${specified_packages[@]}"
648 # Usage: install_package <package1> <package2>...
651 for _package in ${@}; do
652 if ! check_installed_package "${_package}"; then
653 if ! check_aur_package "${_package}"; then
654 # 公式パッケージなのでpacmanでそのままインストール
655 run_pacman "${_package}"
658 install_aur_package "${_package}"
659 #msg_error "Getting the AUR package has not been implemented yet." 1
667 for _package in ${specified_packages[@]}; do
668 if ! check_aur_package "${_package}" && [[ "${force_aur}" = false ]]; then
669 # 公式パッケージなのでpacmanでそのままインストール
670 run_pacman "${_package}"
673 install_aur_package "${_package}"
674 #msg_error "Getting the AUR package has not been implemented yet." 1
682 _opt_short="QRShVdb:a"
683 _opt_long="query,remove,sync,help,version,debug,dbpath:,aururl,aur,noconfirm,config:"
685 OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- ${ARGUMENT})
686 [[ ${?} != 0 ]] && exit 1
687 unset _opt_short _opt_long
690 msg_debug "Argument: ${OPT}"
695 set_operation "query"
699 set_operation "remove"
707 set_operation "version"
726 msg_debug "Assume targets are from the AUR"
731 add_args pacman "--debug"
735 add_args pacman "--dbpath '${2}'"
743 add_args pacman "--noconfirm"
749 add_args pacman "--config \"${2}\""
767 specified_packages=(${@})
769 case "${operation}" in
783 msg_error "Undefined operation." 1