OSDN Git Service

fixed packages
[alterlinux/LFBS.git] / lfbs
1 #!/usr/bin/env bash
2
3 # SPDX-License-Identifier: GPL-3.0
4 #
5 # kokkiemouse
6 # Twitter: @kokkiemouse
7 # Email  : kokkiemouse@gmail.com
8 #
9 # lfbs
10 #
11
12 set -e
13 # set -u
14
15 export LANG=C
16
17 script_path=$(readlink -f "${0%/*}")
18 work_dir="${script_path}/work"
19 channels_dir="${script_path}/channels"
20 codename="32"
21 os_name="Fedora"
22 iso_name="Fedora"
23
24 arch=x86_64
25
26 out_dir="${script_path}/out"
27 iso_label="${os_name}_${codename}_${arch}"
28 iso_publisher='Fascode Network <https://fascode.net>'
29 iso_application="${os_name} Live/Rescue CD"
30 iso_version="${codename}-$(date +%Y.%m.%d)"
31 iso_filename="${iso_name}-${iso_version}-${arch}.iso"
32
33 username="liveuser"
34 usershell="/bin/bash"
35
36 debug=false
37 cache_only=false
38
39
40 start_time="$(date +%s)"
41
42 _msg_common() {
43     if [[ "${debug}" = true ]]; then
44         local _current_time
45         local _time
46         _current_time="$(date +%s)"
47         _time="$(("${_current_time}"-"${start_time}"))"
48
49         if [[ "${_time}" -ge 3600 ]]; then
50             echo "[$(date -d @${_time} +%H:%M.%S)]$("${script_path}/echo_color" -t 6 "[LFBS Core]")"
51         elif [[ "${_time}" -ge 60 ]]; then
52             echo "[00:$(date -d @${_time} +%M.%S)]$("${script_path}/echo_color" -t 6 "[LFBS Core]")"
53         else
54             echo "[00:00.$(date -d @${_time} +%S)] $("${script_path}/echo_color" -t 6 "[LFBS Core]")"
55         fi
56     else
57         "${script_path}/echo_color" -t 6 "[LFBS Core]"
58     fi
59 }
60
61 # Show an INFO message
62 # _msg_info <message>
63 _msg_info() {
64     local _msg
65     _msg="${@}"
66     echo "$(_msg_common)  $("${script_path}/echo_color" -t 2 "Info:") ${_msg}"
67 }
68
69 # Show an debug message
70 # _msg_debug <message>
71 _msg_debug() {
72     if [[ "${debug}" = true ]]; then
73         local _msg
74         _msg="${@}"
75         echo "$(_msg_common)  $("${script_path}/echo_color" -t 3 "Debug:") ${_msg}"
76     fi
77 }
78
79 # Show an ERROR message then exit with status
80 # _msg_error <message> <exit code>
81 _msg_error() {
82     local _msg
83     local _error
84     _msg="${1}"
85     _error=${2}
86     echo "$(_msg_common)  $("${script_path}/echo_color" -t 1 "Error:") ${_msg}"
87
88     if [[ ! ${_error} = 0 ]]; then
89         exit ${_error}
90     fi
91 }
92
93 # Unmount chroot dir
94 umount_chroot () {
95     local mount
96
97     for mount in $(mount | awk '{print $3}' | grep "$(realpath "${work_dir}")" | sort -r); do
98         _msg_info "Unmounting ${mount}"
99         umount -fl "${mount}"
100     done
101 }
102
103 # Helper function to run make_*() only one time.
104 run_once() {
105     local name
106     umount_chroot
107     name="$1"
108
109     if [[ ! -e "${work_dir}/build.${name}" ]]; then
110         _msg_info "$(echo $name | sed "s@_@ @g") is starting."
111         "${1}"
112         _msg_info "$(echo $name | sed "s@_@ @g") was done!"
113         touch "${work_dir}/build.${name}"
114     fi
115 }
116
117 run_cmd() {
118     local mount
119
120     for mount in "dev" "dev/pts" "proc" "sys" "etc/resolv.conf"; do
121     #for mount in "dev" "dev/pts" "proc" "sys" ; do
122         if [[ "${mount}" == "etc/resolv.conf" ]]; then
123             cp /etc/resolv.conf "${work_dir}/airootfs/${mount}"
124         else
125             mount --bind /${mount} "${work_dir}/airootfs/${mount}"
126         fi
127     done
128     
129     chroot "${work_dir}/airootfs" "${@}"
130
131     for mount in $(mount | awk '{print $3}' | grep "$(realpath "${work_dir}")" | sort -r); do
132         umount -fl "${mount}"
133     done
134 }
135
136 _dnf_install() {
137     run_cmd dnf install -y ${@}
138 }
139
140 # rm helper
141 # Delete the file if it exists.
142 # For directories, rm -rf is used.
143 # If the file does not exist, skip it.
144 # remove <file> <file> ...
145 remove() {
146     local _list
147     local _file
148     _list=($(echo "$@"))
149
150     for _file in "${_list[@]}"; do
151         _msg_debug "Removeing ${_file}"
152
153         if [[ -f ${_file} ]]; then
154             rm -f "${_file}"
155         elif [[ -d ${_file} ]]; then
156             rm -rf "${_file}"
157         fi
158     done
159 }
160
161 # Show help
162 _usage () {
163     echo "usage ${0} [options] [channel]"
164     echo
165     echo " General options:"
166     echo
167     echo "    -a | --arch <str>      Set architecture"
168     echo "                           Default: ${arch}"
169     echo "    -c | --codename <str>  Set ubuntu codename"
170     echo "                           Default: ${codename}"
171     echo "    -m | --mirror <url>    Set apt mirror server."
172     echo "                           Default: ${mirror}"
173     echo "    -o | --out <out_dir>   Set the output directory"
174     echo "                           Default: ${out_dir}"
175     echo "    -w | --work <work_dir> Set the working directory"
176     echo "                           Default: ${work_dir}"
177     echo
178     echo "    -d | --debug           "
179     echo "    -h | --help            This help message and exit"
180     echo
181     echo "You can switch between installed packages, files included in images, etc. by channel."
182     echo
183     echo " Channel:"
184     
185     local _channel
186     local channel_list
187     local description
188
189     for _channel in $(ls -l "${channels_dir}" | awk '$1 ~ /d/ {print $9 }'); do
190         if [[ -n $(ls "${channels_dir}/${_channel}") ]] && [[ ! "${_channel}" = "share" ]]; then
191             channel_list+=( "${_channel}" )
192         fi
193     done
194
195     for _channel in ${channel_list[@]}; do
196         if [[ -f "${channels_dir}/${_channel}/description.txt" ]]; then
197             description=$(cat "${channels_dir}/${_channel}/description.txt")
198         else
199             description="This channel does not have a description.txt."
200         fi
201
202         echo -ne "    ${_channel}"
203
204         for i in $( seq 1 $(( 23 - ${#_channel} )) ); do
205             echo -ne " "
206         done
207         
208         echo -ne "${description}\n"
209     done
210 }
211
212
213 prepare_build() {
214     if [[ ${EUID} -ne 0 ]]; then
215         _msg_error "This script must be run as root." 1
216     fi
217
218     [[ ! -d "${work_dir}" ]] && mkdir -p "${work_dir}"
219     [[ ! -d "${out_dir}" ]] && mkdir -p "${out_dir}"
220     umount_chroot
221
222     # Check codename
223     if [[ -z $(grep -h -v ^'#' ${channels_dir}/${channel_name}/codename.${arch} | grep -x ${codename}) ]]; then
224         _msg_error "This codename (${channel_name}) is not supported on this channel (${codename})."
225     fi
226
227 }
228
229 make_basefs() {
230     remove "${work_dir}/${codename}"
231     _msg_info "Installing Fedora to '${work_dir}/airootfs'..."
232     mkdir -p "${work_dir}/airootfs"
233     dnf --installroot="${work_dir}/airootfs" $(${script_path}/system/repository-json-parser.py ${script_path}/system/repository.json) groupinstall core -y
234     _msg_info "${codename} installed successfully!"
235     
236     echo 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH}' > "${work_dir}/airootfs/etc/bash.bashrc"
237     run_cmd dnf upgrade -y
238     run_cmd dnf -y remove $(run_cmd dnf repoquery --installonly --latest-limit=-1 -q)
239     run_cmd dnf clean all
240     # run_cmd apt-get upgrade
241 }
242
243
244 prepare_build() {
245     if [[ ${EUID} -ne 0 ]]; then
246         _msg_error "This script must be run as root." 1
247     fi
248
249     [[ ! -d "${work_dir}" ]] && mkdir -p "${work_dir}"
250     [[ ! -d "${out_dir}" ]] && mkdir -p "${out_dir}"
251     umount_chroot
252
253     # Check codename
254     if [[ -z $(grep -h -v ^'#' ${channels_dir}/${channel_name}/codename.${arch} | grep -x ${codename}) ]]; then
255         _msg_error "This codename (${channel_name}) is not supported on this channel (${codename})."
256     fi
257
258 }
259
260 make_systemd() {
261     _dnf_install dbus-tools
262     run_cmd dbus-uuidgen --ensure=/etc/machine-id
263     run_cmd mkdir /var/lib/dbus
264     run_cmd ln -sf /etc/machine-id /var/lib/dbus/machine-id
265 }
266 make_dnf_packages() {
267     remove "${work_dir}/airootfs/dnfpkglist"
268     #_apt_install initramfs-tools
269     # run_cmd env -i bash -c 'DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade --yes'
270
271     if [[ -f "${channels_dir}/share/packages.${arch}" ]]; then
272         grep -h -v ^'#' "${channels_dir}/share/packages.${arch}" | grep -v "^$" >> "${work_dir}/airootfs/dnfpkglist"
273     fi
274
275     if [[ -f "${channels_dir}/${channel_name}/packages.${arch}" ]]; then
276         grep -h -v ^'#' "${channels_dir}/${channel_name}/packages.${arch}" | grep -v "^$" >> "${work_dir}/airootfs/dnfpkglist"
277     fi
278
279     if [[ -s "${work_dir}/airootfs/dnfpkglist" ]]; then
280         run_cmd env -i bash -c 'dnf -y --nogpgcheck install $(echo $(<dnfpkglist))'
281     fi
282
283     remove "${work_dir}/airootfs/dnfpkglist"
284 }
285
286 # 引数解析()
287 # 参考記事:https://0e0.pw/ci83 https://0e0.pw/VJlg
288
289 _opt_short="w:o:ha:-:m:c:d"
290 _opt_long="help,arch:,codename:,debug,help,mirror:,out:,work,cache-only"
291 OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- "${@}")
292
293 if [[ ${?} != 0 ]]; then
294     exit 1
295 fi
296
297 eval set -- "${OPT}"
298
299 while :; do
300     case ${1} in
301         -a | --arch)
302             if [[ -z ${2} ]]; then
303                 _msg_error "Please specify the architecture."
304                 exit 1
305             else
306                 arch="${2}"
307             fi
308             shift 2
309             ;;
310         -c | --codename)
311             if [[ -z ${2} ]]; then
312                 _msg_error "Please specify the codename."
313                 exit 1
314             else
315                 codename="${2}"
316             fi
317             shift 2
318             ;;
319         -d | --debug)
320             debug=true
321             shift 1
322             ;;
323         -h | --help)
324             _usage
325             exit 0
326             ;;
327         -m | --mirror)
328             if [[ -z ${2} ]]; then
329                 _msg_error "Please specify the mirror server."
330                 exit 1
331             else
332                 mirror="${2}"
333             fi
334
335             shift 2
336             ;;
337         -o | --out)
338             if [[ -z ${2} ]]; then
339                 _msg_error "Please specify the out dir."
340                 exit 1
341             else
342                 out_dir="${2}"
343             fi
344
345             shift 2
346             ;;
347         -w | --work)
348             if [[ -z ${2} ]]; then
349                 _msg_error "Please specify the out dir."
350                 exit 1
351             else
352                 work_dir="${2}"
353             fi
354
355             shift 2
356             ;;
357         --cache-only)
358             cache_only=true
359             shift 1
360             ;;
361         --)
362             shift
363             break
364             ;;
365         *)
366             _msg_error "Invalid argument '${1}'"
367             _usage 1
368             ;;
369     esac
370 done
371
372 bootfiles_dir="${work_dir}/bootfiles"
373 trap  umount_chroot 0 2 15
374
375 if [[ -n "${1}" ]]; then
376     channel_name="${1}"
377
378     check_channel() {
379         local channel_list
380         local i
381         channel_list=()
382
383         for _channel in $(ls -l "${channels_dir}" | awk '$1 ~ /d/ {print $9 }'); do
384             if [[ -n $(ls "${channels_dir}/${_channel}") ]] && [[ ! "${_channel}" = "share" ]]; then
385                 channel_list+=( "${_channel}" )
386             fi
387         done
388
389         for i in ${channel_list[@]}; do
390             if [[ "${i}" = "${channel_name}" ]]; then
391                 echo -n "true"
392                 return 0
393             fi
394         done
395
396         echo -n "false"
397         return 1
398     }
399
400     if [[ $(check_channel ${channel_name}) = false ]]; then
401         _msg_error "Invalid channel ${channel_name}"
402         exit 1
403     fi
404 fi
405
406
407 prepare_build
408 run_once make_basefs
409 run_once make_systemd
410 run_once make_dnf_packages
411 run_once make_config
412 run_once make_add_user
413 run_once make_clean
414 run_once make_squashfs
415 run_once make_nfb
416 run_once make_efi
417 run_once make_iso
418 run_once make_checksum