Still more updates to 'p'
[wiggle.git] / p
blob41660001e2a7747951ef313176af1b4c0786d7a4
1 #!/bin/bash
3 # patch management
5 # Copyright (C) 2003 Neil Brown <neilb@cse.unsw.edu.au>
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 # Author: Neil Brown
23 # Email: <neilb@cse.unsw.edu.au>
24 # Paper: Neil Brown
25 # School of Computer Science and Engineering
26 # The University of New South Wales
27 # Sydney, 2052
28 # Australia
31 # metadata is in .patches
32 # there is:
33 # files: list of all files checked out
34 # name: name of current patch
35 # status: status of current patch
36 # notes: notes on current patch
37 # applied/ patches applied nnn-name
38 # removed/ patches removed nnn-name
39 # included/ patches that have been included upstream
40 # patch: a recent copy of the 'current' patch
41 # get-version: a script which will report the version number of the base dist
42 # dest/ symlink to directory to publish snapshots to
43 # mail/ composed mail messages ready for sending
44 # maintainer who to email patches to (Linus etc)
45 # cc who to CC patches to: prefix address
47 # the nnn in names in applied and removed are sequence numbers
48 # whenever we add a file we choose one more than the highest used number
49 # patch files contain then name implicitly and start with
50 # Status: status
51 # then a blank line, normally a one line description, another blank, and more detail.
55 # Todo - auto bk pull:
56 # bk pull
57 # bk export -t patch -r DEVEL, > /tmp/apatch
58 # bk tag DEVEL
59 # while p open last && p discard ; do : ; done
60 # p clean
61 # patch -p1 -f < /tmp/apatch
63 find_home()
65 # walk up directory tree until a .patches directory
66 # is found.
67 # set OrigDir to name of where we were .. not dots.
68 OrigDir=
69 dir=`pwd`
70 while [ ! -d .patches -a " $dir" != " /" ]
72 base=${dir##*/}
73 base=${base#/}
74 dir=${dir%/*}
75 case $dir in
76 "" ) dir=/
77 esac
78 OrigDir=$base/$OrigDir
79 cd ..
80 done
81 test -d .patches
84 get_meta()
86 name=`cat .patches/name 2> /dev/null`
87 status=`cat .patches/status 2> /dev/null`
90 forget_one()
92 if true # || cmp -s "$1" "$1~current~" && cmp -s "$1" "$1~orig~"
93 then
94 rm -f "$1~current~" "$1~orig~"
95 chmod -w "$1"
96 else
97 echo >&2 "ERROR $1 doesn't match original"
102 snap_one()
104 cp "$1" "$1~snapshot~"
107 snap_diff()
109 diff -u "$1" "$1~snapshot~"
111 snap_back()
113 cp "$1~snapshot~" "$1"
116 check_out()
118 file=$1
119 file=${file#./}
120 [ -f $file ] || >> $file
121 if [ -f $file ]
122 then
123 if [ ! -f "$file~orig~" ] ; then
124 mv "$file" "$file~orig~"
125 cp "$file~orig~" "$file"
126 echo $file >> .patches/files
127 sort -o .patches/files .patches/files
128 chmod u+w "$file"
130 if [ ! -f "$file~current~" ] ; then
131 mv "$file" "$file~current~"
132 cp "$file~current~" "$file"
134 else
135 echo >&2 Cannot checkout $file
139 all_files()
141 >> .patches/files
142 while read file
143 do eval $1 $file $2
144 done < .patches/files
147 diff_one()
149 if cmp -s "$1~current~" "$1" || [ ! -f "$1" -a ! -f "$1~current~" ]
150 then :
151 else
152 echo
153 echo "diff ./$1~current~ ./$1"
154 if [ " $2" = " -R" ]
155 then
156 diff -N --show-c-function -u ./$1 ./$1~current~
157 else
158 diff -N --show-c-function -u ./$1~current~ ./$1
163 diff_one_orig()
165 if cmp -s "$1~orig~" "$1"
166 then :
167 else
168 echo
169 echo "diff ./$1~orig~ ./$1"
170 diff --show-c-function -u ./$1~orig~ ./$1
174 commit_one()
176 rm -f "$1~current~"
177 if [ -f "$1" ] ; then
178 mv "$1" "$1~current~"
179 cp -p "$1~current~" $1
180 chmod u+w $1
184 discard_one()
186 cmp -s "$1~current~" $1 || { rm -f "$1" ; cp "$1~current~" $1; }
187 chmod u+w $1
190 swap_one()
192 mv "$1" "$1.tmp"
193 mv "$1~current~" "$1"
194 mv "$1.tmp" "$1~current~"
197 CERT='Signed-off-by: Neil Brown <neilb@suse.de>'
198 make_diff()
201 [ -s .patches/status ] && echo "Status: `cat .patches/status`"
202 [ -s .patches/notes ] && { echo; cat .patches/notes ; }
203 if grep -F "$CERT" .patches/notes > /dev/null 2>&1
204 then :
205 else echo "$CERT"
207 echo
208 all_files diff_one $1 > .patches/tmp
209 echo "### Diffstat output"
210 diffstat -p0 2> /dev/null < .patches/tmp
211 cat .patches/tmp
212 [ -s .patches/tmp ] || rm .patches/patch
213 rm .patches/tmp
214 } > .patches/patch
217 save_patch()
219 dir=.patches/$1
220 name=$2
221 # move .patches/patch to $dir/nnn$name
222 #for some new nnn
223 [ -d $dir ] || mkdir $dir || exit 1
224 largest=`ls $dir | sed -n -e 's/^\([0-9][0-9][0-9]\).*/\1/p' | sort -n | tail -1`
225 if [ "0$largest" -eq 999 ]
226 then echo >&2 'ARRG - too many patches!' ; exit 1
228 new=`expr "0$largest" + 1001`
229 new=${new#1}
230 mv .patches/patch $dir/$new$name
233 find_prefix()
235 # set "prefix" to number for -pn by looking at first file in given patch.
236 n=${2-1}
237 file=`lsdiff $1 | head -$n | tail -1`
238 orig=$file
239 prefix=0
240 while [ \( -n "$file" -a ! -f "$file" \) -o " $file" != " ${file#/}" ]
242 file=`expr "$file" : '[^/]*/\(.*\)'`
243 prefix=`expr $prefix + 1`
244 done
245 if [ -z "$file" ]
246 then echo "Cannot find $orig" >&2
247 if [ $n -gt 4 ]
248 then exit 2;
249 else find_prefix "$1" $[n+1]
252 if [ " $orig" != " $file" ]
253 then
254 echo "Found $orig as $file - prefix $prefix"
258 extract_notes()
260 # remove first line, Status: line, leading blanks,
261 # everything from ' *---' and trailing blanks
262 awk '
263 BEGIN { head= 1; blanks=0 ; }
264 head == 1 && ( $1 == "Status:" || $0 == "" ) {
265 next;
267 { head = 0; }
268 $0 == "" { blanks++; next; }
269 $0 ~ /^ *---/ { exit }
270 $0 ~ /^###/ { exit }
271 { while (blanks > 0) {
272 blanks--; print "";
274 print $0;
276 ' $1
280 if [ $# -eq 0 ]
281 then
282 echo >&2 'Usage: p [help|co|make|discard|commit|status|name|...] args'
283 exit 1
285 cmd=$1
286 shift
288 if [ " $cmd" = " help" ] || find_home
289 then :
290 else echo >&2 "p $cmd: cannot find .patches directory"
291 exit 1
294 case $cmd in
295 co )
296 if [ $# -ne 1 ] ; then
297 echo >&2 Usage: p co file; exit 1
299 file=$1
300 if [ ! -f "$OrigDir$file" ]
301 then
302 echo >&2 "p co: file $file not found"; exit 1;
304 check_out "$OrigDir$file"
307 make | view )
308 case $1 in
309 "" )
310 make_diff
311 if [ -s .patches/patch ] ; then
312 pfile=.patches/patch
313 else
314 echo >&2 "No current patch" ; exit 1;
318 */* ) pfile=$1;;
319 * ) pfile=`echo .patches/[ra][ep][mp]*/*$1*`
320 esac
321 if [ ! -f "$pfile" ]
322 then echo >&2 "Cannot find unique patch '$1' - found: $pfile"; exit 1;
324 if grep -s '^+.*[ ]$' $pfile > /dev/null
325 then
326 ${PAGER-less -p '^\+.*[ ]$'} $pfile
327 else
328 ${PAGER-less} $pfile
332 all )
333 all_files diff_one_orig
335 status | name )
336 case $# in
338 get_meta
339 if [ $cmd = name ] ; then
340 if [ -n "$name" ]; then
341 echo "changing name from '$name' to '$1'"
342 else
343 echo "Setting name to '$1'"
345 echo "$1" > .patches/name
347 if [ $cmd = status ] ; then
348 if [ -n "$status" ]; then
349 echo "changing status from '$status' to '$1'"
350 else
351 echo "Setting status to '$1'"
353 echo "$1" > .patches/status
357 get_meta
358 echo -n "Name ($name)? " ; read name
359 echo -n "Status ($status)? " ; read status
360 [ -n "$name" ] && { echo $name > .patches/name ; }
361 [ -n "$status" ] && { echo $status > .patches/status ; }
364 echo "Usage: p $cmd [new-$cmd]"; exit 1;
365 esac
367 note* )
368 >> .patches/notes
369 ${EDITOR:-vi} .patches/notes
371 discard|commit )
372 make_diff
373 if [ -s .patches/patch ]
374 then :
375 else echo >&2 No patch to $cmd ; exit 1
377 if grep -s '^+.*[ ]$' .patches/patch > /dev/null
378 then
379 echo >&2 remove trailing spaces/tabs first !!
380 # exit 1
382 if [ -s .patches/to-resolv ]
383 then echo "Please resolve outstanding conflicts first with 'p resolve'"
384 exit 1
386 get_meta
387 if [ -z "$name" ] ; then
388 echo -n "Name? " ; read name
389 if [ -z "$name" ] ; then
390 echo >&2 "No current name, please set with 'p name'"
391 exit 1;
393 echo $name > .patches/name
395 if [ -z "$status" ] ; then
396 echo -n "Status? " ; read status
397 if [ -z "$status" ] ; then
398 echo >&2 "No current status, please set with 'p status'"
399 exit 1;
401 echo $status > .patches/status
403 if [ -s .patches/notes ]
404 then :
405 else
406 { echo "Title...."
407 echo
408 echo "Description..."
409 echo
410 echo "====Do Not Remove===="
411 cat .patches/patch
412 } > .patches/notes
413 ${EDITOR-vi} .patches/notes
414 mv .patches/notes .patches/tmp
415 sed '/^====Do Not Remove====/,$d' .patches/tmp > .patches/notes
416 rm .patches/tmp
418 make_diff
420 if [ $cmd = commit ] ; then
421 save_patch applied "$name"
422 echo Saved as $new$name
423 all_files commit_one
424 else
425 save_patch removed "$name"
426 echo Saved as $new$name
427 all_files discard_one
429 rm -f .patches/name .patches/status .patches/notes
432 purge )
433 make_diff
434 mv .patches/patch .patches/last-purge
435 all_files discard_one
436 rm -f .patches/name .patches/status .patches/notes
438 open )
439 make_diff
440 get_meta
441 if [ -s .patches/patch ]
442 then
443 echo >&2 Patch $name already open - please commit; exit 1;
445 if [ $# -eq 0 ]
446 then
447 echo "Available patches are:"
448 ls .patches/applied
449 exit 0
451 if [ $# -ne 1 ]
452 then echo >&2 "Usage: p open patchname" ; exit 1
454 if [ " $1" = " last" ]
455 then
456 pfile=`ls -d .patches/applied/[0-9]* | tail -1`
457 else
458 pfile=`echo .patches/applied/*$1*`
460 if [ ! -f "$pfile" ]
461 then echo >&2 "Cannot find unique patch '$1' - found: $pfile"; exit 1
463 # lets see if it applies cleanly
464 if patch -s --fuzz=0 --dry-run -R -f -p0 < "$pfile"
465 then echo Ok, it seems to apply
466 else echo >&2 "Sorry, that patch doesn't apply" ; exit 1
468 # lets go for it ...
469 patch --fuzz=0 -R -f -p0 < "$pfile"
470 all_files swap_one
471 sed -n -e '2q' -e 's/^Status: *//p' $pfile > .patches/status
472 base=${pfile##*/[0-9][0-9][0-9]}
473 [ -s .patches/name ] || echo $base > .patches/name
474 extract_notes $pfile >> .patches/notes
475 mv $pfile .patches/patch
478 included )
479 force=
480 if [ " $1" = " -f" ] ; then
481 force=yes; shift
483 make_diff; get_meta
484 if [ -s .patches/patch ]
485 then
486 echo >&2 Patch $name already open, please commit; exit 1;
488 if [ $# -eq 0 ]
489 then
490 echo "Unapplied patches are:"
491 ls .patches/removed
492 exit 0;
494 if [ $# -ne 1 ]
495 then
496 echo >&2 "Usage: p included patchname"; exit 1
498 case $1 in
499 last ) pfile=`ls -d .patches/removed/[0-9]* | tail -1` ;;
500 */* ) echo >&2 "Only local patches can have been included"; exit 1 ;;
501 *) pfile=`echo .patches/removed/*$1*`
502 esac
503 if [ ! -f "$pfile" ]
504 then echo >&2 "Cannot find unique patch '$1' - found $pfile"; exit 1
506 echo "Using $pfile..."
508 # make sure patch applies in reverse
509 if patch -s --fuzz=0 -l --dry-run -f -p0 -R < "$pfile"
510 then echo "Yep, that seems to be included"
511 elif [ -n "$force" ]
512 then echo "It doesn't apply reverse-out cleanly, but you asked for it..."
513 else echo >&2 "Sorry, patch cannot be removed"; exit 1
515 mv "$pfile" .patches/patch
516 name=${pfile##*/[0-9][0-9][0-9]}
517 save_patch included $name
518 echo "Moved to $new$name"
520 review )
521 # there are some patches in .removed that may be included in the current source
522 # we try to backout each one. If it backs out successfully, we move it to
523 # .reviewed and conitnue, else we abort
524 # Once this has been done often enough, 'reviewed' should be run to
525 # move stuff to 'included' and to revert those patches
526 force=
527 if [ " $1" = " -f" ] ; then
528 force=yes; shift
530 make_diff; get_meta
531 if [ -s .patches/path ]
532 then
533 echo >&2 Patch $name already open, please deal with it; exit 1;
535 if [ $# -eq 0 ]
536 then
537 echo "Pending patches are:"
538 ls .patches/removed
539 exit 0;
541 if [ $# -ne 1 ]
542 then
543 echo >&2 "Usage: p review patchname"; exit 1
545 case $1 in
546 */* ) echo >&2 "Only local patches can have been included"; exit 1 ;;
547 *) pfile=`echo .patches/removed/*$1*`
548 esac
549 if [ ! -f "$pfile" ]
550 then echo >&2 "Cannot find unique patch '$1' - found $pfile"; exit 1
552 echo "Starting from $pfile..."
553 found=
554 for fl in .patches/removed/*
556 if [ " $fl" = " $pfile" ]; then found=yes ; fi
557 if [ -n "$found" ]; then
558 echo Checking $fl
559 find_prefix "$fl"
560 lsdiff --strip=$prefix "$fl" | grep -v 'file.*changed' | while read a b
561 do check_out $a
562 done
563 if patch -s --fuzz=0 --dry-run -f -p$prefix -R < "$fl"
564 then echo Looks good..
565 elif [ -n "$force" ]
566 then echo "It doesn't backout cleanly, but you asked for it..."
567 cp $fl .patches/last-backed
568 else echo "Patch won't back out, sorry"
569 exit 1
571 patch --fuzz=0 -f -p$prefix -R < "$fl" | tee .patches/tmp
572 sed -n -e '2q' -e 's/^Status: *//p' $fl > .patches/status
573 base=${fl##*/}
574 base=${base##[0-9][0-9][0-9]}
575 base=${base##patch-?-}
576 [ -s .patches/name ] || echo $base > .patches/name
577 extract_notes $fl >> .patches/notes
578 rm -f .patches/wiggled
579 sed -n -e 's/.*saving rejects to file \(.*\).rej/\1/p' .patches/tmp |
580 while read file
581 do echo Wiggling $file.rej into place
582 rm -f $file.porig
583 > .patches/wiggled
584 wiggle --replace --merge $file $file.rej ||
585 echo $file >> .patches/to-resolve
586 done
588 mv $fl .patches/patch
589 save_patch reviewed $base
590 if [ -f .patches/wiggled ]
591 then echo 'Some wiggling was needed. Please review and commit'
592 exit 0
594 p commit || exit 1
596 done
599 reviewed )
600 # all the currently applied patches are patches that have been
601 # reviewed as included.
602 # rip them out and stick them (reversed) into included.
603 while p open last
605 make_diff -R
606 get_meta
607 save_patch included "$name"
608 echo Saved as "$new$name"
609 all_files discard_one
610 rm -f .patches/name .patches/status .patches/notes
611 done
613 list )
614 echo "Applied patches are:"
615 ls .patches/applied
617 echo "Unapplied patches are:"
618 ls .patches/removed
619 exit 0
621 apply )
622 force= append=
623 if [ " $1" = " -f" ]; then
624 force=yes; shift
626 if [ " $1" = " -a" ]; then
627 append=yes; shift
629 make_diff
630 get_meta
631 if [ -s .patches/patch -a -z "$append" ]
632 then
633 echo >&2 Patch $name already open - please commit ; exit 1;
635 if [ $# -eq 0 ]
636 then
637 echo "Unapplied patches are:"
638 ls .patches/removed
639 exit 0
641 if [ $# -ne 1 ]
642 then echo >&2 "Usage: p apply patchname"; exit 1
644 case $1 in
645 last ) pfile=`ls -d .patches/removed/[0-9]* | tail -1` ; echo last is "$pfile";;
646 */* ) pfile=$1 ;;
647 * ) pfile=`echo .patches/removed/*$1*`
648 esac
649 if [ ! -f "$pfile" ]
650 then echo >&2 "Cannot find unique patch '$1' - found: $pfile"; exit 1
652 find_prefix "$pfile"
653 lsdiff --strip=$prefix "$pfile" | grep -v 'file.*changed' | while read a b
654 do check_out $a
655 done
656 # lets see if it applies cleanly
657 if patch -s --fuzz=0 --dry-run -f -p$prefix < "$pfile"
658 then echo OK, it seems to apply
659 elif [ -n "$force" ]
660 then echo "It doesn't apply cleanly, but you asked for it...."
661 echo "Saving original at .patches/last-applied"
662 cp $pfile .patches/last-applied
663 else echo >&2 "Sorry, patch doesn't apply"; exit 1
665 # lets go for it ...
666 patch --fuzz=0 -f -p$prefix < "$pfile" | tee .patches/tmp
667 sed -n -e '2q' -e 's/^Status: *//p' $pfile > .patches/status
668 base=${pfile##*/}
669 base=${base##[0-9][0-9][0-9]}
670 base=${base##patch-?-}
671 [ -s .patches/name ] || echo $base > .patches/name
672 extract_notes $pfile >> .patches/notes
674 sed -n -e 's/.*saving rejects to file \(.*\).rej/\1/p' .patches/tmp |
675 while read file
676 do echo Wiggling $file.rej into place
677 rm -f $file.porig
678 wiggle --replace --merge $file $file.rej ||
679 echo $file >> .patches/to-resolve
680 done
682 case $pfile in
683 .patches/removed/* )
684 mv $pfile .patches/patch
685 esac
688 publish )
689 name=`date -u +%Y-%m-%d-%H`
690 if [ -d .patches/dest ]
691 then : good
692 else echo >&2 No destination specified at .patches/dest ; exit 1;
694 if [ -d .patches/dest/$name ]
695 then
696 echo >&2 $name already exists ; exit 1
698 target=.patches/dest/$name
699 mkdir $target
700 if [ -f .patches/get-version ] ;
701 then ./.patches/get-version > $target/version
703 [ -f .config ] && cp .config $target
704 cp .patches/applied/* $target
705 mkdir $target/misc
706 cp 2> /dev/null .patches/removed/* $target/misc || rmdir $target/misc
707 chmod -R a+rX $target
708 all_files diff_one_orig > $target/patch-all-$name
709 cd $target
710 echo Published at `/bin/pwd`
712 clean )
713 all_files forget_one
714 > .patches/files
716 openall )
717 while p open last && p discard ; do : ; done
719 recommit )
720 make_diff
721 get_meta
722 if [ -s .patches/patch ]
723 then
724 echo >&2 Patch $name already open - please commit ; exit 1;
726 if [ $# -eq 0 ]
727 then
728 echo "Unapplied patches are:"
729 ls .patches/removed
730 exit 0
732 if [ $# -ne 1 ]
733 then echo >&2 "Usage: p recommit patchname"; exit 1
735 case $1 in
736 last ) pfile=`ls -d .patches/removed/[0-9]* | tail -1` ; echo last is "$pfile";;
737 */* ) pfile=$1 ;;
738 * ) pfile=`echo .patches/removed/*$1*`
739 esac
740 if [ ! -f "$pfile" ]
741 then echo >&2 "Cannot find unique patch '$1' - found: $pfile"; exit 1
743 while [ -s "$pfile" ] &&
744 p apply last && p commit ; do : ; done
746 decommit )
747 make_diff
748 get_meta
749 if [ -s .patches/patch ]
750 then
751 echo >&2 Patch $name already open - please commit ; exit 1;
753 if [ $# -eq 0 ]
754 then
755 echo "Applied patches are:"
756 ls .patches/applied
757 exit 0
759 if [ $# -ne 1 ]
760 then echo >&2 "Usage: p decommit patchname"; exit 1
762 case $1 in
763 last ) pfile=`ls -d .patches/applied/[0-9]* | tail -1` ; echo last is "$pfile";;
764 */* ) pfile=$1 ;;
765 * ) pfile=`echo .patches/applied/*$1*`
766 esac
767 if [ ! -f "$pfile" ]
768 then echo >&2 "Cannot find unique patch '$1' - found: $pfile"; exit 1
770 while [ -s "$pfile" ] &&
771 p open last && p discard ; do : ; done
773 snapshot )
774 all_files snap_one
776 snapdiff )
777 all_files snap_diff
779 snapback )
780 all_files snap_back
782 resolve )
783 if [ ! -s .patches/resolving ]
784 then sort -u .patches/to-resolve > .patches/resolving ; > .patches/to-resolve
786 if [ ! -s .patches/resolving ]
787 then echo "Nothing to resolve" ; exit 0;
789 echo "Resolving: " ; cat .patches/resolving
790 for file in `cat .patches/resolving`
792 ${EDITOR:-vi} $file
793 rm -f $file.porig
794 wiggle --replace --merge $file ||
795 echo $file >> .patches/to-resolve
796 done
797 > .patches/resolving
799 pull )
800 cd .patches/SOURCE && bk pull
802 update )
803 make_diff
804 get_meta
805 if [ -s .patches/patch ]
806 then
807 echo >&2 Patch $name already open - please commit; exit 1;
809 p openall && p clean &&
810 (cd .patches/SOURCE ; bk export -tpatch -rLATEST, ) > .patches/imported-patch &&
811 patch --dry-run -f -p1 < .patches/imported-patch &&
812 patch -f -p1 < .patches/imported-patch &&
813 ( rm .patches/imported-patch ; cd .patches/SOURCE ; bk tag LATEST )
816 premail )
817 # Convert some applied patches into email messages.
818 # Select patches that start with $1. Look in .patches/cc for who to Cc: to
819 rmdir .patches/mail 2>/dev/null
820 if [ -d .patches/mail ] ; then
821 echo >&2 There is already some email - run "email" or "nomail"
822 ls .patches/mail
823 exit 1;
825 mkdir .patches/mail
826 if [ ! -s .patches/maintainer ] ; then
827 echo "No maintainer - please add one"
828 exit 1;
830 if [ ! -s .patches/owner ] ; then
831 echo "Your address and other headers must be in .patches/owner"
832 exit 1;
834 messid="<`date +'%Y%m%d%H%M%S'`.$$.patches@`uname -n`>"
835 cnt=0
836 for patch in .patches/applied/???${1}*
838 n=${patch##*/}
839 n=${n:0:3}
840 if [ -n "$2" ] && [ $2 -gt $n ] ; then continue; fi
841 if [ -n "$3" ] && [ $3 -lt $n ] ; then continue; fi
842 cnt=$(expr $cnt + 1 )
843 done
844 this=1
845 if [ $cnt -gt 1 ]
846 then
848 if [ -s .patches/owner.$1 ] ; then
849 cat .patches/owner.$1
850 else
851 cat .patches/owner
853 echo "To: `cat .patches/maintainer`"
854 if [ -s .patches/cc ] ; then
855 while read word prefix addr
856 do if [ " $word" = " $1" ] ; then
857 echo "Cc: $addr"
858 sprefix="$prefix: "
860 done < .patches/cc
862 if [ $cnt = 1 ]
863 then
864 echo "Subject: [PATCH] ${sprefix}Intro"
865 else
866 echo "Subject: [PATCH 000 of $cnt] ${sprefix}Introduction"
868 echo "Message-ID: $messid"
869 echo
870 echo PUT COMMENTS HERE
871 } > .patches/mail/000Intro
874 for patch in .patches/applied/???${1}*
876 n=${patch##*/}
877 n=${n:0:3}
878 if [ -n "$2" ] && [ $2 -gt $n ] ; then continue; fi
879 if [ -n "$3" ] && [ $3 -lt $n ] ; then continue; fi
881 sprefix=
882 if [ -s .patches/owner.$1 ] ; then
883 cat .patches/owner.$1
884 else
885 cat .patches/owner
887 echo "To: `cat .patches/maintainer`"
888 if [ -s .patches/cc ] ; then
889 while read word prefix addr
890 do if [ " $word" = " $1" ] ; then
891 echo "Cc: $addr"
892 sprefix="$prefix: "
894 done < .patches/cc
896 head=`sed -e '/^Status/d' -e '/^$/d' -e q $patch`
897 zerothis=$(expr $this + 1000)
898 if [ $cnt = 1 ]
899 then
900 echo "Subject: [PATCH] $sprefix$head"
901 else
902 echo "Subject: [PATCH ${zerothis#1} of $cnt] $sprefix$head"
904 echo "References: $messid"
905 echo
906 if [ $cnt = 1 ] ; then
907 echo "### Comments for Changeset"
909 sed -e '1,3d' $patch
910 } > .patches/mail/${patch#.patches/applied/}
911 this=$(expr $this + 1)
912 done
913 if [ -f .patches/mail/000Intro ]; then cat .patches/mail/* | sed -n -e 's/^Subject://p' >> .patches/mail/000Intro ; fi
914 ls .patches/mail
917 nomail )
918 echo "Removing .patches/mail directory"
919 rm -rf .patches/mail
922 email )
923 PATH=$HOME/bin:/usr/lib:/usr/sbin:$PATH
924 for i in .patches/mail/*
926 if [ -f "$i" ]
927 then
928 echo Sending $i.
929 sendmail -t < $i && rm $i
931 done
933 help )
934 helpfile=$0.help
935 if [ ! -f $helpfile ]
936 then echo >&2 $helpfile not found: no help available ; exit 2;
938 if [ -z "$1" ] ; then
939 echo
940 sed -n -e '/^ /p' -e '/^[^ ]/q' $helpfile
941 echo
942 echo "Available help topics are:"
943 sed -n '/^[^ ]/p' $helpfile | sort | column
944 else
945 echo
946 awk '$0 ~ /^[^ ]/ && printed {doprint=0; printed=0}
947 doprint && $0 !~ /^[^ ]/ {print; printed=1;}
948 $0 == "'$1'" {doprint=1; found=1}
949 END { if (!found) print "No help available for '$1'"; }
950 ' $helpfile
951 echo
955 echo >&2 "p $cmd - unknown command - try 'p help'"; exit 1;
956 esac
957 exit 0;