{"thread":{"id":"47123","subject":"[PATCH v2 0/8] Create Git/Packet.pm","startedAt":"2017-11-05T21:38:50Z","lastAt":"2017-11-07T06:34:54Z","messageCount":14,"participants":["Christian Couder","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":8},"messages":[{"id":"331882","messageId":"20171105213836.11717-1-chriscool@tuxfamily.org","threadId":"47123","inReplyTo":null,"subject":"[PATCH v2 0/8] Create Git/Packet.pm","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-05T21:38:28Z","receivedAt":"2017-11-05T21:38:50Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Goal\n~~~~\n\nPacket related functions in Perl can be useful to write new filters or\nto debug or test existing filters. They might also in the future be\nused by other software using the same packet line protocol. So instead\nof having them in t0021/rot13-filter.pl, let's extract them into a new\nGit/Packet.pm module.\n\nChanges since the previous version\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n  - Patch 1/8 is new. It fixes a list comparison bug that existed\n    since the beginning of t0021/rot13-filter.pl.\n\n  - Patch 2/8 is much improved. It now checks for unexpected EOF in\n    all the code paths and introduces a new\n    packet_required_key_val_read() function.\n\n  - Patchs 3/8, 4/8 and 5/8 have not changed since v1.\n\n  - Patch 6/8 is new. It adds a small helper function.\n\n  - Patch 7/8 is much improved. It now describe better all the changes\n    and better check that the capabilities we advertise are supported\n    by the remote.\n\n  - Patch 8/8 has been improved. It contains the Makefile change\n    suggested by Dscho.\n\nLinks\n~~~~~\n\nThis patch series is on the following branch:\n\nhttps://github.com/chriscool/git/commits/gl-prep-external-odb\n\nVersion 1 of this patch series is on the mailing list here:\n\nhttps://public-inbox.org/git/20171019123030.17338-1-chriscool@tuxfamily.org/\n\nIt is also available in the following branch:\n\nhttps://github.com/chriscool/git/commits/gl-prep-external-odb1\n\nThis patch series was extracted from previous \"Add initial\nexperimental external ODB support\" patch series.\n\nVersion 1, 2, 3, 4, 5 and 6 of this previous series are on the mailing\nlist here:\n\nhttps://public-inbox.org/git/20160613085546.11784-1-chriscool@tuxfamily.org/\nhttps://public-inbox.org/git/20160628181933.24620-1-chriscool@tuxfamily.org/\nhttps://public-inbox.org/git/20161130210420.15982-1-chriscool@tuxfamily.org/\nhttps://public-inbox.org/git/20170620075523.26961-1-chriscool@tuxfamily.org/\nhttps://public-inbox.org/git/20170803091926.1755-1-chriscool@tuxfamily.org/\nhttps://public-inbox.org/git/20170916080731.13925-1-chriscool@tuxfamily.org/\n\nThey are also available in the following branches:\n\nhttps://github.com/chriscool/git/commits/gl-external-odb12\nhttps://github.com/chriscool/git/commits/gl-external-odb22\nhttps://github.com/chriscool/git/commits/gl-external-odb61\nhttps://github.com/chriscool/git/commits/gl-external-odb239\nhttps://github.com/chriscool/git/commits/gl-external-odb373\nhttps://github.com/chriscool/git/commits/gl-external-odb411\n\n\nChristian Couder (8):\n  t0021/rot13-filter: fix list comparison\n  t0021/rot13-filter: refactor packet reading functions\n  t0021/rot13-filter: improve 'if .. elsif .. else' style\n  t0021/rot13-filter: improve error message\n  t0021/rot13-filter: add packet_initialize()\n  t0021/rot13-filter: refactor checking final lf\n  t0021/rot13-filter: add capability functions\n  Add Git/Packet.pm from parts of t0021/rot13-filter.pl\n\n perl/Git/Packet.pm      | 168 ++++++++++++++++++++++++++++++++++++++++++++++++\n perl/Makefile           |   1 +\n t/t0021/rot13-filter.pl | 127 ++++++++++--------------------------\n 3 files changed, 202 insertions(+), 94 deletions(-)\n create mode 100644 perl/Git/Packet.pm\n\n-- \n2.15.0.7.ga9ff306ed9.dirty\n\n"},{"id":"331883","messageId":"20171105213836.11717-2-chriscool@tuxfamily.org","threadId":"47123","inReplyTo":"20171105213836.11717-1-chriscool@tuxfamily.org","subject":"[PATCH v2 1/8] t0021/rot13-filter: fix list comparison","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-05T21:38:29Z","receivedAt":"2017-11-05T21:38:55Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Since edcc8581 (\"convert: add filter.<driver>.process\noption\", 2016-10-16) when t0021/rot13-filter.pl was created, list\ncomparison in this perl script have been quite broken.\n\npacket_txt_read() returns a 2-element list, and the right hand\nside of \"eq\" also has a list with (two, elements), but \"eq\" takes\nthe last element of the list on each side, and compares them. The\nfirst elements (0 or 1) on the right hand side lists do not matter,\nwhich means we do not require to see a flush at the end of the\nversion -- a simple empty string or an EOF would do, which is\ndefinitely not what we want.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t0021/rot13-filter.pl | 35 ++++++++++++++++++++++++++++-------\n 1 file changed, 28 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl\nindex ad685d92f8..4b2d9087d4 100644\n--- a/t/t0021/rot13-filter.pl\n+++ b/t/t0021/rot13-filter.pl\n@@ -55,6 +55,20 @@ sub rot13 {\n \treturn $str;\n }\n \n+sub packet_compare_lists {\n+\tmy ($expect, @result) = @_;\n+\tmy $ix;\n+\tif (scalar @$expect != scalar @result) {\n+\t\treturn undef;\n+\t}\n+\tfor ($ix = 0; $ix < $#result; $ix++) {\n+\t\tif ($expect->[$ix] ne $result[$ix]) {\n+\t\t\treturn undef;\n+\t\t}\n+\t}\n+\treturn 1;\n+}\n+\n sub packet_bin_read {\n \tmy $buffer;\n \tmy $bytes_read = read STDIN, $buffer, 4;\n@@ -110,18 +124,25 @@ sub packet_flush {\n print $debug \"START\\n\";\n $debug->flush();\n \n-( packet_txt_read() eq ( 0, \"git-filter-client\" ) ) || die \"bad initialize\";\n-( packet_txt_read() eq ( 0, \"version=2\" ) )         || die \"bad version\";\n-( packet_bin_read() eq ( 1, \"\" ) )                  || die \"bad version end\";\n+packet_compare_lists([0, \"git-filter-client\"], packet_txt_read()) ||\n+\tdie \"bad initialize\";\n+packet_compare_lists([0, \"version=2\"], packet_txt_read()) ||\n+\tdie \"bad version\";\n+packet_compare_lists([1, \"\"], packet_bin_read()) ||\n+\tdie \"bad version end\";\n \n packet_txt_write(\"git-filter-server\");\n packet_txt_write(\"version=2\");\n packet_flush();\n \n-( packet_txt_read() eq ( 0, \"capability=clean\" ) )  || die \"bad capability\";\n-( packet_txt_read() eq ( 0, \"capability=smudge\" ) ) || die \"bad capability\";\n-( packet_txt_read() eq ( 0, \"capability=delay\" ) )  || die \"bad capability\";\n-( packet_bin_read() eq ( 1, \"\" ) )                  || die \"bad capability end\";\n+packet_compare_lists([0, \"capability=clean\"], packet_txt_read()) ||\n+\tdie \"bad capability\";\n+packet_compare_lists([0, \"capability=smudge\"], packet_txt_read()) ||\n+\tdie \"bad capability\";\n+packet_compare_lists([0, \"capability=delay\"], packet_txt_read()) ||\n+\tdie \"bad capability\";\n+packet_compare_lists([1, \"\"], packet_bin_read()) ||\n+\tdie \"bad capability end\";\n \n foreach (@capabilities) {\n \tpacket_txt_write( \"capability=\" . $_ );\n-- \n2.15.0.7.ga9ff306ed9.dirty\n\n"},{"id":"331884","messageId":"20171105213836.11717-3-chriscool@tuxfamily.org","threadId":"47123","inReplyTo":"20171105213836.11717-1-chriscool@tuxfamily.org","subject":"[PATCH v2 2/8] t0021/rot13-filter: refactor packet reading functions","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-05T21:38:30Z","receivedAt":"2017-11-05T21:38:58Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"To make it possible in a following commit to move packet\nreading and writing functions into a Packet.pm module,\nlet's refactor these functions, so they don't handle\nprinting debug output and exiting.\n\nWhile at it let's create packet_required_key_val_read()\nto still handle erroring out in a common case.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t0021/rot13-filter.pl | 38 ++++++++++++++++++++++++++++----------\n 1 file changed, 28 insertions(+), 10 deletions(-)\n\ndiff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl\nindex 4b2d9087d4..c025518c0a 100644\n--- a/t/t0021/rot13-filter.pl\n+++ b/t/t0021/rot13-filter.pl\n@@ -74,8 +74,7 @@ sub packet_bin_read {\n \tmy $bytes_read = read STDIN, $buffer, 4;\n \tif ( $bytes_read == 0 ) {\n \t\t# EOF - Git stopped talking to us!\n-\t\tprint $debug \"STOP\\n\";\n-\t\texit();\n+\t\treturn ( -1, \"\" );\n \t}\n \telsif ( $bytes_read != 4 ) {\n \t\tdie \"invalid packet: '$buffer'\";\n@@ -99,12 +98,21 @@ sub packet_bin_read {\n \n sub packet_txt_read {\n \tmy ( $res, $buf ) = packet_bin_read();\n-\tunless ( $buf eq '' or $buf =~ s/\\n$// ) {\n+\tunless ( $res == -1 or $buf eq '' or $buf =~ s/\\n$// ) {\n \t\tdie \"A non-binary line MUST be terminated by an LF.\";\n \t}\n \treturn ( $res, $buf );\n }\n \n+sub packet_required_key_val_read {\n+\tmy ( $key ) = @_;\n+\tmy ( $res, $buf ) = packet_txt_read();\n+\tunless ( $res == -1 or ( $buf =~ s/^$key=// and $buf ne '' ) ) {\n+\t\tdie \"bad $key: '$buf'\";\n+\t}\n+\treturn ( $res, $buf );\n+}\n+\n sub packet_bin_write {\n \tmy $buf = shift;\n \tprint STDOUT sprintf( \"%04x\", length($buf) + 4 );\n@@ -152,13 +160,18 @@ print $debug \"init handshake complete\\n\";\n $debug->flush();\n \n while (1) {\n-\tmy ( $command ) = packet_txt_read() =~ /^command=(.+)$/;\n+\tmy ( $res, $command ) = packet_required_key_val_read(\"command\");\n+\tif ( $res == -1 ) {\n+\t\tprint $debug \"STOP\\n\";\n+\t\texit();\n+\t}\n \tprint $debug \"IN: $command\";\n \t$debug->flush();\n \n \tif ( $command eq \"list_available_blobs\" ) {\n \t\t# Flush\n-\t\tpacket_bin_read();\n+\t\tpacket_compare_lists([1, \"\"], packet_bin_read()) ||\n+\t\t\tdie \"bad list_available_blobs end\";\n \n \t\tforeach my $pathname ( sort keys %DELAY ) {\n \t\t\tif ( $DELAY{$pathname}{\"requested\"} >= 1 ) {\n@@ -184,14 +197,13 @@ while (1) {\n \t\tpacket_flush();\n \t}\n \telse {\n-\t\tmy ( $pathname ) = packet_txt_read() =~ /^pathname=(.+)$/;\n+\t\tmy ( $res, $pathname ) = packet_required_key_val_read(\"pathname\");\n+\t\tif ( $res == -1 ) {\n+\t\t\tdie \"unexpected EOF while expecting pathname\";\n+\t\t}\n \t\tprint $debug \" $pathname\";\n \t\t$debug->flush();\n \n-\t\tif ( $pathname eq \"\" ) {\n-\t\t\tdie \"bad pathname '$pathname'\";\n-\t\t}\n-\n \t\t# Read until flush\n \t\tmy ( $done, $buffer ) = packet_txt_read();\n \t\twhile ( $buffer ne '' ) {\n@@ -205,6 +217,9 @@ while (1) {\n \n \t\t\t( $done, $buffer ) = packet_txt_read();\n \t\t}\n+\t\tif ( $done == -1 ) {\n+\t\t\tdie \"unexpected EOF after pathname '$pathname'\";\n+\t\t}\n \n \t\tmy $input = \"\";\n \t\t{\n@@ -215,6 +230,9 @@ while (1) {\n \t\t\t\t( $done, $buffer ) = packet_bin_read();\n \t\t\t\t$input .= $buffer;\n \t\t\t}\n+\t\t\tif ( $done == -1 ) {\n+\t\t\t\tdie \"unexpected EOF while reading input for '$pathname'\";\n+\t\t\t}\t\t\t\n \t\t\tprint $debug \" \" . length($input) . \" [OK] -- \";\n \t\t\t$debug->flush();\n \t\t}\n-- \n2.15.0.7.ga9ff306ed9.dirty\n\n"},{"id":"331885","messageId":"20171105213836.11717-9-chriscool@tuxfamily.org","threadId":"47123","inReplyTo":"20171105213836.11717-1-chriscool@tuxfamily.org","subject":"[PATCH v2 8/8] Add Git/Packet.pm from parts of t0021/rot13-filter.pl","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-05T21:38:36Z","receivedAt":"2017-11-05T21:39:01Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"And while at it let's simplify t0021/rot13-filter.pl by\nusing Git/Packet.pm.\n\nThis will make it possible to reuse packet related\nfunctions in other test scripts.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n perl/Git/Packet.pm      | 168 ++++++++++++++++++++++++++++++++++++++++++++++++\n perl/Makefile           |   1 +\n t/t0021/rot13-filter.pl | 140 +---------------------------------------\n 3 files changed, 172 insertions(+), 137 deletions(-)\n create mode 100644 perl/Git/Packet.pm\n\ndiff --git a/perl/Git/Packet.pm b/perl/Git/Packet.pm\nnew file mode 100644\nindex 0000000000..255b28c098\n--- /dev/null\n+++ b/perl/Git/Packet.pm\n@@ -0,0 +1,168 @@\n+package Git::Packet;\n+use 5.008;\n+use strict;\n+use warnings;\n+BEGIN {\n+\trequire Exporter;\n+\tif ($] < 5.008003) {\n+\t\t*import = \\&Exporter::import;\n+\t} else {\n+\t\t# Exporter 5.57 which supports this invocation was\n+\t\t# released with perl 5.8.3\n+\t\tExporter->import('import');\n+\t}\n+}\n+\n+our @EXPORT = qw(\n+\t\t\tpacket_compare_lists\n+\t\t\tpacket_bin_read\n+\t\t\tpacket_txt_read\n+\t\t\tpacket_required_key_val_read\n+\t\t\tpacket_bin_write\n+\t\t\tpacket_txt_write\n+\t\t\tpacket_flush\n+\t\t\tpacket_initialize\n+\t\t\tpacket_read_capabilities\n+\t\t\tpacket_read_and_check_capabilities\n+\t\t\tpacket_check_and_write_capabilities\n+\t\t);\n+our @EXPORT_OK = @EXPORT;\n+\n+sub packet_compare_lists {\n+\tmy ($expect, @result) = @_;\n+\tmy $ix;\n+\tif (scalar @$expect != scalar @result) {\n+\t\treturn undef;\n+\t}\n+\tfor ($ix = 0; $ix < $#result; $ix++) {\n+\t\tif ($expect->[$ix] ne $result[$ix]) {\n+\t\t\treturn undef;\n+\t\t}\n+\t}\n+\treturn 1;\n+}\n+\n+sub packet_bin_read {\n+\tmy $buffer;\n+\tmy $bytes_read = read STDIN, $buffer, 4;\n+\tif ( $bytes_read == 0 ) {\n+\t\t# EOF - Git stopped talking to us!\n+\t\treturn ( -1, \"\" );\n+\t} elsif ( $bytes_read != 4 ) {\n+\t\tdie \"invalid packet: '$buffer'\";\n+\t}\n+\tmy $pkt_size = hex($buffer);\n+\tif ( $pkt_size == 0 ) {\n+\t\treturn ( 1, \"\" );\n+\t} elsif ( $pkt_size > 4 ) {\n+\t\tmy $content_size = $pkt_size - 4;\n+\t\t$bytes_read = read STDIN, $buffer, $content_size;\n+\t\tif ( $bytes_read != $content_size ) {\n+\t\t\tdie \"invalid packet ($content_size bytes expected; $bytes_read bytes read)\";\n+\t\t}\n+\t\treturn ( 0, $buffer );\n+\t} else {\n+\t\tdie \"invalid packet size: $pkt_size\";\n+\t}\n+}\n+\n+sub remove_final_lf_or_die {\n+\tmy $buf = shift;\n+\tunless ( $buf =~ s/\\n$// ) {\n+\t\tdie \"A non-binary line MUST be terminated by an LF.\\n\"\n+\t\t    . \"Received: '$buf'\";\n+\t}\n+\treturn $buf;\n+}\n+\n+sub packet_txt_read {\n+\tmy ( $res, $buf ) = packet_bin_read();\n+\tunless ( $res == -1 or $buf eq '' ) {\n+\t\t$buf = remove_final_lf_or_die($buf);\n+\t}\n+\treturn ( $res, $buf );\n+}\n+\n+sub packet_required_key_val_read {\n+\tmy ( $key ) = @_;\n+\tmy ( $res, $buf ) = packet_txt_read();\n+\tunless ( $res == -1 or ( $buf =~ s/^$key=// and $buf ne '' ) ) {\n+\t\tdie \"bad $key: '$buf'\";\n+\t}\n+\treturn ( $res, $buf );\n+}\n+\n+sub packet_bin_write {\n+\tmy $buf = shift;\n+\tprint STDOUT sprintf( \"%04x\", length($buf) + 4 );\n+\tprint STDOUT $buf;\n+\tSTDOUT->flush();\n+}\n+\n+sub packet_txt_write {\n+\tpacket_bin_write( $_[0] . \"\\n\" );\n+}\n+\n+sub packet_flush {\n+\tprint STDOUT sprintf( \"%04x\", 0 );\n+\tSTDOUT->flush();\n+}\n+\n+sub packet_initialize {\n+\tmy ($name, $version) = @_;\n+\n+\tpacket_compare_lists([0, $name . \"-client\"], packet_txt_read()) ||\n+\t\tdie \"bad initialize\";\n+\tpacket_compare_lists([0, \"version=\" . $version], packet_txt_read()) ||\n+\t\tdie \"bad version\";\n+\tpacket_compare_lists([1, \"\"], packet_bin_read()) ||\n+\t\tdie \"bad version end\";\n+\n+\tpacket_txt_write( $name . \"-server\" );\n+\tpacket_txt_write( \"version=\" . $version );\n+\tpacket_flush();\n+}\n+\n+sub packet_read_capabilities {\n+\tmy @cap;\n+\twhile (1) {\n+\t\tmy ( $res, $buf ) = packet_bin_read();\n+\t\tif ( $res == -1 ) {\n+\t\t\tdie \"unexpected EOF when reading capabilities\";\n+\t\t}\n+\t\treturn ( $res, @cap ) if ( $res != 0 );\n+\t\t$buf = remove_final_lf_or_die($buf);\n+\t\tunless ( $buf =~ s/capability=// ) {\n+\t\t\tdie \"bad capability buf: '$buf'\";\n+\t\t}\n+\t\tpush @cap, $buf;\n+\t}\n+}\n+\n+# Read remote capabilities and check them against capabilities we require\n+sub packet_read_and_check_capabilities {\n+\tmy @required_caps = @_;\n+\tmy ($res, @remote_caps) = packet_read_capabilities();\n+\tmy %remote_caps = map { $_ => 1 } @remote_caps;\n+\tforeach (@required_caps) {\n+\t\tunless (exists($remote_caps{$_})) {\n+\t\t\tdie \"required '$_' capability not available from remote\" ;\n+\t\t}\n+\t}\n+\treturn %remote_caps;\n+}\n+\n+# Check our capabilities we want to advertise against the remote ones\n+# and then advertise our capabilities\n+sub packet_check_and_write_capabilities {\n+\tmy ($remote_caps, @our_caps) = @_;\n+\tforeach (@our_caps) {\n+\t\tunless (exists($remote_caps->{$_})) {\n+\t\t\tdie \"our capability '$_' is not available from remote\"\n+\t\t}\n+\t\tpacket_txt_write( \"capability=\" . $_ );\n+\t}\n+\tpacket_flush();\n+}\n+\n+1;\ndiff --git a/perl/Makefile b/perl/Makefile\nindex 15d96fcc7a..f657de20e3 100644\n--- a/perl/Makefile\n+++ b/perl/Makefile\n@@ -30,6 +30,7 @@ instdir_SQ = $(subst ','\\'',$(prefix)/lib)\n modules += Git\n modules += Git/I18N\n modules += Git/IndexInfo\n+modules += Git/Packet\n modules += Git/SVN\n modules += Git/SVN/Memoize/YAML\n modules += Git/SVN/Fetcher\ndiff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl\nindex f919d798a6..6fd7fa476b 100644\n--- a/t/t0021/rot13-filter.pl\n+++ b/t/t0021/rot13-filter.pl\n@@ -30,9 +30,12 @@\n #     to the \"list_available_blobs\" response.\n #\n \n+use 5.008;\n+use lib (split(/:/, $ENV{GITPERLLIB}));\n use strict;\n use warnings;\n use IO::File;\n+use Git::Packet;\n \n my $MAX_PACKET_CONTENT_SIZE = 65516;\n my $log_file                = shift @ARGV;\n@@ -55,143 +58,6 @@ sub rot13 {\n \treturn $str;\n }\n \n-sub packet_compare_lists {\n-\tmy ($expect, @result) = @_;\n-\tmy $ix;\n-\tif (scalar @$expect != scalar @result) {\n-\t\treturn undef;\n-\t}\n-\tfor ($ix = 0; $ix < $#result; $ix++) {\n-\t\tif ($expect->[$ix] ne $result[$ix]) {\n-\t\t\treturn undef;\n-\t\t}\n-\t}\n-\treturn 1;\n-}\n-\n-sub packet_bin_read {\n-\tmy $buffer;\n-\tmy $bytes_read = read STDIN, $buffer, 4;\n-\tif ( $bytes_read == 0 ) {\n-\t\t# EOF - Git stopped talking to us!\n-\t\treturn ( -1, \"\" );\n-\t} elsif ( $bytes_read != 4 ) {\n-\t\tdie \"invalid packet: '$buffer'\";\n-\t}\n-\tmy $pkt_size = hex($buffer);\n-\tif ( $pkt_size == 0 ) {\n-\t\treturn ( 1, \"\" );\n-\t} elsif ( $pkt_size > 4 ) {\n-\t\tmy $content_size = $pkt_size - 4;\n-\t\t$bytes_read = read STDIN, $buffer, $content_size;\n-\t\tif ( $bytes_read != $content_size ) {\n-\t\t\tdie \"invalid packet ($content_size bytes expected; $bytes_read bytes read)\";\n-\t\t}\n-\t\treturn ( 0, $buffer );\n-\t} else {\n-\t\tdie \"invalid packet size: $pkt_size\";\n-\t}\n-}\n-\n-sub remove_final_lf_or_die {\n-\tmy $buf = shift;\n-\tunless ( $buf =~ s/\\n$// ) {\n-\t\tdie \"A non-binary line MUST be terminated by an LF.\\n\"\n-\t\t    . \"Received: '$buf'\";\n-\t}\n-\treturn $buf;\n-}\n-\n-sub packet_txt_read {\n-\tmy ( $res, $buf ) = packet_bin_read();\n-\tunless ( $res == -1 or $buf eq '' ) {\n-\t\t$buf = remove_final_lf_or_die($buf);\n-\t}\n-\treturn ( $res, $buf );\n-}\n-\n-sub packet_required_key_val_read {\n-\tmy ( $key ) = @_;\n-\tmy ( $res, $buf ) = packet_txt_read();\n-\tunless ( $res == -1 or ( $buf =~ s/^$key=// and $buf ne '' ) ) {\n-\t\tdie \"bad $key: '$buf'\";\n-\t}\n-\treturn ( $res, $buf );\n-}\n-\n-sub packet_bin_write {\n-\tmy $buf = shift;\n-\tprint STDOUT sprintf( \"%04x\", length($buf) + 4 );\n-\tprint STDOUT $buf;\n-\tSTDOUT->flush();\n-}\n-\n-sub packet_txt_write {\n-\tpacket_bin_write( $_[0] . \"\\n\" );\n-}\n-\n-sub packet_flush {\n-\tprint STDOUT sprintf( \"%04x\", 0 );\n-\tSTDOUT->flush();\n-}\n-\n-sub packet_initialize {\n-\tmy ($name, $version) = @_;\n-\n-\tpacket_compare_lists([0, $name . \"-client\"], packet_txt_read()) ||\n-\t\tdie \"bad initialize\";\n-\tpacket_compare_lists([0, \"version=\" . $version], packet_txt_read()) ||\n-\t\tdie \"bad version\";\n-\tpacket_compare_lists([1, \"\"], packet_bin_read()) ||\n-\t\tdie \"bad version end\";\n-\n-\tpacket_txt_write( $name . \"-server\" );\n-\tpacket_txt_write( \"version=\" . $version );\n-\tpacket_flush();\n-}\n-\n-sub packet_read_capabilities {\n-\tmy @cap;\n-\twhile (1) {\n-\t\tmy ( $res, $buf ) = packet_bin_read();\n-\t\tif ( $res == -1 ) {\n-\t\t\tdie \"unexpected EOF when reading capabilities\";\n-\t\t}\n-\t\treturn ( $res, @cap ) if ( $res != 0 );\n-\t\t$buf = remove_final_lf_or_die($buf);\n-\t\tunless ( $buf =~ s/capability=// ) {\n-\t\t\tdie \"bad capability buf: '$buf'\";\n-\t\t}\n-\t\tpush @cap, $buf;\n-\t}\n-}\n-\n-# Read remote capabilities and check them against capabilities we require\n-sub packet_read_and_check_capabilities {\n-\tmy @required_caps = @_;\n-\tmy ($res, @remote_caps) = packet_read_capabilities();\n-\tmy %remote_caps = map { $_ => 1 } @remote_caps;\n-\tforeach (@required_caps) {\n-\t\tunless (exists($remote_caps{$_})) {\n-\t\t\tdie \"required '$_' capability not available from remote\" ;\n-\t\t}\n-\t}\n-\treturn %remote_caps;\n-}\n-\n-# Check our capabilities we want to advertise against the remote ones\n-# and then advertise our capabilities\n-sub packet_check_and_write_capabilities {\n-\tmy ($remote_caps, @our_caps) = @_;\n-\tforeach (@our_caps) {\n-\t\tunless (exists($remote_caps->{$_})) {\n-\t\t\tdie \"our capability '$_' is not available from remote\"\n-\t\t}\n-\t\tpacket_txt_write( \"capability=\" . $_ );\n-\t}\n-\tpacket_flush();\n-}\n-\n print $debug \"START\\n\";\n $debug->flush();\n \n-- \n2.15.0.7.ga9ff306ed9.dirty\n\n"},{"id":"331886","messageId":"20171105213836.11717-6-chriscool@tuxfamily.org","threadId":"47123","inReplyTo":"20171105213836.11717-1-chriscool@tuxfamily.org","subject":"[PATCH v2 5/8] t0021/rot13-filter: add packet_initialize()","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-05T21:38:33Z","receivedAt":"2017-11-05T21:39:05Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Let's refactor the code to initialize communication into its own\npacket_initialize() function, so that we can reuse this\nfunctionality in following patches.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t0021/rot13-filter.pl | 26 ++++++++++++++++----------\n 1 file changed, 16 insertions(+), 10 deletions(-)\n\ndiff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl\nindex f31ff595fe..2f74ab2e45 100644\n--- a/t/t0021/rot13-filter.pl\n+++ b/t/t0021/rot13-filter.pl\n@@ -127,19 +127,25 @@ sub packet_flush {\n \tSTDOUT->flush();\n }\n \n+sub packet_initialize {\n+\tmy ($name, $version) = @_;\n+\n+\tpacket_compare_lists([0, $name . \"-client\"], packet_txt_read()) ||\n+\t\tdie \"bad initialize\";\n+\tpacket_compare_lists([0, \"version=\" . $version], packet_txt_read()) ||\n+\t\tdie \"bad version\";\n+\tpacket_compare_lists([1, \"\"], packet_bin_read()) ||\n+\t\tdie \"bad version end\";\n+\n+\tpacket_txt_write( $name . \"-server\" );\n+\tpacket_txt_write( \"version=\" . $version );\n+\tpacket_flush();\n+}\n+\n print $debug \"START\\n\";\n $debug->flush();\n \n-packet_compare_lists([0, \"git-filter-client\"], packet_txt_read()) ||\n-\tdie \"bad initialize\";\n-packet_compare_lists([0, \"version=2\"], packet_txt_read()) ||\n-\tdie \"bad version\";\n-packet_compare_lists([1, \"\"], packet_bin_read()) ||\n-\tdie \"bad version end\";\n-\n-packet_txt_write(\"git-filter-server\");\n-packet_txt_write(\"version=2\");\n-packet_flush();\n+packet_initialize(\"git-filter\", 2);\n \n packet_compare_lists([0, \"capability=clean\"], packet_txt_read()) ||\n \tdie \"bad capability\";\n-- \n2.15.0.7.ga9ff306ed9.dirty\n\n"},{"id":"331887","messageId":"20171105213836.11717-4-chriscool@tuxfamily.org","threadId":"47123","inReplyTo":"20171105213836.11717-1-chriscool@tuxfamily.org","subject":"[PATCH v2 3/8] t0021/rot13-filter: improve 'if .. elsif .. else' style","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-05T21:38:31Z","receivedAt":"2017-11-05T21:39:09Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Before further refactoring the \"t0021/rot13-filter.pl\" script,\nlet's modernize the style of its 'if .. elsif .. else' clauses\nto improve its readability by making it more similar to our\nother perl scripts.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t0021/rot13-filter.pl | 39 +++++++++++++--------------------------\n 1 file changed, 13 insertions(+), 26 deletions(-)\n\ndiff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl\nindex c025518c0a..37cecd8654 100644\n--- a/t/t0021/rot13-filter.pl\n+++ b/t/t0021/rot13-filter.pl\n@@ -75,23 +75,20 @@ sub packet_bin_read {\n \tif ( $bytes_read == 0 ) {\n \t\t# EOF - Git stopped talking to us!\n \t\treturn ( -1, \"\" );\n-\t}\n-\telsif ( $bytes_read != 4 ) {\n+\t} elsif ( $bytes_read != 4 ) {\n \t\tdie \"invalid packet: '$buffer'\";\n \t}\n \tmy $pkt_size = hex($buffer);\n \tif ( $pkt_size == 0 ) {\n \t\treturn ( 1, \"\" );\n-\t}\n-\telsif ( $pkt_size > 4 ) {\n+\t} elsif ( $pkt_size > 4 ) {\n \t\tmy $content_size = $pkt_size - 4;\n \t\t$bytes_read = read STDIN, $buffer, $content_size;\n \t\tif ( $bytes_read != $content_size ) {\n \t\t\tdie \"invalid packet ($content_size bytes expected; $bytes_read bytes read)\";\n \t\t}\n \t\treturn ( 0, $buffer );\n-\t}\n-\telse {\n+\t} else {\n \t\tdie \"invalid packet size: $pkt_size\";\n \t}\n }\n@@ -195,8 +192,7 @@ while (1) {\n \t\t$debug->flush();\n \t\tpacket_txt_write(\"status=success\");\n \t\tpacket_flush();\n-\t}\n-\telse {\n+\t} else {\n \t\tmy ( $res, $pathname ) = packet_required_key_val_read(\"pathname\");\n \t\tif ( $res == -1 ) {\n \t\t\tdie \"unexpected EOF while expecting pathname\";\n@@ -240,17 +236,13 @@ while (1) {\n \t\tmy $output;\n \t\tif ( exists $DELAY{$pathname} and exists $DELAY{$pathname}{\"output\"} ) {\n \t\t\t$output = $DELAY{$pathname}{\"output\"}\n-\t\t}\n-\t\telsif ( $pathname eq \"error.r\" or $pathname eq \"abort.r\" ) {\n+\t\t} elsif ( $pathname eq \"error.r\" or $pathname eq \"abort.r\" ) {\n \t\t\t$output = \"\";\n-\t\t}\n-\t\telsif ( $command eq \"clean\" and grep( /^clean$/, @capabilities ) ) {\n+\t\t} elsif ( $command eq \"clean\" and grep( /^clean$/, @capabilities ) ) {\n \t\t\t$output = rot13($input);\n-\t\t}\n-\t\telsif ( $command eq \"smudge\" and grep( /^smudge$/, @capabilities ) ) {\n+\t\t} elsif ( $command eq \"smudge\" and grep( /^smudge$/, @capabilities ) ) {\n \t\t\t$output = rot13($input);\n-\t\t}\n-\t\telse {\n+\t\t} else {\n \t\t\tdie \"bad command '$command'\";\n \t\t}\n \n@@ -259,25 +251,21 @@ while (1) {\n \t\t\t$debug->flush();\n \t\t\tpacket_txt_write(\"status=error\");\n \t\t\tpacket_flush();\n-\t\t}\n-\t\telsif ( $pathname eq \"abort.r\" ) {\n+\t\t} elsif ( $pathname eq \"abort.r\" ) {\n \t\t\tprint $debug \"[ABORT]\\n\";\n \t\t\t$debug->flush();\n \t\t\tpacket_txt_write(\"status=abort\");\n \t\t\tpacket_flush();\n-\t\t}\n-\t\telsif ( $command eq \"smudge\" and\n+\t\t} elsif ( $command eq \"smudge\" and\n \t\t\texists $DELAY{$pathname} and\n-\t\t\t$DELAY{$pathname}{\"requested\"} == 1\n-\t\t) {\n+\t\t\t$DELAY{$pathname}{\"requested\"} == 1 ) {\n \t\t\tprint $debug \"[DELAYED]\\n\";\n \t\t\t$debug->flush();\n \t\t\tpacket_txt_write(\"status=delayed\");\n \t\t\tpacket_flush();\n \t\t\t$DELAY{$pathname}{\"requested\"} = 2;\n \t\t\t$DELAY{$pathname}{\"output\"} = $output;\n-\t\t}\n-\t\telse {\n+\t\t} else {\n \t\t\tpacket_txt_write(\"status=success\");\n \t\t\tpacket_flush();\n \n@@ -297,8 +285,7 @@ while (1) {\n \t\t\t\tprint $debug \".\";\n \t\t\t\tif ( length($output) > $MAX_PACKET_CONTENT_SIZE ) {\n \t\t\t\t\t$output = substr( $output, $MAX_PACKET_CONTENT_SIZE );\n-\t\t\t\t}\n-\t\t\t\telse {\n+\t\t\t\t} else {\n \t\t\t\t\t$output = \"\";\n \t\t\t\t}\n \t\t\t}\n-- \n2.15.0.7.ga9ff306ed9.dirty\n\n"},{"id":"331888","messageId":"20171105213836.11717-8-chriscool@tuxfamily.org","threadId":"47123","inReplyTo":"20171105213836.11717-1-chriscool@tuxfamily.org","subject":"[PATCH v2 7/8] t0021/rot13-filter: add capability functions","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-05T21:38:35Z","receivedAt":"2017-11-05T21:39:10Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"These function help read and write capabilities.\n\nTo make them more generic and make it easy to reuse them,\nthe following changes are made:\n\n- we don't require capabilities to come in a fixed order,\n- we allow duplicates,\n- we check that the remote supports the capabilities we\n  advertise,\n- we don't check if the remote declares any capability we\n  don't know about.\n\nThe reason behind the last change is that the protocol\nshould work using only the capabilities that both ends\nsupport, and it should not stop working if one end starts\nto advertise a new capability.\n\nDespite those changes, we can still require a set of\ncapabilities, and die if one of them is not supported.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t0021/rot13-filter.pl | 58 ++++++++++++++++++++++++++++++++++++++-----------\n 1 file changed, 45 insertions(+), 13 deletions(-)\n\ndiff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl\nindex d47b7f5666..f919d798a6 100644\n--- a/t/t0021/rot13-filter.pl\n+++ b/t/t0021/rot13-filter.pl\n@@ -150,24 +150,56 @@ sub packet_initialize {\n \tpacket_flush();\n }\n \n+sub packet_read_capabilities {\n+\tmy @cap;\n+\twhile (1) {\n+\t\tmy ( $res, $buf ) = packet_bin_read();\n+\t\tif ( $res == -1 ) {\n+\t\t\tdie \"unexpected EOF when reading capabilities\";\n+\t\t}\n+\t\treturn ( $res, @cap ) if ( $res != 0 );\n+\t\t$buf = remove_final_lf_or_die($buf);\n+\t\tunless ( $buf =~ s/capability=// ) {\n+\t\t\tdie \"bad capability buf: '$buf'\";\n+\t\t}\n+\t\tpush @cap, $buf;\n+\t}\n+}\n+\n+# Read remote capabilities and check them against capabilities we require\n+sub packet_read_and_check_capabilities {\n+\tmy @required_caps = @_;\n+\tmy ($res, @remote_caps) = packet_read_capabilities();\n+\tmy %remote_caps = map { $_ => 1 } @remote_caps;\n+\tforeach (@required_caps) {\n+\t\tunless (exists($remote_caps{$_})) {\n+\t\t\tdie \"required '$_' capability not available from remote\" ;\n+\t\t}\n+\t}\n+\treturn %remote_caps;\n+}\n+\n+# Check our capabilities we want to advertise against the remote ones\n+# and then advertise our capabilities\n+sub packet_check_and_write_capabilities {\n+\tmy ($remote_caps, @our_caps) = @_;\n+\tforeach (@our_caps) {\n+\t\tunless (exists($remote_caps->{$_})) {\n+\t\t\tdie \"our capability '$_' is not available from remote\"\n+\t\t}\n+\t\tpacket_txt_write( \"capability=\" . $_ );\n+\t}\n+\tpacket_flush();\n+}\n+\n print $debug \"START\\n\";\n $debug->flush();\n \n packet_initialize(\"git-filter\", 2);\n \n-packet_compare_lists([0, \"capability=clean\"], packet_txt_read()) ||\n-\tdie \"bad capability\";\n-packet_compare_lists([0, \"capability=smudge\"], packet_txt_read()) ||\n-\tdie \"bad capability\";\n-packet_compare_lists([0, \"capability=delay\"], packet_txt_read()) ||\n-\tdie \"bad capability\";\n-packet_compare_lists([1, \"\"], packet_bin_read()) ||\n-\tdie \"bad capability end\";\n-\n-foreach (@capabilities) {\n-\tpacket_txt_write( \"capability=\" . $_ );\n-}\n-packet_flush();\n+my %remote_caps = packet_read_and_check_capabilities(\"clean\", \"smudge\", \"delay\");\n+packet_check_and_write_capabilities(\\%remote_caps, @capabilities);\n+\n print $debug \"init handshake complete\\n\";\n $debug->flush();\n \n-- \n2.15.0.7.ga9ff306ed9.dirty\n\n"},{"id":"331889","messageId":"20171105213836.11717-7-chriscool@tuxfamily.org","threadId":"47123","inReplyTo":"20171105213836.11717-1-chriscool@tuxfamily.org","subject":"[PATCH v2 6/8] t0021/rot13-filter: refactor checking final lf","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-05T21:38:34Z","receivedAt":"2017-11-05T21:39:15Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"As checking for a lf character at the end of a buffer\nwill be useful in another function, let's refactor this\nfunctionality into a small remove_final_lf_or_die()\nhelper function.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t0021/rot13-filter.pl | 14 +++++++++++---\n 1 file changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl\nindex 2f74ab2e45..d47b7f5666 100644\n--- a/t/t0021/rot13-filter.pl\n+++ b/t/t0021/rot13-filter.pl\n@@ -93,12 +93,20 @@ sub packet_bin_read {\n \t}\n }\n \n-sub packet_txt_read {\n-\tmy ( $res, $buf ) = packet_bin_read();\n-\tunless ( $res == -1 or $buf eq '' or $buf =~ s/\\n$// ) {\n+sub remove_final_lf_or_die {\n+\tmy $buf = shift;\n+\tunless ( $buf =~ s/\\n$// ) {\n \t\tdie \"A non-binary line MUST be terminated by an LF.\\n\"\n \t\t    . \"Received: '$buf'\";\n \t}\n+\treturn $buf;\n+}\n+\n+sub packet_txt_read {\n+\tmy ( $res, $buf ) = packet_bin_read();\n+\tunless ( $res == -1 or $buf eq '' ) {\n+\t\t$buf = remove_final_lf_or_die($buf);\n+\t}\n \treturn ( $res, $buf );\n }\n \n-- \n2.15.0.7.ga9ff306ed9.dirty\n\n"},{"id":"331890","messageId":"20171105213836.11717-5-chriscool@tuxfamily.org","threadId":"47123","inReplyTo":"20171105213836.11717-1-chriscool@tuxfamily.org","subject":"[PATCH v2 4/8] t0021/rot13-filter: improve error message","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-05T21:38:32Z","receivedAt":"2017-11-05T21:39:17Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"If there is no new line at the end of something it receives,\nthe packet_txt_read() function die()s, but it's difficult to\ndebug without much context.\n\nLet's give a bit more information when that happens.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t0021/rot13-filter.pl | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl\nindex 37cecd8654..f31ff595fe 100644\n--- a/t/t0021/rot13-filter.pl\n+++ b/t/t0021/rot13-filter.pl\n@@ -96,7 +96,8 @@ sub packet_bin_read {\n sub packet_txt_read {\n \tmy ( $res, $buf ) = packet_bin_read();\n \tunless ( $res == -1 or $buf eq '' or $buf =~ s/\\n$// ) {\n-\t\tdie \"A non-binary line MUST be terminated by an LF.\";\n+\t\tdie \"A non-binary line MUST be terminated by an LF.\\n\"\n+\t\t    . \"Received: '$buf'\";\n \t}\n \treturn ( $res, $buf );\n }\n-- \n2.15.0.7.ga9ff306ed9.dirty\n\n"},{"id":"331958","messageId":"xmqqvaimhph3.fsf@gitster.mtv.corp.google.com","threadId":"47123","inReplyTo":"20171105213836.11717-2-chriscool@tuxfamily.org","subject":"Re: [PATCH v2 1/8] t0021/rot13-filter: fix list comparison","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-07T01:00:56Z","receivedAt":"2017-11-07T01:01:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> +sub packet_compare_lists {\n> +\tmy ($expect, @result) = @_;\n> +\tmy $ix;\n> +\tif (scalar @$expect != scalar @result) {\n> +\t\treturn undef;\n> +\t}\n> +\tfor ($ix = 0; $ix < $#result; $ix++) {\n> +\t\tif ($expect->[$ix] ne $result[$ix]) {\n> +\t\t\treturn undef;\n> +\t\t}\n> +\t}\n> +\treturn 1;\n> +}\n> +\n>  sub packet_bin_read {\n>  \tmy $buffer;\n>  \tmy $bytes_read = read STDIN, $buffer, 4;\n> @@ -110,18 +124,25 @@ sub packet_flush {\n>  print $debug \"START\\n\";\n>  $debug->flush();\n>  \n> -( packet_txt_read() eq ( 0, \"git-filter-client\" ) ) || die \"bad initialize\";\n> -( packet_txt_read() eq ( 0, \"version=2\" ) )         || die \"bad version\";\n> -( packet_bin_read() eq ( 1, \"\" ) )                  || die \"bad version end\";\n> +packet_compare_lists([0, \"git-filter-client\"], packet_txt_read()) ||\n> +\tdie \"bad initialize\";\n\nFor now this should do, but the \"packet_compare_lists\" may later\nwant to become more specific to the needs of these callers.  It\ntries to be a generic comparison function for list of strings, but\nwhat these callers feed is always two-element tuple, whose first\nelement is an integer (not just a random thing that can be made into\na string to be compared with \"ne\") and whose second element is a\nstring.\n\n"},{"id":"331960","messageId":"xmqqo9oehotn.fsf@gitster.mtv.corp.google.com","threadId":"47123","inReplyTo":"20171105213836.11717-3-chriscool@tuxfamily.org","subject":"Re: [PATCH v2 2/8] t0021/rot13-filter: refactor packet reading functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-07T01:15:00Z","receivedAt":"2017-11-07T01:15:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> +sub packet_required_key_val_read {\n> +\tmy ( $key ) = @_;\n> +\tmy ( $res, $buf ) = packet_txt_read();\n> +\tunless ( $res == -1 or ( $buf =~ s/^$key=// and $buf ne '' ) ) {\n> +\t\tdie \"bad $key: '$buf'\";\n> +\t}\n> +\treturn ( $res, $buf );\n> +}\n\nThe function calls itself \"required\", but it does not die when it\nsees an unexpected EOF or an empty line.  Neither of these cases\ngives it a key (nor val), but it is not treated as an error.\n\nThat is curious, isn't it?\n\nBy the way, is it just me who finds this \"unless\" even less\nunerstandable than the original in packet_txt_read() you modeled\nthis one after?  The original depended on packet_bin_read() to die\non an unexpected EOF, so its \"unless\" made some sense (we know we\ngot some input, and it is an error for the input not to end with LF\nunless it is an empty string).  Negating the condition and making it\n\"if\" may make it easier to understand, perhaps.  I dunno.\n"},{"id":"331961","messageId":"xmqqk1z2hon0.fsf@gitster.mtv.corp.google.com","threadId":"47123","inReplyTo":"20171105213836.11717-7-chriscool@tuxfamily.org","subject":"Re: [PATCH v2 6/8] t0021/rot13-filter: refactor checking final lf","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-07T01:18:59Z","receivedAt":"2017-11-07T01:19:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> As checking for a lf character at the end of a buffer\n> will be useful in another function, let's refactor this\n> functionality into a small remove_final_lf_or_die()\n> helper function.\n>\n> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n> ---\n>  t/t0021/rot13-filter.pl | 14 +++++++++++---\n>  1 file changed, 11 insertions(+), 3 deletions(-)\n>\n> diff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl\n> index 2f74ab2e45..d47b7f5666 100644\n> --- a/t/t0021/rot13-filter.pl\n> +++ b/t/t0021/rot13-filter.pl\n> @@ -93,12 +93,20 @@ sub packet_bin_read {\n>  \t}\n>  }\n>  \n> -sub packet_txt_read {\n> -\tmy ( $res, $buf ) = packet_bin_read();\n> -\tunless ( $res == -1 or $buf eq '' or $buf =~ s/\\n$// ) {\n> +sub remove_final_lf_or_die {\n> +\tmy $buf = shift;\n> +\tunless ( $buf =~ s/\\n$// ) {\n>  \t\tdie \"A non-binary line MUST be terminated by an LF.\\n\"\n>  \t\t    . \"Received: '$buf'\";\n>  \t}\n> +\treturn $buf;\n> +}\n> +\n> +sub packet_txt_read {\n> +\tmy ( $res, $buf ) = packet_bin_read();\n> +\tunless ( $res == -1 or $buf eq '' ) {\n> +\t\t$buf = remove_final_lf_or_die($buf);\n> +\t}\n\nAfter patch 2/8 I found the \"unless\" in packet_txt_read impossible\nto read, but this makes it a bit more understandable.\n\n"},{"id":"331962","messageId":"xmqqfu9qhoed.fsf@gitster.mtv.corp.google.com","threadId":"47123","inReplyTo":"20171105213836.11717-8-chriscool@tuxfamily.org","subject":"Re: [PATCH v2 7/8] t0021/rot13-filter: add capability functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-07T01:24:10Z","receivedAt":"2017-11-07T01:24:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n>  t/t0021/rot13-filter.pl | 58 ++++++++++++++++++++++++++++++++++++++-----------\n>  1 file changed, 45 insertions(+), 13 deletions(-)\n\nMakes sense.\n\n"},{"id":"331975","messageId":"CAP8UFD2vk4jV7jEBx3Axd-dhfcsGSJVFFt+pumdT1j8GD_oM_w@mail.gmail.com","threadId":"47123","inReplyTo":"xmqqo9oehotn.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/8] t0021/rot13-filter: refactor packet reading functions","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-11-07T06:34:48Z","receivedAt":"2017-11-07T06:34:54Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Tue, Nov 7, 2017 at 2:15 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Christian Couder <christian.couder@gmail.com> writes:\n>\n>> +sub packet_required_key_val_read {\n>> +     my ( $key ) = @_;\n>> +     my ( $res, $buf ) = packet_txt_read();\n>> +     unless ( $res == -1 or ( $buf =~ s/^$key=// and $buf ne '' ) ) {\n>> +             die \"bad $key: '$buf'\";\n>> +     }\n>> +     return ( $res, $buf );\n>> +}\n>\n> The function calls itself \"required\", but it does not die when it\n> sees an unexpected EOF or an empty line.\n\nIf $res is not -1, it will die if $buf is empty.\n\n> Neither of these cases\n> gives it a key (nor val), but it is not treated as an error.\n>\n> That is curious, isn't it?\n\nYeah it is a bit strange for the unexpected EOF case.\nI think I will remove \"required\" from the name and add a comment\nbefore the function.\n\n> By the way, is it just me who finds this \"unless\" even less\n> unerstandable than the original in packet_txt_read() you modeled\n> this one after?  The original depended on packet_bin_read() to die\n> on an unexpected EOF, so its \"unless\" made some sense (we know we\n> got some input, and it is an error for the input not to end with LF\n> unless it is an empty string).  Negating the condition and making it\n> \"if\" may make it easier to understand, perhaps.  I dunno.\n\nI can remove the \"unless\" and make it easier to understand like this:\n\n  if ( $res == -1 ) {\n          return ( $res, $buf );\n  }\n  if ( $buf =~ s/^$key=// and $buf ne '' ) ) {\n          return ( $res, $buf );\n  }\n  die \"bad $key: '$buf'\";\n\nOr to keep it short just:\n\n  if ( $res == -1 or ( $buf =~ s/^$key=// and $buf ne '' ) ) {\n          return ( $res, $buf );\n  }\n  die \"bad $key: '$buf'\";\n"}]}