]> CyberLeo.Net >> Repos - CDN/Mosi.git/blob - script/lib/chroot.sh
script/lib/chroot: functions for building ports independent of host system
[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() {
137     # rdeps for rdeps are rdeps, rdeps for bdeps are bdeps; thus:
138     ( port_bdeps "${@}"; port_all_rdeps "${@}" ) | while read port
139     do
140       port_all_bdeps "${port}"
141       port_all_rdeps "${port}"
142     done | sort | uniq
143   }
144   pkg_bdeps() {
145     port2pkg $(port_all_bdeps "${@}")
146   }
147
148   # Runtime dependencies (shallow, recursive, package)
149   port_rdeps() {
150     while [ "${1}" ]
151     do
152       chmake "${1}" run-depends-list | sed -e 's#^/usr/ports/##'
153       shift
154     done
155   }
156   port_all_rdeps() {
157     port_rdeps "${@}" | while read port
158     do
159       echo "${port}"
160       port_all_rdeps "${port}"
161     done | sort | uniq
162   }
163   pkg_rdeps() {
164     port2pkg $(port_all_rdeps "${@}")
165   }
166
167   # All dependencies (shallow, recursive, package)
168   port_deps() {
169     while [ "${1}" ]
170     do
171       chmake "${1}" all-depends-list | sed -e 's#^/usr/ports/##'
172       shift
173     done
174   }
175   port_all_deps() {
176     port_deps "${@}" | while read port
177     do
178       echo "${port}"
179       port_deps "${port}"
180     done | sort | uniq
181   }
182   pkg_deps() {
183     port2pkg $(port_all_deps "${@}")
184   }
185
186   ########
187   #
188   # Port Configuration Handling
189   #
190   ########
191
192   # Run make config on a list of ports
193   port_config() {
194     while [ "${1}" ]
195     do
196       meh "port config ${1}"
197       chmake "${1}" config < /dev/tty
198       shift
199     done
200   }
201
202   # Make config-conditional for a list of ports, and all dependencies
203   port_config_recursive() {
204     # If the first parameter is not --, then clear the cache
205     [ "${1}" == "--" ] && shift || unset _port_config_recursive_cache
206
207     while [ "${1}" ]
208     do
209       # Do not use config-recursive because it computes the depchain first;
210       # instead, manually compute the depchain after each config to ensure the
211       # proper depchain is followed. Use config-conditional to avoid dialog
212       # if the config is already complete. Also use a cache to avoid re-config
213       # and re-recurse on previously handled port branches.
214       if echo "${_port_config_recursive_cache}" | grep -qv " ${1} "
215       then
216         meh "port config-recursive ${1}"
217         chmake "${1}" config-conditional < /dev/tty
218         port_config_recursive -- $(port_deps "${1}")
219         _port_config_recursive_cache="${_port_config_recursive_cache} ${1} "
220       fi
221       shift
222     done
223   }
224
225   # Remove saved config for a list of ports
226   port_rmconfig() {
227     while [ "${1}" ]
228     do
229       meh "port rmconfig ${1}"
230       chmake "${1}" rmconfig
231       shift
232     done
233   }
234
235   # Remove saved config for a list of ports and all dependencies
236   port_rmconfig_recursive() {
237     meh "port rmconfig-recursive ${*}"
238     port_rmconfig $(echo "${@}" $(port_all_deps "${@}") | sort | uniq)
239   }
240
241   # Obliterate saved configuration for all ports
242   port_rmconfig_all() {
243     meh "port rmconfig-all"
244     cheval "cd /var/db/ports; find . -name 'options' -delete; find . -type d | xargs rmdir 2>/dev/null"
245   }
246
247   # Restore port build options from cpio
248   port_load_config() {
249     meh "port load-config"
250     cheval "cd /var/db/ports; cpio -iv"
251   }
252
253   # Dump port build options to cpio
254   port_save_config() {
255     meh "port save-config"
256     cheval "cd /var/db/ports; find . -type d -o -type f -name options | cpio -ovHnewc"
257   }
258
259   ########
260   #
261   # Port distfile handling
262   #
263   ########
264
265   # Recursively retrieve distfiles
266   port_fetch_recursive() {
267     while [ "${1}" ]
268     do
269       meh "fetch-recursive ${1}"
270       chmake "${1}" fetch-recursive
271     done
272   }
273
274   ########
275   #
276   # Port building and packaging
277   #
278   ########
279
280   # Copy in and install dependency packages
281   port_load_deps() {
282     local port="${1}"
283     for pkg in $(port2pkg $(port_all_deps "${port}"))
284     do
285       cp -f "${final_bdeps_dir}/${pkg}.tbz" "${bdeps_dir}" 2>/dev/null && meh "Loading dependent ${pkg}"
286     done
287     if ls "${bdeps_dir}"/*.tbz >/dev/null 2>&1
288     then
289       meh "Installing dependencies"
290       cheval "cd ${chroot_bdeps_dir}; pkg_add -F *" || wtf "port_load_deps ${port} failed"
291     fi
292   }
293
294   # Build and install a port
295   port_build() {
296     local port="${1}"
297     meh "Building ${port}"
298     chmake "${port}" clean build install clean || wtf "port_build ${port} failed"
299   }
300
301   # Package a port
302   port_package() {
303     local port="${1}"
304     meh "Creating rdep package tree for ${port}"
305     cheval "pkg_create -Rvb $(port2pkg "${port}")" || wtf "port_package ${port} failed"
306   }
307
308   # Package port build dependencies, unless they're already run deps
309   port_stash_bdeps() {
310     meh "Stashing unsaved bdeps"
311     # This doesn't work well, because there can be bdeps that aren't listed as bdeps (bison)
312     #for pkg in $(pkg_bdeps "${1}")
313     #do
314     #  [ ! -f "${pkg_dir}/${pkg}.tbz" ] && cheval "cd ${chroot_bdeps_dir}; pkg_create -vb ${pkg}"
315     #done
316     #
317     # Instead, just save everything that's not already in rdeps as bdeps
318     for pkg in $(cheval pkg_info | awk '{print $1}')
319     do
320       if [ ! -f "${pkg_dir}/${pkg}.tbz" -a ! -f "${bdeps_dir}/${pkg}.tbz" ]
321       then
322         cheval "cd ${chroot_bdeps_dir}; pkg_create -vb ${pkg}" || wtf "port_stash_bdeps failed"
323       fi
324     done
325   }
326
327   # Copy generated packages out of tree
328   pkg_final() {
329     meh "Moving created packages to repo"
330     ls "${pkg_dir}"/*.tbz >/dev/null 2>&1 && mv -f "${pkg_dir}"/*.tbz "${final_pkg_dir}"
331     ls "${bdeps_dir}"/*.tbz >/dev/null 2>&1 && mv -f "${bdeps_dir}"/*.tbz "${final_bdeps_dir}"
332     # link everything into ${bdeps_dir} so we can find it easily later
333     ( cd "${final_pkg_dir}"; find . -type f | cpio -plu --quiet "${final_bdeps_dir}" )
334   }
335
336   # Delete all installed packages (hope you saved them first)
337   pkg_delete_all() {
338     meh "Clearing out installed packages"
339     cheval "pkg_delete -f \*" || wtf "pkg_delete_all failed"
340   }
341
342   ########
343   #
344   # All of the above?
345   #
346   ########
347
348   # Execute a complete port build, using prebuilt packages to fulfill dependencies when available
349   # Be sure to chsetup and populate your config before running!
350   chport() {
351     local port="${1}"
352     port_load_deps "${port}"
353     port_build "${port}"
354     port_package "${port}"
355     port_stash_bdeps
356     pkg_final
357     pkg_delete_all
358   }
359 fi