[Top][All Lists]
[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