OSDN Git Service

[update] : Added --recursive
[alterlinux/wfa.git] / wfa
diff --git a/wfa b/wfa
index f5032d6..13fff5f 100755 (executable)
--- a/wfa
+++ b/wfa
@@ -1,21 +1,87 @@
 #!/usr/bin/env bash
+#
+# 1. Author info
+#
+# Yamada Hayao
+# Twitter: @Hayao0819
+# Email  : hayao@fascode.net
+#
+# (c) 2019-2020 Fascode Network.
+#
+# 2. Overview
+# 
+# Wfa is a multilingual AUR helper written in bash that is being developed to replace yaourt
+#
+# 3. License
+# 
+#        DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
+#                    Version 2, December 2004 
+#
+# Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> 
+#
+# Everyone is permitted to copy and distribute verbatim or modified 
+# copies of this license document, and changing it is allowed as long 
+# as the name is changed. 
+#
+#            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
+#   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 
+#
+#  0. You just DO WHAT THE FUCK YOU WANT TO.
+#
+#
 
 set -eu
 
 
 ######################################################################################
 # ここから翻訳データ
+# 翻訳はBashの連想配列を使用して行います
+# 連想配列名は echo "${LANG}" | cut -d "." -f 1 の実行結果の値です
+# 
 
+# 日本語
 declare -A ja_JP=(
-    ["Undefined operation."]="未定義のオペレーションです。"
+    ["Undefined operation"]="未定義のオペレーションです"
     ["only one operation may be used at a time"]="一度に使用できるオペレーションは1つだけです"
     ["Failed to set the argument of %s"]="%sの引数の設定に失敗しました"
-    ["Setting that command is not currently supported."]="そのコマンドの設定は現在サポートされていません。"
-    ["Install dependent packages..."]="依存パッケージをインストールします..."
-    ["No package with an exact name match was found."]="完全に一致する名前のパッケージが見つかりませんでした。"
-    ["Select a package %s with an exact name match"]="名前が完全に一致するパッケージ s を選択します"
+    ["Setting that command is not currently supported"]="そのコマンドの設定は現在サポートされていません"
+    ["Searching in AUR ..."]="AUR内を検索しています..."
+    ["No package with an exact name match was found"]="完全に一致する名前のパッケージが見つかりませんでした"
+    ["Select a package %s with an exact name match"]="名前が完全に一致するパッケージ %s を選択します"
     ["Download PKGBUILD of %s"]="%s のPKGBUILDをダウンロード"
+    ["Get PKGBUILD from %s"]="%sからPKGBUILDを取得します"
+    ["PKGBUILD has already been downloaded"]="PKGBUILDは既にダウンロードされています"
+    ["Do you want to overwrite and download? [n] :"]="上書きダウンロードしますか? [n] :"
+    ["Unpacking the tarball of PKGBUILD ..."]="PKGBUILDを展開しています ..."
+    [".SRCINFO was not found.\nGenerating it using makepkg"]=".SCRINFOが見つかりませんでした。makepkgを使用して生成しています"
+    ["Conflict(s) was found"]="衝突が見つかりました"
+    ["Install dependent packages..."]="依存パッケージをインストールします..."
+    ["Found %s"]="%s を見つけました"
+    ["Packages to cleanBuild? [n] :"]="パッケージをクリーンビルドしますか? [n] :"
+    ["Could not find all required packages: %s"]="必要なすべてのパッケージが見つかりませんでした: %s"
+    ["This is a feature that has not been implemented yet"]="まだ実装されていない機能です"
+    ["Package not found on AUR: %s"]="パッケージがAUR上から見つかりませんでした: "
+    ["There is no aurvote"]="aurvote が見つかりませんでした"
+    ["Please install with %s"]="%s でインストールしてください"
+    ["Voted for %s"]="%s に投票しました"
+    ["Unvoted for %s"]="%s の投票を解除しました"
+    ["Help for this operation is not implemented"]="このオペレーションのヘルプは実装されていません"
+    ["(Orphaned)"]="(メンテナ不在)"
+    ["[Installed]"]="[インストール済み]"
+    ["This is a feature that has not been implemented yet"]="まだ実装されていない機能です"
+    ["Operation: %s"]="オペレーション: %s"
+    ["Raw popularity: %s"]="人気度の正確な値: %s"
+    ["This program is an alpha version that is not yet stable\nIf you find a bug, please share it on GitHub\nhttps://github.com/hayao0819/wfa/issues"]="このプログラムはまだ安定しないアルファ版です\nもしバグを見つけたらGitHub上で共有してください\nhttps://github.com/hayao0819/wfa/issues"
+    ["Please make a contract with me and become a Puella Magi !"]="僕と契約して魔法少女になってよ! "
 )
+
+
+# English
+# 翻訳データが存在しない場合はデフォルトメッセージ(英語)が出力されます
+# そのため英語の翻訳データは必要ありません
+declare -A en_US=()
+declare -A C=()
+
 ######################################################################################
 # ここからデフォルト設定の定義
 
@@ -23,11 +89,14 @@ declare -A ja_JP=(
 wfa_version="0.1"
 wfa_name="WFA"
 wfa_command="wfa"
+wfa_path="$(dirname "$(realpath "${0}")")/$(basename "${0}")"
 
 #-- options (int) --#
 option_y_count=0
+sync_clean_count=0
 
 #-- options (str) --#
+arch="$(uname -m)"
 aururl="https://aur.archlinux.org/"
 operation="none"
 
@@ -41,6 +110,8 @@ noconfirm=false
 nodeps=false
 nomakepkgconf=false
 sync_search=false
+sync_upgrade=false
+quiet=false
 
 #-- makepkg --#
 # 実行ファイル
@@ -76,12 +147,33 @@ sudo_command="/usr/bin/sudo"
 # 引数
 sudo_args=""
 
+#-- curl --#
+# 実行ファイル
+curl_command="/usr/bin/curl"
+# 引数
+curl_args=""
 
 
 ######################################################################################
 # ここからメッセージ関連の関数定義
 
 
+start_msg_debug() {
+    if [[ "${msgdebug}" = true ]]; then
+        set -xv
+    else
+        set +vx
+    fi
+}
+
+end_msg_debug() {
+    if [[ "${bash_debug}" = true ]]; then
+        set -xv
+    else
+        set +xv
+    fi
+}
+
 # メッセージ出力の制御
 # https://github.com/FascodeNet/alterlinux/blob/dev/tools/msg.sh の変数名にアンダーバーを追加し関数化
 msg() {
@@ -104,7 +196,7 @@ msg() {
     local _output="stdout"
 
     _help() {
-        echo "usage ${0} [option] [type] [message]"
+        echo "usage msg [option] [type] [message]"
         echo
         echo "Display a message with a colored app name and message type label"
         echo
@@ -341,7 +433,6 @@ msg() {
 }
 
 # テキストの翻訳
-#set -xv
 translate() {
     local _msg_translate
     _msg_translate() {
@@ -350,9 +441,15 @@ translate() {
 
         _get_text() {
             set +eu
-            local _translated_text="$(eval echo '$'{${_locale}["${*}"]})"
+            if [[ -z "${*}" ]]; then
+                return 1
+            fi
+            local _translated_text="$(eval echo '$'{${_locale}[\"${*}\"]})"
             set -eu
             if [[ -z "${_translated_text}" ]]; then
+                if [[ ! "${_locale}" = "C" ]] && [[ ! "${_locale}" = "en_US" ]]; then
+                    echo "$(text -nc cyan "[WFA]") $(text -nc yellow "Warning") No translation data was found (${*})" 1>&2
+                fi
                 echo "${*}"
             else
                 echo "${_translated_text}"
@@ -367,7 +464,7 @@ translate() {
             _main="${1}"
         fi
         shift 1
-        echo "$(printf "${_main}" ${@})"
+        echo "$(printf "${_main}" "${@}")"
     }
     _msg_translate "${@}"
 }
@@ -377,9 +474,7 @@ translate() {
 # Show an INFO message
 # $1: message string
 msg_info() {
-    if [[ "${msgdebug}" = false ]]; then
-        set +xv
-    fi
+    start_msg_debug
     local _msg_opts="-a ${wfa_name}"
     if [[ "${1}" = "-n" ]]; then
         _msg_opts="${_msg_opts} -o -n"
@@ -388,17 +483,13 @@ msg_info() {
     [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
     [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
     msg ${_msg_opts} info "$(translate "${@}")"
-    if [[ "${bash_debug}" = true ]]; then
-        set -xv
-    fi
+    end_msg_debug
 }
 
 # Show an Warning message
 # $1: message string
 msg_warn() {
-    if [[ "${msgdebug}" = false ]]; then
-        set +xv
-    fi
+    start_msg_debug
     local _msg_opts="-a ${wfa_name}"
     if [[ "${1}" = "-n" ]]; then
         _msg_opts="${_msg_opts} -o -n"
@@ -407,17 +498,13 @@ msg_warn() {
     [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
     [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
     msg ${_msg_opts} warn "$(translate "${@}")"
-    if [[ "${bash_debug}" = true ]]; then
-        set -xv
-    fi
+    end_msg_debug
 }
 
 # Show an debug message
 # $1: message string
 msg_debug() {
-    if [[ "${msgdebug}" = false ]]; then
-        set +xv
-    fi
+    start_msg_debug
     if [[ "${debug}" = true ]]; then
         local _msg_opts="-a ${wfa_name}"
         if [[ "${1}" = "-n" ]]; then
@@ -428,18 +515,14 @@ msg_debug() {
         [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
         msg ${_msg_opts} debug "$(translate "${@}")"
     fi
-    if [[ "${bash_debug}" = true ]]; then
-        set -xv
-    fi
+    end_msg_debug
 }
 
 # Show an ERROR message then exit with status
 # $1: message string
 # $2: exit code number (with 0 does not exit)
 msg_error() {
-    if [[ "${msgdebug}" = false ]]; then
-        set +xv
-    fi
+    start_msg_debug
     local _msg_opts="-a ${wfa_name}"
     if [[ "${1}" = "-n" ]]; then
         _msg_opts="${_msg_opts} -o -n"
@@ -448,9 +531,74 @@ msg_error() {
     [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
     [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
     msg ${_msg_opts} error "$(translate "${@}")"
-    if [[ "${bash_debug}" = true ]]; then
-        set -xv
+    end_msg_debug
+}
+
+# 使い方
+# text [-b/-c color/-n/-f/-l/]
+text() {
+    start_msg_debug
+    local OPTIND OPTARG arg _textcolor _decotypes="" _message _notranslate=false
+    while getopts "c:bnfl" arg; do
+        case ${arg} in
+            c)
+                case "${OPTARG}" in
+                    "black")
+                        _textcolor="30"
+                        ;;
+                    "red")
+                        _textcolor="31"
+                        ;;
+                    "green")
+                        _textcolor="32"
+                        ;;
+                    "yellow")
+                        _textcolor="33"
+                        ;;
+                    "blue")
+                        _textcolor="34"
+                        ;;
+                    "magenta")
+                        _textcolor="35"
+                        ;;
+                    "cyan")
+                        _textcolor="36"
+                        ;;
+                    "white")
+                        _textcolor="37"
+                        ;;
+                    *)
+                        return 1
+                        ;;
+                esac
+                ;;
+            b)
+                _decotypes="${_decotypes};1"
+                ;;
+            f)
+                _decotypes="${_decotypes};5"
+                ;;
+            l)
+                _decotypes="${_decotypes};4"
+                ;;
+            n)
+                _notranslate=true
+                ;;
+        esac
+    done
+    shift $((OPTIND - 1))
+
+    _message="${@}"
+    if [[ "${_notranslate}" = false ]]; then
+        _message="$(translate "${@}")"
     fi
+    if [[ "${nocolor}" = true ]]; then
+        echo -ne "${@}"
+    else
+        echo -ne "\e[$([[ -v _textcolor ]] && echo -n ";${_textcolor}"; [[ -v _decotypes ]] && echo -n "${_decotypes}")m${_message}\e[m"
+    fi
+
+    end_msg_debug
 }
 
 ######################################################################################
@@ -485,6 +633,7 @@ usage (){
         echo
         echo "operations:"
         echo "    ${wfa_command} {-h --help}"
+        echo "    ${wfa_command} {-A --vote}"
         echo "    ${wfa_command} {-V --version}"
        #echo "    ${wfa_command} {-D --database}    <options> <package(s)>"
        #echo "    ${wfa_command} {-F --files}       [options] [package(s)]"
@@ -515,6 +664,13 @@ usage (){
         echo "    --makepkgconf <file>  makepkg.conf file to use"
         echo "    --nomakepkgconf       Use the default makepkg.conf"
         echo
+        echo "wfa specific options:"
+        echo "    -c --clean            Remove unneeded dependencies"
+        echo
+        echo "This program is an alpha version that is not yet stable"
+        echo "If you find a bug, please share it on GitHub"
+        echo "https://github.com/hayao0819/wfa/issues"
+        echo
     }
 
     local _wfa_usage_sync
@@ -522,11 +678,40 @@ usage (){
         echo "usage:  ${wfa_command} {-S --sync} [options] [package(s)]"
         echo "options:"
         echo "  -b, --dbpath <path>  set an alternate database location"
+        echo "  -c, --clean          remove old packages from cache directory (-cc for all)"
+        echo "  -d, --nodeps         skip dependency version checks (-dd to skip all checks)"
+        echo "  -s, --search <regex> search remote repositories for matching strings"
+        echo "  -u, --sysupgrade     upgrade installed packages (-uu enables downgrades)"
+        echo "  -y, --refresh        download fresh package databases from the server"
+        echo "                       (-yy to force a refresh even if up to date)"
+        echo "      --arch <arch>    set an alternate architecture"
+        echo "      --color <when>   colorize the output"
         echo "      --config <path>  set an alternate configuration file"
+        echo "      --confirm        always ask for confirmation"
+        echo "      --debug          display debug messages"
+        echo "      --disable-download-timeout"
+        echo "                       use relaxed timeouts for download"
         echo "      --noconfirm      do not ask for any confirmation"
 
     }
 
+    local _wfa_usage_remove
+    _wfa_usage_remove() {
+        echo "usage:  ${wfa_command} {-R --remove} [options] <package(s)>"
+        echo "options:"
+        echo "  -b, --dbpath <path>  set an alternate database location"
+        echo "  -d, --nodeps         skip dependency version checks (-dd to skip all checks)"
+        echo "  -u, --unneeded       remove unneeded packages"
+        echo "      --arch <arch>    set an alternate architecture"
+        echo "      --color <when>   colorize the output"
+        echo "      --config <path>  set an alternate configuration file"
+        echo "      --confirm        always ask for confirmation"
+        echo "      --debug          display debug messages"
+        echo "      --disable-download-timeout"
+        echo "                       use relaxed timeouts for download"
+        echo "      --noconfirm      do not ask for any confirmation"
+    }
+
     if [[ "${operation}" = "none" ]]; then
         _wfa_usage
     elif [[ "${_pacman_help}" = true ]]; then
@@ -534,7 +719,7 @@ usage (){
     elif [[ "$(type -t "_wfa_usage_${operation}" )" = "function" ]]; then
         _wfa_usage_${operation}
     else
-        msg_error "Undefined operation."
+        msg_error "Help for this operation is not implemented"
         exit 1
     fi
 }
@@ -561,9 +746,13 @@ run_pacman() {
     run_sudo "${pacman_command}" ${@}
 }
 
+wfa() {
+    "${wfa_path}" ${@}
+}
+
 # pacmanの引数を追加する
 # https://github.com/FascodeNet/aptpac/blob/master/aptpac のADD_OPTION関数を参考
-# Usage: add_args [pacman/makepkg] <args1> <args2>...
+# Usage: add_args [pacman/makepkg/git/gpg/sudo/curl] <args1> <args2>...
 add_args() {
     local _target="${1}"
     local _args_array
@@ -601,9 +790,15 @@ add_args() {
             sudo_args=${_args_array[@]}
             msg_debug "sudo ARGS: ${sudo_args}"
             ;;
+        "curl")
+            _args_array=(${curl_args})
+            _args_array+="${@}"
+            curl_args=${_args_array[@]}
+            msg_debug "curl ARGS: ${curl_args}"
+            ;;
         *)
             msg_error "Failed to set the argument of %s" "${_target}"
-            msg_error "Setting that command is not currently supported."
+            msg_error "Setting that command is not currently supported"
             exit 1
             ;;
     esac
@@ -632,8 +827,9 @@ check_installed_package() {
     fi
 }
 
+# ~/.cacheに相当するディレクトリを返します
 get_cache_dir() {
-    local _user_config_dir
+    local _user_config_dir _cache_dir
     if [[ -v XDG_CONFIG_HOME ]]; then
         _user_config_dir="${XDG_CONFIG_HOME}"
     else
@@ -643,12 +839,11 @@ get_cache_dir() {
         source "${_use_config_dir}/user-dirs.dirs"
     fi
     if [[ -v XDG_CACHE_HOME ]]; then
-        echo -n "${XDG_CACHE_HOME}"
-        return 0
+        _cache_dir="${XDG_CACHE_HOME}"
     else
-        echo -n "${HOME}/.cache"
-        return 0
+        _cache_dir="${HOME}/.cache"
     fi
+    echo -n "${_cache_dir}"
 }
 
 # Usage: get_srcinfo_data <path> <var>
@@ -667,6 +862,14 @@ EOF
     echo "${_srcinfo_json}" | jq -rc "${2}" | tr '\n' ' '
 }
 
+get_aur_json() {
+    local _package="${1}"
+    local _aur_json=$("${curl_command}" ${curl_args} -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name&arg=${_package}" | jq -r)
+    if (( "$(echo "${_aur_json}" | jq -r ".resultcount")" != 0 )); then
+        echo "${_aur_json}" | jq -r ".results[]"
+    fi
+}
+
 
 # AURからパッケージをビルドしてインストールします
 # 現在1つのパッケージしか指定できません
@@ -681,33 +884,33 @@ install_aur_package() {
     mkdir -p "${wfa_cache_dir}/build/${_package}"
 
     # AurJsonから値を取得
-    local _aur_json=$(curl -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name&arg=${_package}" | jq -r)
-    if (( "$(echo "${_aur_json}" | jq -r ".resultcount")" == 0 )); then
-        msg_error "Could not find all required packages:\n     ${_package}"
+    msg_info "Searching in AUR ..."
+    local _aur_json="$(get_aur_json "${_package}")"
+    if [[ -z "${_aur_json}" ]]; then
+        msg_error "Could not find all required packages: %s" "${_package}"
         exit 1
     fi
-
-    local _found_packages="$(echo "${_aur_json}" | jq -r --tab '.results[].Name')"
+    local _found_packages="$(echo "${_aur_json}" | jq -r --tab '.Name')"
     #msg_debug "Found package: $(echo ${_found_packages} | tr '\n' ' ')"
 
     if [[ -n "$(echo "${_found_packages}" | grep -x "${_package}" )" ]]; then
         msg_debug "Select a package %s with an exact name match" "${_package}"
     else
-        msg_error "No package with an exact name match was found."
+        msg_error "No package with an exact name match was found"
         exit 1
     fi
 
     # PKGBUILDをダウンロード
-    msg_info "Download PKGBUILD of %s" "${_package}" #ここまで翻訳
-    _aur_json=$(echo "${_aur_json}" | jq -r ".results[] | select(.Name == \"${_package}\")" )
+    msg_info "Download PKGBUILD of %s" "${_package}"
+    _aur_json=$(echo "${_aur_json}" | jq -r "select(.Name == \"${_package}\")" )
     local _aur_snapshot_url="${aururl%/}$(echo "${_aur_json}" | jq -r ".URLPath")"
     local _aur_version="$(echo "${_aur_json}" | jq -r ".Version")"
-    msg_debug "Get PKGBUILD from ${_aur_snapshot_url}"
+    msg_debug "Get PKGBUILD from %s" "${_aur_snapshot_url}"
 
     local _pkgbuild_archive_path="${wfa_cache_dir}/archive/${_package}-${_aur_version}"
     local _download_pkgbuild=true
     if [[ -f "${_pkgbuild_archive_path}" ]]; then
-        msg_warn "PKGBUILD has already been downloaded."
+        msg_warn "PKGBUILD has already been downloaded"
         msg_warn -n "Do you want to overwrite and download? [n] :"
         local _yes_or_no
         if [[ "${noconfirm}" = true ]]; then
@@ -723,7 +926,7 @@ install_aur_package() {
     fi
     if [[ "${_download_pkgbuild}" = true ]]; then
         remove "${_pkgbuild_archive_path}"
-        curl -L -C - -f -o "${_pkgbuild_archive_path}" "${_aur_snapshot_url}"
+        "${curl_command}"  ${curl_args} -L -C - -f -o "${_pkgbuild_archive_path}" "${_aur_snapshot_url}"
     fi
 
     # PKGBUILDを展開
@@ -733,7 +936,7 @@ install_aur_package() {
     # .SRCINFOを解析
     local _build_dir="${wfa_cache_dir}/build/${_package}"
     if [[ ! -f "${_build_dir}/.SRCINFO" ]]; then
-        msg_warn ".SRCINFO was not found.\nGenerate it using makepkg."
+        msg_warn ".SRCINFO was not found.\nGenerating it using makepkg"
         (
             cd "${_build_dir}"
             "${makepkg_command}" --printsrcinfo > "${_build_dir}/.SRCINFO"
@@ -743,9 +946,9 @@ install_aur_package() {
     local _makedepends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".makedepends[]?")"
     local _depends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".depends[]?")"
     local _conflicts="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".conflicts[]?")"
-    msg_debug "makedepends: ${_makedepends}"
-    msg_debug "depends: ${_depends}"
-    msg_debug "conflicts: ${_conflicts}"
+    msg_debug "makedepends: %s" "${_makedepends}"
+    msg_debug "depends: %s" "${_depends}"
+    msg_debug "conflicts: %s " "${_conflicts}"
 
 
     # 衝突を確認
@@ -761,7 +964,7 @@ install_aur_package() {
         _conflicts_found=true
     fi
     if [[ "${_conflicts_found}" = true ]]; then
-        msg_error "A conflict was found."
+        msg_error "Conflict(s) was found"
         exit 1
     fi
 
@@ -779,8 +982,8 @@ install_aur_package() {
     # ビルド準備
     # srcdirの確認
     if [[ -d "${_build_dir}/src" ]]; then
-        msg_info "Found ${_build_dir}/src"
-        msg_info "Packages to cleanBuild? [n] :"
+        msg_info "Found %s" "${_build_dir}/src"
+        msg_info -n "Packages to cleanBuild? [n] :"
         local _yes_or_no
         unset _yes_or_no
         if [[ "${noconfirm}" = true ]]; then
@@ -808,7 +1011,7 @@ install_aur_package() {
         cd "${_build_dir}"
         "${makepkg_command}" --printsrcinfo > "${_build_dir}/.SRCINFO"
     )
-    local _pkgnames=($(get_srcinfo_data "${_build_dir}/.SRCINFO" ".packages | keys[]" | sed 's/ //g'))
+    local _pkgnames=($(get_srcinfo_data "${_build_dir}/.SRCINFO" ".packages | keys[]"))
     local _pkgver="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".pkgver" | sed 's/ //g')"
     local _pkgrel="$(get_srcinfo_data "${_build_dir}/.SRCINFO" ".pkgrel" | sed 's/ //g')"
     local _arch_array=($(get_srcinfo_data "${_build_dir}/.SRCINFO" ".arch[]"))
@@ -816,7 +1019,7 @@ install_aur_package() {
     if [[ "${_arch_array[*]}" = "any" ]]; then
         _arch="any"
     else
-        _arch="$(uname -m)"
+        _arch="${arch}"
     fi
     local _PKGEXT=$(
         source "${makepkg_config}"
@@ -834,33 +1037,63 @@ install_aur_package() {
 # AURのパッケージを検索
 search_aur_package() {
     local _package="${1}"
-    local _aur_json=$(curl -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name-desc&arg=${_package}" | jq -r )
-    local _found_result_count="$(echo "${_aur_json}" | jq -r ".resultcount")"
-    if (( "${_found_result_count}" == 0 )); then
-        msg_error "Could not find all required packages:\n     ${_package}"
+    local _aur_json="$(get_aur_json "${_package}")"
+    if [[ -z "${_aur_json}" ]]; then
+        msg_error "Could not find all required packages: %s" "${_package}"
         exit 1
     fi
-    _aur_json=$(echo "${_aur_json}" | jq -r ".results[]")
-
-    #echo ${_aur_json} 
-
     local _found_pkgname=($(echo "${_aur_json}" | jq -r ".Name" ))
 
+    if [[ "${quiet}" = true ]]; then
+        local _IFS="${IFS}"
+        IFS=$'\n'
+        echo "${_found_pkgname[*]}"
+        IFS="${_IFS}"
+    else
+        local  _found_package __pkgver __popularity __vote __pkgdesc __orphaned __installed __output_text=()
+        for _found_package in ${_found_pkgname[@]}; do
+            __orphaned=false
+            __installed=false
+            _found_json="$(echo ${_aur_json} | jq "select(.Name == \"${_found_package}\")")"
+
+            #echo "${_found_json}"
+            __pkgver="$(echo "${_found_json}" | jq -r ".Version" )"
+            __popularity="$(echo "${_found_json}" | jq -r ".Popularity" )"
+            __vote="$(echo "${_found_json}" | jq -r ".NumVotes" )"
+            __pkgdesc="$(echo "${_found_json}" | jq -r ".Description" )"
+
+            # 人気度の少数2位以下を四捨五入
+            # 参考: http://www.rivhiro-weather.com/knowledge/?p=536
+            msg_debug "Raw popularity: %s" "${__popularity}"
+            __popularity="$(printf "%g\n" "${__popularity}" | awk '{printf("%4.2f", $1)}')"
+
+            # 孤児判定
+            #参考: https://www.366service.com/jp/qa/7c95f46e5236039134ff5b862ae2cd13
+            if ! echo "${_found_json}" | jq -r --exit-status ".Maintainer" 1> /dev/null 2> /dev/null ; then
+                __orphaned=true
+            fi
 
+            # インストール済み判定
+            if check_installed_package "${_found_package}"; then
+                __installed=true
+            fi
 
+            __output_text+=(
+                "$(text -n -c blue -b "aur")/$(text -n -b "${_found_package}") $(text -n -c cyan "${__pkgver}") (+$(text -n -b "${__vote} ${__popularity}"))"
+            )
+            
+            if [[ "${__orphaned}" = true ]]; then
+                __output_text+=("$(text -bc red "(Orphaned)")")
+            fi
 
-    local  _found_package __pkgver __popularity __vote __pkgdesc
-    for _found_package in ${_found_pkgname[@]}; do
-        _found_json="$(echo ${_aur_json} | jq "select(.Name == \"${_found_package}\")")"
-        __pkgver="$(echo "${_found_json}" | jq -r ".Version" )"
-        __popularity="$(echo "${_found_json}" | jq -r ".Popularity" )"
-        __vote="$(echo "${_found_json}" | jq -r ".NumVotes" )"
-        __pkgdesc="$(echo "${_found_json}" | jq -r ".Description" )"
-    
-        echo "aur/${_found_package} ${__pkgver} (+${__vote} ${__popularity})"
-        echo "    ${__pkgdesc}"
-        unset __pkgver __popularity __vote __pkgdesc _found_json
-    done
+            if [[ "${__installed}" = true ]]; then
+                __output_text+=("$(text -bc cyan "[Installed]")")
+            fi
+            echo "${__output_text[*]}"
+            echo "    ${__pkgdesc}"
+            unset __pkgver __popularity __vote __pkgdesc _found_json __orphaned __installed __output_text
+        done
+    fi
 }
 
 # バージョンを表示して終了
@@ -878,30 +1111,59 @@ operation_remove() {
 
 # Usage: install_package <package1> <package2>...
 install_package() {
-    local _package
+    local _package _repo_packages=() _aur_packages=()
     for _package in ${@}; do
         if ! check_installed_package "${_package}"; then
             if ! check_aur_package "${_package}"; then
                 # 公式パッケージなのでpacmanでそのままインストール
-                run_pacman ${pacman_args} "${_package}"
+                _repo_packages+=("${_package}")
             else
                 # AUR上のパッケージの場合の処理
-                install_aur_package "${_package}"
-                #msg_error "Getting the AUR package has not been implemented yet.
-                #exit 1
+                _aur_packages+=("${_package}")
             fi
         fi
     done
+
+    if (( "${#_repo_packages[@]}" > 0 )); then
+        run_pacman --asdeps ${pacman_args} "${_repo_packages[@]}"
+    fi
+
+    if (( "${#_aur_packages[@]}" > 0 )); then
+        unset _package
+        for _package in ${_aur_packages[@]}; do
+            install_aur_package "${_package}"
+        done
+    fi
+}
+
+upgrade_aur_package() {
+    #ここまで翻訳
+    msg_error "This is a feature that has not been implemented yet"
 }
 
 operation_sync(){
     local _package
+    if (( "${sync_clean_count}" >= 1 )); then
+        remove "$(get_cache_dir)/wfa"
+        run_pacman ${pacman_args} $(
+            local _count
+            for _count in $(seq 1 ${sync_clean_count}); do
+                echo -n "-c "
+            done
+        )
+    fi
+
+
     if [[ "${sync_search}" = true ]]; then
         for _package in ${specified_packages[@]}; do
             search_aur_package "${_package}"
         done
-        "${pacman_command}" ${pacman_args} ${specified_packages[@]}
+        "${pacman_command}" ${pacman_args} ${specified_packages[@]} || :
     else
+        if [[ "${sync_upgrade}" = true ]]; then
+            upgrade_aur_package
+            run_pacman ${pacman_args} --sysupgrade
+        fi
         for _package in ${specified_packages[@]}; do
             if ! check_aur_package "${_package}" && [[ "${force_aur}" = false ]]; then
                 # 公式パッケージなのでpacmanでそのままインストール
@@ -917,10 +1179,70 @@ operation_sync(){
 }
 
 
+operation_vote() {
+
+    # aurvoteの確認
+    if ! type aurvote 1> /dev/null 2> /dev/null; then
+        msg_error "There is no aurvote"
+        msg_error "Please install with %s" "\"wfa -S aurvote\""
+        exit 1
+    fi
+
+    local _package _aur_json _found_result_count _pkgver _before_popularity _before_vote
+    for _package in ${specified_packages[@]}; do
+
+        # 存在するパッケージか確認
+        local _aur_json="$(get_aur_json "${_package}")"
+        if [[ -z "${_aur_json}" ]]; then
+            msg_error "Could not find all required packages: %s" "${_package}"
+            exit 1
+        fi
+        _aur_json=$(echo "${_aur_json}" | jq -r "select(.Name == \"${_package}\")")
+
+        # jsonから値を取り出して整形
+        _pkgver="$(echo "${_aur_json}" | jq -r ".Version" )"
+        _before_popularity="$(printf "%g\n" "$(echo "${_aur_json}" | jq -r ".Popularity" )" | awk '{printf("%4.2f", $1)}')"
+        _before_vote="$(echo "${_aur_json}" | jq -r ".NumVotes" )"
+
+        # 投票を操作
+        if [[ "$(aurvote --check "${_package}")" = "not voted" ]]; then
+            msg_info "Voted for %s" "${_package}"
+            aurvote --vote "${_package}" 1> /dev/null
+        else
+            msg_info "Unvoted for %s" "${_package}"
+            aurvote --unvote "${_package}" 1> /dev/null
+        fi
+
+        # 投票後の値を取得
+        _aur_json=$(get_aur_json | jq -r "select(.Name == \"${_package}\")")
+        _after_popularity="$(printf "%g\n" "$(echo "${_aur_json}" | jq -r ".Popularity" )" | awk '{printf("%4.2f", $1)}')"
+        _after_vote="$(echo "${_aur_json}" | jq -r ".NumVotes" )"
+
+        # 結果を出力
+        msg_info "%s %s (+%s) → (+%s)" "$(text -b "${_package}")" "$(text -c cyan "${_pkgver}")" "$(text -b "${_before_vote} ${_before_popularity}")" "$(text -b "${_after_vote} ${_after_popularity}")"
+    done
+}
+
+unavailable_in_this_operation() {
+    msg_error "This option is not available in the current operation"
+    exit 1
+}
+
+# オペレーションを実行します
+run_operation() {
+    local _operation="${1}"
+    msg_debug "Operation: %s" "${_operation}"
+    if [[ "${quiet}" = false ]]; then
+        msg_warn "This program is an alpha version that is not yet stable\nIf you find a bug, please share it on GitHub\nhttps://github.com/hayao0819/wfa/issues"
+    fi
+
+    operation_${_operation}
+}
+
 # Parse options
 ARGUMENT="${@}"
-_opt_short="QRShVdb:ays"
-_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"
+_opt_short="AQRShVdb:aysucqn"
+_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,color:,nocolor,clean,quiet,arch:,confirm,disable-download-timeout,curl:,curlflags:,unneeded,puella,wfa-debug,cascade"
 
 OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- ${ARGUMENT})
 [[ ${?} != 0 ]] && exit 1
@@ -931,6 +1253,10 @@ msg_debug "Argument: ${OPT}"
 
 while :; do
     case ${1} in
+        -A | --vote)
+            set_operation "vote"
+            shift 1
+            ;;
         -Q | --query)
             set_operation "query"
             shift 1
@@ -984,11 +1310,121 @@ while :; do
             option_y_count=$(( option_y_count + 1 ))
             shift 1
             ;;
-        -s | --search)
-            add_args pacman "--search"
-            sync_search=true
+        -s | --search | --recursive)
+            case "${1}" in
+                --search)
+                    if [[ "${operation}" = "sync" ]]; then
+                        add_args pacman "--search"
+                        sync_search=true
+                    else
+                        unavailable_in_this_operation
+                    fi
+                    ;;
+                --recursive)
+                    if [[ "${operation}" = "remove" ]]; then
+                        add_args pacman "--recursive"
+                    else
+                        unavailable_in_this_operation
+                    fi
+                    ;;
+                -s)
+                    case "${operation}" in
+                        "sync")
+                            add_args pacman "--search"
+                            sync_search=true
+                            ;;
+                        "remove")
+                            add_args pacman "--recursive"
+                            ;;
+                        *)
+                            unavailable_in_this_operation
+                            ;;
+                    esac
+                    ;;
+            esac
+            shift 1
+            ;;
+        -u | --sysupgrade | --unneeded)
+            case "${1}" in
+                --sysupgrade)
+                    if [[ "${operation}" = "sync" ]]; then
+                        sync_upgrade=true
+                    else
+                        unavailable_in_this_operation
+                    fi
+                    ;;
+                --unneeded)
+                    if [[ "${operation}" = "remove" ]]; then
+                        add_args pacman "--unneeded"
+                    else
+                        unavailable_in_this_operation
+                    fi
+                    ;;
+                -u)
+                    case "${operation}" in
+                        "sync")
+                            sync_upgrade=true
+                            ;;
+                        "remove")
+                            add_args pacman "--unneeded"
+                            ;;
+                        "none")
+                            :
+                            ;;
+                        *)
+                            unavailable_in_this_operation
+                            ;;
+                    esac
+                    ;;
+            esac
+            shift 1
+            ;;
+        -c | --clean | --cascade)
+            case "${1}" in
+                --clean)
+                    if [[ "${operation}" = "sync" ]]; then
+                        sync_clean_count=$(( sync_clean_count + 1 ))
+                    else
+                        unavailable_in_this_operation
+                    fi
+                    ;;
+                --cascade)
+                    if [[ "${operation}" = "remove"  ]]; then
+                        add_args pacman "--cascade"
+                    else
+                        unavailable_in_this_operation
+                    fi
+                    ;;
+                -c)
+                    case "${operation}" in
+                        "sync")
+                            sync_clean_count=$(( sync_clean_count + 1 ))
+                            ;;
+                        "remove")
+                            add_args pacman "--cascade"
+                            ;;
+                        *)
+                            unavailable_in_this_operation
+                            ;;
+                    esac
+                    ;;
+            esac
+            shift 1
+            ;;
+        -q | --quiet)
+            quiet=true
+            add_args pacman "--quiet"
             shift 1
             ;;
+        -n | --nosave)
+            add_args pacman "--nosave"
+            shift 1
+            ;;
+        --arch)
+            arch="${2}"
+            add_args pacman "--arch ${2}"
+            shift 2
+            ;;
         --aururl)
             aururl="${2}"
             shift 2
@@ -1000,7 +1436,7 @@ while :; do
             ;;
         --config)
             pacman_config="${2}"
-            add_args pacman "--config \"${2}\""
+            add_args pacman "--config ${2}"
             shift 2
             ;;
         --makepkg)
@@ -1008,7 +1444,8 @@ while :; do
             shift 2
             ;;
         --mflags)
-            makepkg_args="${2}"
+            #makepkg_args="${2}"
+            add_args makepkg "${2}"
             shift 2
             ;;
         --pacman)
@@ -1020,7 +1457,8 @@ while :; do
             shift 2
             ;;
         --gitflags)
-            git_args="${2}"
+            #git_args="${2}"
+            add_args git "${2}"
             shift 2
             ;;
         --makepkgconfig)
@@ -1045,6 +1483,54 @@ while :; do
             msgdebug=true
             shift 1
             ;;
+        --color)
+            case "${2}" in
+                "never")
+                    nocolor=true
+                    add_args pacman "--color never"
+                    ;;
+                "always")
+                    nocolor=false
+                    add_args pacman "--color always"
+                    ;;
+                "auto")
+                    msg_error "auto is not currently supported."
+                    add_args pacman "--color auto"
+                    ;;
+            esac
+            ;;
+        --nocolor)
+            nocolor=true
+            add_args pacman "--color never"
+            shift 1
+            ;;
+        --confirm)
+            noconfirm=false
+            shift 1
+            ;;
+        --disable-download-timeout)
+            add_args curl "--max-time 0"
+            add_args pacman "--disable-download-timeout"
+            shift 1
+            ;;
+        --curl)
+            curl_command="${2}"
+            shift 2
+            ;;
+        --curlflags)
+            add_args curl "${2}"
+            shift 2
+            ;;
+        --puella)
+            text -flb "Please make a contract with me and become a Puella Magi !"
+            echo
+            shift 1
+            exit 0
+            ;;
+        --wfa-debug)
+            debug=true
+            shift 1
+            ;;
         -h | --help)
             usage
             shift 1
@@ -1069,21 +1555,16 @@ elif (( "${option_y_count}" >= 2 )); then
     run_pacman -Syy
 fi
 
+# set_operationで設定された操作を実行
 case "${operation}" in
-    "version")
-        operation_version
-        ;;
-    "sync")
-        operation_sync
-        ;;
-    "remove")
-        operation_remove
+    "version" | "sync" | "remove" | "vote")
+        run_operation "${operation}"
         ;;
     "none")
         exit 0
         ;;
     *)
-        msg_error "Undefined operation."
+        msg_error "Undefined operation"
         exit 1
         ;;
 esac