 20b20a22f8
			
		
	
	20b20a22f8
	
	
	
		
			
			When upload-pack serves a client request, it turns to
pack-objects to do the heavy lifting of creating a
packfile. There's no easy way to intercept the call to
pack-objects, but there are a few good reasons to want to do
so:
  1. If you're debugging a client or server issue with
     fetching, you may want to store a copy of the generated
     packfile.
  2. If you're gathering data from real-world fetches for
     performance analysis or debugging, storing a copy of
     the arguments and stdin lets you replay the pack
     generation at your leisure.
  3. You may want to insert a caching layer around
     pack-objects; it is the most CPU- and memory-intensive
     part of serving a fetch, and its output is a pure
     function[1] of its input, making it an ideal place to
     consolidate identical requests.
This patch adds a simple "hook" interface to intercept calls
to pack-objects. The new test demonstrates how it can be
used for debugging (using it for caching is a
straightforward extension; the tricky part is writing the
actual caching layer).
This hook is unlike the normal hook scripts found in the
"hooks/" directory of a repository. Because we promise that
upload-pack is safe to run in an untrusted repository, we
cannot execute arbitrary code or commands found in the
repository (neither in hooks/, nor in the config). So
instead, this hook is triggered from a config variable that
is explicitly ignored in the per-repo config.
The config variable holds the actual shell command to run as
the hook.  Another approach would be to simply treat it as a
boolean: "should I respect the upload-pack hooks in this
repo?", and then run the script from "hooks/" as we usually
do. However, that isn't as flexible; there's no way to run a
hook approved by the site administrator (e.g., in
"/etc/gitconfig") on a repository whose contents are not
trusted. The approach taken by this patch is more
fine-grained, if a little less conventional for git hooks
(it does behave similar to other configured commands like
diff.external, etc).
[1] Pack-objects isn't _actually_ a pure function. Its
    output depends on the exact packing of the object
    database, and if multi-threading is used for delta
    compression, can even differ racily. But for the
    purposes of caching, that's OK; of the many possible
    outputs for a given input, it is sufficient only that we
    output one of them.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
		
	
		
			
				
	
	
		
			63 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			63 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/sh
 | |
| 
 | |
| test_description='test custom script in place of pack-objects'
 | |
| . ./test-lib.sh
 | |
| 
 | |
| test_expect_success 'create some history to fetch' '
 | |
| 	test_commit one &&
 | |
| 	test_commit two
 | |
| '
 | |
| 
 | |
| test_expect_success 'create debugging hook script' '
 | |
| 	write_script .git/hook <<-\EOF
 | |
| 		echo >&2 "hook running"
 | |
| 		echo "$*" >hook.args
 | |
| 		cat >hook.stdin
 | |
| 		"$@" <hook.stdin >hook.stdout
 | |
| 		cat hook.stdout
 | |
| 	EOF
 | |
| '
 | |
| 
 | |
| clear_hook_results () {
 | |
| 	rm -rf .git/hook.* dst.git
 | |
| }
 | |
| 
 | |
| test_expect_success 'hook runs via global config' '
 | |
| 	clear_hook_results &&
 | |
| 	test_config_global uploadpack.packObjectsHook ./hook &&
 | |
| 	git clone --no-local . dst.git 2>stderr &&
 | |
| 	grep "hook running" stderr
 | |
| '
 | |
| 
 | |
| test_expect_success 'hook outputs are sane' '
 | |
| 	# check that we recorded a usable pack
 | |
| 	git index-pack --stdin <.git/hook.stdout &&
 | |
| 
 | |
| 	# check that we recorded args and stdin. We do not check
 | |
| 	# the full argument list or the exact pack contents, as it would make
 | |
| 	# the test brittle. So just sanity check that we could replay
 | |
| 	# the packing procedure.
 | |
| 	grep "^git" .git/hook.args &&
 | |
| 	$(cat .git/hook.args) <.git/hook.stdin >replay
 | |
| '
 | |
| 
 | |
| test_expect_success 'hook runs from -c config' '
 | |
| 	clear_hook_results &&
 | |
| 	git clone --no-local \
 | |
| 	  -u "git -c uploadpack.packObjectsHook=./hook upload-pack" \
 | |
| 	  . dst.git 2>stderr &&
 | |
| 	grep "hook running" stderr
 | |
| '
 | |
| 
 | |
| test_expect_success 'hook does not run from repo config' '
 | |
| 	clear_hook_results &&
 | |
| 	test_config uploadpack.packObjectsHook "./hook" &&
 | |
| 	git clone --no-local . dst.git 2>stderr &&
 | |
| 	! grep "hook running" stderr &&
 | |
| 	test_path_is_missing .git/hook.args &&
 | |
| 	test_path_is_missing .git/hook.stdin &&
 | |
| 	test_path_is_missing .git/hook.stdout
 | |
| '
 | |
| 
 | |
| test_done
 |