OSDN Git Service

6373f5b8ec6ce195b5e6b92a6a28aed9ffb5467b
[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 cache_dir="${script_path}/cache"
19
20 work_dir="${script_path}/work"
21 channels_dir="${script_path}/channels"
22 codename="32"
23 os_name="Fedora"
24 iso_name="Fedora"
25
26 arch=amd64
27
28 out_dir="${script_path}/out"
29 iso_label="${os_name}_${codename}_${arch}"
30 iso_publisher='Fascode Network <https://fascode.net>'
31 iso_application="${os_name} Live/Rescue CD"
32 iso_version="${codename}-$(date +%Y.%m.%d)"
33 iso_filename="${iso_name}-${iso_version}-${arch}.iso"
34
35 username="liveuser"
36 usershell="/bin/bash"
37
38 debug=false
39 cache_only=false
40
41
42 start_time="$(date +%s)"
43
44 _msg_common() {
45     if [[ "${debug}" = true ]]; then
46         local _current_time
47         local _time
48         _current_time="$(date +%s)"
49         _time="$(("${_current_time}"-"${start_time}"))"
50
51         if [[ "${_time}" -ge 3600 ]]; then
52             echo "[$(date -d @${_time} +%H:%M.%S)]$("${script_path}/echo_color" -t 6 "[LUBS Core]")"
53         elif [[ "${_time}" -ge 60 ]]; then
54             echo "[00:$(date -d @${_time} +%M.%S)]$("${script_path}/echo_color" -t 6 "[LUBS Core]")"
55         else
56             echo "[00:00.$(date -d @${_time} +%S)] $("${script_path}/echo_color" -t 6 "[LUBS Core]")"
57         fi
58     else
59         "${script_path}/echo_color" -t 6 "[LUBS Core]"
60     fi
61 }
62
63 # Show an INFO message
64 # _msg_info <message>
65 _msg_info() {
66     local _msg
67     _msg="${@}"
68     echo "$(_msg_common)  $("${script_path}/echo_color" -t 2 "Info:") ${_msg}"
69 }
70
71 # Show an debug message
72 # _msg_debug <message>
73 _msg_debug() {
74     if [[ "${debug}" = true ]]; then
75         local _msg
76         _msg="${@}"
77         echo "$(_msg_common)  $("${script_path}/echo_color" -t 3 "Debug:") ${_msg}"
78     fi
79 }
80
81 # Show an ERROR message then exit with status
82 # _msg_error <message> <exit code>
83 _msg_error() {
84     local _msg
85     local _error
86     _msg="${1}"
87     _error=${2}
88     echo "$(_msg_common)  $("${script_path}/echo_color" -t 1 "Error:") ${_msg}"
89
90     if [[ ! ${_error} = 0 ]]; then
91         exit ${_error}
92     fi
93 }
94
95 # Unmount chroot dir
96 umount_chroot () {
97     local mount
98
99     for mount in $(mount | awk '{print $3}' | grep "$(realpath "${work_dir}")" | sort -r); do
100         _msg_info "Unmounting ${mount}"
101         umount -fl "${mount}"
102     done
103 }
104
105 # Helper function to run make_*() only one time.
106 run_once() {
107     local name
108     umount_chroot
109     name="$1"
110
111     if [[ ! -e "${work_dir}/build.${name}" ]]; then
112         _msg_info "$(echo $name | sed "s@_@ @g") is starting."
113         "${1}"
114         _msg_info "$(echo $name | sed "s@_@ @g") was done!"
115         touch "${work_dir}/build.${name}"
116     fi
117 }
118
119 run_cmd() {
120     local mount
121
122     for mount in "dev" "dev/pts" "proc" "sys" "run/systemd/resolve/stub-resolv.conf"; do
123         if [[ "${mount}" == "run/systemd/resolve/stub-resolv.conf" ]]; then
124             mount --bind /etc/resolv.conf "${work_dir}/airootfs/${mount}"
125         else
126             mount --bind /${mount} "${work_dir}/airootfs/${mount}"
127         fi
128     done
129     
130     chroot "${work_dir}/airootfs" "${@}"
131
132     for mount in $(mount | awk '{print $3}' | grep "$(realpath "${work_dir}")" | sort -r); do
133         umount -fl "${mount}"
134     done
135 }
136
137 _apt_install() {
138     run_cmd apt-get --no-install-recommends --yes install ${@}
139 }
140
141 # rm helper
142 # Delete the file if it exists.
143 # For directories, rm -rf is used.
144 # If the file does not exist, skip it.
145 # remove <file> <file> ...
146 remove() {
147     local _list
148     local _file
149     _list=($(echo "$@"))
150
151     for _file in "${_list[@]}"; do
152         _msg_debug "Removeing ${_file}"
153
154         if [[ -f ${_file} ]]; then
155             rm -f "${_file}"
156         elif [[ -d ${_file} ]]; then
157             rm -rf "${_file}"
158         fi
159     done
160 }
161
162 # Show help
163 _usage () {
164     echo "usage ${0} [options] [channel]"
165     echo
166     echo " General options:"
167     echo
168     echo "    -a | --arch <str>      Set architecture"
169     echo "                           Default: ${arch}"
170     echo "    -c | --codename <str>  Set ubuntu codename"
171     echo "                           Default: ${codename}"
172     echo "    -m | --mirror <url>    Set apt mirror server."
173     echo "                           Default: ${mirror}"
174     echo "    -o | --out <out_dir>   Set the output directory"
175     echo "                           Default: ${out_dir}"
176     echo "    -w | --work <work_dir> Set the working directory"
177     echo "                           Default: ${work_dir}"
178     echo
179     echo "    -d | --debug           "
180     echo "    -h | --help            This help message and exit"
181     echo
182     echo "You can switch between installed packages, files included in images, etc. by channel."
183     echo
184     echo " Channel:"
185     
186     local _channel
187     local channel_list
188     local description
189
190     for _channel in $(ls -l "${channels_dir}" | awk '$1 ~ /d/ {print $9 }'); do
191         if [[ -n $(ls "${channels_dir}/${_channel}") ]] && [[ ! "${_channel}" = "share" ]]; then
192             channel_list+=( "${_channel}" )
193         fi
194     done
195
196     for _channel in ${channel_list[@]}; do
197         if [[ -f "${channels_dir}/${_channel}/description.txt" ]]; then
198             description=$(cat "${channels_dir}/${_channel}/description.txt")
199         else
200             description="This channel does not have a description.txt."
201         fi
202
203         echo -ne "    ${_channel}"
204
205         for i in $( seq 1 $(( 23 - ${#_channel} )) ); do
206             echo -ne " "
207         done
208         
209         echo -ne "${description}\n"
210     done
211 }
212
213
214 prepare_build() {
215     if [[ ${EUID} -ne 0 ]]; then
216         _msg_error "This script must be run as root." 1
217     fi
218
219     [[ ! -d "${work_dir}" ]] && mkdir -p "${work_dir}"
220     [[ ! -d "${out_dir}" ]] && mkdir -p "${out_dir}"
221     umount_chroot
222
223     # Check codename
224     if [[ -z $(grep -h -v ^'#' ${channels_dir}/${channel_name}/codename.${arch} | grep -x ${codename}) ]]; then
225         _msg_error "This codename (${channel_name}) is not supported on this channel (${codename})."
226     fi
227
228 }
229
230 make_basefs() {
231     local dnf_status
232     statusfile="${cache_dir}/${codename}/status"
233
234     dnf_status() {
235         if [[ ! -d "$(dirname ${statusfile})" ]]; then
236             mkdir -p "$(dirname ${statusfile})"
237         fi
238         echo "${1}" > "${statusfile}"
239     }
240
241     if [[ -f "${statusfile}" ]] && [[ $(cat "${statusfile}" 2> /dev/null) = "Done" ]]; then
242         _msg_info "${codename} cache is found."
243     else
244         remove "${cache_dir}/${codename}"
245         dnf_status "Running"
246         _msg_info "Installing Fedora to '${cache_dir}/${codename}/airootfs'..."
247         mkdir -p "${cache_dir}/${codename}/airootfs"
248         dnf install dnf --releasever=${codename} --installroot="${cache_dir}/${codename}/airootfs"  -y
249         _msg_info "${codename} installed successfully!"
250         dnf_status "Done"
251     fi
252
253     if [[ "${cache_only}" = true ]]; then
254         exit 0
255     fi
256
257     rm -rf "${work_dir}/airootfs" && mkdir -p "${work_dir}/airootfs"
258     _msg_info "copy base files from '${cache_dir}/${codename}/airootfs' to '${work_dir}/airootfs'..."
259     rsync  -au "${cache_dir}/${codename}/airootfs/" "${work_dir}/airootfs"
260     echo 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH}' >> "${work_dir}/airootfs/etc/bash.bashrc"
261     #run_cmd apt-get update
262     # run_cmd apt-get upgrade
263 }
264 make_basefs