Skip to content

Commit a8563ec

Browse files
committed
upload-pack: add a trigger for post-upload-pack hook
After upload-pack successfully finishes its operation, post-upload-pack hook can be called for logging purposes. The hook is passed various pieces of information, one per line, from its standard input. Currently the following items can be fed to the hook, but more types of information may be added in the future: want SHA-1:: 40-byte hexadecimal object name the client asked to include in the resulting pack. Can occur one or more times in the input. have SHA-1:: 40-byte hexadecimal object name the client asked to exclude from the resulting pack, claiming to have them already. Can occur zero or more times in the input. time float:: Number of seconds spent for creating the packfile. size decimal:: Size of the resulting packfile in bytes. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 68ea474 commit a8563ec

File tree

4 files changed

+144
-2
lines changed

4 files changed

+144
-2
lines changed

Documentation/git-upload-pack.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ The UI for the protocol is on the 'git-fetch-pack' side, and the
2020
program pair is meant to be used to pull updates from a remote
2121
repository. For push operations, see 'git-send-pack'.
2222

23+
After finishing the operation successfully, `post-upload-pack`
24+
hook is called (see linkgit:githooks[5]).
2325

2426
OPTIONS
2527
-------

Documentation/githooks.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,31 @@ Both standard output and standard error output are forwarded to
307307
'git-send-pack' on the other end, so you can simply `echo` messages
308308
for the user.
309309

310+
post-upload-pack
311+
----------------
312+
313+
After upload-pack successfully finishes its operation, this hook is called
314+
for logging purposes.
315+
316+
The hook is passed various pieces of information, one per line, from its
317+
standard input. Currently the following items can be fed to the hook, but
318+
more types of information may be added in the future:
319+
320+
want SHA-1::
321+
40-byte hexadecimal object name the client asked to include in the
322+
resulting pack. Can occur one or more times in the input.
323+
324+
have SHA-1::
325+
40-byte hexadecimal object name the client asked to exclude from
326+
the resulting pack, claiming to have them already. Can occur zero
327+
or more times in the input.
328+
329+
time float::
330+
Number of seconds spent for creating the packfile.
331+
332+
size decimal::
333+
Size of the resulting packfile in bytes.
334+
310335
pre-auto-gc
311336
-----------
312337

t/t5501-post-upload-pack.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/bin/sh
2+
3+
test_description='post upload-hook'
4+
5+
. ./test-lib.sh
6+
7+
LOGFILE=".git/post-upload-pack-log"
8+
9+
test_expect_success setup '
10+
test_commit A &&
11+
test_commit B &&
12+
git reset --hard A &&
13+
test_commit C &&
14+
git branch prev B &&
15+
mkdir -p .git/hooks &&
16+
{
17+
echo "#!$SHELL_PATH" &&
18+
echo "cat >post-upload-pack-log"
19+
} >".git/hooks/post-upload-pack" &&
20+
chmod +x .git/hooks/post-upload-pack
21+
'
22+
23+
test_expect_success initial '
24+
rm -fr sub &&
25+
git init sub &&
26+
(
27+
cd sub &&
28+
git fetch --no-tags .. prev
29+
) &&
30+
want=$(sed -n "s/^want //p" "$LOGFILE") &&
31+
test "$want" = "$(git rev-parse --verify B)" &&
32+
! grep "^have " "$LOGFILE"
33+
'
34+
35+
test_expect_success second '
36+
rm -fr sub &&
37+
git init sub &&
38+
(
39+
cd sub &&
40+
git fetch --no-tags .. prev:refs/remotes/prev &&
41+
git fetch --no-tags .. master
42+
) &&
43+
want=$(sed -n "s/^want //p" "$LOGFILE") &&
44+
test "$want" = "$(git rev-parse --verify C)" &&
45+
have=$(sed -n "s/^have //p" "$LOGFILE") &&
46+
test "$have" = "$(git rev-parse --verify B)"
47+
'
48+
49+
test_done

upload-pack.c

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,19 +141,75 @@ static int do_rev_list(int fd, void *create_full_pack)
141141
return 0;
142142
}
143143

144+
static int feed_msg_to_hook(int fd, const char *fmt, ...)
145+
{
146+
int cnt;
147+
char buf[1024];
148+
va_list params;
149+
150+
va_start(params, fmt);
151+
cnt = vsprintf(buf, fmt, params);
152+
va_end(params);
153+
return write_in_full(fd, buf, cnt) != cnt;
154+
}
155+
156+
static int feed_obj_to_hook(const char *label, struct object_array *oa, int i, int fd)
157+
{
158+
return feed_msg_to_hook(fd, "%s %s\n", label,
159+
sha1_to_hex(oa->objects[i].item->sha1));
160+
}
161+
162+
static int run_post_upload_pack_hook(size_t total, struct timeval *tv)
163+
{
164+
const char *argv[2];
165+
struct child_process proc;
166+
int err, i;
167+
168+
argv[0] = "hooks/post-upload-pack";
169+
argv[1] = NULL;
170+
171+
if (access(argv[0], X_OK) < 0)
172+
return 0;
173+
174+
memset(&proc, 0, sizeof(proc));
175+
proc.argv = argv;
176+
proc.in = -1;
177+
proc.stdout_to_stderr = 1;
178+
err = start_command(&proc);
179+
if (err)
180+
return err;
181+
for (i = 0; !err && i < want_obj.nr; i++)
182+
err |= feed_obj_to_hook("want", &want_obj, i, proc.in);
183+
for (i = 0; !err && i < have_obj.nr; i++)
184+
err |= feed_obj_to_hook("have", &have_obj, i, proc.in);
185+
if (!err)
186+
err |= feed_msg_to_hook(proc.in, "time %ld.%06ld\n",
187+
(long)tv->tv_sec, (long)tv->tv_usec);
188+
if (!err)
189+
err |= feed_msg_to_hook(proc.in, "size %ld\n", (long)total);
190+
if (close(proc.in))
191+
err = 1;
192+
if (finish_command(&proc))
193+
err = 1;
194+
return err;
195+
}
196+
144197
static void create_pack_file(void)
145198
{
199+
struct timeval start_tv, tv;
146200
struct async rev_list;
147201
struct child_process pack_objects;
148202
int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr);
149203
char data[8193], progress[128];
150204
char abort_msg[] = "aborting due to possible repository "
151205
"corruption on the remote side.";
152206
int buffered = -1;
153-
ssize_t sz;
207+
ssize_t sz, total_sz;
154208
const char *argv[10];
155209
int arg = 0;
156210

211+
gettimeofday(&start_tv, NULL);
212+
total_sz = 0;
157213
if (shallow_nr) {
158214
rev_list.proc = do_rev_list;
159215
rev_list.data = 0;
@@ -262,7 +318,7 @@ static void create_pack_file(void)
262318
sz = xread(pack_objects.out, cp,
263319
sizeof(data) - outsz);
264320
if (0 < sz)
265-
;
321+
total_sz += sz;
266322
else if (sz == 0) {
267323
close(pack_objects.out);
268324
pack_objects.out = -1;
@@ -314,6 +370,16 @@ static void create_pack_file(void)
314370
}
315371
if (use_sideband)
316372
packet_flush(1);
373+
374+
gettimeofday(&tv, NULL);
375+
tv.tv_sec -= start_tv.tv_sec;
376+
if (tv.tv_usec < start_tv.tv_usec) {
377+
tv.tv_sec--;
378+
tv.tv_usec += 1000000;
379+
}
380+
tv.tv_usec -= start_tv.tv_usec;
381+
if (run_post_upload_pack_hook(total_sz, &tv))
382+
warning("post-upload-hook failed");
317383
return;
318384

319385
fail:

0 commit comments

Comments
 (0)