generic-poky/meta/recipes-devtools/guilt/files/guilt.patch

320 lines
9.1 KiB
Diff

guilt: enhanced patch queue management
guilt prefers to track the status and series of patches
under .git/patches. But this location doesn't allow the
status of a quilt queue to be committed to a secondary
repository and later restored.
This change does three things:
- allows GUILT_BASE to be changed (with a default to "wrs")
- allows shadow tracking of the patches (for rebase)
- enhances the header detection and creation of patches
as they are pushed onto the tree.
Upstream-Status: Inappropriate [oe-specific]
Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
---
guilt | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 159 insertions(+), 24 deletions(-)
--- a/guilt
+++ b/guilt
@@ -153,14 +153,16 @@ get_branch()
verify_branch()
{
- [ ! -d "$GIT_DIR/patches" ] &&
+ [ ! -d "$GUILT_DIR" ] &&
die "Patches directory doesn't exist, try guilt-init"
- [ ! -d "$GIT_DIR/patches/$branch" ] &&
+ [ ! -d "$GUILT_DIR/$branch" ] &&
die "Branch $branch is not initialized, try guilt-init"
- [ ! -f "$GIT_DIR/patches/$branch/series" ] &&
+ [ ! -f "$GUILT_DIR/$branch/series" ] &&
die "Branch $branch does not have a series file"
- [ ! -f "$GIT_DIR/patches/$branch/status" ] &&
+ [ ! -f "$GUILT_DIR/$branch/status" ] &&
die "Branch $branch does not have a status file"
+ [ -f "$GUILT_DIR/$branch/applied" ] &&
+ die "Warning: Branch $branch has 'applied' file - guilt is not compatible with stgit"
[ -f "$GIT_DIR/patches/$branch/applied" ] &&
die "Warning: Branch $branch has 'applied' file - guilt is not compatible with stgit"
}
@@ -339,6 +341,17 @@ BEGIN{}
'
}
+# usage: do_get_only_patch patchfile
+# similar to do_get_patch except everything leading up to
+# the first diff line and after the last chunk are removed
+do_get_only_patch()
+{
+ cat "$1" | awk '
+BEGIN{}
+/^(diff )/,/^(-- |END{})/
+' | sed '/^-- *$/D'
+}
+
# usage: do_get_header patchfile
do_get_header()
{
@@ -352,8 +365,13 @@ do_get_header()
BEGIN{skip=0}
/^Subject:/ && (NR==1){print substr($0, 10); next}
/^From:/{skip=1; next}
+/^Author:/{skip=1; next}
+/^Date:/{skip=1; next}
+/^commit/{skip=1; next}
/^[ \t\f\n\r\v]*$/ && (skip==1){skip=0; next}
/^(diff |---$|--- )/{exit}
+/^diff --git/{exit}
+/^Index: /{exit}
{print $0}
END{}
'
@@ -415,6 +433,15 @@ series_insert_patch()
mv "$series.tmp" "$series"
}
+series_append_patch()
+{
+ # unlike series_insert_patch, which inserts the passed
+ # patch after the current top patch, this function always
+ # appends the patch to the series
+
+ echo $1 >> "$series"
+}
+
# usage: series_remove_patch <patchname>
series_remove_patch()
{
@@ -473,8 +500,7 @@ remove_patch_refs()
# usage: pop_many_patches <commitish> <number of patches>
pop_many_patches()
{
- assert_head_check
-
+ head_check "`tail -1 < "$applied" | cut -d: -f 1`"
(
cd_to_toplevel
@@ -508,50 +534,149 @@ remove_ref()
)
}
+prep_patch()
+{
+ patch=$1;
+ tgt=$2;
+
+ if test -f $patch; then
+ case $patch in
+ *.gz) gzip -dc $patch > $tgt ;;
+ *.bz2) bzip2 -dc $patch > $tgt ;;
+ *) cp $patch $tgt ;;
+ esac;
+ fi;
+}
+
# usage: commit patchname parent
commit()
{
(
TMP_MSG=`get_tmp_file msg`
+ TMP_PATCH=`get_tmp_file patch`
+ TMP_PATCH_OUT=`get_tmp_file patch_out`
+ TMP_INFO=`get_tmp_file info`
p="$GUILT_DIR/$branch/$1"
pname="$1"
+ prep_patch "$p" "$TMP_PATCH"
+ p=$TMP_PATCH
+
cd_to_toplevel
git diff-files --name-only | (while read n; do git update-index "$n" ; done)
+ # borrowed from git-am
+ header_type=git
+ git mailinfo "$TMP_MSG" "$TMP_PATCH_OUT" \
+ <"$p" >"$TMP_INFO";
+
+ # skip pine's internal folder data
+ grep '^Author: Mail System Internal Data$' \
+ <"$TMP_INFO" >/dev/null
+
+ git stripspace < "$TMP_MSG" > "$TMP_MSG.clean"
+ mv "$TMP_MSG.clean" "$TMP_MSG"
+ git stripspace < "$TMP_INFO" > "$TMP_INFO.clean"
+ mv "$TMP_INFO.clean" "$TMP_INFO"
+
+ # If mailinfo couldn't get something , try another way
# grab a commit message out of the patch
- do_get_header "$p" > "$TMP_MSG"
+ if [ ! -s "$TMP_MSG" ] || [ ! -s "$TMP_INFO" ]; then
+ do_get_header "$p" > "$TMP_MSG"
+ header_type=guilt
+ fi
- # make a default commit message if patch doesn't contain one
- [ ! -s "$TMP_MSG" ] && echo "patch $pname" > "$TMP_MSG"
+ # last try: make a default commit message if patch doesn't contain one
+ [ ! -s "$TMP_MSG" ] && echo "auto_msg: patch $pname" > "$TMP_MSG"
- # extract a From line from the patch header, and set
- # GIT_AUTHOR_{NAME,EMAIL}
- author_str=`sed -n -e '/^From:/ { s/^From: //; p; q; }; /^(diff |---$|--- )/ q' "$p"`
- if [ ! -z "$author_str" ]; then
+
+ if [ "$header_type" = "guilt" ]; then
+
+ # extract a From line from the patch header, and set
+ # GIT_AUTHOR_{NAME,EMAIL}
+ author_str=`sed -n -e '/^From:/ { s/^From: //; p; q }; /^(diff |---)/ q' "$p"`
+ if [ ! -z "$author_str" ]; then
GIT_AUTHOR_NAME=`echo $author_str | sed -e 's/ *<.*$//'`
export GIT_AUTHOR_NAME="${GIT_AUTHOR_NAME:-" "}"
export GIT_AUTHOR_EMAIL="`echo $author_str | sed -e 's/[^<]*//'`"
- fi
+ fi
+
+
+ # check in the patch for a subject
+ SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$p")"
+ if [ -z "$SUBJECT" ]; then
+ # if we can't find a subject in the patch, then let's construct
+ # one from the header of the patch itself
+ SUBJECT=`cat "$TMP_MSG" | head -n 1`
+ if [ ${#SUBJECT} -gt 60 ]; then
+ SUBJECT=${SUBJECT: -60}
+ fi
+ fi
+
+ if [ -z "$SUBJECT" ]; then
+ # if we are *still* without a subject, then just use
+ # the patch name
+ SUBJECT=`echo $1 | sed 's%^patch *%%'`
+
+ if [ ${#SUBJECT} -gt 60 ]; then
+ SUBJECT=${SUBJECT: -60}
+ fi
+ fi
- # must strip nano-second part otherwise git gets very
- # confused, and makes up strange timestamps from the past
- # (chances are it decides to interpret it as a unix
- # timestamp).
- export GIT_AUTHOR_DATE="`stat -c %y "$p" | sed -e '
+ SUBJECT=`echo $SUBJECT | sed s'%^ *%%'`
+
+ if [ ! -z "$SUBJECT" ]; then
+ echo "$SUBJECT" >> $TMP_MSG.subject
+ echo "" >> $TMP_MSG.subject
+ cat "$TMP_MSG" >> $TMP_MSG.subject
+ mv "$TMP_MSG.subject" "$TMP_MSG"
+ fi
+
+ # must strip nano-second part otherwise git gets very
+ # confused, and makes up strange timestamps from the past
+ # (chances are it decides to interpret it as a unix
+ # timestamp).
+ export GIT_AUTHOR_DATE="`stat -c %y "$p" | sed -e '\
s/^\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\) \([0-9]\{2\}\):\([0-9]\{2\}\):\([0-9]\{2\}\)\.[0-9]* \(.*\)$/\1-\2-\3 \4:\5:\6 \7/'`"
- export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+ export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+ else
+ # using git headers, closely related to git-am
+
+ GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$TMP_INFO")"
+ GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$TMP_INFO")"
+ GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$TMP_INFO")"
+ if test -z "$GIT_AUTHOR_EMAIL"
+ then
+ echo "Warning: patch does not have a valid e-mail address."
+ GIT_AUTHOR_EMAIL=$GIT_AUTHOR_NAME
+ fi
+
+ SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$TMP_INFO")"
+ if [ ! -z "$SUBJECT" ]; then
+ echo "$SUBJECT" >> $TMP_MSG.subject
+ echo "" >> $TMP_MSG.subject
+ cat "$TMP_MSG" >> $TMP_MSG.subject
+ mv "$TMP_MSG.subject" "$TMP_MSG"
+ fi
+ export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+ fi
# commit
treeish=`git write-tree`
commitish=`git commit-tree $treeish -p $2 < "$TMP_MSG"`
+ if [ ! $? -eq 0 ]; then
+ echo "ERROR. Could not commit tree"
+ git-reset --hard HEAD^
+ exit 1
+ fi
git update-ref HEAD $commitish
# mark patch as applied
git update-ref "refs/patches/$branch/$pname" HEAD
- rm -f "$TMP_MSG"
+ rm -f "$TMP_MSG" "$TMP_LOG" "$TMP_PATCH" "$TMP_INFO" "$TMP_PATCH_OUT"
+
)
}
@@ -568,7 +693,7 @@ push_patch()
bail_action="$2"
reject="--reject"
- assert_head_check
+ head_check "`tail -1 < "$applied" | cut -d: -f 1`"
cd_to_toplevel
# apply the patch if and only if there is something to apply
@@ -671,7 +796,7 @@ refresh_patch()
# incldiffstat
__refresh_patch()
{
- assert_head_check
+ head_check "`tail -1 < "$applied" | cut -d: -f 1`"
(
TMP_DIFF=`get_tmp_file diff`
@@ -711,6 +836,10 @@ __refresh_patch()
head -n "-$N" < "$applied" > "$applied.tmp"
mv "$applied.tmp" "$applied"
+
+ # update the shadow status.
+ ref=`cat $GIT_DIR/refs/tags/${branch}_top`
+ echo "$ref:$1" >> $applied_shadow
)
}
@@ -791,7 +920,12 @@ diffstat=`git config --bool guilt.diffst
# The following gets run every time this file is source'd
#
-GUILT_DIR="$GIT_DIR/patches"
+
+# GUILT_DIR="$GIT_DIR/patches"
+if [ -z "$GUILT_BASE" ]; then
+ GUILT_BASE=wrs
+fi
+GUILT_DIR="$GUILT_BASE/patches"
branch=`get_branch`
@@ -814,6 +948,7 @@ fi
# very useful files
series="$GUILT_DIR/$branch/series"
applied="$GUILT_DIR/$branch/status"
+applied_shadow="$GUILT_DIR/$branch/shadow_status"
guards_file="$GUILT_DIR/$branch/guards"
# determine a pager to use for anything interactive (fall back to more)