Skip to content

Commit 0f71fa2

Browse files
larsxschneidergitster
authored andcommitted
contrib/long-running-filter: add long running filter example
Add a simple pass-thru filter as example implementation for the Git filter protocol version 2. See Documentation/gitattributes.txt, section "Filter Protocol" for more info. Signed-off-by: Lars Schneider <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent edcc858 commit 0f71fa2

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-1
lines changed

Documentation/gitattributes.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,9 @@ the command pipe on exit. The filter is expected to detect EOF
516516
and exit gracefully on its own. Git will wait until the filter
517517
process has stopped.
518518

519-
If you develop your own long running filter
519+
A long running filter demo implementation can be found in
520+
`contrib/long-running-filter/example.pl` located in the Git
521+
core repository. If you develop your own long running filter
520522
process then the `GIT_TRACE_PACKET` environment variables can be
521523
very helpful for debugging (see linkgit:git[1]).
522524

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/perl
2+
#
3+
# Example implementation for the Git filter protocol version 2
4+
# See Documentation/gitattributes.txt, section "Filter Protocol"
5+
#
6+
# Please note, this pass-thru filter is a minimal skeleton. No proper
7+
# error handling was implemented.
8+
#
9+
10+
use strict;
11+
use warnings;
12+
13+
my $MAX_PACKET_CONTENT_SIZE = 65516;
14+
15+
sub packet_bin_read {
16+
my $buffer;
17+
my $bytes_read = read STDIN, $buffer, 4;
18+
if ( $bytes_read == 0 ) {
19+
20+
# EOF - Git stopped talking to us!
21+
exit();
22+
}
23+
elsif ( $bytes_read != 4 ) {
24+
die "invalid packet: '$buffer'";
25+
}
26+
my $pkt_size = hex($buffer);
27+
if ( $pkt_size == 0 ) {
28+
return ( 1, "" );
29+
}
30+
elsif ( $pkt_size > 4 ) {
31+
my $content_size = $pkt_size - 4;
32+
$bytes_read = read STDIN, $buffer, $content_size;
33+
if ( $bytes_read != $content_size ) {
34+
die "invalid packet ($content_size bytes expected; $bytes_read bytes read)";
35+
}
36+
return ( 0, $buffer );
37+
}
38+
else {
39+
die "invalid packet size: $pkt_size";
40+
}
41+
}
42+
43+
sub packet_txt_read {
44+
my ( $res, $buf ) = packet_bin_read();
45+
unless ( $buf =~ s/\n$// ) {
46+
die "A non-binary line MUST be terminated by an LF.";
47+
}
48+
return ( $res, $buf );
49+
}
50+
51+
sub packet_bin_write {
52+
my $buf = shift;
53+
print STDOUT sprintf( "%04x", length($buf) + 4 );
54+
print STDOUT $buf;
55+
STDOUT->flush();
56+
}
57+
58+
sub packet_txt_write {
59+
packet_bin_write( $_[0] . "\n" );
60+
}
61+
62+
sub packet_flush {
63+
print STDOUT sprintf( "%04x", 0 );
64+
STDOUT->flush();
65+
}
66+
67+
( packet_txt_read() eq ( 0, "git-filter-client" ) ) || die "bad initialize";
68+
( packet_txt_read() eq ( 0, "version=2" ) ) || die "bad version";
69+
( packet_bin_read() eq ( 1, "" ) ) || die "bad version end";
70+
71+
packet_txt_write("git-filter-server");
72+
packet_txt_write("version=2");
73+
packet_flush();
74+
75+
( packet_txt_read() eq ( 0, "capability=clean" ) ) || die "bad capability";
76+
( packet_txt_read() eq ( 0, "capability=smudge" ) ) || die "bad capability";
77+
( packet_bin_read() eq ( 1, "" ) ) || die "bad capability end";
78+
79+
packet_txt_write("capability=clean");
80+
packet_txt_write("capability=smudge");
81+
packet_flush();
82+
83+
while (1) {
84+
my ($command) = packet_txt_read() =~ /^command=([^=]+)$/;
85+
my ($pathname) = packet_txt_read() =~ /^pathname=([^=]+)$/;
86+
87+
packet_bin_read();
88+
89+
my $input = "";
90+
{
91+
binmode(STDIN);
92+
my $buffer;
93+
my $done = 0;
94+
while ( !$done ) {
95+
( $done, $buffer ) = packet_bin_read();
96+
$input .= $buffer;
97+
}
98+
}
99+
100+
my $output;
101+
if ( $command eq "clean" ) {
102+
### Perform clean here ###
103+
$output = $input;
104+
}
105+
elsif ( $command eq "smudge" ) {
106+
### Perform smudge here ###
107+
$output = $input;
108+
}
109+
else {
110+
die "bad command '$command'";
111+
}
112+
113+
packet_txt_write("status=success");
114+
packet_flush();
115+
while ( length($output) > 0 ) {
116+
my $packet = substr( $output, 0, $MAX_PACKET_CONTENT_SIZE );
117+
packet_bin_write($packet);
118+
if ( length($output) > $MAX_PACKET_CONTENT_SIZE ) {
119+
$output = substr( $output, $MAX_PACKET_CONTENT_SIZE );
120+
}
121+
else {
122+
$output = "";
123+
}
124+
}
125+
packet_flush(); # flush content!
126+
packet_flush(); # empty list, keep "status=success" unchanged!
127+
128+
}

0 commit comments

Comments
 (0)