# 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_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> $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/^'"$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]*:--- '"$from"':' \ -e 's:^+++ [^ \t]*:+++ '"$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