# This file contains the common functions used in all quilt script
# It is meant to be sourced by bash scripts.
# This script is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# See the COPYING and AUTHORS files for more details.
if [ -n "$PATCHSCRIPTS" ]
then
P=$PATCHSCRIPTS/
else
unset P
fi
if [ -e .pc/series ]
then
SERIES=.pc/series
elif [ -e series ]
then
SERIES=series
else
SERIES=${P}patches/series
fi
DB=".pc/applied-patches"
# Define where diffstat lives (may be missing)
DIFFSTAT=/usr/bin/diffstat
# Quote a string for use in a basic regular expression.
quote_bre()
{
echo "$1" | sed -e 's:\([][^$/.*\\]\):\\\1:g'
}
# Quote a string for use in an extended regular expression.
quote_re()
{
echo "$1" | sed -e 's:\([][?{(|)}^$/.+*\\]\):\\\1:g'
}
#basename()
#{
# local path=${1%/}
# echo "${path/*\/}"
#}
#dirname()
#{
# local path=${1%/}
#}
patch_file_name()
{
local patch=$1
if [ -e $SERIES ]
then
awk '/^'"$(quote_re $patch)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \
{ printf "'"$P"'patches/%s\n", $1
exit
}
' $SERIES
fi
}
# The -pN option and possibly others that should be passed to patch.
patch_args()
{
local patch=$1
if [ -e $SERIES ]
then
awk '
/^'"$(quote_re $patch)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \
{ if (NF >= 2)
for (i=2; i <= NF; i++)
print $i
else
print "-p1" ;
exit
}
' $SERIES
fi
}
patch_strip_level()
{
local patch=$1 i
for i in $(patch_args $patch)
do
case $i in
-p)
echo $2
return ;;
-p*)
echo ${i:2}
return ;;
esac
done
echo "1"
}
change_db_strip_level()
{
local level=$1 patch=$2
if [ x$level != x-p1 ]
then
level="$level"
else
level=""
fi
if [ -e $SERIES ]
then
local tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX)
awk '
/^'"$(quote_re $patch)"'(\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \
{ for(i=2; i<=NF; i++)
if ($i ~ /^-p/) {
$i="'"$level"'"
break
}
if (i > NF)
$i="'"$level"'"
}
{ print }
' $SERIES > $tmpfile
if cmp $SERIES $tmpfile >/dev/null 2>/dev/null
then
rm -f $tmpfile
else
mv -f $tmpfile $SERIES
fi
else
return 1
fi
}
patch_in_series()
{
local patch=$1
if ! [ -e $SERIES ]
then
return 1
else
grep -q -E '^'"$(quote_re $patch)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)' $SERIES
fi
}
# Insert new patch after topmost patch
insert_in_series()
{
local patch=$1 patch_args=$2
local top=$(top_patch) tmpfile
if [ -n "$patch_args" ]
then
patch_args=" $patch_args"
fi
tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX) || return 1
mkdir -p $(dirname $SERIES)
if [ -n "$top" ]
then
awk '
{ print }
/^'"$(quote_re $top)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \
{ print "'"$patch$patch_args"'" }
' $SERIES > $tmpfile
status=$?
if [ $status -ne 0 ]
then
rm -f $tmpfile
return 1
fi
else
echo $patch$patch_args > $tmpfile
if [ -e $SERIES ]
then
cat $SERIES >> $tmpfile
fi
fi
mv -f $tmpfile $SERIES
}
remove_from_series()
{
local patch=$1
tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX) || return 1
awk '
! /^'"$(quote_re $patch)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \
{ print }
' $SERIES > $tmpfile
if [ $? -eq 0 ]
then
mv -f $tmpfile $SERIES
else
rm -f $tmpfile
return 1
fi
}
pc_file_name()
{
while [ $# -gt 0 ]
do
echo ".pc/$1/.pc"
shift
done
}
backup_file_name()
{
local patch=$1
while [ $# -gt 1 ]
do
echo ".pc/$patch/$2"
shift
done
}
cat_series()
{
if [ -e $SERIES ]
then
sed -e '/^#/d' -e 's/^[ \t]*//' -e 's/[ \t].*//' \
-e 's/\.gz$//' -e 's/\.bz2$//' \
-e 's/\.patch$//' -e 's/\.diff\?$//' $SERIES
else
return 1
fi
}
top_patch()
{
[ -e $DB ] && tail -1 $DB
}
is_numeric()
{
echo $1 | grep -q '^[0-9]*$'
}
is_applied_last()
{
local patch=$1
[ "$(top_patch)" == $patch ]
}
is_applied()
{
local patch=$1
[ -e $DB ] || return 1
grep -q -E "^$(quote_re $patch)\$" $DB
}
patches_before()
{
local patch=$1
if [ -n "$patch" ]
then
cat_series \
| awk '
$0 == "'"$patch"'" { exit }
{ print }
'
fi
}
patches_after()
{
local patch=$1
if [ -n "$patch" ]
then
cat_series \
| awk '
seen { print }
$0 == "'"$patch"'" { seen=1 }
'
else
cat_series
fi
}
# List all patches that have been applied on top of patch $1
patches_on_top_of()
{
local patch=$1
[ -e $DB ] || return
awk '
$0 == "'"$patch"'" { seen=1 ; next }
seen { print }
' $DB
}
# Print the name of the patch that modified the file $2 next after
# patch $1, or print nothing if patch $1 is on top.
next_patch_for_file()
{
local patch=$1 file=$2
local patches_on_top=$(patches_on_top_of $patch)
if [ -n "$patches_on_top" ]
then
grep -l -E "^$(quote_re $file)\$" \
$(pc_file_name $patches_on_top) \
| head -1 \
| sed -e 's:^\.pc/::' -e 's:/\.pc$::'
fi
#modified_files $file -- $patches_on_top \
#| cut -d $'\t' -f2 \
#| cut -d ' ' -f1
}
# Create a list of files and the patches that modify them.
refresh_patches_per_file()
{
local pc_files=$(pc_file_name $(cat_series))
local ex_pc_files pc_file
if [ -e .pc/patches-per-file ]
then
local needs_refresh
for pc_file in pc_files
do
if [ .pc/patches-per-file -ot $pc_file ]
then
needs_refresh=1
break
fi
done
if [ -z "$needs_refresh" ]
then
return 0
fi
fi
for pc_file in $pc_files
do
if [ -e $pc_file ]
then
ex_pc_files[${#ex_pc_files[@]}]=$pc_file
fi
done
if [ ${#ex_pc_files[@]} -eq 0 ]
then
rm -f .pc/patches-per-file
return 0
fi
awk '
ARGIND!=saved { sub(/^.pc\//, "", FILENAME)
sub(/\/\.pc/, "", FILENAME)
saved=ARGIND
}
{ if (files[$0])
files[$0]=files[$0] " " FILENAME
else
files[$0]=FILENAME
}
END { for (file in files)
printf "%s\t%s\n", file, files[file]
}
' "${ex_pc_files[@]}" > .pc/patches-per-file
}
# For a lists of patches and a list of files, compute which patches
# modify which files. Invoked as
# modified_files file ... [-- patch ...]
#
modified_files()
{
if ! refresh_patches_per_file
then
return 1
fi
awk '
BEGIN { no_files=1
no_patches=1
for (i=1; i<ARGC; i++) {
if (ARGV[i]=="--")
break
files[ARGV[i]]=1
no_files=0
}
for (i++; i<ARGC; i++) {
patches[ARGV[i]]=1
no_patches=0
}
split("", ARGV) # read from standard input
}
no_files || files[$1] {
if (no_patches) {
print
next
}
for (i=2; i<=NF; i++)
if ($i in patches) {
printf "%s\t%s", $1, $i
for (i++; i<=NF; i++)
if ($i in patches)
printf " %s", $i
printf "\n"
}
}
' "$@" < .pc/patches-per-file
}
add_to_db()
{
echo $1 >> $DB
}
remove_from_db()
{
local patch=$1
local tmpfile
if tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX)
then
grep -v -E "^$(quote_re $patch)\$" $DB > $tmpfile
mv -f $tmpfile $DB
rm -f $tmpfile
[ -s $DB ] || rm -f $DB
fi
}
stripit()
{
if [ -n "$1" ]
then
echo $1 |
sed -e 's/^\(\.\/\)*//' \
-e 's/^'"$(quote_bre $P)"'patches\///' -e 's/^\.pc\///' \
-e 's/\.gz$//' -e 's/\.bz2$//' \
-e 's/\.patch$//' -e 's/\.diff\?$//'
fi
}
file_in_patch()
{
local file=$1 patch=$2
files_in_patch $patch \
| grep -q -E "^$(quote_re $file)\$"
}
files_in_patch()
{
local pc_file=$(pc_file_name $1)
if [ -e "$pc_file" ]
then
cat $pc_file
fi
}
touched_by_patch()
{
local strip=$1 patch=$2
cat_file $(patch_file_name $patch) \
| awk '
/^\+\+\+[ \t]/ {
sub(/^\+\+\+[ \t]/, "")
sub(/[ \t].*/, "")
sub(/^\/dev\/null/, "")
for (i=0; i<'$strip'; i++)
sub(/^[^\/]*\//, "")
print
}'
}
refresh_file_list()
{
local patch=$1
local pc_file=$(pc_file_name $patch)
local patch_file=$(patch_file_name $patch)
if ! [ -e "$patch_file" ]
then
return 0
fi
if [ ! -e $pc_file -o \
$pc_file -ot $patch_file -o \
$pc_file -ot $SERIES ]
then
local tmpfile status
if ! mkdir -p $(dirname $pc_file) || \
! tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX)
then
return 1
fi
if [ -e $pc_file ]
then
cat $pc_file >> $tmpfile
fi
if ! touched_by_patch $(patch_strip_level $patch) \
$patch >> $tmpfile
then
return 1
fi
sort $tmpfile | uniq > $pc_file
rm $tmpfile
return 0
fi
}
diff_file()
{
local file=$1 suffix=$2 old_file=$3 new_file=$4
local old_file new_file
if [ ! -e "$old_file" -a ! -e "$new_file" ]
then
echo "File $file does not exist" >&2
return 0
fi
local old_hdr new_hdr
if [ $opt_strip_level -eq 0 ]
then
old_hdr=$file$suffix
new_hdr=$file
else
local dir=$(basename $PWD)
old_hdr=$dir$suffix/$file
new_hdr=$dir/$file
fi
echo Index: $new_hdr
@DIFF@ -Nu $DIFF_OPTS $old_file $new_file |
fix_diff_header $old_hdr $new_hdr
}
fix_diff_header()
{
local from=$1 to=$2
sed -e 's/^--- [^ \t]*/--- '"$(quote_bre $from)"'/' \
-e 's/^+++ [^ \t]*/+++ '"$(quote_bre $to)"'/'
}
cat_file()
{
local filename
for filename in "$@"
do
if [ -e "$filename" ]
then
case "$filename" in
*.gz|*.tgz)
gzip -cd "$filename" ;;
*.bz2)
bzip2 -cd "$filename" ;;
*)
cat "$filename" ;;
esac
fi
done
}
cat_to_file()
{
local filename="$1"
if [ -z "$filename" ]
then
cat
else
case "$filename" in
*.gz|*.tgz)
gzip -c > "$filename" ;;
*.bz2)
bzip2 -c > "$filename" ;;
*)
cat > "$filename" ;;
esac
fi
}
patch_description()
{
local patch_file=$1
if [ -e "$patch_file" -o -z "$patch_file" ]
then
awk '
$1 == "---" { exit }
$1 == "Index:" { eat = eat $0
next }
$1 == "diff" { eat = eat $0
next }
eat { print eat
eat="" }
{ print }
' $patch_file
fi
}
in_array()
{
local a=$1
while [ $# -gt 1 ]
do
shift
[ "$a" = "$1" ] && return 0
done
return 1
}
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh