]>
Commit | Line | Data |
---|---|---|
edcc8581 LS |
1 | # |
2 | # Example implementation for the Git filter protocol version 2 | |
3 | # See Documentation/gitattributes.txt, section "Filter Protocol" | |
4 | # | |
684dd4c2 MT |
5 | # Usage: rot13-filter.pl [--always-delay] <log path> <capabilities> |
6 | # | |
7 | # Log path defines a debug log file that the script writes to. The | |
8 | # subsequent arguments define a list of supported protocol capabilities | |
9 | # ("clean", "smudge", etc). | |
10 | # | |
11 | # When --always-delay is given all pathnames with the "can-delay" flag | |
12 | # that don't appear on the list bellow are delayed with a count of 1 | |
13 | # (see more below). | |
edcc8581 LS |
14 | # |
15 | # This implementation supports special test cases: | |
16 | # (1) If data with the pathname "clean-write-fail.r" is processed with | |
17 | # a "clean" operation then the write operation will die. | |
18 | # (2) If data with the pathname "smudge-write-fail.r" is processed with | |
19 | # a "smudge" operation then the write operation will die. | |
20 | # (3) If data with the pathname "error.r" is processed with any | |
21 | # operation then the filter signals that it cannot or does not want | |
22 | # to process the file. | |
23 | # (4) If data with the pathname "abort.r" is processed with any | |
24 | # operation then the filter signals that it cannot or does not want | |
25 | # to process the file and any file after that is processed with the | |
26 | # same command. | |
2841e8f8 LS |
27 | # (5) If data with a pathname that is a key in the DELAY hash is |
28 | # requested (e.g. "test-delay10.a") then the filter responds with | |
29 | # a "delay" status and sets the "requested" field in the DELAY hash. | |
30 | # The filter will signal the availability of this object after | |
31 | # "count" (field in DELAY hash) "list_available_blobs" commands. | |
32 | # (6) If data with the pathname "missing-delay.a" is processed that the | |
33 | # filter will drop the path from the "list_available_blobs" response. | |
34 | # (7) If data with the pathname "invalid-delay.a" is processed that the | |
35 | # filter will add the path "unfiltered" which was not delayed before | |
36 | # to the "list_available_blobs" response. | |
edcc8581 LS |
37 | # |
38 | ||
0fe8d516 | 39 | use 5.008; |
3306f652 JS |
40 | sub gitperllib { |
41 | # Git assumes that all path lists are Unix-y colon-separated ones. But | |
42 | # when the Git for Windows executes the test suite, its MSYS2 Bash | |
43 | # calls git.exe, and colon-separated path lists are converted into | |
44 | # Windows-y semicolon-separated lists of *Windows* paths (which | |
45 | # naturally contain a colon after the drive letter, so splitting by | |
46 | # colons simply does not cut it). | |
47 | # | |
48 | # Detect semicolon-separated path list and handle them appropriately. | |
49 | ||
50 | if ($ENV{GITPERLLIB} =~ /;/) { | |
51 | return split(/;/, $ENV{GITPERLLIB}); | |
52 | } | |
53 | return split(/:/, $ENV{GITPERLLIB}); | |
54 | } | |
55 | use lib (gitperllib()); | |
edcc8581 LS |
56 | use strict; |
57 | use warnings; | |
4821494e | 58 | use IO::File; |
0fe8d516 | 59 | use Git::Packet; |
edcc8581 LS |
60 | |
61 | my $MAX_PACKET_CONTENT_SIZE = 65516; | |
684dd4c2 MT |
62 | |
63 | my $always_delay = 0; | |
64 | if ( $ARGV[0] eq '--always-delay' ) { | |
65 | $always_delay = 1; | |
66 | shift @ARGV; | |
67 | } | |
68 | ||
e1ec4721 | 69 | my $log_file = shift @ARGV; |
edcc8581 LS |
70 | my @capabilities = @ARGV; |
71 | ||
e1ec4721 | 72 | open my $debug, ">>", $log_file or die "cannot open log file: $!"; |
edcc8581 | 73 | |
2841e8f8 LS |
74 | my %DELAY = ( |
75 | 'test-delay10.a' => { "requested" => 0, "count" => 1 }, | |
76 | 'test-delay11.a' => { "requested" => 0, "count" => 1 }, | |
77 | 'test-delay20.a' => { "requested" => 0, "count" => 2 }, | |
78 | 'test-delay10.b' => { "requested" => 0, "count" => 1 }, | |
79 | 'missing-delay.a' => { "requested" => 0, "count" => 1 }, | |
80 | 'invalid-delay.a' => { "requested" => 0, "count" => 1 }, | |
81 | ); | |
82 | ||
edcc8581 LS |
83 | sub rot13 { |
84 | my $str = shift; | |
85 | $str =~ y/A-Za-z/N-ZA-Mn-za-m/; | |
86 | return $str; | |
87 | } | |
88 | ||
edcc8581 LS |
89 | print $debug "START\n"; |
90 | $debug->flush(); | |
91 | ||
25cbfe34 | 92 | packet_initialize("git-filter", 2); |
edcc8581 | 93 | |
f11c8ce1 CC |
94 | my %remote_caps = packet_read_and_check_capabilities("clean", "smudge", "delay"); |
95 | packet_check_and_write_capabilities(\%remote_caps, @capabilities); | |
96 | ||
edcc8581 LS |
97 | print $debug "init handshake complete\n"; |
98 | $debug->flush(); | |
99 | ||
100 | while (1) { | |
cb1c64b4 | 101 | my ( $res, $command ) = packet_key_val_read("command"); |
2c9ea595 CC |
102 | if ( $res == -1 ) { |
103 | print $debug "STOP\n"; | |
104 | exit(); | |
105 | } | |
edcc8581 LS |
106 | print $debug "IN: $command"; |
107 | $debug->flush(); | |
108 | ||
2841e8f8 LS |
109 | if ( $command eq "list_available_blobs" ) { |
110 | # Flush | |
2c9ea595 CC |
111 | packet_compare_lists([1, ""], packet_bin_read()) || |
112 | die "bad list_available_blobs end"; | |
c6b0831c | 113 | |
2841e8f8 LS |
114 | foreach my $pathname ( sort keys %DELAY ) { |
115 | if ( $DELAY{$pathname}{"requested"} >= 1 ) { | |
116 | $DELAY{$pathname}{"count"} = $DELAY{$pathname}{"count"} - 1; | |
117 | if ( $pathname eq "invalid-delay.a" ) { | |
118 | # Send Git a pathname that was not delayed earlier | |
119 | packet_txt_write("pathname=unfiltered"); | |
120 | } | |
121 | if ( $pathname eq "missing-delay.a" ) { | |
122 | # Do not signal Git that this file is available | |
123 | } elsif ( $DELAY{$pathname}{"count"} == 0 ) { | |
124 | print $debug " $pathname"; | |
125 | packet_txt_write("pathname=$pathname"); | |
126 | } | |
127 | } | |
edcc8581 | 128 | } |
edcc8581 | 129 | |
edcc8581 | 130 | packet_flush(); |
2841e8f8 LS |
131 | |
132 | print $debug " [OK]\n"; | |
edcc8581 | 133 | $debug->flush(); |
2841e8f8 | 134 | packet_txt_write("status=success"); |
edcc8581 | 135 | packet_flush(); |
ed17d262 | 136 | } else { |
cb1c64b4 | 137 | my ( $res, $pathname ) = packet_key_val_read("pathname"); |
2c9ea595 CC |
138 | if ( $res == -1 ) { |
139 | die "unexpected EOF while expecting pathname"; | |
140 | } | |
2841e8f8 LS |
141 | print $debug " $pathname"; |
142 | $debug->flush(); | |
143 | ||
2841e8f8 LS |
144 | # Read until flush |
145 | my ( $done, $buffer ) = packet_txt_read(); | |
146 | while ( $buffer ne '' ) { | |
147 | if ( $buffer eq "can-delay=1" ) { | |
148 | if ( exists $DELAY{$pathname} and $DELAY{$pathname}{"requested"} == 0 ) { | |
149 | $DELAY{$pathname}{"requested"} = 1; | |
684dd4c2 MT |
150 | } elsif ( !exists $DELAY{$pathname} and $always_delay ) { |
151 | $DELAY{$pathname} = { "requested" => 1, "count" => 1 }; | |
2841e8f8 | 152 | } |
c397aac0 | 153 | } elsif ($buffer =~ /^(ref|treeish|blob)=/) { |
13e7ed6a | 154 | print $debug " $buffer"; |
2841e8f8 | 155 | } else { |
c397aac0 | 156 | # In general, filters need to be graceful about |
157 | # new metadata, since it's documented that we | |
158 | # can pass any key-value pairs, but for tests, | |
159 | # let's be a little stricter. | |
2841e8f8 LS |
160 | die "Unknown message '$buffer'"; |
161 | } | |
edcc8581 | 162 | |
2841e8f8 LS |
163 | ( $done, $buffer ) = packet_txt_read(); |
164 | } | |
2c9ea595 CC |
165 | if ( $done == -1 ) { |
166 | die "unexpected EOF after pathname '$pathname'"; | |
167 | } | |
2841e8f8 LS |
168 | |
169 | my $input = ""; | |
170 | { | |
171 | binmode(STDIN); | |
172 | my $buffer; | |
173 | my $done = 0; | |
174 | while ( !$done ) { | |
175 | ( $done, $buffer ) = packet_bin_read(); | |
176 | $input .= $buffer; | |
177 | } | |
2c9ea595 CC |
178 | if ( $done == -1 ) { |
179 | die "unexpected EOF while reading input for '$pathname'"; | |
180 | } | |
2841e8f8 | 181 | print $debug " " . length($input) . " [OK] -- "; |
edcc8581 | 182 | $debug->flush(); |
edcc8581 LS |
183 | } |
184 | ||
2841e8f8 LS |
185 | my $output; |
186 | if ( exists $DELAY{$pathname} and exists $DELAY{$pathname}{"output"} ) { | |
187 | $output = $DELAY{$pathname}{"output"} | |
ed17d262 | 188 | } elsif ( $pathname eq "error.r" or $pathname eq "abort.r" ) { |
2841e8f8 | 189 | $output = ""; |
ed17d262 | 190 | } elsif ( $command eq "clean" and grep( /^clean$/, @capabilities ) ) { |
2841e8f8 | 191 | $output = rot13($input); |
ed17d262 | 192 | } elsif ( $command eq "smudge" and grep( /^smudge$/, @capabilities ) ) { |
2841e8f8 | 193 | $output = rot13($input); |
ed17d262 | 194 | } else { |
2841e8f8 LS |
195 | die "bad command '$command'"; |
196 | } | |
197 | ||
198 | if ( $pathname eq "error.r" ) { | |
199 | print $debug "[ERROR]\n"; | |
200 | $debug->flush(); | |
201 | packet_txt_write("status=error"); | |
202 | packet_flush(); | |
ed17d262 | 203 | } elsif ( $pathname eq "abort.r" ) { |
2841e8f8 LS |
204 | print $debug "[ABORT]\n"; |
205 | $debug->flush(); | |
206 | packet_txt_write("status=abort"); | |
207 | packet_flush(); | |
ed17d262 | 208 | } elsif ( $command eq "smudge" and |
2841e8f8 | 209 | exists $DELAY{$pathname} and |
ed17d262 | 210 | $DELAY{$pathname}{"requested"} == 1 ) { |
2841e8f8 LS |
211 | print $debug "[DELAYED]\n"; |
212 | $debug->flush(); | |
213 | packet_txt_write("status=delayed"); | |
214 | packet_flush(); | |
215 | $DELAY{$pathname}{"requested"} = 2; | |
216 | $DELAY{$pathname}{"output"} = $output; | |
ed17d262 | 217 | } else { |
2841e8f8 LS |
218 | packet_txt_write("status=success"); |
219 | packet_flush(); | |
17573334 | 220 | |
2841e8f8 LS |
221 | if ( $pathname eq "${command}-write-fail.r" ) { |
222 | print $debug "[WRITE FAIL]\n"; | |
223 | $debug->flush(); | |
224 | die "${command} write error"; | |
edcc8581 | 225 | } |
2841e8f8 LS |
226 | |
227 | print $debug "OUT: " . length($output) . " "; | |
228 | $debug->flush(); | |
229 | ||
230 | while ( length($output) > 0 ) { | |
231 | my $packet = substr( $output, 0, $MAX_PACKET_CONTENT_SIZE ); | |
232 | packet_bin_write($packet); | |
233 | # dots represent the number of packets | |
234 | print $debug "."; | |
235 | if ( length($output) > $MAX_PACKET_CONTENT_SIZE ) { | |
236 | $output = substr( $output, $MAX_PACKET_CONTENT_SIZE ); | |
ed17d262 | 237 | } else { |
2841e8f8 LS |
238 | $output = ""; |
239 | } | |
edcc8581 | 240 | } |
2841e8f8 LS |
241 | packet_flush(); |
242 | print $debug " [OK]\n"; | |
243 | $debug->flush(); | |
244 | packet_flush(); | |
edcc8581 | 245 | } |
edcc8581 LS |
246 | } |
247 | } |