OSDN Git Service

[update] : Added db update.
[alterlinux/alterlinux.git] / wizard.sh
1 #!/usr/bin/env bash
2
3 set -e
4
5 nobuild=false
6
7 script_path="$(readlink -f ${0%/*})"
8
9 arch=$(uname -m)
10
11 # Pacman configuration file used only when building
12 build_pacman_conf=${script_path}/system/pacman-${arch}.conf
13
14 # 言語(en or jp)
15 #lang="jp"
16 lang="en"
17 skip_set_lang=false
18
19
20 dependence=(
21     "alterlinux-keyring"
22 #   "archiso"
23     "arch-install-scripts"
24     "curl"
25     "dosfstools"
26     "git"
27     "libburn"
28     "libisofs"
29     "lz4"
30     "lzo"
31     "make"
32     "squashfs-tools"
33     "libisoburn"
34  #  "lynx"
35     "xz"
36     "zlib"
37     "zstd"
38 )
39
40
41 # メッセージを表示する
42 # msg [日本語] [英語]
43 function msg() {
44     if [[ ${lang} = "jp" ]]; then
45         echo "${1}"
46     else
47         echo "${2}"
48     fi
49 }
50 function msg_error() {
51     if [[ ${lang} = "jp" ]]; then
52         echo "${1}" >&2
53     else
54         echo "${1}" >&2
55     fi
56 }
57 function msg_n() {
58     if [[ ${lang} = "jp" ]]; then
59         echo -n "${1}"
60     else
61         echo -n "${2}"
62     fi
63 }
64
65 while getopts 'xnje' arg; do
66     case "${arg}" in
67         n)
68             nobuild=true
69             msg \
70                 "シミュレーションモードを有効化しました" "Enabled simulation mode"
71             ;;
72         x)
73             set -x 
74             msg "デバッグモードを有効化しました" "Debug mode enabled"
75             ;;
76         e)
77             lang="en"
78             echo "English is set"
79             skip_set_lang=true
80             ;;
81         j)
82             lang="jp"
83             echo "日本語が設定されました"
84             skip_set_lang=true
85             ;;
86         
87     esac
88 done
89
90 function set_language () {
91     if [[ ${skip_set_lang} = false ]]; then
92         echo "このウィザードでどちらの言語を使用しますか?"
93         echo "この質問はウィザード内のみの設定であり、ビルドへの影響はありません。"
94         echo
95         echo "Which language would you like to use for this wizard?"
96         echo "This question is a wizard-only setting and does not affect the build."
97         echo
98         echo "1: 英語 English"
99         echo "2: 日本語 Japanese"
100         echo
101         echo -n ": "
102         read lang
103
104         case ${lang} in
105             1 ) lang=en ;;
106             2 ) lang=jp ;;
107             "英語" ) lang=en ;;
108             "日本語" ) lang=jp ;;
109             "English" ) lang=en ;;
110             "Japanese" ) lang=jp ;;
111             * ) set_language ;;
112         esac
113     fi
114 }
115
116 function check_files () {
117     if [[ ! -f "${script_path}/build.sh" ]]; then
118         msg_error "${script_path}/build.shが見つかりませんでした。" "${script_path}/build.sh was not found."
119         exit 1
120     fi
121     if [[ ! -f "${script_path}/keyring.sh" ]]; then
122         echo "${script_path}/keyring.shが見つかりませんでした。" "${script_path}/keyring.sh was not found."
123         exit 1
124     fi
125 }
126
127
128 function install_dependencies () {
129     local checkpkg
130     local pkg
131     local installed_pkg
132     local installed_ver
133     local check_pkg
134
135     sudo pacman -Sy --config "${build_pacman_conf}"
136     installed_pkg=($(pacman -Q | awk '{print $1}'))
137     installed_ver=($(pacman -Q | awk '{print $2}'))
138
139     check_pkg() {
140         local i
141         for i in $(seq 0 $(( ${#installed_pkg[@]} - 1 ))); do
142             if [[ ${installed_pkg[${i}]} = ${1} ]]; then
143                 if [[ ${installed_ver[${i}]} = $(pacman -Sp --print-format '%v' --config ${build_pacman_conf} ${1}) ]]; then
144                     echo -n "true"
145                     return 0
146                 else
147                     echo -n "false"
148                     return 0
149                 fi
150             fi
151         done
152         echo -n "false"
153         return 0
154     }
155
156     for pkg in ${dependence[@]}; do
157         msg "依存パッケージ ${pkg} を確認しています..." "Checking dependency package ${pkg} ..."
158         if [[ $(check_pkg ${pkg}) = false ]]; then
159             install=(${install[@]} ${pkg})
160         fi
161     done
162     if [[ -n "${install[@]}" ]]; then
163         sudo pacman -Sy
164         sudo pacman -S --needed --config ${build_pacman_conf} ${install[@]}
165     fi
166     echo
167 }
168
169
170 function run_add_key_script () {
171     local yn
172     msg_n "AlterLinuxの鍵を追加しますか?(y/N): " "Are you sure you want to add the AlterLinux key? (y/N):"
173     read yn
174     if ${nobuild}; then
175         msg \
176             "${yn}が入力されました。シミュレーションモードが有効化されているためスキップします。" \
177             "You have entered ${yn}. Simulation mode is enabled and will be skipped."
178     else
179         case ${yn} in
180             y | Y | yes | Yes | YES ) sudo "${script_path}/keyring.sh" --alter-add   ;;
181             n | N | no  | No  | NO  ) return 0                                       ;;
182             *                       ) run_add_key_script                             ;;
183         esac
184     fi
185 }
186
187
188 function remove_dependencies () {
189     if [[ -n "${install[@]}" ]]; then
190         sudo pacman -Rsn --config ${build_pacman_conf} ${install[@]}
191     fi
192 }
193
194
195 function enable_plymouth () {
196     local yn
197     msg_n "Plymouthを有効化しますか?[no](y/N) : " "Do you want to enable Plymouth? [no] (y/N) : "
198     read yn
199     case ${yn} in
200         y | Y | yes | Yes | YES ) plymouth=true   ;;
201         n | N | no  | No  | NO  ) plymouth=false  ;;
202         *                       ) enable_plymouth ;;
203     esac
204 }
205
206
207 function enable_japanese () {
208     local yn
209     msg_n "日本語を有効化しますか?[no](y/N) : " "Do you want to activate Japanese? [no] (y/N) : "
210     read yn
211     case ${yn} in
212         y | Y | yes | Yes | YES ) japanese=true   ;;
213         n | N | no  | No  | NO  ) japanese=false  ;;
214         *                       ) enable_japanese ;;
215     esac
216 }
217
218
219 function select_comp_type () {
220     local yn
221     local details
222     local ask_comp_type
223     msg_n "圧縮方式を設定しますか?[zstd](y/N) : " "Do you want to set the compression method?[zstd](y/N)"
224     read yn
225     case ${yn} in
226         y | Y | yes | Yes | YES ) details=true               ;;
227         n | N | no  | No  | NO  ) details=false              ;;
228         *                       ) select_comp_type; return 0 ;;
229     esac
230
231     function ask_comp_type () {
232         msg \
233             "圧縮方式を以下の番号から選択してください " \
234             "Please select the compression method from the following numbers"
235         echo
236         echo "1: gzip"
237         echo "2: lzma"
238         echo "3: lzo"
239         echo "4: lz4"
240         echo "5: xz"
241         echo "6: zstd (default)"
242         echo -n ": "
243
244         read yn
245
246         case ${yn} in
247             1    ) comp_type="gzip" ;;
248             2    ) comp_type="lzma" ;;
249             3    ) comp_type="lzo"  ;;
250             4    ) comp_type="lz4"  ;;
251             5    ) comp_type="xz"   ;;
252             6    ) comp_type="zstd" ;;
253             gzip ) comp_type="gzip" ;;
254             lzma ) comp_type="lzma" ;;
255             lzo  ) comp_type="lzo"  ;;
256             lz4  ) comp_type="lz4"  ;;
257             xz   ) comp_type="xz"   ;;
258             zstd ) comp_type="zstd" ;;
259             *    ) ask_comp_type    ;;
260         esac
261     }
262
263     if [[ ${details} = true ]]; then
264         ask_comp_type
265     else
266         comp_type="zstd"
267     fi
268
269     return 0
270 }
271
272
273 function set_comp_option () {
274     local ask_comp_option
275     ask_comp_option() {
276         local gzip
277         local lzo
278         local lz4
279         local xz
280         local zstd
281         comp_option=""
282
283         function gzip () {
284             local comp_level
285             function comp_level () {
286                 local level
287                 msg_n "gzipの圧縮レベルを入力してください。 (1~22) : " "Enter the gzip compression level.  (1~22) : "
288                 read level
289                 if [[ ${level} -lt 23 && ${level} -ge 4 ]]; then
290                     comp_option="-Xcompression-level ${level}"
291                 else
292                     comp_level
293                 fi
294             }
295             local window_size
296             function window_size () {
297                 local window
298                 msg_n \
299                     "gzipのウィンドウサイズを入力してください。 (1~15) : " \
300                     "Please enter the gzip window size. (1~15) : "
301
302                 read window
303                 if [[ ${window} -lt 16 && ${window} -ge 4 ]]; then
304                     comp_option="${comp_option} -Xwindow-size ${window}"
305                 else
306                     window_size
307                 fi
308             }
309
310         }
311
312         function lz4 () {
313             local yn
314             msg_n \
315                 "高圧縮モードを有効化しますか? (y/N) : " \
316                 "Do you want to enable high compression mode? (y/N) : "
317             read yn
318             case ${yn} in
319                 y | Y | yes | Yes | YES ) comp_option="-Xhc" ;;
320                 n | N | no  | No  | NO  ) :                  ;;
321                 *                       ) lz4                ;;
322             esac
323         }
324
325         function zstd () {
326             local level
327             msg_n \
328                 "zstdの圧縮レベルを入力してください。 (1~22) : " \
329                 "Enter the zstd compression level. (1~22) : "
330             read level
331             if [[ ${level} -lt 23 && ${level} -ge 4 ]]; then
332                 comp_option="-Xcompression-level ${level}"
333             else
334                 zstd
335             fi
336         }
337
338         function lzo () {
339             msg_error \
340                 "現在lzoの詳細設定ウィザードがサポートされていません。" \
341                 "The lzo Advanced Wizard is not currently supported."
342         }
343
344         function xz () {
345             msg_error \
346             "現在xzの詳細設定のウィザードがサポートされていません。" \
347             "The xz Advanced Wizard is not currently supported."
348         }
349
350         case ${comp_type} in
351             gzip ) gzip ;;
352             zstd ) zstd ;;
353             lz4  ) lz4  ;;
354             lzo  ) lzo  ;;
355             xz   ) xz   ;;
356             *    ) :    ;;
357         esac
358     }
359
360     # lzmaには詳細なオプションはありません。
361     if [[ ! ${comp_type} = "lzma" ]]; then
362         local yn
363         local details
364         msg_n \
365             "圧縮の詳細を設定しますか? (y/N) : " \
366             "Do you want to set the compression details? (y/N) : "
367         read yn
368         case ${yn} in
369             y | Y | yes | Yes | YES ) details=true              ;;
370             n | N | no  | No  | NO  ) details=false             ;;
371             *                       ) set_comp_option; return 0 ;;
372         esac
373         if [[ ${details} = true ]]; then
374             ask_comp_option
375             return 0
376         else
377             return 0
378         fi
379     fi
380 }
381
382
383 function set_username () {
384     local details
385     local ask_comp_type
386     msg_n \
387         "デフォルトではないユーザー名を設定しますか? (y/N) : " \
388         "Would you like to set a non-default username? (y/N) : "
389     read yn
390     case ${yn} in
391         y | Y | yes | Yes | YES ) details=true           ;;
392         n | N | no  | No  | NO  ) details=false          ;;
393         *                       ) set_username; return 0 ;;
394     esac
395
396     function ask_username () {
397         msg_n "ユーザー名を入力してください : " "Please enter your username : "
398         read username
399         if [[ -z ${username} ]]; then
400             ask_username
401         fi
402     }
403
404     if [[ ${details} = true ]]; then
405         ask_username
406     fi
407
408     return 0
409 }
410
411
412 function set_password () {
413     local details
414     local ask_comp_type
415     msg_n \
416         "デフォルトではないパスワードを設定しますか? (y/N) : " \
417         "Do you want to set a non-default password? (y/N) : "
418     read yn
419     case ${yn} in
420         y | Y | yes | Yes | YES ) details=true           ;;
421         n | N | no  | No  | NO  ) details=false          ;;
422         *                       ) set_password; return 0 ;;
423     esac
424
425     function ask_password () {
426         msg_n "パスワードを入力してください。" "Please enter your password."
427         read -s password
428         echo
429         msg_n "Type it again : "
430         read -s confirm
431         if [[ ! $password = $confirm ]]; then
432             echo
433             msg_error "同じパスワードが入力されませんでした。" "You did not enter the same password."
434             ask_password
435         elif [[ -z $password || -z $confirm ]]; then
436             echo
437             msg_error "パスワードを入力してください。" "Please enter your password."
438             ask_password
439         fi
440         echo
441         unset confirm
442     }
443
444     if [[ ${details} = true ]]; then
445         ask_password
446     fi
447
448     return 0
449 }
450
451
452 function select_kernel () {
453     set +e
454     local do_you_want_to_select_kernel
455
456     function do_you_want_to_select_kernel () {
457         set +e
458         local yn
459         msg_n \
460             "デフォルト(zen)以外のカーネルを使用しますか? (y/N) : " \
461             "Do you want to use a kernel other than the default (zen)? (y/N) : "
462         read yn
463         case ${yn} in
464             y | Y | yes | Yes | YES ) return 0                               ;;
465             n | N | no  | No  | NO  ) return 1                               ;;
466             *                       ) do_you_want_to_select_kernel; return 0 ;;
467         esac
468
469     }
470
471     local what_kernel
472
473     function what_kernel () {
474         msg \
475             "使用するカーネルを以下の番号から選択してください" \
476             "Please select the kernel to use from the following numbers"
477
478
479         #カーネルの一覧を取得
480         kernel_list=($(cat ${script_path}/system/kernel_list | grep -h -v ^'#'))
481
482         #選択肢の生成
483         local count=1
484         local i
485         echo
486         for i in ${kernel_list[@]}; do
487             echo "${count}: linux-${i}"
488             count=$(( count + 1 ))
489         done
490
491         # 質問する
492         echo -n ": "
493         local answer
494         read answer
495
496         # 回答を解析する
497         # 数字かどうか判定する
498         set +e
499         expr "${answer}" + 1 >/dev/null 2>&1
500         if [[ ${?} -lt 2 ]]; then
501             set -e
502             # 数字である
503             answer=$(( answer - 1 ))
504             if [[ -z "${kernel_list[${answer}]}" ]]; then
505                 what_kernel
506                 return 0
507             else
508                 kernel="${kernel_list[${answer}]}"
509             fi
510         else
511             set -e
512             # 数字ではない
513             # 配列に含まれるかどうか判定
514             if [[ ! $(printf '%s\n' "${kernel_list[@]}" | grep -qx "${answer#linux-}"; echo -n ${?} ) -eq 0 ]]; then
515                 ask_channel
516                 return 0
517             else
518                 kernel="${answer#linux-}"
519             fi
520         fi
521     }
522
523     do_you_want_to_select_kernel
524     exit_code=$?
525     if [[ ${exit_code} = 0 ]]; then
526         what_kernel
527     fi
528     set -e
529 }
530
531
532 # チャンネルの指定
533 function select_channel () {
534     local ask_channel
535
536     msg_n \
537         "デフォルト(xfce)以外のチャンネルを使用しますか? (y/N) : " \
538         "Do you want to use a channel other than the default (xfce)? (y/N) : "
539
540     read yn
541     case ${yn} in
542         y | Y | yes | Yes | YES ) details=true             ;;
543         n | N | no  | No  | NO  ) details=false            ;;
544         *                       ) select_channel; return 0 ;;
545     esac
546
547     function ask_channel () {
548         local i
549         local count
550         local _channel
551         local channel_list
552         local description
553
554         # チャンネルの一覧を生成
555         for i in $(ls -l "${script_path}"/channels/ | awk '$1 ~ /d/ {print $9 }'); do
556             if [[ -n $(ls "${script_path}"/channels/${i}) ]]; then
557                 if [[ ! ${i} = "share" ]]; then
558                         channel_list=(${channel_list[@]} ${i})
559                 fi
560             fi
561         done
562         msg "チャンネルを以下の番号から選択してください。" "Select a channel from the numbers below."
563         count=1
564         for _channel in ${channel_list[@]}; do
565             if [[ -f "${script_path}/channels/${_channel}/description.txt" ]]; then
566                 description=$(cat "${script_path}/channels/${_channel}/description.txt")
567             else
568                 if [[ "${lang}"  = "jp" ]]; then
569                     description="このチャンネルにはdescription.txtがありません。"
570                 else
571                     description="This channel does not have a description.txt."
572                 fi
573             fi
574             if [[ $(echo "${_channel}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
575                 echo -ne "${count}    $(echo ${_channel} | sed 's/\.[^\.]*$//')"
576                 for i in $( seq 1 $(( 23 - ${#_channel} )) ); do
577                     echo -ne " "
578                 done
579             else
580                 echo -ne "${count}    ${_channel}"
581                 for i in $( seq 1 $(( 19 - ${#_channel} )) ); do
582                     echo -ne " "
583                 done
584             fi
585             echo -ne "${description}\n"
586             count=$(( count + 1 ))
587         done
588         echo -n ":"
589         read channel
590
591         # 数字かどうか判定する
592         set +e
593         expr "${channel}" + 1 >/dev/null 2>&1
594         if [[ ${?} -lt 2 ]]; then
595             set -e
596             # 数字である
597             channel=$(( channel - 1 ))
598             if [[ -z "${channel_list[${channel}]}" ]]; then
599                 ask_channel
600                 return 0
601             else
602                 channel="${channel_list[${channel}]}"
603             fi
604         else
605             set -e
606             # 数字ではない
607             if [[ ! $(printf '%s\n' "${channel_list[@]}" | grep -qx "${channel}.add"; echo -n ${?} ) -eq 0 ]]; then
608                 if [[ ! $(printf '%s\n' "${channel_list[@]}" | grep -qx "${channel}"; echo -n ${?} ) -eq 0 ]]; then
609                     ask_channel
610                     return 0
611                 fi
612             fi
613         fi
614     }
615
616     if [[ ${details} = true ]]; then
617         ask_channel
618     fi
619     # echo ${channel}
620     return 0
621 }
622
623
624 # イメージファイルの所有者
625 function set_iso_owner () {
626     local owner
627     local user_check
628     function user_check () {
629     if [[ $(getent passwd $1 > /dev/null ; printf $?) = 0 ]]; then
630         if [[ -z $1 ]]; then
631             echo -n "false"
632         fi
633         echo -n "true"
634     else
635         echo -n "false"
636     fi
637     }
638
639     msg_n "イメージファイルの所有者を入力してください。: " "Enter the owner of the image file.: "
640     read owner
641     if [[ $(user_check ${owner}) = false ]]; then
642         echo "ユーザーが存在しません。"
643         set_iso_owner
644         return 0
645     elif  [[ -z "${owner}" ]]; then
646         echo "ユーザー名を入力して下さい。"
647         set_iso_owner
648         return 0
649     elif [[ "${owner}" = root ]]; then
650         echo "所有者の変更を行いません。"
651         return 0
652     fi
653 }
654
655
656 # イメージファイルの作成先
657 function set_out_dir () {
658     msg "イメージファイルの作成先を入力して下さい。" "Enter the destination to create the image file."
659     msg "デフォルトは ${script_path}/out です。" "The default is ${script_path}/out."
660     echo -n ": "
661     read out_dir
662     if [[ -z "${out_dir}" ]]; then
663         out_dir=out
664     else
665         if [[ ! -d "${out_dir}" ]]; then
666             msg_error \
667                 "存在しているディレクトリを指定して下さい。" \
668                 "Please specify the existing directory."
669             set_out_dir
670             return 0
671         elif [[ "${out_dir}" = / ]] || [[ "${out_dir}" = /home ]]; then
672             msg_error \
673                 "そのディレクトリは使用できません。" \
674                 "The directory is unavailable."
675             set_out_dir
676             return 0
677         elif [[ -n "$(ls ${out_dir})" ]]; then
678             msg_error \
679                 "ディレクトリは空ではありません。" \
680                 "The directory is not empty."
681             set_out_dir
682             return 0
683         fi
684     fi
685 }
686
687
688 # 最終的なbuild.shのオプションを生成
689 function generate_argument () {
690     if [[ ${japanese} = true ]]; then
691         argument="${argument} -j"
692     fi
693     if [[ ${plymouth} = true ]]; then
694         argument="${argument} -b"
695     fi
696     if [[ -n ${comp_type} ]]; then
697         argument="${argument} -c ${comp_type}"
698     fi
699     if [[ -n ${kernel} ]]; then
700         argument="${argument} -k ${kernel}"
701     fi
702     if [[ -n "${username}" ]]; then
703         argument="${argument} -u '${username}'"
704     fi
705     if [[ -n ${password} ]]; then
706         argument="${argument} -p '${password}'"
707     fi
708     if [[ -n ${out_dir} ]]; then
709         argument="${argument} -o '${out_dir}'"
710     fi
711     argument="${argument} ${channel}"
712 }
713
714 # 上の質問の関数を実行
715 function ask () {
716     enable_japanese
717     enable_plymouth
718     select_kernel
719     select_comp_type
720     set_comp_option
721     set_username
722     set_password
723     select_channel
724     set_iso_owner
725     # set_out_dir
726     lastcheck
727 }
728
729 # ビルド設定の確認
730 function lastcheck () {
731     msg "以下の設定でビルドを開始します。" "Start the build with the following settings."
732     echo
733     [[ -n "${japanese}"    ]] && echo "           Japanese : ${japanese}"
734     [[ -n "${plymouth}"    ]] && echo "           Plymouth : ${plymouth}"
735     [[ -n "${kernel}"      ]] && echo "             kernel : ${kernel}"
736     [[ -n "${comp_type}"   ]] && echo " Compression method : ${comp_type}"
737     [[ -n "${comp_option}" ]] && echo "Compression options : ${comp_option}"
738     [[ -n "${username}"    ]] && echo "           Username : ${username}"
739     [[ -n "${password}"    ]] && echo "           Password : ${password}"
740     [[ -n "${channel}"     ]] && echo "            Channel : ${channel}"
741     echo
742     msg_n \
743         "この設定で続行します。よろしいですか? (y/N) : " \
744         "Continue with this setting. Is it OK? (y/N) : "
745     local yn
746     read yn
747     case ${yn} in
748         y | Y | yes | Yes | YES ) :         ;;
749         n | N | no  | No  | NO  ) ask       ;;
750         *                       ) lastcheck ;;
751     esac
752 }
753
754 function start_build () {
755     if [[ ${nobuild} = true ]]; then
756         echo "${argument}"
757     else
758         # build.shの引数を表示(デバッグ用)
759         # echo ${argument}
760         sudo ./build.sh ${argument}
761         sudo rm -rf work/
762     fi
763 }
764
765
766 remove_work_dir() {
767     if [[ -d "${script_path}/work/" ]]; then
768         sudo rm -rf "${script_path}/work/"
769     fi
770 }
771
772
773 change_iso_permission() {
774     if [[ -n "${owner}" ]]; then
775         chown -R "${owner}" "${script_path}/out/"
776         chmod -R 750 "${script_path}/out/"
777     fi
778 }
779
780 # 関数を実行
781 set_language
782 check_files
783 install_dependencies
784 run_add_key_script
785 ask
786 generate_argument
787 start_build
788 remove_dependencies
789 remove_work_dir
790 change_iso_permission