#!/bin/sh # # $NetBSD: binpkg-cache,v 1.23 2020/05/30 03:36:45 khorben Exp $ # # Script for generating a cache file with information about # all binary packages contained in a directory. # # Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by Dan McMahill. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # TMPDIR=${TMPDIR:-/tmp} PACKAGES=${PACKAGES:-/usr/pkgsrc/packages/} AWK=${AWK:-awk} CMP=${CMP:-cmp} FIND=${FIND:-find} GREP=${GREP:-grep} GZIP_CMD=${GZIP_CMD:-gzip} BZIP2=${BZIP2:-bzip2} PKG_INFO=${PKG_INFO:-pkg_info} PKG_SUFX=${PKG_SUFX:-.tgz} SED=${SED:-sed} SORT=${SORT:-sort} STAT=${STAT:-stat} cachefile=.pkgcache summaryfile=pkg_summary cacheversion=20050428 prompt="----> " tab=" " tmpd=${TMPDIR}/pkg-cache.$$ mkdir -m 0700 ${tmpd} if test $? -ne 0 ; then echo "ERROR: Could not create temporary directory ${tmpd}" echo "Either you do not have write permission to ${tmpd} or" echo "${tmpd} already exists" exit 1 fi all_dirs=${tmpd}/all_dirs prog=$0 usage(){ echo "$prog - Generates cache files for each directory containing binary" echo " packages. This cache file can then be used by the README.html" echo " generation code to avoid having to call pkg_info(1) over and over" echo " on the same binary package. In addition, pkg_summary.gz files for" echo " use by the pkgtools/pkg_chk package may be generated." echo " " echo "Usage: $prog [-d|--debug] [-v|--verbose] [-s|--summary] [-p|--packages ]" echo " " echo " $prog -h|--help" echo " " echo " $prog -V|--version" echo " " echo "The options supported by $prog are: " echo " " echo " -d|--debug Enables debugging output" echo " " echo " -F|--force Forces a rebuild of the cache files even if they are" echo " otherwise up to date." echo " " echo " -h|--help Displays this help message" echo " " echo " -p|--packages Specifies the top level directory to be searched" echo " for binary packages." echo " " echo " -s|--summary Enables the creation of pkg_summary.gz files in each" echo " directory containing binary packages. The pkg_summary.gz" echo " file is used by the pkgtools/pkg_chk package." echo " " echo " -v|--verbose Enables verbose output from the script." echo " " echo " -V|--version Displays the version of this script and exits." echo " " echo "Returns 0 on success, 1 on errors, 2 if the packages" echo "directory does not exist." echo " " echo "Example: $prog -v --packages /usr/pkgsrc/packages" echo " " } clean_and_exit0(){ rm -fr ${tmpd} exit 0 } clean_and_exit1(){ rm -fr ${tmpd} exit 1 } clean_and_exit2(){ rm -fr ${tmpd} exit 2 } all_cache_files="" ############################################################################# # # process_binpkg_dir() # # Process a directory by checking to see if a cache file exists. If the # cache file exists, make sure it is up to date. If the file does not # exist, create one. # # also keep track of this directory so it can be added to the master # cache. # process_binpkg_dir(){ rdir=`${GREP} "^${d} " ${all_dirs} | ${AWK} '{print $2}'` need_update=no if test -f ${d}/${cachefile} ; then stale_entries=`${FIND} ${d} -type f -name \*${PKG_SUFX} -newer ${d}/${cachefile} -print` # FIX_ME # # We also should find cache entries for files which no longer exist # and nuke them. Right now we simply declare the entire cache out # of date. Once we implement incremental updates to the cache, # we need to remove the entries but not mark the entire cache as # bad. $if_debug echo " Checking for cache entries with no corresponding pkg." # get the list of what pkgs belong in the cache rm -f ${tmpd}/pkg_list ${tmpd}/cache_pkg_list ${FIND} ${d}/ -name \*${PKG_SUFX} -print | \ ${SED} -e "s;^${d}/*;${rdir}/;g" -e 's;//;/;g' | \ ${SORT} > ${tmpd}/pkg_list # and get the list of what is in the cache ${AWK} '/pkgcache_begin/ {gsub(/pkgcache_begin[ \t]*/, ""); print}' \ ${d}/${cachefile} | ${SORT} > ${tmpd}/cache_pkg_list if ${CMP} -s ${tmpd}/pkg_list ${tmpd}/cache_pkg_list ; then $if_debug echo " No extra cache entries in ${d}/${cachefile}" else $if_debug echo "Package list:" $if_debug cat ${tmpd}/pkg_list $if_debug echo "Cache list:" $if_debug cat ${tmpd}/cache_pkg_list echo " Entries found in ${d}/${cachefile} but no packages found" need_update=yes fi else stale_entries="" fi if test "X${force}" = "Xyes" -o "X${need_update}" = "Xyes" ; then need_update=yes echo "${tab}Forcing rebuild of cache ${d}/${cachefile}." elif test ! -f ${d}/${cachefile} ; then need_update=yes echo "${tab}Missing cache file. ${d}/${cachefile} will be generated." elif test -n "${stale_entries}" ; then need_update=yes echo "${tab}Stale cache file. ${d}/${cachefile} will be regenerated." else ${GREP} "pkgcache_version ${cacheversion}" ${d}/${cachefile} >/dev/null 2>&1 if test $? -ne 0 ; then need_update=yes echo "${tab}Invalid version cache file. ${d}/${cachefile} will be regenerated." echo "Need version ${cacheversion} but the file has" ${GREP} "^pkgcache_version " ${d}/${cachefile} else $if_verbose echo "${tab}Cache file ${d}/${cachefile} is up to date." fi fi if test "${build_summary}" = "yes" -a ! -f ${d}/${summaryfile}.gz ; then echo "${tab}Summary file ${d}/${summaryfile}.gz is missing and will be created." need_update=yes fi if test "${build_summary}" = "yes" -a ${d}/${summaryfile}.gz -ot ${d}/${cachefile} ; then echo "${tab}Summary file ${d}/${summaryfile}.gz is out of date and will be regenerated." need_update=yes fi # FIX_ME # We should use stale_entries in a way where we only update the # cache file entries corresponding to these if we're rebuilding # due to stale entries. That should save a good bit of time. # if test "X${need_update}" = "Xyes" ; then echo "pkgcache_version ${cacheversion}" > ${tmpd}/${cachefile} rm -f ${tmpd}/${summaryfile} touch ${tmpd}/${summaryfile} for f in ${d}/*${PKG_SUFX} ; do fn=`grep "^${d} " ${all_dirs} | ${AWK} '{print $2}'`"/"`basename ${f}` $if_debug echo " Adding ${fn} (${f}) to the cache" echo " " >> ${tmpd}/${cachefile} # stat(1) needs to be added to the bootstrap kit # first if we want to use it here #eval $(${STAT} -s ${f} 2>/dev/null) echo "pkgcache_begin ${fn}" >> ${tmpd}/${cachefile} #echo "pkgcache_mtime=${st_mtime}" >> ${tmpd}/${cachefile} $if_debug echo "${PKG_INFO} -q -B ${f}" ${PKG_INFO} -q -B ${f} >> ${tmpd}/${cachefile} if test "${build_summary}" = "yes" ; then $if_debug echo "${PKG_INFO} -X ${f}" ${PKG_INFO} -X ${f} >> ${tmpd}/${summaryfile} fi echo "pkgcache_end ${fn}" >> ${tmpd}/${cachefile} done if test -f ${d}/${cachefile} ; then rm -f ${d}/${cachefile} fi mv -f ${tmpd}/${cachefile} ${d}/${cachefile} if test $? -ne 0 ; then echo "********** WARNING **********" echo "move of ${tmpd}/${cachefile} to ${d}/${cachefile} failed!" echo "Perhaps you do not have write permissions to ${d}?" echo "This directory will be dropped from the master cache file." echo "********** WARNING **********" return fi if test "${build_summary}" = "yes" ; then if test -f ${d}/${summaryfile}.gz ; then rm -f ${d}/${summaryfile}.gz fi cat ${tmpd}/${summaryfile} | ${GZIP_CMD} > ${d}/${summaryfile}.gz if test $? -ne 0 ; then echo "********** WARNING **********" echo "${GZIP_CMD} of ${tmpd}/${summaryfile} to ${d}/${summaryfile}.gz failed!" echo "Perhaps you do not have write permissions to ${d}?" echo "********** WARNING **********" return fi # if it's there, update it, otherwise don't bother if test -f ${d}/${summaryfile}.bz2 ; then rm -f ${d}/${summaryfile}.bz2 cat ${tmpd}/${summaryfile} | ${BZIP2} > ${d}/${summaryfile}.bz2 if test $? -ne 0 ; then echo "********** WARNING **********" echo "${BZIP2} of ${tmpd}/${summaryfile} to ${d}/${summaryfile}.bz2 failed!" echo "Perhaps you do not have write permissions to ${d}?" echo "********** WARNING **********" return fi fi fi fi # if we got here, then this directory should have a good cache file in # it and we should be able to add it to the master cache file all_cache_files="${all_cache_files} ${d}/${cachefile}" } process_cache_files(){ echo "${prompt}Checking master cache file ${PACKAGES}/${cachefile}" echo "pkgcache_version ${cacheversion}" > ${tmpd}/${cachefile} if test -n "${all_cache_files}" ; then for c in ${all_cache_files} ; do echo "pkgcache_cachefile ${c}" >> ${tmpd}/${cachefile} done fi if test ! -f ${PACKAGES}/${cachefile} ; then echo "${tab}Creating master cache file ${PACKAGES}/${cachefile}" mv -f ${tmpd}/${cachefile} ${PACKAGES}/${cachefile} if test $? -ne 0 ; then echo "********** ERROR **********" echo "move of ${tmpd}/${cachefile} to ${PACKAGES}/${cachefile} failed!" echo "Perhaps you do not have write permissions to ${PACKAGES}?" echo "********** ERROR **********" clean_and_exit1 fi elif ${CMP} -s ${tmpd}/${cachefile} ${PACKAGES}/${cachefile} ; then echo "${tab}Master cache file ${PACKAGES}/${cachefile} is up to date" else echo "${tab}Updating master cache file ${PACKAGES}/${cachefile}" mv -f ${tmpd}/${cachefile} ${PACKAGES}/${cachefile} if test $? -ne 0 ; then echo "********** ERROR **********" echo "move of ${tmpd}/${cachefile} to ${PACKAGES}/${cachefile} failed!" echo "Perhaps you do not have write permissions to ${PACKAGES}?" echo "********** ERROR **********" clean_and_exit1 fi fi } ###################################################################### # # Handle command line options # ###################################################################### if_debug=: # either ":" or "" if_verbose=: # either ":" or "" force=no build_summary=no while test -n "$1" do case "$1" in # Turn on debugging -d|--debug) if_debug="" if_verbose="" shift ;; # Force a rebuilde of the cache -F|--force) force=yes shift ;; # Help -h|--help) usage exit 0 ;; # Use the specified packages directory -p|--packages) PACKAGES=$2 shift 2 ;; # Build the pkg_summary.gz files -s|--summary) build_summary=yes shift ;; # Version -V|--version) ${AWK} '/^#[ \t]*\$NetBSD/ {gsub(/,v/,"",$3);printf("%s: Version %s, %s\n",$3,$4,$5); exit 0;}' $prog exit 0 ;; # Turn on verbose output, but not as noisy as debug -v|--verbose) if_verbose="" shift ;; -*) echo "$prog: ERROR: $1 is not a valid option" usage clean_and_exit1 ;; *) break ;; esac done if test $# -ne 0 ; then echo "$0: $* is invalid" usage clean_and_exit1 fi if test ! -d ${PACKAGES} ; then echo "Packages directory ${PACKAGES} seems to be missing" clean_and_exit2 fi # put a trailing / after ${PACKAGES} in case ${PACKAGES} is # a link. # pass 1, we find all directories under PACKAGES. Note that this # may contain some directories more than once depending on what sort # of soft links may be in place rm -f ${all_dirs}.tmp for d in `${FIND} ${PACKAGES}/ -type d -follow -print` ; do cname=`(cd ${d} && pwd -P)` rname=`echo ${d} | ${SED} "s;^${PACKAGES}/*;;g"` echo "${cname} ${rname}" >> ${all_dirs}.tmp done ${SORT} -u -k1,1 ${all_dirs}.tmp > ${all_dirs} $if_debug echo "Full directory list:" $if_debug cat ${all_dirs}.tmp $if_debug echo "Unique directory list:" $if_debug cat ${all_dirs} for d in `${AWK} '{print $1}' ${all_dirs}` ; do $if_debug echo "${prompt}Processing directory ${d}" is_pkg_dir=no for f in ${d}/*${PKG_SUFX} ; do if test -f "${f}" -a ! -h "${f}" ; then ${PKG_INFO} ${f} >/dev/null 2>&1 if test $? -eq 0 ; then is_pkg_dir=yes break fi fi done if test "X${is_pkg_dir}" = "Xyes" ; then $if_verbose echo "${prompt}Checking cache in ${d}" process_binpkg_dir else $if_debug echo "${prompt}no binary packages in ${d}" fi done process_cache_files clean_and_exit0