go-utils/sunrise-commit
Michał Górny 3e7de31fb0 Manually call repoman manifest/full with old repoman.
If we're using old repoman version, call 'repoman full' before asking
for confirmation to allow fixing minor problems before committing. That
implies calling 'repoman manifest' too.

Additionally, don't complain about outdated repoman before the patched
version is released.
2010-07-12 15:34:14 +02:00

380 lines
8.3 KiB
Bash
Executable File

#!/bin/sh
# sunrise-commit -- a helper script for Sunrise commiters.
# (c) 2010 Michał Górny <gentoo@mgorny.alt.pl>
# Released under the terms of the 3-clause BSD license.
# Few output helpers.
say() {
echo "${@}" >&2
}
die() {
say "${RED}${@}${RESET}"
exit 1
}
sayv() {
[ -n "${SC_VERBOSE}" ] && say "${GREEN}${@}${RESET}"
}
req() {
"$@" || die "$@ failed."
}
# POSIX compat.
local_supported() {
local test 2>/dev/null
}
local_supported || eval 'local() {
unset ${@}
}'
# See if we're in a repo, and what VCS are we using.
find_repo() {
svn info >/dev/null 2>&1
if [ ${?} -eq 0 ]; then
SC_VCS=svn
else
local remotes
remotes=$(git branch -r 2>/dev/null)
if [ ${?} -ne 127 -a ${?} -ne 128 ]; then
echo "${remotes}" | grep git-svn >/dev/null 2>&1
if [ ${?} -eq 0 ]; then
SC_VCS=git-svn
else
SC_VCS=git
fi
else
die 'Unable to find any familiar repository type (are you inside the repo?).'
fi
fi
sayv "Ok, we're in ${SC_VCS} working tree. Let's see what I can do around here..."
}
is_whole_dir_removed() {
if [ ${SC_VCS} = svn ]; then
local flist
flist=$(find "${1}" \( -name '.svn' -prune -o ! -name "${1}" -print \))
[ -z "${flist}" ]
elif [ ${SC_VCS%-svn} = git ]; then
[ ! -e "${1}" ]
fi
}
# Check whether we're having a clean package removal.
is_package_removal() {
local fields list
[ -d profiles ] && fields=1-2 || fields=1
if [ ${SC_VCS%-svn} = git ]; then
list=$(git diff-index --relative --name-only --diff-filter=D HEAD)
elif [ ${SC_VCS} = svn ]; then
list=$(svn status -q | sed -n -e 's/^D //p')
fi
list=$(echo "${list}" | cut -d / -f ${fields} | sort | uniq)
# 1) We have to have any removes.
[ -z "${list}" ] && return 1
# Few more checks.
local dir olist
for dir in ${list}; do
# 2) These removes have to remove whole directories.
is_whole_dir_removed ${dir} && olist=${olist+${olist} }${dir}
done
[ -z "${olist}" ] && return 1
SC_CHANGE_LIST=${olist}
return 0
}
# Look around for ebuilds.
find_ebuilds() {
# POSIX is fun -- look for ebuilds in the current directory.
if [ -n "$(find \( -name '*.ebuild' -print -o ! -name '.' -prune \))" ]; then
local stripped
# Get CATEGORY and PN.
stripped=${PWD%/*}
stripped=${stripped%/*}
SC_CP=${PWD#${stripped}/}
SC_SCENARIO=ebuild-commit
sayv "We have some ebuilds for ${SC_CP} here."
elif is_package_removal; then
local cplist category pkg rootprefix
# We can either have the category on the list or in PWD.
if [ -d profiles ]; then
category=
else
local stripped
stripped=${PWD%/*}
category=${PWD#${stripped}/}/
fi
SC_CP=
# Now we can have multiple packages around.
for pkg in ${SC_CHANGE_LIST}; do
if [ -z "${category}" ]; then
case ${pkg} in
eclass/*|licenses/*|local/*|profiles/*|scripts/*)
continue
;;
esac
fi
SC_CP=${SC_CP:+${SC_CP}, }${category}${pkg}
done
local root sdir
root=${category:+../}
for sdir in eclass licenses profiles; do
check_for_changes ${root}${sdir} >/dev/null && SC_CHANGE_LIST="${SC_CHANGE_LIST} ${root}${sdir}"
done
SC_SCENARIO=package-removal
sayv "We're removing ${SC_CP}."
else
die 'No familiar scenario found.'
fi
}
# VCS helpers.
check_for_changes() {
local output
if [ ${SC_VCS%-svn} = git ]; then
output=$(git diff-index --name-only --relative HEAD "$@")
elif [ ${SC_VCS} = svn ]; then
output=$(svn status "$@")
fi
[ -z "${output}" ] && return 1
# We do not care about user mangling ChangeLog, we will reset it anyway.
echo "${output}" | grep -v ChangeLog >/dev/null
}
vcs_reset() {
if [ ${SC_VCS%-svn} = git ]; then
req git reset -q HEAD "${1}"
git checkout -f "${1}" 2>/dev/null || req rm -f ChangeLog
elif [ ${SC_VCS} = svn ]; then
req rm -f ChangeLog
svn up ChangeLog >/dev/null 2>&1
fi
}
vcs_status() {
if [ ${SC_VCS%-svn} = git ]; then
git status -s ${1-.} "${@}"
elif [ ${SC_VCS} = svn ]; then
svn status "${@}"
fi
}
vcs_add() {
${SC_VCS%-svn} add "$@"
}
vcs_commit() {
local msg
msg=${1}
shift
if [ ${SC_VCS%-svn} = git ]; then
exec git commit -m "${msg}" ${1+-o} "${@}"
elif [ ${SC_VCS} = svn ]; then
exec svn commit -m "${msg}" "${@}"
fi
}
print_help() {
cat <<_EOH_
Synopsis:
sunrise-commit [options] [--] <commit message>
Options:
-?, -h, --help print this message,
-V, --version print version string,
-c, --changelog backwards compat (ignored),
-C, --nocolor disable colorful output,
-f, --force force repoman to proceed with the commit,
-t, --trivial trivial changes (do not add a ChangeLog entry),
-v, --verbose enable verbose output.
_EOH_
}
confirm() {
while true; do
local answ
printf '%s' "${WHITE}Commit changes?${RESET} [${BGREEN}Yes${RESET}/${RED}No${RESET}] ${GREEN}" >&2
read answ
printf '%s' "${RESET}"
case "${answ}" in
[yY]|[yY][eE]|[yY][eE][sS])
break
;;
[nN]|[nN][oO])
die 'Aborting.'
;;
*)
say "Response '${answ}' not understood, try again."
esac
done
}
# Guess what!
main() {
local commitmsg force monochrome trivial
unset SC_VERBOSE
while [ ${#} -gt 0 ]; do
case "${1}" in
--help|-\?|-h)
print_help
exit 0
;;
--version|-V)
echo 'sunrise-commit 0.3'
exit 0
;;
-c|--changelog)
# Now changelog entries are implicit -- backwards compat.
;;
-C|--nocolor)
monochrome=1
;;
-f|--force)
force=1
;;
-t|--trivial)
trivial=1
;;
-v|--verbose)
SC_VERBOSE=1
;;
--)
shift
commitmsg=${commitmsg+${commitmsg} }${@}
break
;;
-*)
die "Unknown option: ${1}; see --help." >&2
;;
*)
commitmsg=${commitmsg+${commitmsg} }${1}
;;
esac
shift
done
if [ -n "${monochrome}" ]; then
RESET=
RED=
GREEN=
BGREEN=
YELLOW=
WHITE=
else
local esc
esc=$(printf '\033[')
RESET=${esc}0m
RED="${esc}1;31m"
GREEN=${esc}32m
BGREEN="${esc}1;32m"
YELLOW="${esc}1;33m"
WHITE="${esc}1;37m"
fi
[ -n "${commitmsg}" ] || die 'No commit message provided.'
find_repo
find_ebuilds
case ${SC_SCENARIO} in
ebuild-commit)
check_for_changes || die 'No changes found to commit.'
# With native git repos, we do not do ChangeLogs by default...
# ...at least unless they're already there.
if [ ${SC_VCS} != git -o -f ChangeLog ]; then
sayv 'Cleaning up the ChangeLog...'
vcs_reset ChangeLog
local bns
# Let's take a lucky guess bugnumbers consist of 4+ digits.
bns=$(echo "${commitmsg}" | grep -o -E '[0-9]{4,}')
# Creating a new ChangeLog? Let's take a look at the commit message.
if [ ! -f ChangeLog ]; then
[ -n "${trivial}" ] && die "Trivial change for an initial commit? You're joking, right?"
[ -z "${bns}" ] && die 'Please supply the bug number in the initial commit message!'
if [ ! -f metadata.xml ]; then
req cp ../../skel.metadata.xml metadata.xml
# Output similar to echangelog.
diff -dup /dev/null metadata.xml
req vcs_add metadata.xml
fi
fi
if [ -z "${trivial}" ]; then
sayv '...and appending to it.'
echangelog "${commitmsg}" || die 'Please correct the problems pointed by echangelog.'
echo
fi
if [ -n "${bns}" ]; then
local bn cbn
for bn in ${bns}; do
cbn=#${WHITE}${bn}${NORMAL}
wget -q http://bugs.gentoo.org/show_bug.cgi?id=${bn} -O - | sed -n \
-e "s, *<title>Gentoo Bug \([0-9]*\) - \(.*\)</title>,Bug ${cbn}: ${BGREEN}\2${RESET},p" \
-e "s, *<title>Gentoo \(Invalid Bug ID\)</title>,Bug ${cbn}: ${YELLOW}!! \1${RESET},p"
done
echo
fi
fi
vcs_status
echo
# Do we have repoman new enough?
local old_repoman
repoman --version -a >/dev/null 2>&1
if [ $? -eq 2 ]; then
old_repoman=
#say "${GREEN}Please consider updating portage to newer version.${RESET}"
#say
req repoman manifest
if ! repoman full; then
[ -n "${force}" ] || die 'Please correct the problems pointed out by repoman.'
fi
confirm
fi
sayv "Now, let's let repoman do its job..."
exec repoman commit ${old_repoman--a} ${force+-f} -m "${SC_CP}: ${commitmsg}"
;;
package-removal)
vcs_status ${SC_CHANGE_LIST}
echo
say "Ready to commit ${WHITE}$(echo ${SC_CHANGE_LIST} | wc -w)${RESET} package removal(s), with message:"
say "${BGREEN}${SC_CP}: ${commitmsg}${RESET}"
confirm
vcs_commit "${SC_CP}: ${commitmsg}" ${SC_CHANGE_LIST}
;;
esac
}
main "${@}"