Skip to content

Instantly share code, notes, and snippets.

@bdrewery
Last active June 25, 2018 12:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bdrewery/9877335 to your computer and use it in GitHub Desktop.
Save bdrewery/9877335 to your computer and use it in GitHub Desktop.
FreeBSD MFC script
#! /bin/sh
#
# Copyright (c) 2014 Bryan Drewery <bdrewery@FreeBSD.org>
# All rights reserved.
#
# 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 AUTHOR 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 AUTHOR 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.
set -e
: ${SVN:=svn}
shown=0
digest=0
MFC_LIST=
SVN_REMOTE=^/head
DO_STATUS=1
while getopts "m:M:S" FLAG; do
case "${FLAG}" in
m)
MSG="${OPTARG}"
;;
M)
SVN_REMOTE="${OPTARG%/head}/head"
;;
S)
DO_STATUS=0
;;
*)
echo "Unsupported option ${FLAG}" >&2
exit 1
;;
esac
done
shift $((OPTIND-1))
# Verify checkout is right and determine MFC root
branch=$(svn info | awk '/^Relative URL:/ {print $3}')
# Trim away ^/
branch=${branch#*/}
stable=${branch%/*}
if ! [ "${stable}" = "stable" ]; then
echo "Must be ran from a stable/* checkout root." >&2
exit 1
fi
# Ensure clean tree
if [ ${DO_STATUS} -eq 1 ]; then
svn_status="$(svn status -q)"
if [ -n "${svn_status}" ]; then
echo "Your tree is unclean." >&2
echo "${svn_status}" >&2
exit 1
fi
fi
# Determine MFC root
release=${branch#*/}
if [ ${release} -ge 10 ]; then
mfc_method=root
else
mfc_method=nested
fi
svn_root=${PWD}
REVS="$@"
tmplog=$(mktemp -t mfc)
#trap 'rm -f ${tmplog};exit' exit
for rev in ${REVS}; do
if [ -n "${MFC_LIST}" ]; then
MFC_LIST="${MFC_LIST},"
digest=1
fi
MFC_LIST="${MFC_LIST}r${rev#r}"
done
echo "MFC ${MFC_LIST}:" > ${tmplog}
echo >> ${tmplog}
if [ -n "${MSG}" ]; then
echo " ${MSG}" >> ${tmplog}
echo >> ${tmplog}
fi
if [ ${digest} -eq 1 ]; then
indent=" "
fmt=75
else
indent=" "
fmt=77
fi
patterns=$(cat << EOF
COPYRIGHT
LOCKS
MAINTAINERS
Makefile
Makefile.inc1
Makefile.mips
ObsoleteFiles.inc
README
UPDATING
bin/@DIR@
cddl/contrib/@DIR@
contrib/@DIR@
crypto/@DIR@
etc
games/@DIR@
gnu/lib/@DIR@
gnu/usr.bin/@DIR@
include
kerberos5
lib/@DIR@
libexec/@DIR@
release
rescue
sbin/@DIR@
secure/lib/@DIR@
secure/libexec/@DIR@
secure/usr.bin/@DIR@
secure/usr.sbin/@DIR@
share/@DIR@
share/Makefile
share/man/@DIR@
sys
tools/build/@DIR@
usr.bin/@DIR@
usr.sbin/@DIR@
EOF
)
for rev in ${REVS}; do
[ ${shown} -eq 1 ] && echo
[ ${digest} -eq 1 ] && echo " r${rev#r}:" >&3
# Grab all of the first lines until the first empty line. Also
# indent enough.
fulllog=$(${SVN} log -vr ${rev} ${SVN_REMOTE})
log=$(echo "${fulllog}" | sed -e '/Changed paths:/,/^$/d' |
sed -e '3,/^$/!d;/^[[:space:]]*$/d')
echo "${log}" | fmt -w ${fmt} | sed -e "s/^/${indent}/" >&3
# Show log on stdout and align msg
echo "r${rev#r}: ${log}" | fmt -w 70 | sed -e '2,$s,^, ,'
if [ "${mfc_method}" = "root" ]; then
${SVN} merge -c ${rev} ${SVN_REMOTE} || {
echo "--- Failed to merge r${rev#r}. Fix and resume." \
>&2
kill -SIGSTOP $$
}
else # Do nested merge
# Determine list of directories touches
changed_files=$(echo "${fulllog}" |
sed -e '/Changed paths:/,/^$/!d;/Changed paths:/d;/^$/d;s,/head/,,' |
awk '{print $2}'| sort -r)
merge_path=
for sfile in ${changed_files}; do
path=${sfile}
seen_merge_path=0
until [ -z "${path}" ]; do
file=${path##*/}
path=${path%/*}
if [ "${path}" = "${file}" ]; then
path=""
fullpath="${file}"
else
fullpath="${path}/${file}"
fi
#echo "path: ${path} file: ${file} fullpath: ${fullpath} merge_path: ${merge_path}" >&2
for pattern in ${patterns}; do
[ "${pattern%/@DIR@}" != "${pattern}" ] \
&& pattern="${pattern%/@DIR@}/${file}"
if [ "${pattern}" = "${fullpath}" ]; \
then
# Is this path already merged?
if [ "${merge_path}" = \
"${fullpath}" ]; then
seen_merge_path=1
break 2
fi
${SVN} merge -c ${rev} ${SVN_REMOTE}/${fullpath} ${fullpath}
merge_path="${fullpath}"
seen_merge_path=1
break 2
fi
done
done
#[ ${seen_merge_path} -eq 0 ] && merge_path=
if [ ${seen_merge_path} -eq 0 ]; then
echo "--- Error ---" >&2
echo "No merge path found for ${sfile}" >&2
echo "Unable to continue, not cleaning up." >&2
exit 1
fi
done
fi
shown=1
done 3>> ${tmplog}
echo "--- Commit log:"
vim ${tmplog}
echo ${tmplog}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment