OSDN Git Service

[update] : Added makepkg
[alterlinux/wfa.git] / wfa
1 #!/usr/bin/env bash
2
3 set -eu
4
5 msgdebug=false
6 nocolor=false
7 debug=false
8 pacman_args=""
9 makepkg_args=""
10 operation="none"
11 force_aur=false
12 noconfirm=false
13
14 wfa_version="0.1"
15 aururl="https://aur.archlinux.org/"
16 pacman_config="/etc/pacman.conf"
17
18 # メッセージ出力の制御
19 # https://github.com/FascodeNet/alterlinux/blob/dev/tools/msg.sh の変数名にアンダーバーを追加し関数化
20 msg() {
21     local OPTIND OPTARG arg
22
23     local _appname="msg.sh"
24     local _bash_debug=false
25     local _nocolor=false
26     local _echo_opts=""
27     local _message=""
28     local _msg_type="info"
29     local _msg_label=""
30     local _label_space="7"
31     local _adjust_chr=" "
32     local _customized_label=false
33     local _customized_label_color=false
34     local _nolabel=false
35     local _noappname=false
36     local _noadjust=false
37     local _output="stdout"
38
39     _help() {
40         echo "usage ${0} [option] [type] [message]"
41         echo
42         echo "Display a message with a colored app name and message type label"
43         echo
44         echo " General type:"
45         echo "    info                      General message"
46         echo "    warn                      Warning message"
47         echo "    error                     Error message"
48         echo "    debug                     Debug message"
49         echo
50         echo " General options:"
51         echo "    -a [name]                 Specify the app name"
52         echo "    -c [character]            Specify the character to adjust the label"
53         echo "    -l [label]                Specify the label."
54         echo "    -n | --nocolor            No output colored output"
55         echo "    -o [option]               Specify echo options"
56         echo "    -r [color]                Specify the color of label"
57         echo "    -s [number]               Specifies the label space."
58         echo "    -x | --bash-debug         Enables output bash debugging"
59         echo "    -h | --help               This help message"
60         echo
61         echo "         --nolabel            Do not output label"
62         echo "         --noappname          Do not output app name"
63         echo "         --noadjust           Do not adjust the width of the label"
64     }
65
66     while getopts "a:c:l:no:r:s:xh-:" arg; do
67         case ${arg} in
68                 a) 
69                     _appname="${OPTARG}"
70                     ;;
71                 c) 
72                     _adjust_chr="${OPTARG}"
73                     ;;
74                 l) 
75                     _customized_label=true
76                     _msg_label="${OPTARG}"
77                     ;;
78                 n)
79                     _nocolor=true
80                     ;;
81                 o)
82                     _echo_opts="${OPTARG}"
83                     ;;
84                 r)
85                     _customized_label_color=true
86                     case ${OPTARG} in
87                         "black")
88                             _labelcolor="30"
89                             ;;
90                         "red")
91                             _labelcolor="31"
92                             ;;
93                         "green")
94                             _labelcolor="32"
95                             ;;
96                         "yellow")
97                             _labelcolor="33"
98                             ;;
99                         "blue")
100                             _labelcolor="34"
101                             ;;
102                         "magenta")
103                             _labelcolor="35"
104                             ;;
105                         "cyan")
106                             _labelcolor="36"
107                             ;;
108                         "white")
109                             _labelcolor="37"
110                             ;;
111                         *)
112                             return 1
113                             ;;
114                     esac
115                     ;;
116                 s)
117                     _label_space="${OPTARG}"
118                     ;;
119                 x)
120                     _bash_debug=true
121                     set -xv
122                     ;;
123                 h)
124                     _help
125                     shift 1
126                     exit 0
127                     ;;
128                 -)
129                     case "${OPTARG}" in
130                         "nocolor")
131                             _nocolor=true
132                             ;;
133                         "bash-debug")
134                             _bash_debug=true
135                             set -xv
136                             ;;
137                         "help") 
138                             _help
139                             exit 0
140                             ;;
141                         "nolabel")
142                             _nolabel=true
143                             ;;
144                         "noappname")
145                             _noappname=true
146                             ;;
147                         "noadjust")
148                             _noadjust=true 
149                             ;;
150                         *)
151                             _help
152                             exit 1
153                             ;;
154                     esac
155         esac
156     done
157
158     shift $((OPTIND - 1))
159
160     # Color echo
161     #
162     # Text Color
163     # 30 => Black
164     # 31 => Red
165     # 32 => Green
166     # 33 => Yellow
167     # 34 => Blue
168     # 35 => Magenta
169     # 36 => Cyan
170     # 37 => White
171     #
172     # Background color
173     # 40 => Black
174     # 41 => Red
175     # 42 => Green
176     # 43 => Yellow
177     # 44 => Blue
178     # 45 => Magenta
179     # 46 => Cyan
180     # 47 => White
181     #
182     # Text decoration
183     # You can specify multiple decorations with ;.
184     # 0 => All attributs off (ノーマル)
185     # 1 => Bold on (太字)
186     # 4 => Underscore (下線)
187     # 5 => Blink on (点滅)
188     # 7 => Reverse video on (色反転)
189     # 8 => Concealed on
190
191     case ${1} in
192         "info")
193             _msg_type="type"
194             _output="stdout"
195             [[ "${_customized_label_color}" = false ]] && _labelcolor="32"
196             [[ "${_customized_label}"       = false ]] && _msg_label="Info"
197             shift 1
198             ;;
199         "warn")
200             _msg_type="warn"
201             _output="stdout"
202             [[ "${_customized_label_color}" = false ]] && _labelcolor="33"
203             [[ "${_customized_label}"       = false ]] && _msg_label="Warning"
204             shift 1
205             ;;
206         "debug")
207             _msg_type="debug"
208             _output="stdout"
209             [[ "${_customized_label_color}" = false ]] && _labelcolor="35"
210             [[ "${_customized_label}"       = false ]] && _msg_label="Debug"
211             shift 1
212             ;;
213         "error")
214             _msg_type="error"
215             _output="stderr"
216             [[ "${_customized_label_color}" = false ]] && _labelcolor="31"
217             [[ "${_customized_label}"       = false ]] && _msg_label="Error"
218             shift 1
219             ;;
220         "")
221             echo "Please specify the message type" >&2
222             exit 1
223             ;;
224         *)
225             echo "Unknown message type" >&2
226             exit 1
227             ;;
228     esac
229
230     _word_count="${#_msg_label}"
231     _message="${@}"
232
233     echo_type() {
234         local __time
235         if [[ "${_nolabel}" = false ]]; then
236             if [[ "${_noadjust}" = false ]]; then
237                 for __time in $( seq 1 $(( ${_label_space} - ${_word_count})) ); do
238                     echo -ne "${_adjust_chr}"
239                 done
240             fi
241             if [[ "${_nocolor}" = false ]]; then
242                 echo -ne "\e[$([[ -v _backcolor ]] && echo -n "${_backcolor}"; [[ -v _labelcolor ]] && echo -n ";${_labelcolor}"; [[ -v _decotypes ]] && echo -n ";${_decotypes}")m${_msg_label}\e[m "
243             else
244                 echo -ne "${_msg_label} "
245             fi
246         fi
247     }
248
249     echo_appname() {
250         if [[ "${_noappname}" = false ]]; then
251             if [[ "${_nocolor}" = false ]]; then
252                 echo -ne "\e[36m[${_appname}]\e[m "
253             else
254                 echo -ne "[${_appname}] "
255             fi
256         fi
257     }
258
259     for _count in $(seq "1" "$(echo -ne "${_message}\n" | wc -l)"); do
260         _echo_message=$(echo -ne "${_message}\n" |head -n "${_count}" | tail -n 1 )
261         _full_message="$(echo_appname)$(echo_type)${_echo_message}"
262         case "${_output}" in
263             "stdout")
264                 echo ${_echo_opts} "${_full_message}" >&1
265                 ;;
266             "stderr")
267                 echo ${_echo_opts} "${_full_message}" >&2
268                 ;;
269             *)
270                 echo ${_echo_opts} "${_full_message}" > ${_output}
271                 ;;
272         esac
273     done
274 }
275
276 # Show an INFO message
277 # $1: message string
278 msg_info() {
279     local _msg_opts="-a WFA"
280     if [[ "${1}" = "-n" ]]; then
281         _msg_opts="${_msg_opts} -o -n"
282         shift 1
283     fi
284     [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
285     [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
286     msg ${_msg_opts} info "${1}"
287 }
288
289 # Show an Warning message
290 # $1: message string
291 msg_warn() {
292     local _msg_opts="-a WFA"
293     if [[ "${1}" = "-n" ]]; then
294         _msg_opts="${_msg_opts} -o -n"
295         shift 1
296     fi
297     [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
298     [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
299     msg ${_msg_opts} warn "${1}"
300 }
301
302 # Show an debug message
303 # $1: message string
304 msg_debug() {
305     if [[ "${debug}" = true ]]; then
306         local _msg_opts="-a WFA"
307         if [[ "${1}" = "-n" ]]; then
308             _msg_opts="${_msg_opts} -o -n"
309             shift 1
310         fi
311         [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
312         [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
313         msg ${_msg_opts} debug "${1}"
314     fi
315 }
316
317 # Show an ERROR message then exit with status
318 # $1: message string
319 # $2: exit code number (with 0 does not exit)
320 msg_error() {
321     local _msg_opts="-a WFA"
322     if [[ "${1}" = "-n" ]]; then
323         _msg_opts="${_msg_opts} -o -n"
324         shift 1
325     fi
326     [[ "${msgdebug}" = true ]] && _msg_opts="${_msg_opts} -x"
327     [[ "${nocolor}"  = true ]] && _msg_opts="${_msg_opts} -n"
328     msg ${_msg_opts} error "${1}"
329     if [[ -n "${2:-}" ]]; then
330         exit ${2}
331     fi
332 }
333
334 # rm helper
335 # Delete the file if it exists.
336 # For directories, rm -rf is used.
337 # If the file does not exist, skip it.
338 # remove <file> <file> ...
339 remove() {
340     local _list=($(echo "$@")) _file
341     for _file in "${_list[@]}"; do
342         msg_debug "Removing ${_file}"
343         if [[ -f "${_file}" ]]; then    
344             rm -f "${_file}"
345         elif [[ -d "${_file}" ]]; then
346             rm -rf "${_file}"
347         fi
348     done
349 }
350
351 usage (){
352     local _pacman_help=false
353
354     local _wfa_usage
355     _wfa_usage() {
356         echo "Usage:"
357         echo "wfa"
358         echo "wfa <operation> [...]"
359         echo
360         echo "operations:"
361         echo "wfa {-h --help}"
362         echo "wfa {-V --version}"
363         #echo "wfa {-D --database}    <options> <package(s)>"
364         #echo "wfa {-F --files}       [options] [package(s)]"
365         echo "wfa {-Q --query}       [options] [package(s)]"
366         echo "wfa {-R --remove}      [options] <package(s)>"
367         echo "wfa {-S --sync}        [options] [package(s)]"
368         #echo "wfa {-T --deptest}     [options] [package(s)]"
369         #echo "wfa {-U --upgrade}     [options] <file(s)>"
370     }
371
372     local _wfa_usage_sync
373     _wfa_usage_sync() {
374         echo "usage:  wfa {-S --sync} [options] [package(s)]"
375         echo "options:"
376         echo "  -b, --dbpath <path>  set an alternate database location"
377         echo "      --config <path>  set an alternate configuration file"
378         echo "      --noconfirm      do not ask for any confirmation"
379
380     }
381
382     if [[ "${operation}" = "none" ]]; then
383         _wfa_usage
384     elif [[ "${_pacman_help}" = true ]]; then
385         pacman -h --${operation}
386     elif [[ "$(type -t "_wfa_usage_${operation}" )" = "function" ]]; then
387         _wfa_usage_${operation}
388     else
389         msg_error "Undefined operation." 1
390     fi
391 }
392
393 set_operation() {
394     if [[ "${operation}" = "none" ]]; then
395         operation="${1}"
396         add_args pacman "--${operation}"
397     else
398         msg_error "only one operation may be used at a time" 1
399     fi
400 }
401
402 run_sudo() {
403     if (( ${UID} == 0 )); then
404         ${@}
405     else
406         sudo ${@}
407     fi
408 }
409
410 run_pacman() {
411     run_sudo pacman ${pacman_args} ${@}
412 }
413
414 # pacmanの引数を追加する
415 # https://github.com/FascodeNet/aptpac/blob/master/aptpac のADD_OPTION関数を参考
416 # Usage: add_args [pacman/makepkg] <args1> <args2>...
417 add_args() {
418     local _target="${1}"
419     local _args_array
420     shift 1
421
422     case "${_target}" in
423         "makepkg")
424             _args_array=(${makepkg_args})
425             _args_array+=(${@})
426             makepkg_args=${_args_array[@]}
427             msg_debug "MAKEPKG ARGS: ${makepkg_args}"
428             ;;
429
430         "pacman")
431             _args_array=(${pacman_args})
432             _args_array+=(${@})
433             pacman_args=${_args_array[@]}
434             msg_debug "PACMAN ARGS: ${pacman_args}"
435             ;;
436     esac
437 }
438
439 # 引数で指定されたパッケージがAUR以外の場所に存在しない場合にのみ正常終了します(AURのパッケージの場合に正常終了)
440 check_aur_package() {
441     local _package="${1}"
442     # 参考: https://qiita.com/Hayao0819/items/a8740a17301fafa2fdab
443     if [[ -z "$(pacman -Ssq "${_package}" 2>/dev/null | grep -o ".*${_package}$")" ]]; then
444         #AUR以外のリポジトリに存在しない
445         return 0
446     else
447         return 1
448     fi
449 }
450
451
452 # 引数で指定されたパッケージが既にインストールされている場合は正常終了します。
453 check_installed_package() {
454     local _package="${1}"
455     if pacman -Qq "${_package}" 2> /dev/null 1>&2; then
456         return 0
457     else
458         return 1
459     fi
460 }
461
462 get_cache_dir() {
463     local _user_config_dir
464     if [[ -v XDG_CONFIG_HOME ]]; then
465         _user_config_dir="${XDG_CONFIG_HOME}"
466     else
467         _use_config_dir="${HOME}/.config"
468     fi
469     if [[ -f "${_use_config_dir}/user-dirs.dirs" ]]; then
470         source "${_use_config_dir}/user-dirs.dirs"
471     fi
472     if [[ -v XDG_CACHE_HOME ]]; then
473         echo -n "${XDG_CACHE_HOME}"
474         return 0
475     else
476         echo -n "${HOME}/.cache"
477         return 0
478     fi
479 }
480
481 # Usage: get_srcinfo_data <path> <var>
482 : << "DISABLED"
483 get_srcinfo_data() {
484     local _srcinfo="${1}" _ver="${2}"
485     local _srcinfo_json=$(python << EOF
486 from srcinfo.parse import parse_srcinfo; import json
487 text = """
488 $(cat ${1})
489 """
490 parsed, errors = parse_srcinfo(text)
491 print(json.dumps(parsed))
492 EOF
493     )
494     echo "${_srcinfo_json}" | jq -r .${2}
495 }
496 DISABLED
497
498 get_srcinfo_data() {
499     local _srcinfo="${1}"
500     local _var="${2}"
501     local _pkg _output
502     if [[ ! -f "${_srcinfo}" ]]; then
503         msg_error ".SRCINFO does not exist."
504     fi
505     for _pkg in $(cat "${_srcinfo}" | grep "${_var} = " | cut -d ' ' -f "3"); do
506         _output+=(${_pkg})
507     done
508     echo -n "${_output[@]}"
509 }
510
511
512 # AURからパッケージをビルドしてインストールします
513 # 現在1つのパッケージしか指定できません
514 install_aur_package() {
515     local _package="${1}"
516
517     # Create cache dir
518     if [[ ! -v wfa_cache_dir ]]; then
519         wfa_cache_dir="$(get_cache_dir)/wfa"
520     fi
521     mkdir -p "${wfa_cache_dir}/archive"
522     mkdir -p "${wfa_cache_dir}/build/${_package}"
523
524     # AurJsonから値を取得
525     local _aur_json=$(curl -sL "https://aur.archlinux.org/rpc/?v=5&type=search&by=name&arg=${_package}" | jq -r)
526     if (( "$(echo "${_aur_json}" | jq -r ".resultcount")" == 0 )); then
527         msg_error "Could not find all required packages:\n      ${_package}" 1
528     fi
529
530     local _found_packages="$(echo "${_aur_json}" | jq -r --tab '.results[].Name')"
531     #msg_debug "Found package: $(echo ${_found_packages} | tr '\n' ' ')"
532
533     if [[ -n "$(echo "${_found_packages}" | grep -x "${_package}" )" ]]; then
534         msg_debug "Select a package ${_package} with an exact name match"
535     else
536         msg_error "No package with an exact name match was found." 1
537     fi
538
539     # PKGBUILDをダウンロード
540     msg_info "Download PKGBUILD of ${_package}"
541     _aur_json=$(echo "${_aur_json}" | jq -r ".results[] | select(.Name == \"${_package}\")" )
542     local _aur_snapshot_url="${aururl%/}$(echo "${_aur_json}" | jq -r ".URLPath")"
543     local _aur_version="$(echo "${_aur_json}" | jq -r ".Version")"
544     msg_debug "Get PKGBUILD from ${_aur_snapshot_url}"
545
546     local _pkgbuild_archive_path="${wfa_cache_dir}/archive/${_package}-${_aur_version}"
547     local _download_pkgbuild=true
548     if [[ -f "${_pkgbuild_archive_path}" ]]; then
549         msg_warn "PKGBUILD has already been downloaded."
550         msg_warn -n "Do you want to overwrite and download? [n] :"
551         local _yes_or_no
552         if [[ "${noconfirm}" = true ]]; then
553             echo
554             _yes_or_no="No"
555         else
556             read _yes_or_no
557         fi
558         case "${_yes_or_no}" in
559             "y" | "Y" | "yes" | "Yes" | "YES" ) _download_pkgbuild=true  ;;
560             *                                 ) _download_pkgbuild=false ;;
561         esac
562     fi
563     if [[ "${_download_pkgbuild}" = true ]]; then
564         remove "${_pkgbuild_archive_path}"
565         curl -L -C - -f -o "${_pkgbuild_archive_path}" "${_aur_snapshot_url}"
566     fi
567
568     # PKGBUILDを展開
569     msg_info "Unpacking the tarball of PKGBUILD ..."
570     tar -xv -f "${_pkgbuild_archive_path}" -C "${wfa_cache_dir}/build/" 2>/dev/null 1>&2
571
572     # .SRCINFOを解析
573     local _build_dir="${wfa_cache_dir}/build/${_package}"
574     if [[ ! -f "${_build_dir}/.SRCINFO" ]]; then
575         msg_warn ".SRCINFO was not found.\nGenerate it using makepkg."
576         makepkg -p "${_build_dir}/PKGBUILD" --printsrcinfo > "${_build_dir}/.SRCINFO"
577     fi
578
579     local _makedepends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" "makedepends")"
580     local _depends="$(get_srcinfo_data "${_build_dir}/.SRCINFO" "depends")"
581     local _conflicts="$(get_srcinfo_data "${_build_dir}/.SRCINFO" "conflicts")"
582     msg_debug "makedepends: ${_makedepends}"
583     msg_debug "depends: ${_depends}"
584     msg_debug "conflicts: ${_conflicts}"
585
586
587     # 衝突を確認
588     local _pkg _conflicts_found=false
589     for _pkg in ${_conflicts[@]}; do
590         if pacman -Qq "${_pkg}" 2>/dev/null 1>&2 ; then
591             _conflicts_found=true
592             msg_error "${_package} is colliding with ${_pkg}"
593         fi
594     done
595     if [[ ! "$(pacman -Qq "${_package}")" = "${_package}" ]]; then
596         msg_error "${_package} is colliding with $(pacman -Qq "${_package}")"
597         _conflicts_found=true
598     fi
599     if [[ "${_conflicts_found}" = true ]]; then
600         msg_error "A conflict was found." 1
601     fi
602
603
604     # 依存パッケージをインストール
605     msg_info "Install dependent packages..."
606     local _force_aur="${force_aur}"
607     force_aur=false
608     install_package "${_depends}"
609     force_aur="${_force_aur}"
610     unset _force_aur
611
612     # ビルド準備
613     # srcdirの確認
614     if [[ -d "${_build_dir}/src" ]]; then
615         msg_info "Found ${_build_dir}/src"
616         msg_info "Packages to cleanBuild? [n] :"
617         local _yes_or_no
618         unset _yes_or_no
619         if [[ "${noconfirm}" = true ]]; then
620             echo
621             _yes_or_no="No"
622         else
623             read _yes_or_no
624         fi
625         case "${_yes_or_no}" in
626             "y" | "Y" | "yes" | "Yes" | "YES" ) add_args makepkg "--clean" ;;
627         esac
628     fi
629
630     # ビルド
631     add_args makepkg "-p '${_build_dir}/PKGBUILD'"
632     makepkg ${makepkg_args}
633 }
634
635 # バージョンを表示して終了
636 operation_version() {
637     # Pyalpmからlibalpmの値を取得
638     # 参考: https://pyalpm.readthedocs.io/en/latest/pyalpm/pyalpm.html
639     local _libalpm_version="$(python3 -c 'import pyalpm; print(pyalpm.alpmversion())')"
640     local _pacman_version="$(pacman -Q pacman | cut -d ' ' -f 2)"
641     echo "wfa v${wfa_version} - pacman v${_pacman_version} - libalpm v${_libalpm_version}"
642 }
643
644 operation_remove() {
645     run_pacman "${specified_packages[@]}"
646 }
647
648 # Usage: install_package <package1> <package2>...
649 install_package() {
650     local _package
651     for _package in ${@}; do
652         if ! check_installed_package "${_package}"; then
653             if ! check_aur_package "${_package}"; then
654                 # 公式パッケージなのでpacmanでそのままインストール
655                 run_pacman "${_package}"
656             else
657                 # AUR上のパッケージの場合の処理
658                 install_aur_package "${_package}"
659                 #msg_error "Getting the AUR package has not been implemented yet." 1
660             fi
661         fi
662     done
663 }
664
665 operation_sync(){
666     local _package
667     for _package in ${specified_packages[@]}; do
668         if ! check_aur_package "${_package}" && [[ "${force_aur}" = false ]]; then
669             # 公式パッケージなのでpacmanでそのままインストール
670             run_pacman "${_package}"
671         else
672             # AUR上のパッケージの場合の処理
673             install_aur_package "${_package}"
674             #msg_error "Getting the AUR package has not been implemented yet." 1
675         fi
676     done
677 }
678
679
680 # Parse options
681 ARGUMENT="${@}"
682 _opt_short="QRShVdb:a"
683 _opt_long="query,remove,sync,help,version,debug,dbpath:,aururl,aur,noconfirm,config:"
684
685 OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- ${ARGUMENT})
686 [[ ${?} != 0 ]] && exit 1
687 unset _opt_short _opt_long
688
689 eval set -- "${OPT}"
690 msg_debug "Argument: ${OPT}"
691
692 while :; do
693     case ${1} in
694         -Q | --query)
695             set_operation "query"
696             shift 1
697             ;;
698         -R | --remove)
699             set_operation "remove"
700             shift 1
701             ;;
702         -S | --sync)
703             set_operation "sync"
704             shift 1
705             ;;
706         -V | --version)
707             set_operation "version"
708             shift 1
709             ;;
710         --)
711             shift
712             break
713             ;;
714         *)
715             shift 1
716             ;;
717     esac
718 done
719
720 eval set -- "${OPT}"
721
722 while :; do
723     case ${1} in
724         -a | --aur)
725             force_aur=true
726             msg_debug "Assume targets are from the AUR"
727             shift 1
728             ;;
729         -d | --debug)
730             debug=true
731             add_args pacman "--debug"
732             shift 1
733             ;;
734         -b | --dbpath)
735             add_args pacman "--dbpath '${2}'"
736             shift 2
737             ;;
738         --aururl)
739             aururl="${2}"
740             shift 2
741             ;;
742         --noconfirm)
743             add_args pacman "--noconfirm"
744             noconfirm=true
745             shift 1
746             ;;
747         --config)
748             pacman_config="${2}"
749             add_args pacman "--config \"${2}\""
750             shift 2
751             ;;
752         -h | --help)
753             usage
754             shift 1
755             exit 0
756             ;;
757         --)
758             shift
759             break
760             ;;
761         *)
762             shift 1
763             ;;
764     esac
765 done
766
767 specified_packages=(${@})
768
769 case "${operation}" in
770     "version")
771         operation_version
772         ;;
773     "sync")
774         operation_sync
775         ;;
776     "remove")
777         operation_remove
778         ;;
779     "none")
780         exit 0
781         ;;
782     *)
783         msg_error "Undefined operation." 1
784         ;;
785 esac