14 aururl="https://aur.archlinux.org/"
15 pacman_config="/etc/pacman.conf"
18 # https://github.com/FascodeNet/alterlinux/blob/dev/tools/msg.sh の変数名にアンダーバーを追加し関数化
20 local OPTIND OPTARG arg
22 local _appname="msg.sh"
23 local _bash_debug=false
27 local _msg_type="info"
29 local _label_space="7"
31 local _customized_label=false
32 local _customized_label_color=false
34 local _noappname=false
36 local _output="stdout"
39 echo "usage ${0} [option] [type] [message]"
41 echo "Display a message with a colored app name and message type label"
44 echo " info General message"
45 echo " warn Warning message"
46 echo " error Error message"
47 echo " debug Debug message"
49 echo " General options:"
50 echo " -a [name] Specify the app name"
51 echo " -c [character] Specify the character to adjust the label"
52 echo " -l [label] Specify the label."
53 echo " -n | --nocolor No output colored output"
54 echo " -o [option] Specify echo options"
55 echo " -r [color] Specify the color of label"
56 echo " -s [number] Specifies the label space."
57 echo " -x | --bash-debug Enables output bash debugging"
58 echo " -h | --help This help message"
60 echo " --nolabel Do not output label"
61 echo " --noappname Do not output app name"
62 echo " --noadjust Do not adjust the width of the label"
65 while getopts "a:c:l:no:r:s:xh-:" arg; do
71 _adjust_chr="${OPTARG}"
74 _customized_label=true
75 _msg_label="${OPTARG}"
81 _echo_opts="${OPTARG}"
84 _customized_label_color=true
116 _label_space="${OPTARG}"
157 shift $((OPTIND - 1))
182 # You can specify multiple decorations with ;.
183 # 0 => All attributs off (ノーマル)
185 # 4 => Underscore (下線)
187 # 7 => Reverse video on (色反転)
194 [[ "${_customized_label_color}" = false ]] && _labelcolor="32"
195 [[ "${_customized_label}" = false ]] && _msg_label="Info"
201 [[ "${_customized_label_color}" = false ]] && _labelcolor="33"
202 [[ "${_customized_label}" = false ]] && _msg_label="Warning"
208 [[ "${_customized_label_color}" = false ]] && _labelcolor="35"
209 [[ "${_customized_label}" = false ]] && _msg_label="Debug"
215 [[ "${_customized_label_color}" = false ]] && _labelcolor="31"
216 [[ "${_customized_label}" = false ]] && _msg_label="Error"
220 echo "Please specify the message type" >&2
224 echo "Unknown message type" >&2
229 _word_count="${#_msg_label}"
234 if [[ "${_nolabel}" = false ]]; then
235 if [[ "${_noadjust}" = false ]]; then
236 for __time in $( seq 1 $(( ${_label_space} - ${_word_count})) ); do
237 echo -ne "${_adjust_chr}"
240 if [[ "${_nocolor}" = false ]]; then
241 echo -ne "\e[$([[ -v _backcolor ]] && echo -n "${_backcolor}"; [[ -v _labelcolor ]] && echo -n ";${_labelcolor}"; [[ -v _decotypes ]] && echo -n ";${_decotypes}")m${_msg_label}\e[m "
243 echo -ne "${_msg_label} "
249 if [[ "${_noappname}" = false ]]; then
250 if [[ "${_nocolor}" = false ]]; then
251 echo -ne "\e[36m[${_appname}]\e[m "
253 echo -ne "[${_appname}] "
258 for _count in $(seq "1" "$(echo -ne "${_message}\n" | wc -l)"); do
259 _echo_message=$(echo -ne "${_message}\n" |head -n "${_count}" | tail -n 1 )
260 _full_message="$(echo_appname)$(echo_type)${_echo_message}"
263 echo ${_echo_opts} "${_full_message}" >&1
266 echo ${_echo_opts} "${_full_message}" >&2
269 echo ${_echo_opts} "${_full_message}" > ${_output}
275 # Show an INFO message
278 local _msg_opts="-a WFA"
279 if [[ "${1}" = "-n" ]]; then
280 _msg_opts="${_msg_opts} -o -n"
283 [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
284 [[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
285 msg ${_msg_opts} info "${1}"
288 # Show an Warning message
291 local _msg_opts="-a WFA"
292 if [[ "${1}" = "-n" ]]; then
293 _msg_opts="${_msg_opts} -o -n"
296 [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
297 [[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
298 msg ${_msg_opts} warn "${1}"
301 # Show an debug message
304 if [[ "${debug}" = true ]]; then
305 local _msg_opts="-a WFA"
306 if [[ "${1}" = "-n" ]]; then
307 _msg_opts="${_msg_opts} -o -n"
310 [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
311 [[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
312 msg ${_msg_opts} debug "${1}"
316 # Show an ERROR message then exit with status
318 # $2: exit code number (with 0 does not exit)
320 local _msg_opts="-a WFA"
321 if [[ "${1}" = "-n" ]]; then
322 _msg_opts="${_msg_opts} -o -n"
325 [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
326 [[ "${nocolor}" = true ]] && _msg_opts="${_msg_opts} -n"
327 msg ${_msg_opts} error "${1}"
328 if [[ -n "${2:-}" ]]; then
334 # Delete the file if it exists.
335 # For directories, rm -rf is used.
336 # If the file does not exist, skip it.
337 # remove <file> <file> ...
339 local _list=($(echo "$@")) _file
340 for _file in "${_list[@]}"; do
341 msg_debug "Removing ${_file}"
342 if [[ -f "${_file}" ]]; then
344 elif [[ -d "${_file}" ]]; then
351 local _pacman_help=false
357 echo "wfa <operation> [...]"
360 echo "wfa {-h --help}"
361 echo "wfa {-V --version}"
362 #echo "wfa {-D --database} <options> <package(s)>"
363 #echo "wfa {-F --files} [options] [package(s)]"
364 echo "wfa {-Q --query} [options] [package(s)]"
365 echo "wfa {-R --remove} [options] <package(s)>"
366 echo "wfa {-S --sync} [options] [package(s)]"
367 #echo "wfa {-T --deptest} [options] [package(s)]"
368 #echo "wfa {-U --upgrade} [options] <file(s)>"
371 local _wfa_usage_sync
373 echo "usage: wfa {-S --sync} [options] [package(s)]"
375 echo " -b, --dbpath <path> set an alternate database location"
376 echo " --config <path> set an alternate configuration file"
377 echo " --noconfirm do not ask for any confirmation"
381 if [[ "${operation}" = "none" ]]; then
383 elif [[ "${_pacman_help}" = true ]]; then
384 pacman -h --${operation}
385 elif [[ "$(type -t "_wfa_usage_${operation}" )" = "function" ]]; then
386 _wfa_usage_${operation}
388 msg_error "Undefined operation." 1
393 if [[ "${operation}" = "none" ]]; then
395 add_pacman_args "--${operation}"
397 msg_error "only one operation may be used at a time" 1
402 if (( ${UID} == 0 )); then
410 run_sudo pacman ${pacman_args} ${@}
414 # https://github.com/FascodeNet/aptpac/blob/master/aptpac のADD_OPTION関数を参考
416 local _pacman_args_array=(${pacman_args})
417 _pacman_args_array+=(${@})
418 pacman_args=${_pacman_args_array[@]}
419 msg_debug "PACMAN ARGS: ${pacman_args}"
422 # 引数で指定されたパッケージがAUR以外の場所に存在しない場合にのみ正常終了します(AURのパッケージの場合に正常終了)
423 check_aur_package() {
424 local _package="${1}"
425 # 参考: https://qiita.com/Hayao0819/items/a8740a17301fafa2fdab
426 if [[ -z "$(pacman -Fq "${_package}" 2>/dev/null | grep -o ".*${_package}$")" ]]; then
436 local _user_config_dir
437 if [[ -v XDG_CONFIG_HOME ]]; then
438 _user_config_dir="${XDG_CONFIG_HOME}"
440 _use_config_dir="${HOME}/.config"
442 if [[ -f "${_use_config_dir}/user-dirs.dirs" ]]; then
443 source "${_use_config_dir}/user-dirs.dirs"
445 if [[ -v XDG_CACHE_HOME ]]; then
446 echo -n "${XDG_CACHE_HOME}"
449 echo -n "${HOME}/.cache"
454 # Usage: get_srcinfo_data <path> <var>
457 local _srcinfo="${1}" _ver="${2}"
458 local _srcinfo_json=$(python << EOF
459 from srcinfo.parse import parse_srcinfo; import json
463 parsed, errors = parse_srcinfo(text)
464 print(json.dumps(parsed))
467 echo "${_srcinfo_json}" | jq -r .${2}
472 local _srcinfo="${1}"
475 if [[ ! -f "${_srcinfo}" ]]; then
476 msg_error ".SRCINFO does not exist."
478 for _pkg in $(cat "${_srcinfo}" | grep "${_var} = " | cut -d ' ' -f "3"); do
481 echo -n "${_output[@]}"
485 # AURからパッケージをビルドしてインストールします
486 # 現在1つのパッケージしか指定できません
487 install_aur_package() {
488 local _package="${1}"
491 if [[ ! -v wfa_cache_dir ]]; then
492 wfa_cache_dir="$(get_cache_dir)/wfa"
494 mkdir -p "${wfa_cache_dir}/archive"
495 mkdir -p "${wfa_cache_dir}/build/${_package}"
498 local _aur_json=$(curl -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name&arg=${_package}" | jq -r)
499 if (( "$(echo "${_aur_json}" | jq -r ".resultcount")" == 0 )); then
500 msg_error "Could not find all required packages:\n ${_package}" 1
503 local _found_packages="$(echo "${_aur_json}" | jq -r --tab '.results[].Name')"
504 #msg_debug "Found package: $(echo ${_found_packages} | tr '\n' ' ')"
506 if [[ -n "$(echo "${_found_packages}" | grep -x "${_package}" )" ]]; then
507 msg_debug "Select a package ${_package} with an exact name match"
509 msg_error "No package with an exact name match was found." 1
513 msg_info "Download PKGBUILD of ${_package}"
514 _aur_json=$(echo "${_aur_json}" | jq -r ".results[] | select(.Name == \"${_package}\")" )
515 local _aur_snapshot_url="${aururl%/}$(echo "${_aur_json}" | jq -r ".URLPath")"
516 local _aur_version="$(echo "${_aur_json}" | jq -r ".Version")"
517 msg_debug "Get PKGBUILD from ${_aur_snapshot_url}"
519 local _pkgbuild_archive_path="${wfa_cache_dir}/archive/${_package}-${_aur_version}"
520 local _download_pkgbuild=true
521 if [[ -f "${_pkgbuild_archive_path}" ]]; then
522 msg_warn "PKGBUILD has already been downloaded."
523 msg_warn -n "Do you want to overwrite and download? [n] :"
525 if [[ "${noconfirm}" = true ]]; then
531 case "${_yes_or_no}" in
532 "y" | "Y" | "yes" | "Yes" | "YES" ) _download_pkgbuild=true ;;
533 * ) _download_pkgbuild=false ;;
536 if [[ "${_download_pkgbuild}" = true ]]; then
537 remove "${_pkgbuild_archive_path}"
538 curl -L -C - -f -o "${_pkgbuild_archive_path}" "${_aur_snapshot_url}"
542 msg_info "Unpacking the tarball of PKGBUILD ..."
543 tar -xv -f "${_pkgbuild_archive_path}" -C "${wfa_cache_dir}/build/" 2>/dev/null 1>&2
546 local _build_dir="${wfa_cache_dir}/build/${_package}"
547 if [[ ! -f "${_build_dir}/.SRCINFO" ]]; then
548 msg_warn ".SRCINFO was not found.\nGenerate it using makepkg."
549 makepkg -p "${_build_dir}/PKGBUILD" --printsrcinfo > "${_build_dir}/.SRCINFO"
552 local _makedepends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" "makedepends")"
553 local _depends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" "depends")"
554 local _conflicts="$(get_srcinfo_data "${_build_dir}/.SRCINFO" "conflicts")"
555 msg_debug "makedepends: ${_makedepends}"
556 msg_debug "depends: ${_depends}"
557 msg_debug "conflicts: ${_conflicts}"
561 local _pkg _conflicts_found=false
562 for _pkg in ${_conflicts[@]}; do
563 if pacman -Qq "${_pkg}" 2>/dev/null 1>&2 ; then
564 _conflicts_found=true
565 msg_error "${_package} is colliding with ${_pkg}"
568 if [[ ! "$(pacman -Qq "${_package}")" = "${_package}" ]]; then
569 msg_error "${_package} is colliding with $(pacman -Qq "${_package}")"
570 _conflicts_found=true
572 if [[ "${_conflicts_found}" = true ]]; then
573 msg_error "A conflict was found." 1
578 msg_info "Install dependent packages..."
579 local _force_aur="${force_aur}"
581 install_package "${_makedepends}" "${_depends}"
582 force_aur="${_force_aur}"
589 operation_version() {
590 # Pyalpmからlibalpmの値を取得
591 # 参考: https://pyalpm.readthedocs.io/en/latest/pyalpm/pyalpm.html
592 local _libalpm_version="$(python3 -c 'import pyalpm; print(pyalpm.alpmversion())')"
593 local _pacman_version="$(pacman -Q pacman | cut -d ' ' -f 2)"
594 echo "wfa v${wfa_version} - pacman v${_pacman_version} - libalpm v${_libalpm_version}"
598 run_pacman "${specified_packages[@]}"
601 # Usage: install_package <package1> <package2>...
604 for _package in ${@}; do
605 if ! check_aur_package "${_package}" && [[ "${force_aur}" = false ]]; then
606 # 公式パッケージなのでpacmanでそのままインストール
607 run_pacman "${_package}"
610 install_aur_package "${_package}"
611 #msg_error "Getting the AUR package has not been implemented yet." 1
617 install_package "${specified_packages[@]}"
623 _opt_short="QRShVdb:a"
624 _opt_long="query,remove,sync,help,version,debug,dbpath:,aururl,aur,noconfirm,config:"
626 OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- ${ARGUMENT})
627 [[ ${?} != 0 ]] && exit 1
628 unset _opt_short _opt_long
631 msg_debug "Argument: ${OPT}"
636 set_operation "query"
640 set_operation "remove"
648 set_operation "version"
667 msg_debug "Assume targets are from the AUR"
672 add_pacman_args "--debug"
676 add_pacman_args "--dbpath '${2}'"
684 add_pacman_args "--noconfirm"
690 add_pacman_args "--config \"${2}\""
708 specified_packages=(${@})
710 case "${operation}" in
724 msg_error "Undefined operation." 1