Merge branch 'jk/coding-guidelines-update' into maint
[git] / t / t0021 / rot13-filter.pl
1 #
2 # Example implementation for the Git filter protocol version 2
3 # See Documentation/gitattributes.txt, section "Filter Protocol"
4 #
5 # The script takes the list of supported protocol capabilities as
6 # arguments ("clean", "smudge", etc).
7 #
8 # This implementation supports special test cases:
9 # (1) If data with the pathname "clean-write-fail.r" is processed with
10 #     a "clean" operation then the write operation will die.
11 # (2) If data with the pathname "smudge-write-fail.r" is processed with
12 #     a "smudge" operation then the write operation will die.
13 # (3) If data with the pathname "error.r" is processed with any
14 #     operation then the filter signals that it cannot or does not want
15 #     to process the file.
16 # (4) If data with the pathname "abort.r" is processed with any
17 #     operation then the filter signals that it cannot or does not want
18 #     to process the file and any file after that is processed with the
19 #     same command.
20 #
21
22 use strict;
23 use warnings;
24 use IO::File;
25
26 my $MAX_PACKET_CONTENT_SIZE = 65516;
27 my @capabilities            = @ARGV;
28
29 open my $debug, ">>", "rot13-filter.log" or die "cannot open log file: $!";
30
31 sub rot13 {
32         my $str = shift;
33         $str =~ y/A-Za-z/N-ZA-Mn-za-m/;
34         return $str;
35 }
36
37 sub packet_bin_read {
38         my $buffer;
39         my $bytes_read = read STDIN, $buffer, 4;
40         if ( $bytes_read == 0 ) {
41                 # EOF - Git stopped talking to us!
42                 print $debug "STOP\n";
43                 exit();
44         }
45         elsif ( $bytes_read != 4 ) {
46                 die "invalid packet: '$buffer'";
47         }
48         my $pkt_size = hex($buffer);
49         if ( $pkt_size == 0 ) {
50                 return ( 1, "" );
51         }
52         elsif ( $pkt_size > 4 ) {
53                 my $content_size = $pkt_size - 4;
54                 $bytes_read = read STDIN, $buffer, $content_size;
55                 if ( $bytes_read != $content_size ) {
56                         die "invalid packet ($content_size bytes expected; $bytes_read bytes read)";
57                 }
58                 return ( 0, $buffer );
59         }
60         else {
61                 die "invalid packet size: $pkt_size";
62         }
63 }
64
65 sub packet_txt_read {
66         my ( $res, $buf ) = packet_bin_read();
67         unless ( $buf =~ s/\n$// ) {
68                 die "A non-binary line MUST be terminated by an LF.";
69         }
70         return ( $res, $buf );
71 }
72
73 sub packet_bin_write {
74         my $buf = shift;
75         print STDOUT sprintf( "%04x", length($buf) + 4 );
76         print STDOUT $buf;
77         STDOUT->flush();
78 }
79
80 sub packet_txt_write {
81         packet_bin_write( $_[0] . "\n" );
82 }
83
84 sub packet_flush {
85         print STDOUT sprintf( "%04x", 0 );
86         STDOUT->flush();
87 }
88
89 print $debug "START\n";
90 $debug->flush();
91
92 ( packet_txt_read() eq ( 0, "git-filter-client" ) ) || die "bad initialize";
93 ( packet_txt_read() eq ( 0, "version=2" ) )         || die "bad version";
94 ( packet_bin_read() eq ( 1, "" ) )                  || die "bad version end";
95
96 packet_txt_write("git-filter-server");
97 packet_txt_write("version=2");
98 packet_flush();
99
100 ( packet_txt_read() eq ( 0, "capability=clean" ) )  || die "bad capability";
101 ( packet_txt_read() eq ( 0, "capability=smudge" ) ) || die "bad capability";
102 ( packet_bin_read() eq ( 1, "" ) )                  || die "bad capability end";
103
104 foreach (@capabilities) {
105         packet_txt_write( "capability=" . $_ );
106 }
107 packet_flush();
108 print $debug "init handshake complete\n";
109 $debug->flush();
110
111 while (1) {
112         my ($command) = packet_txt_read() =~ /^command=(.+)$/;
113         print $debug "IN: $command";
114         $debug->flush();
115
116         my ($pathname) = packet_txt_read() =~ /^pathname=(.+)$/;
117         print $debug " $pathname";
118         $debug->flush();
119
120         if ( $pathname eq "" ) {
121                 die "bad pathname '$pathname'";
122         }
123
124         # Flush
125         packet_bin_read();
126
127         my $input = "";
128         {
129                 binmode(STDIN);
130                 my $buffer;
131                 my $done = 0;
132                 while ( !$done ) {
133                         ( $done, $buffer ) = packet_bin_read();
134                         $input .= $buffer;
135                 }
136                 print $debug " " . length($input) . " [OK] -- ";
137                 $debug->flush();
138         }
139
140         my $output;
141         if ( $pathname eq "error.r" or $pathname eq "abort.r" ) {
142                 $output = "";
143         }
144         elsif ( $command eq "clean" and grep( /^clean$/, @capabilities ) ) {
145                 $output = rot13($input);
146         }
147         elsif ( $command eq "smudge" and grep( /^smudge$/, @capabilities ) ) {
148                 $output = rot13($input);
149         }
150         else {
151                 die "bad command '$command'";
152         }
153
154         print $debug "OUT: " . length($output) . " ";
155         $debug->flush();
156
157         if ( $pathname eq "error.r" ) {
158                 print $debug "[ERROR]\n";
159                 $debug->flush();
160                 packet_txt_write("status=error");
161                 packet_flush();
162         }
163         elsif ( $pathname eq "abort.r" ) {
164                 print $debug "[ABORT]\n";
165                 $debug->flush();
166                 packet_txt_write("status=abort");
167                 packet_flush();
168         }
169         else {
170                 packet_txt_write("status=success");
171                 packet_flush();
172
173                 if ( $pathname eq "${command}-write-fail.r" ) {
174                         print $debug "[WRITE FAIL]\n";
175                         $debug->flush();
176                         die "${command} write error";
177                 }
178
179                 while ( length($output) > 0 ) {
180                         my $packet = substr( $output, 0, $MAX_PACKET_CONTENT_SIZE );
181                         packet_bin_write($packet);
182                         # dots represent the number of packets
183                         print $debug ".";
184                         if ( length($output) > $MAX_PACKET_CONTENT_SIZE ) {
185                                 $output = substr( $output, $MAX_PACKET_CONTENT_SIZE );
186                         }
187                         else {
188                                 $output = "";
189                         }
190                 }
191                 packet_flush();
192                 print $debug " [OK]\n";
193                 $debug->flush();
194                 packet_flush();
195         }
196 }