1# 2# Example implementation for the Git filter protocol version 2 3# See Documentation/gitattributes.txt, section "Filter Protocol" 4# 5# The first argument defines a debug log file that the script write to. 6# All remaining arguments define a list of supported protocol 7# capabilities ("clean", "smudge", etc). 8# 9# This implementation supports special test cases: 10# (1) If data with the pathname "clean-write-fail.r" is processed with 11# a "clean" operation then the write operation will die. 12# (2) If data with the pathname "smudge-write-fail.r" is processed with 13# a "smudge" operation then the write operation will die. 14# (3) If data with the pathname "error.r" is processed with any 15# operation then the filter signals that it cannot or does not want 16# to process the file. 17# (4) If data with the pathname "abort.r" is processed with any 18# operation then the filter signals that it cannot or does not want 19# to process the file and any file after that is processed with the 20# same command. 21# (5) If data with a pathname that is a key in the DELAY hash is 22# requested (e.g. "test-delay10.a") then the filter responds with 23# a "delay" status and sets the "requested" field in the DELAY hash. 24# The filter will signal the availability of this object after 25# "count" (field in DELAY hash) "list_available_blobs" commands. 26# (6) If data with the pathname "missing-delay.a" is processed that the 27# filter will drop the path from the "list_available_blobs" response. 28# (7) If data with the pathname "invalid-delay.a" is processed that the 29# filter will add the path "unfiltered" which was not delayed before 30# to the "list_available_blobs" response. 31# 32 33use5.008; 34use lib (split(/:/,$ENV{GITPERLLIB})); 35use strict; 36use warnings; 37use IO::File; 38use Git::Packet; 39 40my$MAX_PACKET_CONTENT_SIZE=65516; 41my$log_file=shift@ARGV; 42my@capabilities=@ARGV; 43 44open my$debug,">>",$log_fileor die"cannot open log file:$!"; 45 46my%DELAY= ( 47'test-delay10.a'=> {"requested"=>0,"count"=>1}, 48'test-delay11.a'=> {"requested"=>0,"count"=>1}, 49'test-delay20.a'=> {"requested"=>0,"count"=>2}, 50'test-delay10.b'=> {"requested"=>0,"count"=>1}, 51'missing-delay.a'=> {"requested"=>0,"count"=>1}, 52'invalid-delay.a'=> {"requested"=>0,"count"=>1}, 53); 54 55sub rot13 { 56my$str=shift; 57$str=~y/A-Za-z/N-ZA-Mn-za-m/; 58return$str; 59} 60 61print$debug"START\n"; 62$debug->flush(); 63 64packet_initialize("git-filter",2); 65 66my%remote_caps= packet_read_and_check_capabilities("clean","smudge","delay"); 67packet_check_and_write_capabilities(\%remote_caps,@capabilities); 68 69print$debug"init handshake complete\n"; 70$debug->flush(); 71 72while(1) { 73my($res,$command) = packet_required_key_val_read("command"); 74if($res== -1) { 75print$debug"STOP\n"; 76exit(); 77} 78print$debug"IN:$command"; 79$debug->flush(); 80 81if($commandeq"list_available_blobs") { 82# Flush 83 packet_compare_lists([1,""], packet_bin_read()) || 84die"bad list_available_blobs end"; 85 86foreachmy$pathname(sort keys%DELAY) { 87if($DELAY{$pathname}{"requested"} >=1) { 88$DELAY{$pathname}{"count"} =$DELAY{$pathname}{"count"} -1; 89if($pathnameeq"invalid-delay.a") { 90# Send Git a pathname that was not delayed earlier 91 packet_txt_write("pathname=unfiltered"); 92} 93if($pathnameeq"missing-delay.a") { 94# Do not signal Git that this file is available 95}elsif($DELAY{$pathname}{"count"} ==0) { 96print$debug"$pathname"; 97 packet_txt_write("pathname=$pathname"); 98} 99} 100} 101 102 packet_flush(); 103 104print$debug" [OK]\n"; 105$debug->flush(); 106 packet_txt_write("status=success"); 107 packet_flush(); 108}else{ 109my($res,$pathname) = packet_required_key_val_read("pathname"); 110if($res== -1) { 111die"unexpected EOF while expecting pathname"; 112} 113print$debug"$pathname"; 114$debug->flush(); 115 116# Read until flush 117my($done,$buffer) = packet_txt_read(); 118while($bufferne'') { 119if($buffereq"can-delay=1") { 120if(exists$DELAY{$pathname}and$DELAY{$pathname}{"requested"} ==0) { 121$DELAY{$pathname}{"requested"} =1; 122} 123}else{ 124die"Unknown message '$buffer'"; 125} 126 127($done,$buffer) = packet_txt_read(); 128} 129if($done== -1) { 130die"unexpected EOF after pathname '$pathname'"; 131} 132 133my$input=""; 134{ 135binmode(STDIN); 136my$buffer; 137my$done=0; 138while( !$done) { 139($done,$buffer) = packet_bin_read(); 140$input.=$buffer; 141} 142if($done== -1) { 143die"unexpected EOF while reading input for '$pathname'"; 144} 145print$debug" ".length($input) ." [OK] -- "; 146$debug->flush(); 147} 148 149my$output; 150if(exists$DELAY{$pathname}and exists$DELAY{$pathname}{"output"} ) { 151$output=$DELAY{$pathname}{"output"} 152}elsif($pathnameeq"error.r"or$pathnameeq"abort.r") { 153$output=""; 154}elsif($commandeq"clean"and grep(/^clean$/,@capabilities) ) { 155$output= rot13($input); 156}elsif($commandeq"smudge"and grep(/^smudge$/,@capabilities) ) { 157$output= rot13($input); 158}else{ 159die"bad command '$command'"; 160} 161 162if($pathnameeq"error.r") { 163print$debug"[ERROR]\n"; 164$debug->flush(); 165 packet_txt_write("status=error"); 166 packet_flush(); 167}elsif($pathnameeq"abort.r") { 168print$debug"[ABORT]\n"; 169$debug->flush(); 170 packet_txt_write("status=abort"); 171 packet_flush(); 172}elsif($commandeq"smudge"and 173exists$DELAY{$pathname}and 174$DELAY{$pathname}{"requested"} ==1) { 175print$debug"[DELAYED]\n"; 176$debug->flush(); 177 packet_txt_write("status=delayed"); 178 packet_flush(); 179$DELAY{$pathname}{"requested"} =2; 180$DELAY{$pathname}{"output"} =$output; 181}else{ 182 packet_txt_write("status=success"); 183 packet_flush(); 184 185if($pathnameeq"${command}-write-fail.r") { 186print$debug"[WRITE FAIL]\n"; 187$debug->flush(); 188die"${command} write error"; 189} 190 191print$debug"OUT: ".length($output) ." "; 192$debug->flush(); 193 194while(length($output) >0) { 195my$packet=substr($output,0,$MAX_PACKET_CONTENT_SIZE); 196 packet_bin_write($packet); 197# dots represent the number of packets 198print$debug"."; 199if(length($output) >$MAX_PACKET_CONTENT_SIZE) { 200$output=substr($output,$MAX_PACKET_CONTENT_SIZE); 201}else{ 202$output=""; 203} 204} 205 packet_flush(); 206print$debug" [OK]\n"; 207$debug->flush(); 208 packet_flush(); 209} 210} 211}