OSDN Git Service

[update] : Added about license and overview
[alterlinux/wfa.git] / wfa
1 #!/usr/bin/env bash
2 #
3 # 1. Author info
4 #
5 # Yamada Hayao
6 # Twitter: @Hayao0819
7 # Email  : hayao@fascode.net
8 #
9 # (c) 2019-2020 Fascode Network.
10 #
11 # 2. Overview
12
13 # Wfa is a multilingual AUR helper written in bash that is being developed to replace yaourt
14 #
15 # 3. License
16
17 #        DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
18 #                    Version 2, December 2004 
19 #
20 # Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> 
21 #
22 # Everyone is permitted to copy and distribute verbatim or modified 
23 # copies of this license document, and changing it is allowed as long 
24 # as the name is changed. 
25 #
26 #            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
27 #   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 
28 #
29 #  0. You just DO WHAT THE FUCK YOU WANT TO.
30 #
31 #
32
33 set -eu
34
35
36 ######################################################################################
37 # ここから翻訳データ
38
39 declare -A ja_JP=(
40     ["Undefined operation"]="未定義のオペレーションです"
41     ["only one operation may be used at a time"]="一度に使用できるオペレーションは1つだけです"
42     ["Failed to set the argument of %s"]="%sの引数の設定に失敗しました"
43     ["Setting that command is not currently supported"]="そのコマンドの設定は現在サポートされていません"
44     ["Install dependent packages..."]="依存パッケージをインストールします..."
45     ["Searching in AUR ..."]="AUR内を検索しています..."
46     ["No package with an exact name match was found"]="完全に一致する名前のパッケージが見つかりませんでした"
47     ["Select a package %s with an exact name match"]="名前が完全に一致するパッケージ %s を選択します"
48     ["Download PKGBUILD of %s"]="%s のPKGBUILDをダウンロード"
49     ["Get PKGBUILD from %s"]="%sからPKGBUILDを取得します"
50     ["PKGBUILD has already been downloaded"]="PKGBUILDは既にダウンロードされています"
51     ["Do you want to overwrite and download? [n] :"]="上書きダウンロードしますか? [n] :"
52     ["Unpacking the tarball of PKGBUILD ..."]="PKGBUILDを展開しています ..."
53     [".SRCINFO was not found.\nGenerating it using makepkg"]=".SCRINFOが見つかりませんでした。makepkgを使用して生成しています"
54
55     ["This is a feature that has not been implemented yet"]="まだ実装されていない機能です"
56 )
57 ######################################################################################
58 # ここからデフォルト設定の定義
59
60 #-- wfa configs --#
61 wfa_version="0.1"
62 wfa_name="WFA"
63 wfa_command="wfa"
64
65 #-- options (int) --#
66 option_y_count=0
67
68 #-- options (str) --#
69 aururl="https://aur.archlinux.org/"
70 operation="none"
71
72 #-- options (bool) --#
73 bash_debug=false
74 debug=false
75 force_aur=false
76 msgdebug=false
77 nocolor=false
78 noconfirm=false
79 nodeps=false
80 nomakepkgconf=false
81 sync_search=false
82 sync_upgrade=false
83
84 #-- makepkg --#
85 # 実行ファイル
86 makepkg_command="/usr/bin/makepkg" 
87 # 設定ファイル
88 makepkg_config="/etc/makepkg.conf"
89 # 引数
90 makepkg_args=""
91
92 #-- pacman --#
93 # 実行ファイル
94 pacman_command="/usr/bin/pacman"
95 # 設定ファイル
96 pacman_config="/etc/pacman.conf"
97 # 引数
98 pacman_args=""
99
100 #-- git --#
101 # 実行ファイル
102 git_command="/usr/bin/git"
103 # 引数
104 git_args=""
105
106 #-- gpg --#
107 # 実行ファイル
108 gpg_command="/usr/bin/gpg"
109 # 引数
110 gpg_args=""
111
112 #-- sudo --#
113 # 実行ファイル
114 sudo_command="/usr/bin/sudo"
115 # 引数
116 sudo_args=""
117
118
119
120 ######################################################################################
121 # ここからメッセージ関連の関数定義
122
123
124 # メッセージ出力の制御
125 # https://github.com/FascodeNet/alterlinux/blob/dev/tools/msg.sh の変数名にアンダーバーを追加し関数化
126 msg() {
127     local OPTIND OPTARG arg
128
129     local _appname="msg.sh"
130     local _bash_debug=false
131     local _nocolor=false
132     local _echo_opts=""
133     local _message=""
134     local _msg_type="info"
135     local _msg_label=""
136     local _label_space="7"
137     local _adjust_chr=" "
138     local _customized_label=false
139     local _customized_label_color=false
140     local _nolabel=false
141     local _noappname=false
142     local _noadjust=false
143     local _output="stdout"
144
145     _help() {
146         echo "usage ${0} [option] [type] [message]"
147         echo
148         echo "Display a message with a colored app name and message type label"
149         echo
150         echo " General type:"
151         echo "    info                      General message"
152         echo "    warn                      Warning message"
153         echo "    error                     Error message"
154         echo "    debug                     Debug message"
155         echo
156         echo " General options:"
157         echo "    -a [name]                 Specify the app name"
158         echo "    -c [character]            Specify the character to adjust the label"
159         echo "    -l [label]                Specify the label."
160         echo "    -n | --nocolor            No output colored output"
161         echo "    -o [option]               Specify echo options"
162         echo "    -r [color]                Specify the color of label"
163         echo "    -s [number]               Specifies the label space."
164         echo "    -x | --bash-debug         Enables output bash debugging"
165         echo "    -h | --help               This help message"
166         echo
167         echo "         --nolabel            Do not output label"
168         echo "         --noappname          Do not output app name"
169         echo "         --noadjust           Do not adjust the width of the label"
170     }
171
172     while getopts "a:c:l:no:r:s:xh-:" arg; do
173         case ${arg} in
174                 a) 
175                     _appname="${OPTARG}"
176                     ;;
177                 c) 
178                     _adjust_chr="${OPTARG}"
179                     ;;
180                 l) 
181                     _customized_label=true
182                     _msg_label="${OPTARG}"
183                     ;;
184                 n)
185                     _nocolor=true
186                     ;;
187                 o)
188                     _echo_opts="${OPTARG}"
189                     ;;
190                 r)
191                     _customized_label_color=true
192                     case ${OPTARG} in
193                         "black")
194                             _labelcolor="30"
195                             ;;
196                         "red")
197                             _labelcolor="31"
198                             ;;
199                         "green")
200                             _labelcolor="32"
201                             ;;
202                         "yellow")
203                             _labelcolor="33"
204                             ;;
205                         "blue")
206                             _labelcolor="34"
207                             ;;
208                         "magenta")
209                             _labelcolor="35"
210                             ;;
211                         "cyan")
212                             _labelcolor="36"
213                             ;;
214                         "white")
215                             _labelcolor="37"
216                             ;;
217                         *)
218                             return 1
219                             ;;
220                     esac
221                     ;;
222                 s)
223                     _label_space="${OPTARG}"
224                     ;;
225                 x)
226                     _bash_debug=true
227                     set -xv
228                     ;;
229                 h)
230                     _help
231                     shift 1
232                     exit 0
233                     ;;
234                 -)
235                     case "${OPTARG}" in
236                         "nocolor")
237                             _nocolor=true
238                             ;;
239                         "bash-debug")
240                             _bash_debug=true
241                             set -xv
242                             ;;
243                         "help") 
244                             _help
245                             exit 0
246                             ;;
247                         "nolabel")
248                             _nolabel=true
249                             ;;
250                         "noappname")
251                             _noappname=true
252                             ;;
253                         "noadjust")
254                             _noadjust=true 
255                             ;;
256                         *)
257                             _help
258                             exit 1
259                             ;;
260                     esac
261         esac
262     done
263
264     shift $((OPTIND - 1))
265
266     # Color echo
267     #
268     # Text Color
269     # 30 => Black
270     # 31 => Red
271     # 32 => Green
272     # 33 => Yellow
273     # 34 => Blue
274     # 35 => Magenta
275     # 36 => Cyan
276     # 37 => White
277     #
278     # Background color
279     # 40 => Black
280     # 41 => Red
281     # 42 => Green
282     # 43 => Yellow
283     # 44 => Blue
284     # 45 => Magenta
285     # 46 => Cyan
286     # 47 => White
287     #
288     # Text decoration
289     # You can specify multiple decorations with ;.
290     # 0 => All attributs off (ノーマル)
291     # 1 => Bold on (太字)
292     # 4 => Underscore (下線)
293     # 5 => Blink on (点滅)
294     # 7 => Reverse video on (色反転)
295     # 8 => Concealed on
296
297     case ${1} in
298         "info")
299             _msg_type="type"
300             _output="stdout"
301             [[ "${_customized_label_color}" = false ]] && _labelcolor="32"
302             [[ "${_customized_label}"       = false ]] && _msg_label="Info"
303             shift 1
304             ;;
305         "warn")
306             _msg_type="warn"
307             _output="stdout"
308             [[ "${_customized_label_color}" = false ]] && _labelcolor="33"
309             [[ "${_customized_label}"       = false ]] && _msg_label="Warning"
310             shift 1
311             ;;
312         "debug")
313             _msg_type="debug"
314             _output="stdout"
315             [[ "${_customized_label_color}" = false ]] && _labelcolor="35"
316             [[ "${_customized_label}"       = false ]] && _msg_label="Debug"
317             shift 1
318             ;;
319         "error")
320             _msg_type="error"
321             _output="stderr"
322             [[ "${_customized_label_color}" = false ]] && _labelcolor="31"
323             [[ "${_customized_label}"       = false ]] && _msg_label="Error"
324             shift 1
325             ;;
326         "")
327             echo "Please specify the message type" >&2
328             exit 1
329             ;;
330         *)
331             echo "Unknown message type" >&2
332             exit 1
333             ;;
334     esac
335
336     _word_count="${#_msg_label}"
337     _message="${@}"
338
339     echo_type() {
340         local __time
341         if [[ "${_nolabel}" = false ]]; then
342             if [[ "${_noadjust}" = false ]]; then
343                 for __time in $( seq 1 $(( ${_label_space} - ${_word_count})) ); do
344                     echo -ne "${_adjust_chr}"
345                 done
346             fi
347             if [[ "${_nocolor}" = false ]]; then
348                 echo -ne "\e[$([[ -v _backcolor ]] && echo -n "${_backcolor}"; [[ -v _labelcolor ]] && echo -n ";${_labelcolor}"; [[ -v _decotypes ]] && echo -n ";${_decotypes}")m${_msg_label}\e[m "
349             else
350                 echo -ne "${_msg_label} "
351             fi
352         fi
353     }
354
355     echo_appname() {
356         if [[ "${_noappname}" = false ]]; then
357             if [[ "${_nocolor}" = false ]]; then
358                 echo -ne "\e[36m[${_appname}]\e[m "
359             else
360                 echo -ne "[${_appname}] "
361             fi
362         fi
363     }
364
365     for _count in $(seq "1" "$(echo -ne "${_message}\n" | wc -l)"); do
366         _echo_message=$(echo -ne "${_message}\n" |head -n "${_count}" | tail -n 1 )
367         _full_message="$(echo_appname)$(echo_type)${_echo_message}"
368         case "${_output}" in
369             "stdout")
370                 echo ${_echo_opts} "${_full_message}" >&1
371                 ;;
372             "stderr")
373                 echo ${_echo_opts} "${_full_message}" >&2
374                 ;;
375             *)
376                 echo ${_echo_opts} "${_full_message}" > ${_output}
377                 ;;
378         esac
379     done
380 }
381
382 # テキストの翻訳
383 #set -xv
384 translate() {
385     local _msg_translate
386     _msg_translate() {
387         local _get_text
388         local _locale="$(echo "${LANG}" | cut -d "." -f 1)"
389
390         _get_text() {
391             set +eu
392             local _translated_text="$(eval echo '$'{${_locale}[\"${*}\"]})"
393             set -eu
394             if [[ -z "${_translated_text}" ]]; then
395                 echo "${*}"
396             else
397                 echo "${_translated_text}"
398             fi
399         }
400
401         local _text _fulltext=() _main
402
403         if declare -p "${_locale}" 2> /dev/null 1>/dev/null; then
404             _main="$(_get_text ${1})"
405         else
406             _main="${1}"
407         fi
408         shift 1
409         echo "$(printf "${_main}" "${@}")"
410     }
411     _msg_translate "${@}"
412 }
413
414
415
416 # Show an INFO message
417 # $1: message string
418 msg_info() {
419     if [[ "${msgdebug}" = false ]]; then
420         set +xv
421     fi
422     local _msg_opts="-a ${wfa_name}"
423     if [[ "${1}" = "-n" ]]; then
424         _msg_opts="${_msg_opts} -o -n"
425         shift 1
426     fi
427     [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
428     [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
429     msg ${_msg_opts} info "$(translate "${@}")"
430     if [[ "${bash_debug}" = true ]]; then
431         set -xv
432     fi
433 }
434
435 # Show an Warning message
436 # $1: message string
437 msg_warn() {
438     if [[ "${msgdebug}" = false ]]; then
439         set +xv
440     fi
441     local _msg_opts="-a ${wfa_name}"
442     if [[ "${1}" = "-n" ]]; then
443         _msg_opts="${_msg_opts} -o -n"
444         shift 1
445     fi
446     [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
447     [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
448     msg ${_msg_opts} warn "$(translate "${@}")"
449     if [[ "${bash_debug}" = true ]]; then
450         set -xv
451     fi
452 }
453
454 # Show an debug message
455 # $1: message string
456 msg_debug() {
457     if [[ "${msgdebug}" = false ]]; then
458         set +xv
459     fi
460     if [[ "${debug}" = true ]]; then
461         local _msg_opts="-a ${wfa_name}"
462         if [[ "${1}" = "-n" ]]; then
463             _msg_opts="${_msg_opts} -o -n"
464             shift 1
465         fi
466         [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
467         [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
468         msg ${_msg_opts} debug "$(translate "${@}")"
469     fi
470     if [[ "${bash_debug}" = true ]]; then
471         set -xv
472     fi
473 }
474
475 # Show an ERROR message then exit with status
476 # $1: message string
477 # $2: exit code number (with 0 does not exit)
478 msg_error() {
479     if [[ "${msgdebug}" = false ]]; then
480         set +xv
481     fi
482     local _msg_opts="-a ${wfa_name}"
483     if [[ "${1}" = "-n" ]]; then
484         _msg_opts="${_msg_opts} -o -n"
485         shift 1
486     fi
487     [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
488     [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
489     msg ${_msg_opts} error "$(translate "${@}")"
490     if [[ "${bash_debug}" = true ]]; then
491         set -xv
492     fi
493 }
494
495 ######################################################################################
496 # ここから実際の処理開始
497 # ここから下のメッセージは翻訳可能です
498
499 # rm helper
500 # Delete the file if it exists.
501 # For directories, rm -rf is used.
502 # If the file does not exist, skip it.
503 # remove <file> <file> ...
504 remove() {
505     local _list=($(echo "$@")) _file
506     for _file in "${_list[@]}"; do
507         msg_debug "Removing ${_file}"
508         if [[ -f "${_file}" ]]; then    
509             rm -f "${_file}"
510         elif [[ -d "${_file}" ]]; then
511             rm -rf "${_file}"
512         fi
513     done
514 }
515
516 usage (){
517     local _pacman_help=false
518
519     local _wfa_usage
520     _wfa_usage() {
521         echo "Usage:"
522         echo "${wfa_command}"
523         echo "${wfa_command} <operation> [...]"
524         echo
525         echo "operations:"
526         echo "    ${wfa_command} {-h --help}"
527         echo "    ${wfa_command} {-V --version}"
528        #echo "    ${wfa_command} {-D --database}    <options> <package(s)>"
529        #echo "    ${wfa_command} {-F --files}       [options] [package(s)]"
530         echo "    ${wfa_command} {-Q --query}       [options] [package(s)]"
531         echo "    ${wfa_command} {-R --remove}      [options] <package(s)>"
532         echo "    ${wfa_command} {-S --sync}        [options] [package(s)]"
533        #echo "    ${wfa_command} {-T --deptest}     [options] [package(s)]"
534        #echo "    ${wfa_command} {-U --upgrade}     [options] <file(s)>"
535        #echo
536        #echo "New operations:"
537        #echo "    ${wfa_command} {-P --show}        [options]"
538        #echo "    ${wfa_command} {-G --getpkgbuild} [package(s)]"
539         echo
540         echo "New options:"
541         echo "       --repo             Assume targets are from the repositories"
542         echo "    -a --aur              Assume targets are from the AUR"
543         echo
544         echo "Permanent configuration options:"
545         echo "    --aururl      <url>   Set an alternative AUR URL"
546         echo "    --makepkg     <file>  makepkg command to use"
547         echo "    --mflags      <flags> Pass arguments to makepkg"
548         echo "    --pacman      <file>  pacman command to use"
549         echo "    --git         <file>  git command to use"
550         echo "    --gitflags    <flags> Pass arguments to git"
551         echo "    --gpg         <file>  gpg command to use"
552         echo "    --gpgflags    <flags> Pass arguments to gpg"
553         echo "    --config      <file>  pacman.conf file to use"
554         echo "    --makepkgconf <file>  makepkg.conf file to use"
555         echo "    --nomakepkgconf       Use the default makepkg.conf"
556         echo
557     }
558
559     local _wfa_usage_sync
560     _wfa_usage_sync() {
561         echo "usage:  ${wfa_command} {-S --sync} [options] [package(s)]"
562         echo "options:"
563         echo "  -b, --dbpath <path>  set an alternate database location"
564         echo "      --config <path>  set an alternate configuration file"
565         echo "      --noconfirm      do not ask for any confirmation"
566
567     }
568
569     if [[ "${operation}" = "none" ]]; then
570         _wfa_usage
571     elif [[ "${_pacman_help}" = true ]]; then
572         "${pacman_command}" -h --${operation}
573     elif [[ "$(type -t "_wfa_usage_${operation}" )" = "function" ]]; then
574         _wfa_usage_${operation}
575     else
576         msg_error "Undefined operation"
577         exit 1
578     fi
579 }
580
581 set_operation() {
582     if [[ "${operation}" = "none" ]]; then
583         operation="${1}"
584         add_args pacman "--${operation}"
585     else
586         msg_error "only one operation may be used at a time"
587         exit 1
588     fi
589 }
590
591 run_sudo() {
592     if (( ${UID} == 0 )); then
593         ${@}
594     else
595         sudo ${@}
596     fi
597 }
598
599 run_pacman() {
600     run_sudo "${pacman_command}" ${@}
601 }
602
603 # pacmanの引数を追加する
604 # https://github.com/FascodeNet/aptpac/blob/master/aptpac のADD_OPTION関数を参考
605 # Usage: add_args [pacman/makepkg] <args1> <args2>...
606 add_args() {
607     local _target="${1}"
608     local _args_array
609     shift 1
610
611     case "${_target}" in
612         "makepkg")
613             _args_array=(${makepkg_args})
614             _args_array+=(${@})
615             makepkg_args=${_args_array[@]}
616             msg_debug "makepkg ARGS: ${makepkg_args}"
617             ;;
618
619         "pacman")
620             _args_array=(${pacman_args})
621             _args_array+=(${@})
622             pacman_args=${_args_array[@]}
623             msg_debug "pacman ARGS: ${pacman_args}"
624             ;;
625         "git")
626             _args_array=(${mpg_args})
627             _args_array+=(${@})
628             git_args=${_args_array[@]}
629             msg_debug "git ARGS: ${git_args}"
630             ;;
631         "gpg")
632             _args_array=(${gpg_args})
633             _args_array+=(${@})
634             gpg_args=${_args_array[@]}
635             msg_debug "gpg ARGS: ${gpg_args}"
636             ;;
637         "sudo")
638             _args_array=(${sudo_args})
639             _args_array+=(${@})
640             sudo_args=${_args_array[@]}
641             msg_debug "sudo ARGS: ${sudo_args}"
642             ;;
643         *)
644             msg_error "Failed to set the argument of %s" "${_target}"
645             msg_error "Setting that command is not currently supported"
646             exit 1
647             ;;
648     esac
649 }
650
651 # 引数で指定されたパッケージがAUR以外の場所に存在しない場合にのみ正常終了します(AURのパッケージの場合に正常終了)
652 check_aur_package() {
653     local _package="${1}"
654     # 参考: https://qiita.com/Hayao0819/items/a8740a17301fafa2fdab
655     if [[ -z "$(pacman -Ssq "${_package}" 2>/dev/null | grep -o ".*${_package}$")" ]]; then
656         #AUR以外のリポジトリに存在しない
657         return 0
658     else
659         return 1
660     fi
661 }
662
663
664 # 引数で指定されたパッケージが既にインストールされている場合は正常終了します。
665 check_installed_package() {
666     local _package="${1}"
667     if "${pacman_command}" -Qq "${_package}" > /dev/null 2>&1; then
668         return 0
669     else
670         return 1
671     fi
672 }
673
674 get_cache_dir() {
675     local _user_config_dir _cache_dir
676     if [[ -v XDG_CONFIG_HOME ]]; then
677         _user_config_dir="${XDG_CONFIG_HOME}"
678     else
679         _use_config_dir="${HOME}/.config"
680     fi
681     if [[ -f "${_use_config_dir}/user-dirs.dirs" ]]; then
682         source "${_use_config_dir}/user-dirs.dirs"
683     fi
684     if [[ -v XDG_CACHE_HOME ]]; then
685         _cache_dir="${XDG_CACHE_HOME}"
686     else
687         _cache_dir="${HOME}/.cache"
688     fi
689     echo -n "${_cache_dir}"
690 }
691
692 # Usage: get_srcinfo_data <path> <var>
693 # 参考: https://qiita.com/withelmo/items/b0e1ffba639dd3ae18c0
694 get_srcinfo_data() {
695     local _srcinfo="${1}" _ver="${2}"
696     local _srcinfo_json=$(python << EOF
697 from srcinfo.parse import parse_srcinfo; import json
698 text = """
699 $(cat ${1})
700 """
701 parsed, errors = parse_srcinfo(text)
702 print(json.dumps(parsed))
703 EOF
704 )
705     echo "${_srcinfo_json}" | jq -rc "${2}" | tr '\n' ' '
706 }
707
708
709 # AURからパッケージをビルドしてインストールします
710 # 現在1つのパッケージしか指定できません
711 install_aur_package() {
712     local _package="${1}"
713
714     # Create cache dir
715     if [[ ! -v wfa_cache_dir ]]; then
716         wfa_cache_dir="$(get_cache_dir)/wfa"
717     fi
718     mkdir -p "${wfa_cache_dir}/archive"
719     mkdir -p "${wfa_cache_dir}/build/${_package}"
720
721     # AurJsonから値を取得
722     msg_info "Searching in AUR ..."
723     local _aur_json=$(curl -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name&arg=${_package}" | jq -r)
724     if (( "$(echo "${_aur_json}" | jq -r ".resultcount")" == 0 )); then
725         msg_error "Could not find all required packages:\n      ${_package}"
726         exit 1
727     fi
728
729     local _found_packages="$(echo "${_aur_json}" | jq -r --tab '.results[].Name')"
730     #msg_debug "Found package: $(echo ${_found_packages} | tr '\n' ' ')"
731
732     if [[ -n "$(echo "${_found_packages}" | grep -x "${_package}" )" ]]; then
733         msg_debug "Select a package %s with an exact name match" "${_package}"
734     else
735         msg_error "No package with an exact name match was found"
736         exit 1
737     fi
738
739     # PKGBUILDをダウンロード
740     msg_info "Download PKGBUILD of %s" "${_package}"
741     _aur_json=$(echo "${_aur_json}" | jq -r ".results[] | select(.Name == \"${_package}\")" )
742     local _aur_snapshot_url="${aururl%/}$(echo "${_aur_json}" | jq -r ".URLPath")"
743     local _aur_version="$(echo "${_aur_json}" | jq -r ".Version")"
744     msg_debug "Get PKGBUILD from %s" "${_aur_snapshot_url}"
745
746     local _pkgbuild_archive_path="${wfa_cache_dir}/archive/${_package}-${_aur_version}"
747     local _download_pkgbuild=true
748     if [[ -f "${_pkgbuild_archive_path}" ]]; then
749         msg_warn "PKGBUILD has already been downloaded"
750         msg_warn -n "Do you want to overwrite and download? [n] :"
751         local _yes_or_no
752         if [[ "${noconfirm}" = true ]]; then
753             echo
754             _yes_or_no="No"
755         else
756             read _yes_or_no
757         fi
758         case "${_yes_or_no}" in
759             "y" | "Y" | "yes" | "Yes" | "YES" ) _download_pkgbuild=true  ;;
760             *                                 ) _download_pkgbuild=false ;;
761         esac
762     fi
763     if [[ "${_download_pkgbuild}" = true ]]; then
764         remove "${_pkgbuild_archive_path}"
765         curl -L -C - -f -o "${_pkgbuild_archive_path}" "${_aur_snapshot_url}"
766     fi
767
768     # PKGBUILDを展開
769     msg_info "Unpacking the tarball of PKGBUILD ..."  #ここまで翻訳
770     tar -xv -f "${_pkgbuild_archive_path}" -C "${wfa_cache_dir}/build/" > /dev/null 2>&1
771
772     # .SRCINFOを解析
773     local _build_dir="${wfa_cache_dir}/build/${_package}"
774     if [[ ! -f "${_build_dir}/.SRCINFO" ]]; then
775         msg_warn ".SRCINFO was not found.\nGenerating it using makepkg"
776         (
777             cd "${_build_dir}"
778             "${makepkg_command}" --printsrcinfo > "${_build_dir}/.SRCINFO"
779         )
780     fi
781
782     local _makedepends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".makedepends[]?")"
783     local _depends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".depends[]?")"
784     local _conflicts="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".conflicts[]?")"
785     msg_info "makedepends: %s" "${_makedepends}"
786     msg_info "depends: %s" "${_depends}"
787     msg_info "conflicts: %s " "${_conflicts}"
788
789
790     # 衝突を確認
791     local _pkg _conflicts_found=false
792     for _pkg in ${_conflicts[@]}; do
793         if "${pacman_command}" -Qq "${_pkg}" > /dev/null 2>&1 ; then
794             _conflicts_found=true
795             msg_error "${_package} is colliding with ${_pkg}"
796         fi
797     done
798     if "${pacman_command}" -Qq "${_package}" > /dev/null 2>&1 &&  [[ ! "$("${pacman_command}" -Qq "${_package}" 2> /dev/null)" = "${_package}" ]]; then
799         msg_error "${_package} is colliding with $("${pacman_command}" -Qq "${_package}")"
800         _conflicts_found=true
801     fi
802     if [[ "${_conflicts_found}" = true ]]; then
803         msg_error "A conflict was found."
804         exit 1
805     fi
806
807
808     # 依存パッケージをインストール
809     if [[ "${nodeps}" = false ]]; then
810         msg_info "Install dependent packages..."
811         local _force_aur="${force_aur}"
812         force_aur=false
813         install_package "${_depends}"
814         force_aur="${_force_aur}"
815         unset _force_aur
816     fi
817
818     # ビルド準備
819     # srcdirの確認
820     if [[ -d "${_build_dir}/src" ]]; then
821         msg_info "Found ${_build_dir}/src"
822         msg_info -n "Packages to cleanBuild? [n] :"
823         local _yes_or_no
824         unset _yes_or_no
825         if [[ "${noconfirm}" = true ]]; then
826             echo
827             _yes_or_no="No"
828         else
829             read _yes_or_no
830         fi
831         case "${_yes_or_no}" in
832             "y" | "Y" | "yes" | "Yes" | "YES" ) add_args makepkg "--clean" ;;
833         esac
834     fi
835
836
837     # ビルド
838     add_args "makepkg" "-sf"
839     (
840         cd "${_build_dir}"
841         "${makepkg_command}" "${makepkg_args}"
842     )
843
844
845     # ビルド後のパッケージ一覧を生成
846     (
847         cd "${_build_dir}"
848         "${makepkg_command}" --printsrcinfo > "${_build_dir}/.SRCINFO"
849     )
850     local _pkgnames=($(get_srcinfo_data "${_build_dir}/.SRCINFO" ".packages | keys[]" | sed 's/ //g'))
851     local _pkgver="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".pkgver" | sed 's/ //g')"
852     local _pkgrel="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".pkgrel" | sed 's/ //g')"
853     local _arch_array=($(get_srcinfo_data "${_build_dir}/.SRCINFO" ".arch[]"))
854     local _arch _pkgname
855     if [[ "${_arch_array[*]}" = "any" ]]; then
856         _arch="any"
857     else
858         _arch="$(uname -m)"
859     fi
860     local _PKGEXT=$(
861         source "${makepkg_config}"
862         echo "${PKGEXT}"
863     )
864     local _pkgfilelist=()
865     for _pkgname in ${_pkgnames[@]}; do
866         _pkgfilelist+=("${_build_dir}/${_pkgname}-${_pkgver}-${_pkgrel}-${_arch}${_PKGEXT}")
867     done
868
869     # インストール
870     run_pacman -U --noconfirm ${_pkgfilelist[@]}
871 }
872
873 # AURのパッケージを検索
874 search_aur_package() {
875     local _package="${1}"
876     msg_info "Searching in AUR ..."
877     local _aur_json=$(curl -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name-desc&arg=${_package}" | jq -r )
878     local _found_result_count="$(echo "${_aur_json}" | jq -r ".resultcount")"
879     if (( "${_found_result_count}" == 0 )); then
880         msg_error "Could not find all required packages:\n      ${_package}"
881         exit 1
882     fi
883     _aur_json=$(echo "${_aur_json}" | jq -r ".results[]")
884
885     #echo ${_aur_json} 
886
887     local _found_pkgname=($(echo "${_aur_json}" | jq -r ".Name" ))
888
889
890
891
892     local  _found_package __pkgver __popularity __vote __pkgdesc
893     for _found_package in ${_found_pkgname[@]}; do
894         _found_json="$(echo ${_aur_json} | jq "select(.Name == \"${_found_package}\")")"
895         __pkgver="$(echo "${_found_json}" | jq -r ".Version" )"
896         __popularity="$(echo "${_found_json}" | jq -r ".Popularity" )"
897         __vote="$(echo "${_found_json}" | jq -r ".NumVotes" )"
898         __pkgdesc="$(echo "${_found_json}" | jq -r ".Description" )"
899     
900         echo "aur/${_found_package} ${__pkgver} (+${__vote} ${__popularity})"
901         echo "    ${__pkgdesc}"
902         unset __pkgver __popularity __vote __pkgdesc _found_json
903     done
904 }
905
906 # バージョンを表示して終了
907 operation_version() {
908     # Pyalpmからlibalpmの値を取得
909     # 参考: https://pyalpm.readthedocs.io/en/latest/pyalpm/pyalpm.html
910     local _libalpm_version="$(python3 -c 'import pyalpm; print(pyalpm.alpmversion())')"
911     local _pacman_version="$("${pacman_command}" -Q pacman | cut -d ' ' -f 2)"
912     echo "wfa v${wfa_version} - pacman v${_pacman_version} - libalpm v${_libalpm_version}"
913 }
914
915 operation_remove() {
916     run_pacman ${pacman_args} "${specified_packages[@]}"
917 }
918
919 # Usage: install_package <package1> <package2>...
920 install_package() {
921     local _package
922     for _package in ${@}; do
923         if ! check_installed_package "${_package}"; then
924             if ! check_aur_package "${_package}"; then
925                 # 公式パッケージなのでpacmanでそのままインストール
926                 run_pacman ${pacman_args} "${_package}"
927             else
928                 # AUR上のパッケージの場合の処理
929                 install_aur_package "${_package}"
930                 #msg_error "Getting the AUR package has not been implemented yet.
931                 #exit 1
932             fi
933         fi
934     done
935 }
936
937 upgrade_aur_package() {
938     msg_error "This is a feature that has not been implemented yet"
939 }
940
941 operation_sync(){
942     local _package
943     if [[ "${sync_search}" = true ]]; then
944         for _package in ${specified_packages[@]}; do
945             search_aur_package "${_package}"
946         done
947         "${pacman_command}" ${pacman_args} ${specified_packages[@]}
948     else
949         if [[ "${sync_upgrade}" = true ]]; then
950             upgrade_aur_package
951             run_pacman ${pacman_args} --sysupgrade
952         fi
953         for _package in ${specified_packages[@]}; do
954             if ! check_aur_package "${_package}" && [[ "${force_aur}" = false ]]; then
955                 # 公式パッケージなのでpacmanでそのままインストール
956                 run_pacman ${pacman_args} "${_package}"
957             else
958                 # AUR上のパッケージの場合の処理
959                 install_aur_package "${_package}"
960                 #msg_error "Getting the AUR package has not been implemented yet."
961                 #exit 1
962             fi
963         done
964     fi
965 }
966
967
968 # Parse options
969 ARGUMENT="${@}"
970 _opt_short="QRShVdb:aysu"
971 _opt_long="query,remove,sync,help,version,debug,dbpath:,aururl,aur,noconfirm,config:,makepkg:,mflags:,pacman:,git:,gitflags:,gpg:,gpgflags:,makepkgconf:,nomakepkgconf,nodeps,refresh,bash-debug,msg-debug,sysupgrade"
972
973 OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- ${ARGUMENT})
974 [[ ${?} != 0 ]] && exit 1
975 unset _opt_short _opt_long
976
977 eval set -- "${OPT}"
978 msg_debug "Argument: ${OPT}"
979
980 while :; do
981     case ${1} in
982         -Q | --query)
983             set_operation "query"
984             shift 1
985             ;;
986         -R | --remove)
987             set_operation "remove"
988             shift 1
989             ;;
990         -S | --sync)
991             set_operation "sync"
992             shift 1
993             ;;
994         -V | --version)
995             set_operation "version"
996             shift 1
997             ;;
998         --)
999             shift
1000             break
1001             ;;
1002         *)
1003             shift 1
1004             ;;
1005     esac
1006 done
1007
1008 eval set -- "${OPT}"
1009
1010 while :; do
1011     case ${1} in
1012         -a | --aur)
1013             force_aur=true
1014             msg_debug "Assume targets are from the AUR"
1015             shift 1
1016             ;;
1017         --debug)
1018             debug=true
1019             add_args pacman "--debug"
1020             shift 1
1021             ;;
1022         -d | --nodeps)
1023             nodeps=true
1024             add_args pacman "--nodeps"
1025             shift 1
1026             ;;
1027         -b | --dbpath)
1028             add_args pacman "--dbpath '${2}'"
1029             shift 2
1030             ;;
1031         -y | --refresh)
1032             option_y_count=$(( option_y_count + 1 ))
1033             shift 1
1034             ;;
1035         -s | --search)
1036             add_args pacman "--search"
1037             sync_search=true
1038             shift 1
1039             ;;
1040         -u | --sysupgrade)
1041             sync_upgrade=true
1042             shift 1
1043             ;;
1044         --aururl)
1045             aururl="${2}"
1046             shift 2
1047             ;;
1048         --noconfirm)
1049             add_args pacman "--noconfirm"
1050             noconfirm=true
1051             shift 1
1052             ;;
1053         --config)
1054             pacman_config="${2}"
1055             add_args pacman "--config \"${2}\""
1056             shift 2
1057             ;;
1058         --makepkg)
1059             makepkg_command="${2}"
1060             shift 2
1061             ;;
1062         --mflags)
1063             makepkg_args="${2}"
1064             shift 2
1065             ;;
1066         --pacman)
1067             pacman_command="${2}"
1068             shift 2
1069             ;;
1070         --git)
1071             git_command="${2}"
1072             shift 2
1073             ;;
1074         --gitflags)
1075             git_args="${2}"
1076             shift 2
1077             ;;
1078         --makepkgconfig)
1079             if [[ "${nomakepkgconf}" = false ]]; then
1080                 makepkg_config="${2}"
1081             else
1082                 msg_warn "--nomakepkgconf is specified.\n--makepkgconf has been ignored."
1083             fi
1084             shift 2
1085             ;;
1086         --nomakepkgconf)
1087             makepkg_config="/etc/makepkg.conf"
1088             nomakepkgconf=true
1089             shift 1
1090         ;;
1091         --bash-debug)
1092             bash_debug=true
1093             set -xv
1094             shift 1
1095             ;;
1096         --msg-debug)
1097             msgdebug=true
1098             shift 1
1099             ;;
1100         -h | --help)
1101             usage
1102             shift 1
1103             exit 0
1104             ;;
1105         --)
1106             shift
1107             break
1108             ;;
1109         *)
1110             shift 1
1111             ;;
1112     esac
1113 done
1114
1115 specified_packages=(${@})
1116
1117 # Run database update
1118 if (( "${option_y_count}" == 1 )); then
1119     run_pacman -Sy
1120 elif (( "${option_y_count}" >= 2 )); then
1121     run_pacman -Syy
1122 fi
1123
1124 case "${operation}" in
1125     "version")
1126         operation_version
1127         ;;
1128     "sync")
1129         operation_sync
1130         ;;
1131     "remove")
1132         operation_remove
1133         ;;
1134     "none")
1135         exit 0
1136         ;;
1137     *)
1138         msg_error "Undefined operation"
1139         exit 1
1140         ;;
1141 esac