OSDN Git Service

[fix] : Check before asking target
[alterlinux/fascode-live-tools.git] / fascode-gtk-bookmarks / fascode-gtk-bookmarks
1 #!/usr/bin/env bash
2 # Yamada Hayao
3 # Twitter: @Hayao0819
4 # Email  : hayao@fascode.net
5 #
6 # kokkiemouse
7 # Mastodon: @kokkiemouse@mstdn.jp 
8 # Email   : kokkiemouse@fascode.net
9 #
10 # (c) 2019-2021 Fascode Network.
11 #
12
13
14 set -e
15
16 force=false
17 fascodelive=false
18 simulation=false
19 bookmark_file="${HOME}/.config/gtk-3.0/bookmarks"
20 backup_dir="${bookmark_file}.d/"
21
22 # Show message when file is removed
23 # remove <file> <file> ...
24 remove() {
25     rm -rf "${@}"
26 }
27
28 _help() {
29     echo "usage ${0} [options] [command]"
30     echo
31     echo " General options:"
32     echo "    -f | --force          Force overwriting"
33     echo "    -s | --simulation     Enable simulation"
34     echo "    -h | --help           This help message and exit"
35     echo "         --bakdir [dir]   Specify the directory used for backup and restore"
36     echo
37     echo " General command:"
38     echo "    add <dir> <name> ...  Add a item to the sidebar"
39     echo "    delete <dir> ...      Delete item from the sidebar"
40     echo "    alldelete             Delete all sidebar items"
41     echo "    init                  Initializes the sidebar"
42     echo "    backup                Backup sidebar"
43     echo "    restore               Restore bookmark from backup"
44     echo "    help                  This help message and exit"
45 }
46
47 # 質問を行う関数
48 # Returns only the selected result to standard output
49 # _ask -d <デフォルト値> -p <質問文> <選択肢1> <選択肢2> ...
50 _ask(){
51     local arg OPTARG OPTIND _default="" _choice_list _count _choice _question
52     while getopts "d:p:" arg; do
53         case "${arg}" in
54             d) _default="${OPTARG}" ;;
55             p) _question="${OPTARG}" ;;
56             *) exit 1 ;;
57         esac
58     done
59     shift "$((OPTIND - 1))"
60     _choice_list=("${@}")
61     _digit="${##}"
62
63     # 選択肢に関するエラー
64     if (( ${#_choice_list[@]} < 0 )); then
65         _msg_error "An exception error has occurred."
66         exit 1
67     fi
68
69     # 選択肢が1つしか無いならばそのまま値を返す
70     if (( ${#_choice_list[@]} <= 1 )); then
71         echo "${_choice_list[*]}"
72         return 0
73     fi
74
75     if [[ -v _question ]] && [[ ! "${_question}" = "" ]]; then
76         echo -e "${_question}" >&2
77     fi
78
79     for (( _count=1; _count<=${#_choice_list[@]}; _count++)); do
80         _choice="${_choice_list[$(( _count - 1 ))]}"
81         if [[ ! "${_default}" = "" ]] && [[ "${_choice}" = "${_default}" ]]; then
82             printf " * %${_digit}d: ${_choice}\n" "${_count}" >&2
83         else
84             printf "   %${_digit}d: ${_choice}\n" "${_count}" >&2
85         fi
86         unset _choice
87     done
88     echo -n "(1 ~ ${#_choice_list[@]}) > " >&2
89     read -r _input
90
91     # 回答を解析
92     if printf "%s" "${_input}" | grep -E "^[0-9]+$" 1>/dev/null 2>&1; then
93         # 数字が入力された
94         if (( 1 <= _input)) && (( _input <= ${#_choice_list[@]} )); then
95             _choice="${_choice_list[$(( _input - 1 ))]}"
96         else
97             return 1
98         fi
99     else
100         # 文字が入力された
101         if printf "%s\n" "${_choice_list[@]}" | grep -x "${_input}" 1>/dev/null 2>&1; then
102             _choice="${_input}"
103         else
104             return 1
105         fi
106     fi
107     echo "${_choice}"
108     return 0
109 }
110
111 output() {
112     if [[ "${simulation}" = true ]]; then
113         echo "${@}"
114     else
115         echo "${@}" >> "${bookmark_file}"
116     fi
117 }
118
119 _msg_error() {
120     echo "${@}" >&2
121 }
122
123 prepare() {
124     if [[ ! -d "$(dirname "${bookmark_file}")" ]]; then
125         mkdir -p "$(dirname "${bookmark_file}")"
126     fi
127     if [[ ! -f "${bookmark_file}" ]]; then
128         touch "${bookmark_file}"
129     fi
130 }
131
132 add() {
133
134     if [[ "${simulation}" = false ]]; then
135         prepare
136     fi
137     local name dir
138     while true; do
139         if [[ -z "${1+SET}" ]]; then
140             return 0
141         fi
142         if [[ -d "${1}" ]]; then
143             dir="${1}"
144             shift 1
145             if [[ -n "${1+SET}" ]] && [[ ! -d "${1}" ]]; then
146                 name="${1}"
147                 shift 1
148             else
149                 name="$(basename "${dir}")"
150             fi
151         else
152             _msg_error "${dir} does not exist."
153             exit 1
154         fi
155         echo "Added bookmark ${dir} as ${name}"
156         output "file://${dir} ${name}"
157
158     done
159 }
160
161
162 delete() {
163     if [[ ! -f "${bookmark_file}" ]]; then
164         _msg_error "Bookmark file does not exist."
165         exit 1
166     fi
167     local _dir _count _line_contain _remove_line=() _url _remove_count i=1
168     for (( i = 1; i <= "${#}"; i++)); do
169         cd "${PWD}"
170         _dir="$(eval echo '$'${i})"
171         _url="$(realpath "${_dir}" | sed "s/ /%20/g")"
172         cd "${OLDPWD}"
173         for _count in $(seq 1 $(cat "${bookmark_file}" | wc -l )); do
174             _line_contain="$(cat "${bookmark_file}" | head -n "${_count}" | tail -n 1 | cut -d ' ' -f 1)"
175             _line_contain="${_line_contain#file://}"
176             if [[ "${_url}" = "${_line_contain}" ]] || [[ "${_url}" = "file://${_line_contain}" ]] || [[ "${_url}/" = "${_line_contain}" ]] || [[ "${_url}/" = "file://${_line_contain}" ]]; then
177                 _remove_line+=("${_count}")
178             fi
179         done
180         _remove_count=0
181         if (( "${#_remove_line[@]}" == 0 )); then
182             _msg_error "${_dir} is not registered in the sidebar."
183             continue
184         fi
185         for _count in "${_remove_line[@]}"; do
186             if [[ "${simulation}" = true ]]; then
187                 sed "${_count}d" "${bookmark_file}"
188             else
189                 _count="$(( _count - _remove_count ))"
190                 sed -i "${_count}d" "${bookmark_file}"
191                 _remove_count="$(( _remove_count + 1 ))"
192             fi
193         done
194     done
195 }
196
197 init() {
198     if [[ "${simulation}" = false ]]; then
199         remove "${bookmark_file}"
200         prepare
201     fi
202
203     source "${HOME}/.config/user-dirs.dirs"
204
205     init_dirs=(
206         "${XDG_DOCUMENTS_DIR}"
207         "${XDG_DOWNLOAD_DIR}"
208         "${XDG_MUSIC_DIR}"
209         "${XDG_PICTURES_DIR}"
210         "${XDG_VIDEOS_DIR}"
211     )
212
213     local dir
214     for dir in "${init_dirs[@]}"; do
215         output "file://${dir} $(basename "${dir}")"
216     done
217 }
218
219 backup(){
220     if [[ ! -f "${bookmark_file}" ]]; then
221         echo "Initialize with the init command or add the directory with the add command."
222         exit 1
223     fi
224     mkdir -p "${backup_dir}"
225     local path="${backup_dir}/$(date +%s).bak"
226     cp "${bookmark_file}" "${path}"
227     echo "Backuped to ${path}"
228 }
229
230 restore(){
231     local backups=() target_date target_path
232     readarray -t backups < <(find "${backup_dir}" -mindepth 1 -maxdepth 1  -name "*.bak" -type f -printf "%f\0" | xargs -0 -I{} bash -c 'echo {} | sed "s|.bak$||g"' | xargs -I{} date --date "@{}" "+%Y/%m/%d %T")
233     if (( "${#backups[@]}" == 0 )); then
234         _msg_error "Backup was not found"
235         exit 1
236     fi
237     if [[ -f "${bookmark_file}" ]] && [[ "${force}" = false ]] && [[ "${simulation}" = false ]] && [[ -n "$(cat "${bookmark_file}" 2>/dev/null)" ]]; then
238         _msg_error "The sidebar already exists. Use -f to force restore."
239         exit 1
240     fi
241     if ! target_date=$(_ask -p "Select the backup you want to use" "${backups[@]}"); then
242         exit 1
243     else
244         target_path="${backup_dir}/$(date -d "${target_date}" +%s).bak"
245         if [[ -f "${target_path}" ]]; then
246             remove "${bookmark_file}"
247             cp "${target_path}" "${bookmark_file}"
248         else
249             _msg_error "A backup that does not exist was selected."
250             exit 1
251         fi
252     fi
253
254 }
255
256 # Argument analysis and processing
257 ARGUMENT=("${@}")
258 OPTS=("f" "h" "s")
259 OPTL=("force" "help" "fascodelive" "t-mart" "takebayashi" "simulation" "alterlive" "bakdir:")
260 if ! OPT=$(getopt -o "$(printf "%s," "${OPTS[@]}")" -l "$(printf "%s," "${OPTL[@]}")" -- "${ARGUMENT[@]}"); then
261     exit 1
262 fi
263
264 eval set -- "${OPT}"
265 unset ARGUMENT OPTS OPTL OPT
266
267
268 while true; do
269     case "${1}" in
270         -s | --simulation)
271             simulation=true
272             shift 1
273             ;;
274         -f | --force)
275             force=true
276             shift 1
277             ;;
278         -h | --help)
279             _help
280             shift 1
281             exit 0
282             ;;
283         --fascodelive | --alterlive)
284             fascodelive=true
285             shift 1
286             ;;
287         --t-mart)
288             echo "さすが店長、青春ブタ野郎だね"
289             shift 1
290             exit 0
291             ;;
292         --takebayashi)
293             echo "竹林さん。チノちゃんかわいい最高!!"
294             shift 1
295             exit 0
296             ;;
297         -t)
298             if [[ "$(basename $0)" == "alterlinux-gtk-bookmarks" ]]; then
299                 echo "さすが店長、青春ブタ野郎だね"
300             else
301                 echo "竹林さん。チノちゃんかわいい最高!!"
302             fi
303             shift 1
304             exit 0
305             ;;
306         --bakdir)
307             backup_dir="${2}"
308             shift 2
309             ;;
310         --)
311             shift
312             break
313             ;;
314         *)
315             _msg_error "Invalid argument '${1}'"
316             _help
317             exit 1
318             ;;
319     esac
320 done
321
322 mode="${1}"
323
324 case "${mode}" in
325     add) 
326         shift 1
327         if [[ -z "${*}" ]]; then
328             _msg_error "Please specify a directory."
329             exit 1
330         else
331             add "${@}"
332         fi
333         exit 0
334         ;;
335     alldelete)
336         shift 1
337         if [[ "${simulation}" = false ]]; then
338             remove "${bookmark_file}"
339         fi
340         ;;
341     init)
342         shift 1
343         if [[ -f "${bookmark_file}" ]] && [[ "${force}" = false ]] && [[ "${simulation}" = false ]] && [[ -n "$(cat "${bookmark_file}" 2>/dev/null)" ]]; then
344             _msg_error "The sidebar already exists. Use -f to force initialization."
345             exit 1
346         else
347             init
348         fi
349         ;;
350     delete)
351         shift 1
352         if [[ -z "${*}" ]]; then
353             _msg_error "Please specify a directory."
354             exit 1
355         else
356             delete "${@}"
357         fi
358         exit 0
359         ;;
360     backup)
361         shift 1
362         backup
363         ;;
364     restore)
365         shift 1
366         restore
367         ;;
368     help)
369         shift 1
370         _help
371         ;;
372     *)
373         _msg_error "Please specify a command."
374         exit 1
375         ;;
376 esac
377
378 if [[ "${fascodelive}" = true ]]; then
379     remove "${HOME}/.config/autostart/gensidebar.desktop"
380 fi