contrib / long-running-filter / example.plon commit worktree: disallow adding same path multiple times (cb56f55)
   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
  10use strict;
  11use warnings;
  12
  13my $MAX_PACKET_CONTENT_SIZE = 65516;
  14
  15sub 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
  43sub 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
  51sub packet_bin_write {
  52        my $buf = shift;
  53        print STDOUT sprintf( "%04x", length($buf) + 4 );
  54        print STDOUT $buf;
  55        STDOUT->flush();
  56}
  57
  58sub packet_txt_write {
  59        packet_bin_write( $_[0] . "\n" );
  60}
  61
  62sub 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
  71packet_txt_write("git-filter-server");
  72packet_txt_write("version=2");
  73packet_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
  79packet_txt_write("capability=clean");
  80packet_txt_write("capability=smudge");
  81packet_flush();
  82
  83while (1) {
  84        my ($command)  = packet_txt_read() =~ /^command=(.+)$/;
  85        my ($pathname) = packet_txt_read() =~ /^pathname=(.+)$/;
  86
  87        if ( $pathname eq "" ) {
  88                die "bad pathname '$pathname'";
  89        }
  90
  91        packet_bin_read();
  92
  93        my $input = "";
  94        {
  95                binmode(STDIN);
  96                my $buffer;
  97                my $done = 0;
  98                while ( !$done ) {
  99                        ( $done, $buffer ) = packet_bin_read();
 100                        $input .= $buffer;
 101                }
 102        }
 103
 104        my $output;
 105        if ( $command eq "clean" ) {
 106                ### Perform clean here ###
 107                $output = $input;
 108        }
 109        elsif ( $command eq "smudge" ) {
 110                ### Perform smudge here ###
 111                $output = $input;
 112        }
 113        else {
 114                die "bad command '$command'";
 115        }
 116
 117        packet_txt_write("status=success");
 118        packet_flush();
 119        while ( length($output) > 0 ) {
 120                my $packet = substr( $output, 0, $MAX_PACKET_CONTENT_SIZE );
 121                packet_bin_write($packet);
 122                if ( length($output) > $MAX_PACKET_CONTENT_SIZE ) {
 123                        $output = substr( $output, $MAX_PACKET_CONTENT_SIZE );
 124                }
 125                else {
 126                        $output = "";
 127                }
 128        }
 129        packet_flush();    # flush content!
 130        packet_flush();    # empty list, keep "status=success" unchanged!
 131
 132}