#!/bin/sh # Written by dieter roelants =dieter.NetBSD@pandora.be # $Id: scu,v 1.5 2008/10/28 21:04:21 dieter Exp $ MYREV='$Revision: 1.5 $' CFG=${SCUCFG:-${HOME}/.scu.conf} [ -r "${CFG}" ] && . ${CFG} DEBUG=${DEBUG:-0} trap cleanup INT debug() { [ -n "$1" ] && [ "${DEBUG}" -gt "$1" ] } cleanup() { [ -n "${CLEANUP}" ] || exit $1 for c in ${CLEANUP}; do CLEANUP="${CLEANUP} ${c}.$$" done if ! debug; then rm -fr ${CLEANUP} else CLEANSH=CVS/cleanup.sh CLEANUP="${CLEANUP} ${CLEANSH}" echo "rm -fr ${CLEANUP}" > ${CLEANSH} echo; echo "Run sh ${CLEANSH} to remove temporary files." fi exit $1 } cmprev() { R1=$1; R2=$2 R1P=${R1%%.*}; R2P=${R2%%.*} [ ${R1P} -lt ${R2P} ] && return 1 [ ${R2P} -lt ${R1P} ] && return 0 R1S=${R1#*.}; R2S=${R2#*.} [ ${#R2} -eq ${#R2S} ] && return 0 [ ${#R1} -eq ${#R1S} ] && return 1 cmprev ${R1S} ${R2S} return $? } escpat() { read str SPECIALS=0 ESC="" for c in '+' '.'; do str_=${str#*${c}} [ "${#str}" -eq "${#str_}" ] && continue SPECIALS=1 break done [ ${SPECIALS} -eq 0 ] && { echo ${str}; exit; } echo ${str} | sed -E 's/(\+|\.)/\\&/g;q' } haverev() { REVISION=$1 FILEPATH=$2 BFILE="$(echo ${FILEPATH##*/} | escpat)" RELFILEPATH="${FILEPATH#${REPOSITORY}/}" LRELFILEPATH="./${RELFILEPATH}" ENTRIES="$(echo ${LRELFILEPATH%/*})/CVS/Entries" RETURN=0 [ "${REVISION}" = "?" ] && RETURN=$((${RETURN} | 1)) [ "${REVISION}" = "0" ] && RETURN=$((${RETURN} | 2)) [ -e ${ENTRIES} ] && RETURN=$((${RETURN} | 4)) [ ${RETURN} -lt 4 ] && return ${RETURN} HAVEREVISION="$(grep ^/${BFILE}/ ${ENTRIES} | cut -d '/' -f 3)" [ -n "${HAVEREVISION}" ] || RETURN=$((${RETURN} | 8)) [ ${RETURN} -ge 5 ] && return ${RETURN} cmprev ${HAVEREVISION} ${REVISION} [ $? -eq 0 ] && RETURN=$((${RETURN} | 16)) return ${RETURN} } updatecheck () { AUTOUPD=$(echo ${AUTOUPD} | tr 'A-Z' 'a-z') [ "${AUTOUPD}" = "no" ] && return 0 MYVER=${MYREV#* } MYVER=${MYVER% *} # XXX Need error checking on DISTSITE DISTSITE=${DISTSITE:-http://scu.bsdusr.net/scu} LATEST=$(ftp -o - ${DISTSITE}?latest) [ -z "${MYVER}" -o -z "${LATEST}" ] && return 1 cmprev ${MYVER} ${LATEST} [ $? -eq 0 ] && return 0 if [ "${AUTOUPD}" = "yes" ]; then echo "Upgrading from ${MYVER} to ${LATEST}." ftp -o $0 ${DISTSITE}?download && exec $0 echo "Failed upgrading... maybe check permissions?" return 1 fi echo "A newer version (${LATEST}) is available from ${DISTSITE}." echo "The following changes were made since this version (${MYVER}):" ftp -o - "${DISTSITE}?changes&since=${MYVER}" | more -s [ -t 0 ] && read -p "Press Enter to continue..." null && unset null } updatecheck [ -d CVS -a -e CVS/Repository ] || { echo "No CVS repository"; cleanup 1; } echo Using CVS Root ${CVSROOT:=$(head -1 CVS/Root)} CVSOPTS="-d ${CVSROOT} ${CVSOPTS}" [ -r CVS/Tag ] && BRANCH="-$(sed -E 's/(^T)|-//g;q' CVS/Tag)" REPOSITORY="$(head -1 CVS/Repository)" RBASE="${RBASE:-logs/nb-}" COMMITHIST="${RBASE}${REPOSITORY%%/*}${BRANCH}" RSITE="${RSITE:-http://scu.bsdusr.net}" RDIR="${RDIR:-${RSITE}/${COMMITHIST}}" LDIR="CVS/${COMMITHIST}" LINDEX="${LDIR}/index" TOTALHIST="CVS/${COMMITHIST}.history" CLEANUP="${LDIR} ${TOTALHIST}" if debug; then echo LDIR: ${LDIR} echo RDIR: ${RDIR} fi mkdir -p ${LDIR} || { echo "Unable to mkdir ${LDIR}."; cleanup 1; } > ${TOTALHIST} ftp -o ${LINDEX} ${RDIR}/index [ -r ${LINDEX} ] || { echo "Index not downloaded?"; cleanup 1; } n=$(grep -c ^ ${LINDEX}) while [ $n -gt 0 ]; do DAYLOG="$(sed "$n!d;q" ${LINDEX})" LDAYLOG="${LDIR}/${DAYLOG}" debug && echo LDAYLOG: ${LDAYLOG} ftp -o ${LDAYLOG} ${RDIR}/${DAYLOG} { while read cvslogentry; do debug && echo cvslogentry: ${cvslogentry} haverev ${cvslogentry}; REVSTAT=$? debug && echo REVSTAT: ${REVSTAT} if [ ${REVSTAT} -ge 16 ]; then cat ${LDAYLOG} ${TOTALHIST} > ${TOTALHIST}.$$ mv ${TOTALHIST}.$$ ${TOTALHIST} break 2 fi if [ ${REVSTAT} -eq 4 ]; then break fi done } < ${LDAYLOG} cat ${LDAYLOG} ${TOTALHIST} > ${TOTALHIST}.$$ mv ${TOTALHIST}.$$ ${TOTALHIST} n=$(($n - 1)) debug 2 && sleep 2 done [ $n -eq 0 ] && { echo "Your repository is too old."; cleanup 1; } # Process the fetched history files; find out what action needs to be taken # for each file. debug 1 && OKFILES="CVS/RevOK" && CLEANUP="${CLEANUP} ${OKFILES}" UPDFILES="CVS/UpdateF" UPDDIRS1="CVS/UpdateD1" UPDDIRS2="CVS/UpdateD2" CLEANUP="${CLEANUP} ${UPDFILES} ${UPDDIRS1} ${UPDDIRS2}" { while read cvslogentry; do haverev ${cvslogentry}; REVSTAT=$? if debug 1; then echo RELFILEPATH: ${RELFILEPATH}: ${REVSTAT} [ ${REVSTAT} -ge 16 ] && \ echo ${RELFILEPATH} >> ${OKFILES} [ ${REVSTAT} -eq 4 ] && [ -r ${OKFILES} ] && \ grep -v ^${RELFILEPATH}$ ${OKFILES} \ > ${OKFILES}.$$ && \ mv ${OKFILES}.$$ ${OKFILES} fi [ $((${REVSTAT} & 4)) -eq 4 -a $((${REVSTAT} & 18)) -eq 0 ] && \ echo ${RELFILEPATH} >> ${UPDFILES} [ ${REVSTAT} -eq 0 -o $((${REVSTAT} & 5)) -eq 1 ] && \ dirname ${RELFILEPATH} >> ${UPDDIRS1} [ ${REVSTAT} -eq 6 ] && { echo ${RELFILEPATH} >> ${UPDFILES} dirname ${RELFILEPATH} >> ${UPDDIRS2} } debug 2 && sleep 1 done } < ${TOTALHIST} # Process $UPDDIRS1, these are directories that do not exist yet # but are needed for new files. if [ -r ${UPDDIRS1} ]; then if debug 2; then echo sleeping 15 seconds before processing ${UPDDIRS1} sleep 15 fi ALLDIRS="CVS/D1All" BASEDIRS="CVS/D1Base" CLEANUP="${CLEANUP} ${ALLDIRS} ${BASEDIRS}" cp ${UPDDIRS1} ${ALLDIRS} PATTERN="$(head -1 ${ALLDIRS})" EPATTERN="$(echo ${PATTERN} | escpat)" while [ -n "${PATTERN}" ]; do debug && echo PATTERN: ${PATTERN} debug && echo EPATTERN: ${EPATTERN} DN="$(dirname ${PATTERN})" if [ ! -d ${DN} ]; then echo ${DN} > ${ALLDIRS}.$$ cat ${ALLDIRS} >> ${ALLDIRS}.$$ mv ${ALLDIRS}.$$ ${ALLDIRS} else echo ${PATTERN} >> ${BASEDIRS} grep -Ev "^${EPATTERN}(/|$)" ${ALLDIRS} > ${ALLDIRS}.$$ mv ${ALLDIRS}.$$ ${ALLDIRS} fi PATTERN="$(head -1 ${ALLDIRS})" EPATTERN="$(echo ${PATTERN} | escpat)" debug 2 && sleep 5 done sort -o ${BASEDIRS} -u ${BASEDIRS} xargs -t cvs ${CVSOPTS} update -d -P < ${BASEDIRS} fi # Process $UPDFILES, files that need to get updated if [ -r ${UPDFILES} ]; then if debug 2; then echo sleeping 15 seconds before processing ${UPDFILES} sleep 15 fi sort -o ${UPDFILES} -u ${UPDFILES} UNSELECT="CVS/Unselect" CLEANUP="${CLEANUP} ${UNSELECT}" while read file; do echo ${file%/*} done < ${UPDFILES} | uniq | \ while read dir; do [ -d ${dir} ] || echo "${dir}/" done > ${UNSELECT} grep -f ${UNSELECT} -v ${UPDFILES} >> ${UPDFILES}.$$ mv ${UPDFILES}.$$ ${UPDFILES} xargs -t cvs ${CVSOPTS} update < ${UPDFILES} fi # Process $UPDDIRS2, these are the directories that need to be # checked for emptyness after a file has been removed from them. if [ -r ${UPDDIRS2} ]; then if debug 2; then echo sleeping 15 seconds before processing ${UPDDIRS2} sleep 15 fi sort -o ${UPDDIRS2} -r -u ${UPDDIRS2} if debug 2; then cat ${UPDDIRS2} sleep 15 fi xargs -t cvs ${CVSOPTS} update -lP < ${UPDDIRS2} fi cleanup