OSDN Git Service

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