quilt-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Quilt-dev] Re: [PATCH 4/4] Quilt push and quilt pop can execute patch a


From: Don Mullis
Subject: [Quilt-dev] Re: [PATCH 4/4] Quilt push and quilt pop can execute patch as script
Date: Sun, 11 Apr 2010 20:46:23 -0700
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux)

Extend push and pop to scan the first line of the patch for the
Unix executable 'magic byte' sequence "#!".  If found, the patch is
executed twice, first before the push/pop, then after.  Arguments are
passed to the script to help it distinguish the four cases.

This extension opens up a new class of application to quilt, namely
system administration.  A /patches/ directory at the top of the root
filesystem can contain edits to, for instance, daemon configuration
files in /etc.  When the /etc file is modified by push or pop, and
quilt sees the patch beginning with "#!", it will try to execute the
patch, which can contain shell commands to signal the daemon to reload
its /etc configuration file.

Another application is working around buggy build-dependency checking in
makefiles.  In this case, the executable patch would contain `rm`
commands to remove the stale built objects.

Since push and pop are performance-sensitive, here are some
without/with timings using an MMOTM tree, best case.  There's about a
3% penalty on the pop only:

Without change
---
$ time quilt push -aq >/dev/null
real    0m29.529s
user    0m9.529s
sys     0m10.317s

$ time quilt pop -aq >/dev/null
real    0m42.699s
user    0m13.193s
sys     0m24.682s

With change
---
$ time quilt push -aq >/dev/null
real    0m29.106s
user    0m9.661s
sys     0m10.557s

$ time quilt pop -aq >/dev/null
real    0m44.110s
user    0m13.421s
sys     0m26.166s

---
 quilt/pop.in               |    5 +
 quilt/push.in              |    6 +
 quilt/scripts/patchfns.in  |   44 +++++++++++
 test/executable_patch.test |  166 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 221 insertions(+)

Index: quilt/quilt/pop.in
===================================================================
--- quilt.orig/quilt/pop.in     2010-04-11 18:44:38.000000000 -0700
+++ quilt/quilt/pop.in  2010-04-11 19:18:24.000000000 -0700
@@ -143,6 +143,9 @@ check_for_pending_changes()
 remove_patch()
 {
        local patch=$1 status=0
+       local patch_file=$(patch_file_name $patch)
+
+       executable_patch_ok $patch_file pre pop || return $?
 
        trap "status=1" SIGINT
        if [ -z "$opt_force" ] && \
@@ -180,6 +183,8 @@ remove_patch()
                fi
                remove_from_db $patch
                rm -f $QUILT_PC/$patch~refresh
+
+               executable_patch_ok $patch_file post pop || status=$?
        fi
        trap - SIGINT
        return $status
Index: quilt/quilt/push.in
===================================================================
--- quilt.orig/quilt/push.in    2010-04-11 18:44:38.000000000 -0700
+++ quilt/quilt/push.in 2010-04-11 19:23:08.000000000 -0700
@@ -175,6 +175,8 @@ add_patch()
        local patch_file=$(patch_file_name $patch)
        local file status tmp
 
+       executable_patch_ok $patch_file pre push || return $?
+
        printf $"Applying patch %s\n" "$(print_patch $patch)"
        trap "interrupt $patch" SIGINT
 
@@ -221,7 +223,11 @@ add_patch()
                        printf $"Applied patch %s (forced; needs refresh)\n" \
                               "$(print_patch $patch)"
                fi
+
+               executable_patch_ok $patch_file post push || status=$?
        else
+               # Either patch did not apply (and not forced), or there was
+               # more serious trouble (status==2).
                rollback_patch $patch
                tmp="$(gen_tempfile)"
                no_reject_files="-r $tmp"
Index: quilt/quilt/scripts/patchfns.in
===================================================================
--- quilt.orig/quilt/scripts/patchfns.in        2010-04-11 18:44:38.000000000 
-0700
+++ quilt/quilt/scripts/patchfns.in     2010-04-11 19:18:24.000000000 -0700
@@ -1023,6 +1023,50 @@ quilt_command()
        QUILT_COMMAND="" bash $BASH_OPTS -c "${SUBDIR:+cd $SUBDIR;} . 
$QUILT_DIR/$command" "quilt $command" "$@"
 }
 
+executable_patch_ok()
+{
+       local patch_file=$1
+       local pre_post=$2
+       local push_pop=$3
+       local line
+
+       if ! [ -e $patch_file ]
+       then
+               return 0
+       fi
+
+       read -a line <$patch_file
+       set -- address@hidden
+
+       if [ "$1" = '#!' ]
+       then
+               shift
+
+               # Redirect stdin from /dev/null, so scripts cannot block on a 
read from stdin.
+               # Redirect stderr onto stdout, to keep any error messages from 
patch
+               # execution correctly ordered w.r.t. push/pop messages from 
quilt.
+               # XX quilt/push.in sends stdout to a pipe (buffered) -- how to 
flush stdout after
+               #    execution of each patch?
+               # XX Add a filter to make sure execution output is hidden from 
push's
+               #    post-processing of diff output?
+               eval "$@" $patch_file $pre_post $push_pop </dev/null 2>&1
+
+               local exe_status=$?
+               if [ $exe_status -ne 0 ]
+               then
+                       printf $"executable patch %s %s %s call returned status 
%d\n" \
+                              "$(print_patch $patch)" $pre_post $push_pop 
$exe_status
+                       if [ -n "$opt_force" ]
+                       then
+                               printf $"continuing anyway due to -f\n"
+                       else
+                               return 1
+                       fi
+               fi
+       fi
+       return 0
+}
+
 declare pager_fifo pager_fifo_dir pager_pid
 
 wait_for_pager()
Index: quilt/test/executable_patch.test
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ quilt/test/executable_patch.test    2010-04-11 19:18:24.000000000 -0700
@@ -0,0 +1,166 @@
+       $ mkdir patches
+
+Create a script that merely reports how it is called.
+       $ quilt new exe_script
+       > Patch %{P}exe_script is now on top
+       $ quilt add placeholder_file
+       > File placeholder_file added to patch patches/exe_script
+       $ echo x >placeholder_file
+       $ quilt refresh
+       > Refreshed patch patches/exe_script
+       $ quilt header -a
+       < #! /bin/bash
+       < echo script called with args $1 $2
+       < exit 0
+       > Appended text to header of patch %{P}exe_script
+
+       $ quilt pop
+       > script called with args pre pop
+       > Removing patch patches/exe_script
+       > Removing placeholder_file
+       > script called with args post pop
+       >
+       > No patches applied
+
+       $ quilt delete exe_script
+       > Removed patch %{P}exe_script
+       $ quilt import %{P}exe_script
+       > Importing patch %{P}exe_script
+
+       $ quilt push
+       > script called with args pre push
+       > Applying patch patches/exe_script
+       > patching file placeholder_file
+       > script called with args post push
+       >
+       > Now at patch patches/exe_script
+
+       $ quilt delete
+       > script called with args pre pop
+       > Removing patch patches/exe_script
+       > script called with args post pop
+       > No patches applied
+       > Removed patch patches/exe_script
+       $ quilt import %{P}exe_script
+       > Importing patch %{P}exe_script
+       $ quilt delete -r %{P}exe_script
+       > Removed patch patches/exe_script
+
+Create a script that will fail execution on both push and pop, and force it
+       $ quilt new exe_script
+       > Patch %{P}exe_script is now on top
+       $ quilt add placeholder_file
+       > File placeholder_file added to patch patches/exe_script
+       $ echo x >placeholder_file
+       $ quilt refresh
+       > Refreshed patch patches/exe_script
+       $ quilt header -a
+       < #! /bin/bash
+       < echo script called with args $1 $2
+       < exit 1
+       > Appended text to header of patch %{P}exe_script
+
+       $ quilt pop
+       > script called with args pre pop
+       > executable patch patches/exe_script pre pop call returned status 1
+       $ quilt pop -f
+       > script called with args pre pop
+       > executable patch patches/exe_script pre pop call returned status 1
+       > continuing anyway due to -f
+       > Removing patch patches/exe_script
+       > Removing placeholder_file
+       > script called with args post pop
+       > executable patch patches/exe_script post pop call returned status 1
+       > continuing anyway due to -f
+       >
+       > No patches applied
+
+       $ quilt push -f
+       > script called with args pre push
+       > executable patch patches/exe_script pre push call returned status 1
+       > continuing anyway due to -f
+       > Applying patch patches/exe_script
+       > patching file placeholder_file
+       > script called with args post push
+       > executable patch patches/exe_script post push call returned status 1
+       > continuing anyway due to -f
+       >
+       > Now at patch patches/exe_script
+       $ quilt pop
+       > script called with args pre pop
+       > executable patch patches/exe_script pre pop call returned status 1
+       $ quilt pop -f
+       > script called with args pre pop
+       > executable patch patches/exe_script pre pop call returned status 1
+       > continuing anyway due to -f
+       > Removing patch patches/exe_script
+       > Removing placeholder_file
+       > script called with args post pop
+       > executable patch patches/exe_script post pop call returned status 1
+       > continuing anyway due to -f
+       >
+       > No patches applied
+       $ quilt delete -r %{P}exe_script
+       > Removed patch patches/exe_script
+
+Create a script that modifies the CWD
+       $ quilt new exe_script
+       > Patch %{P}exe_script is now on top
+       $ quilt add placeholder_file
+       > File placeholder_file added to patch patches/exe_script
+       $ echo x >placeholder_file
+       $ quilt header -a
+       < #! /bin/bash -e
+       < if [ $1 = post ] && [ $2 = push ]; then echo file created by push 
>push_file; exit 0; fi
+       < if [ $1 = pre ] && [ $2 = pop  ]; then rm push_file; exit 0; fi
+       < exit 0
+       > Appended text to header of patch %{P}exe_script
+       $ quilt refresh
+       > Refreshed patch patches/exe_script
+       $ quilt pop -f
+       > rm: cannot remove `push_file': No such file or directory
+       > executable patch patches/exe_script pre pop call returned status 1
+       > continuing anyway due to -f
+       > Removing patch patches/exe_script
+       > Removing placeholder_file
+       >
+       > No patches applied
+
+       $ quilt push
+       > Applying patch patches/exe_script
+       > patching file placeholder_file
+       >
+       > Now at patch patches/exe_script
+       $ ls | wc --words
+       > 3
+       $ quilt delete -r %{P}exe_script
+       > Removing patch patches/exe_script
+       > No patches applied
+       > Removed patch patches/exe_script
+
+Create a script that tries to read from stdin.
+It is a limitation of the test environment that a quilt command's standard 
input
+cannot be a terminal as in ordinary interactive use, but rather only a pipe.
+       $ quilt new exe_script
+       > Patch %{P}exe_script is now on top
+       $ quilt add placeholder_file
+       > File placeholder_file added to patch patches/exe_script
+       $ echo x >placeholder_file
+       $ quilt header -a
+       < #! /bin/bash -e
+       < cat
+       < exit 0
+       > Appended text to header of patch %{P}exe_script
+       $ quilt refresh
+       > Refreshed patch patches/exe_script
+
+       $ quilt pop
+       > Removing patch patches/exe_script
+       > Removing placeholder_file
+       >
+       > No patches applied
+       $ ls | wc --words
+       > 1
+
+       $ quilt pop -qaR
+       > No patch removed




reply via email to

[Prev in Thread] Current Thread [Next in Thread]