OSDN Git Service

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