]> CyberLeo.Net >> Repos - CDN/Mosi.git/blob - script/lib/chroot.sh
script/lib/chroot: tweak port_all_bdeps logic to be more thorough
[CDN/Mosi.git] / script / lib / chroot.sh
1 # Chroot build handler functions
2
3 if [ -z "${__chroot_sh_loaded}" ]
4 then
5   __chroot_sh_loaded=yes
6
7   # Where should this one go?
8   #
9   # Dump a list of leaf ports from a working system
10   # Leaf ports are ports that have nothing depending upon them
11   # These are generally the top-level ports; everything else should
12   # be pulled in by them
13   leaf_ports() {
14     ( cd /var/db/pkg; ls -1 ) | while read pkg
15     do
16       pkg_info -Rq "${pkg}" | grep -q '' || pkg_info -oq "${pkg}"
17     done | sort
18   }
19
20   ########
21   #
22   # Configuration variable setup
23   #
24   ########
25
26   # Base directory for everything
27   base_dir="${basedir:-/usr/home/cyberleo/vitanitest}"
28
29   # Ports tree to use for building
30   ports_dir="${ports_dir:-/usr/ports}"
31
32   # Directory where distfiles will be stored between builds
33   dist_dir="${dist_dir:-${base_dir}/distfiles}"
34
35   # Final directory for built packages (Outside chroot)
36   final_pkg_dir="${final_pkg_dir:-${base_dir}/pkg}"
37   final_bdeps_dir="${final_bdeps_dir:-${base_dir}/bdeps}"
38
39   # Chroot directory
40   chroot_dir="${chroot_dir:-${base_dir}/root}"
41
42   # Package directories, must be under ${chroot_dir}
43   pkg_dir="${pkg_dir:-${chroot_dir}/pkg}"
44   bdeps_dir="${bdeps_dir:-${pkg_dir}/bdeps}"
45
46   # Compute in-chroot pkg and bdeps dirs
47   chroot_pkg_dir="${chroot_pkg_dir:-${pkg_dir##${chroot_dir}}}"
48   chroot_bdeps_dir="${chroot_bdeps_dir:-${bdeps_dir##${chroot_dir}}}"
49
50   # Chroot environment
51   chroot_env="${chroot_env:-
52   USER=root
53   HOME=/root
54   LOGNAME=root
55   PATH=:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
56   SHELL=/bin/sh
57   TERM=${TERM}
58   }"
59
60   ########
61   #
62   # Boilerplate functions
63   #
64   ########
65
66   meh() { printf " \033[1;32m*\033[0m %s\n" "${*}" >&2; }
67   omg() { printf " \033[1;33m*\033[0m %s\n" "${*}" >&2; }
68   wtf() { printf " \033[1;31m*\033[0m %s\n" "${*}" >&2; exit 1; }
69
70   ########
71   #
72   # Chroot handling
73   #
74   ########
75
76   # Setup a chroot
77   chsetup() {
78     # Necessary mountpoints
79     mkdir -p "${chroot_dir}/dev" || return 1
80     mount -t devfs devfs "${chroot_dir}/dev" || return 1
81     mkdir -p "${chroot_dir}/usr/ports" || return 1
82     mount -t nullfs -r "${ports_dir}" "${chroot_dir}/usr/ports" || return 1
83     mkdir -p "${chroot_dir}/var/ports/distfiles" || return 1
84     mount -t nullfs -w "${dist_dir}" "${chroot_dir}/var/ports/distfiles" || return 1
85
86     # Chroot configuration
87     cp -f /etc/resolv.conf "${chroot_dir}/etc/resolv.conf" || return 1
88
89     # Target package directories
90     mkdir -p "${pkg_dir}" || return 1
91     mkdir -p "${bdeps_dir}" || return 1
92   }
93
94   # Tear down a chroot
95   chteardown() {
96     umount "${chroot_dir}/var/ports/distfiles"
97     umount "${chroot_dir}/usr/ports"
98     umount "${chroot_dir}/dev"
99   }
100
101   # Evaluate a command line within the chroot
102   cheval() {
103     chroot "${chroot_dir}" env -i ${chroot_env} /bin/sh -c "cd ${chroot_pkg_dir}; ${*}"
104   }
105
106   # Run chrooted make
107   chmake() {
108     local port="/usr/ports/${1##/usr/ports/}"
109     shift
110     cheval "make -C ${port} ${*}"
111   }
112
113   ########
114   #
115   # Port Dependency Tracking
116   #
117   ########
118
119   # Translate port origin to package name
120   port2pkg() {
121     while [ "${1}" ]
122     do
123       chmake "${1}" -V PKGNAME
124       shift
125     done
126   }
127
128   # Build dependencies (shallow, recursive, package)
129   port_bdeps() {
130     while [ "${1}" ]
131     do
132       chmake "${1}" build-depends-list | sed -e 's#^/usr/ports/##'
133       shift
134     done
135   }
136   port_all_bdeps() { # Test this one further; I'm not confident in the logic
137     # rdeps for rdeps are rdeps, rdeps for bdeps are bdeps; thus:
138     (
139       # Handle bdeps, bdeps of bdeps, and rdeps of bdeps
140       port_bdeps "${@}" | while read port
141       do
142         echo "${port}"
143         port_all_bdeps "${port}"
144         port_all_rdeps "${port}"
145       done
146       # Handle bdeps of rdeps
147       port_all_rdeps "${@}" | while read port
148       do
149         port_all_bdeps "${port}"
150       done
151     ) | sort | uniq
152   }
153   pkg_bdeps() {
154     port2pkg $(port_all_bdeps "${@}")
155   }
156
157   # Runtime dependencies (shallow, recursive, package)
158   port_rdeps() {
159     while [ "${1}" ]
160     do
161       chmake "${1}" run-depends-list | sed -e 's#^/usr/ports/##'
162       shift
163     done
164   }
165   port_all_rdeps() {
166     port_rdeps "${@}" | while read port
167     do
168       echo "${port}"
169       port_all_rdeps "${port}"
170     done | sort | uniq
171   }
172   pkg_rdeps() {
173     port2pkg $(port_all_rdeps "${@}")
174   }
175
176   # All dependencies (shallow, recursive, package)
177   port_deps() {
178     while [ "${1}" ]
179     do
180       chmake "${1}" all-depends-list | sed -e 's#^/usr/ports/##'
181       shift
182     done
183   }
184   port_all_deps() {
185     port_deps "${@}" | while read port
186     do
187       echo "${port}"
188       port_deps "${port}"
189     done | sort | uniq
190   }
191   pkg_deps() {
192     port2pkg $(port_all_deps "${@}")
193   }
194
195   ########
196   #
197   # Port Configuration Handling
198   #
199   ########
200
201   # Run make config on a list of ports
202   port_config() {
203     while [ "${1}" ]
204     do
205       meh "port config ${1}"
206       chmake "${1}" config < /dev/tty
207       shift
208     done
209   }
210
211   # Make config-conditional for a list of ports, and all dependencies
212   port_config_recursive() {
213     # If the first parameter is not --, then clear the cache
214     [ "${1}" == "--" ] && shift || unset _port_config_recursive_cache
215
216     while [ "${1}" ]
217     do
218       # Do not use config-recursive because it computes the depchain first;
219       # instead, manually compute the depchain after each config to ensure the
220       # proper depchain is followed. Use config-conditional to avoid dialog
221       # if the config is already complete. Also use a cache to avoid re-config
222       # and re-recurse on previously handled port branches.
223       if echo "${_port_config_recursive_cache}" | grep -qv " ${1} "
224       then
225         meh "port config-recursive ${1}"
226         chmake "${1}" config-conditional < /dev/tty
227         port_config_recursive -- $(port_deps "${1}")
228         _port_config_recursive_cache="${_port_config_recursive_cache} ${1} "
229       fi
230       shift
231     done
232   }
233
234   # Remove saved config for a list of ports
235   port_rmconfig() {
236     while [ "${1}" ]
237     do
238       meh "port rmconfig ${1}"
239       chmake "${1}" rmconfig
240       shift
241     done
242   }
243
244   # Remove saved config for a list of ports and all dependencies
245   port_rmconfig_recursive() {
246     meh "port rmconfig-recursive ${*}"
247     port_rmconfig $(echo "${@}" $(port_all_deps "${@}") | sort | uniq)
248   }
249
250   # Obliterate saved configuration for all ports
251   port_rmconfig_all() {
252     meh "port rmconfig-all"
253     cheval "cd /var/db/ports; find . -name 'options' -delete; find . -type d | xargs rmdir 2>/dev/null"
254   }
255
256   # Restore port build options from cpio
257   port_load_config() {
258     meh "port load-config"
259     cheval "cd /var/db/ports; cpio -iv"
260   }
261
262   # Dump port build options to cpio
263   port_save_config() {
264     meh "port save-config"
265     cheval "cd /var/db/ports; find . -type d -o -type f -name options | cpio -ovHnewc"
266   }
267
268   ########
269   #
270   # Port distfile handling
271   #
272   ########
273
274   # Recursively retrieve distfiles
275   port_fetch_recursive() {
276     while [ "${1}" ]
277     do
278       meh "fetch-recursive ${1}"
279       chmake "${1}" fetch-recursive
280     done
281   }
282
283   ########
284   #
285   # Port building and packaging
286   #
287   ########
288
289   # Copy in and install dependency packages
290   port_load_deps() {
291     local port="${1}"
292     for pkg in $(port2pkg $(port_all_deps "${port}"))
293     do
294       cp -f "${final_bdeps_dir}/${pkg}.tbz" "${bdeps_dir}" 2>/dev/null && meh "Loading dependent ${pkg}"
295     done
296     if ls "${bdeps_dir}"/*.tbz >/dev/null 2>&1
297     then
298       meh "Installing dependencies"
299       cheval "cd ${chroot_bdeps_dir}; pkg_add -F *" || wtf "port_load_deps ${port} failed"
300     fi
301   }
302
303   # Build and install a port
304   port_build() {
305     local port="${1}"
306     meh "Building ${port}"
307     chmake "${port}" clean build install clean || wtf "port_build ${port} failed"
308   }
309
310   # Package a port
311   port_package() {
312     local port="${1}"
313     meh "Creating rdep package tree for ${port}"
314     cheval "pkg_create -Rvb $(port2pkg "${port}")" || wtf "port_package ${port} failed"
315   }
316
317   # Package port build dependencies, unless they're already run deps
318   port_stash_bdeps() {
319     meh "Stashing unsaved bdeps"
320     # This doesn't work well, because there can be bdeps that aren't listed as bdeps (bison)
321     #for pkg in $(pkg_bdeps "${1}")
322     #do
323     #  [ ! -f "${pkg_dir}/${pkg}.tbz" ] && cheval "cd ${chroot_bdeps_dir}; pkg_create -vb ${pkg}"
324     #done
325     #
326     # Instead, just save everything that's not already in rdeps as bdeps
327     for pkg in $(cheval pkg_info | awk '{print $1}')
328     do
329       if [ ! -f "${pkg_dir}/${pkg}.tbz" -a ! -f "${bdeps_dir}/${pkg}.tbz" ]
330       then
331         cheval "cd ${chroot_bdeps_dir}; pkg_create -vb ${pkg}" || wtf "port_stash_bdeps failed"
332       fi
333     done
334   }
335
336   # Copy generated packages out of tree
337   pkg_final() {
338     meh "Moving created packages to repo"
339     ls "${pkg_dir}"/*.tbz >/dev/null 2>&1 && mv -f "${pkg_dir}"/*.tbz "${final_pkg_dir}"
340     ls "${bdeps_dir}"/*.tbz >/dev/null 2>&1 && mv -f "${bdeps_dir}"/*.tbz "${final_bdeps_dir}"
341     # link everything into ${bdeps_dir} so we can find it easily later
342     ( cd "${final_pkg_dir}"; find . -type f | cpio -plu --quiet "${final_bdeps_dir}" )
343   }
344
345   # Delete all installed packages (hope you saved them first)
346   pkg_delete_all() {
347     meh "Clearing out installed packages"
348     cheval "pkg_delete -f \*" || wtf "pkg_delete_all failed"
349   }
350
351   ########
352   #
353   # All of the above?
354   #
355   ########
356
357   # Execute a complete port build, using prebuilt packages to fulfill dependencies when available
358   # Be sure to chsetup and populate your config before running!
359   chport() {
360     local port="${1}"
361     port_load_deps "${port}"
362     port_build "${port}"
363     port_package "${port}"
364     port_stash_bdeps
365     pkg_final
366     pkg_delete_all
367   }
368 fi