go-utils/sunrise-commit
Michał Górny 80434064dc Support for initial commits.
'git checkout' can fail when file is not in index, thus we should
fallback to removing the file. Support adding metadata.xml like old
sunrise-commit did.
2010-07-12 13:43:17 +02:00

357 lines
7.6 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
if [ ${SC_VCS} = svn ]; then
die 'Native subversion repositories are not supported at the moment.'
fi
sayv "Ok, we're in ${SC_VCS} working tree. Let's see what I can do around here..."
}
# 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 \
| cut -d / -f ${fields} | sort | uniq)
fi
# 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.
[ -e ${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 "$@")
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
fi
}
vcs_status() {
if [ ${SC_VCS%-svn} = git ]; then
git status -s ${1-.} "${@}"
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} "${@}"
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
;;
*)
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.'
req echangelog "${commitmsg}"
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 -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" -e d
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 update portage to newer version in order to have repoman supporting"
say "--ask option and thus delay the following question until after 'repoman full'.${RESET}"
say
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 "${@}"