Git fork

Merge branch 'jx/sideband-chomp-newline-fix'

Sideband demultiplexer fixes.

* jx/sideband-chomp-newline-fix:
pkt-line: do not chomp newlines for sideband messages
pkt-line: memorize sideband fragment in reader
test-pkt-line: add option parser for unpack-sideband

+147 -10
+31 -5
pkt-line.c
··· 463 463 } 464 464 465 465 if ((options & PACKET_READ_CHOMP_NEWLINE) && 466 - len && buffer[len-1] == '\n') 467 - len--; 466 + len && buffer[len-1] == '\n') { 467 + if (options & PACKET_READ_USE_SIDEBAND) { 468 + int band = *buffer & 0xff; 469 + switch (band) { 470 + case 1: 471 + /* Chomp newline for payload */ 472 + len--; 473 + break; 474 + case 2: 475 + case 3: 476 + /* 477 + * Do not chomp newline for progress and error 478 + * message. 479 + */ 480 + break; 481 + default: 482 + /* 483 + * Bad sideband, let's leave it to 484 + * demultiplex_sideband() to catch this error. 485 + */ 486 + break; 487 + } 488 + } else { 489 + len--; 490 + } 491 + } 468 492 469 493 buffer[len] = 0; 470 494 if (options & PACKET_READ_REDACT_URI_PATH && ··· 593 617 reader->options = options; 594 618 reader->me = "git"; 595 619 reader->hash_algo = &hash_algos[GIT_HASH_SHA1]; 620 + strbuf_init(&reader->scratch, 0); 596 621 } 597 622 598 623 enum packet_read_status packet_reader_read(struct packet_reader *reader) 599 624 { 600 - struct strbuf scratch = STRBUF_INIT; 601 - 602 625 if (reader->line_peeked) { 603 626 reader->line_peeked = 0; 604 627 return reader->status; 605 628 } 629 + 630 + if (reader->use_sideband) 631 + reader->options |= PACKET_READ_USE_SIDEBAND; 606 632 607 633 /* 608 634 * Consume all progress packets until a primary payload packet is ··· 621 647 break; 622 648 if (demultiplex_sideband(reader->me, reader->status, 623 649 reader->buffer, reader->pktlen, 1, 624 - &scratch, &sideband_type)) 650 + &reader->scratch, &sideband_type)) 625 651 break; 626 652 } 627 653
+4
pkt-line.h
··· 84 84 #define PACKET_READ_DIE_ON_ERR_PACKET (1u<<2) 85 85 #define PACKET_READ_GENTLE_ON_READ_ERROR (1u<<3) 86 86 #define PACKET_READ_REDACT_URI_PATH (1u<<4) 87 + #define PACKET_READ_USE_SIDEBAND (1u<<5) 87 88 int packet_read(int fd, char *buffer, unsigned size, int options); 88 89 89 90 /* ··· 193 194 194 195 /* hash algorithm in use */ 195 196 const struct git_hash_algo *hash_algo; 197 + 198 + /* hold temporary sideband message */ 199 + struct strbuf scratch; 196 200 }; 197 201 198 202 /*
+54 -5
t/helper/test-pkt-line.c
··· 3 3 #include "pkt-line.h" 4 4 #include "sideband.h" 5 5 #include "write-or-die.h" 6 + #include "parse-options.h" 6 7 7 8 static void pack_line(const char *line) 8 9 { ··· 65 66 } 66 67 } 67 68 68 - static void unpack_sideband(void) 69 + static void unpack_sideband(int argc, const char **argv) 69 70 { 70 71 struct packet_reader reader; 71 - packet_reader_init(&reader, 0, NULL, 0, 72 - PACKET_READ_GENTLE_ON_EOF | 73 - PACKET_READ_CHOMP_NEWLINE); 72 + int options = PACKET_READ_GENTLE_ON_EOF; 73 + int chomp_newline = 1; 74 + int reader_use_sideband = 0; 75 + const char *const unpack_sideband_usage[] = { 76 + "test_tool unpack_sideband [options...]", NULL 77 + }; 78 + struct option cmd_options[] = { 79 + OPT_BOOL(0, "reader-use-sideband", &reader_use_sideband, 80 + "set use_sideband bit for packet reader (Default: off)"), 81 + OPT_BOOL(0, "chomp-newline", &chomp_newline, 82 + "chomp newline in packet (Default: on)"), 83 + OPT_END() 84 + }; 85 + 86 + argc = parse_options(argc, argv, "", cmd_options, unpack_sideband_usage, 87 + 0); 88 + if (argc > 0) 89 + usage_msg_opt(_("too many arguments"), unpack_sideband_usage, 90 + cmd_options); 91 + 92 + if (chomp_newline) 93 + options |= PACKET_READ_CHOMP_NEWLINE; 94 + packet_reader_init(&reader, 0, NULL, 0, options); 95 + reader.use_sideband = reader_use_sideband; 74 96 75 97 while (packet_reader_read(&reader) != PACKET_READ_EOF) { 76 98 int band; ··· 80 102 case PACKET_READ_EOF: 81 103 break; 82 104 case PACKET_READ_NORMAL: 105 + /* 106 + * When the "use_sideband" field of the reader is turned 107 + * on, sideband packets other than the payload have been 108 + * parsed and consumed in packet_reader_read(), and only 109 + * the payload arrives here. 110 + */ 111 + if (reader.use_sideband) { 112 + write_or_die(1, reader.line, reader.pktlen - 1); 113 + break; 114 + } 115 + 83 116 band = reader.line[0] & 0xff; 84 117 if (band < 1 || band > 2) 85 118 continue; /* skip non-sideband packets */ ··· 98 131 99 132 static int send_split_sideband(void) 100 133 { 134 + const char *foo = "Foo.\n"; 135 + const char *bar = "Bar.\n"; 101 136 const char *part1 = "Hello,"; 102 137 const char *primary = "\001primary: regular output\n"; 103 138 const char *part2 = " world!\n"; 104 139 140 + /* Each sideband message has a trailing newline character. */ 141 + send_sideband(1, 2, foo, strlen(foo), LARGE_PACKET_MAX); 142 + send_sideband(1, 2, bar, strlen(bar), LARGE_PACKET_MAX); 143 + 144 + /* 145 + * One sideband message is divided into part1 and part2 146 + * by the primary message. 147 + */ 105 148 send_sideband(1, 2, part1, strlen(part1), LARGE_PACKET_MAX); 106 149 packet_write(1, primary, strlen(primary)); 107 150 send_sideband(1, 2, part2, strlen(part2), LARGE_PACKET_MAX); 108 151 packet_response_end(1); 152 + 153 + /* 154 + * We use unpack_sideband() to consume packets. A flush packet 155 + * is required to end parsing. 156 + */ 157 + packet_flush(1); 109 158 110 159 return 0; 111 160 } ··· 127 176 else if (!strcmp(argv[1], "unpack")) 128 177 unpack(); 129 178 else if (!strcmp(argv[1], "unpack-sideband")) 130 - unpack_sideband(); 179 + unpack_sideband(argc - 1, argv + 1); 131 180 else if (!strcmp(argv[1], "send-split-sideband")) 132 181 send_split_sideband(); 133 182 else if (!strcmp(argv[1], "receive-sideband"))
+58
t/t0070-fundamental.sh
··· 53 53 test_grep "missing sideband" err 54 54 ' 55 55 56 + test_expect_success 'unpack-sideband: --no-chomp-newline' ' 57 + test_when_finished "rm -f expect-out expect-err" && 58 + test-tool pkt-line send-split-sideband >split-sideband && 59 + test-tool pkt-line unpack-sideband \ 60 + --no-chomp-newline <split-sideband >out 2>err && 61 + cat >expect-out <<-EOF && 62 + primary: regular output 63 + EOF 64 + cat >expect-err <<-EOF && 65 + Foo. 66 + Bar. 67 + Hello, world! 68 + EOF 69 + test_cmp expect-out out && 70 + test_cmp expect-err err 71 + ' 72 + 73 + test_expect_success 'unpack-sideband: --chomp-newline (default)' ' 74 + test_when_finished "rm -f expect-out expect-err" && 75 + test-tool pkt-line send-split-sideband >split-sideband && 76 + test-tool pkt-line unpack-sideband \ 77 + --chomp-newline <split-sideband >out 2>err && 78 + printf "primary: regular output" >expect-out && 79 + printf "Foo.Bar.Hello, world!" >expect-err && 80 + test_cmp expect-out out && 81 + test_cmp expect-err err 82 + ' 83 + 84 + test_expect_success 'unpack-sideband: packet_reader_read() consumes sideband, no chomp payload' ' 85 + test_when_finished "rm -f expect-out expect-err" && 86 + test-tool pkt-line send-split-sideband >split-sideband && 87 + test-tool pkt-line unpack-sideband \ 88 + --reader-use-sideband \ 89 + --no-chomp-newline <split-sideband >out 2>err && 90 + cat >expect-out <<-EOF && 91 + primary: regular output 92 + EOF 93 + printf "remote: Foo. \n" >expect-err && 94 + printf "remote: Bar. \n" >>expect-err && 95 + printf "remote: Hello, world! \n" >>expect-err && 96 + test_cmp expect-out out && 97 + test_cmp expect-err err 98 + ' 99 + 100 + test_expect_success 'unpack-sideband: packet_reader_read() consumes sideband, chomp payload' ' 101 + test_when_finished "rm -f expect-out expect-err" && 102 + test-tool pkt-line send-split-sideband >split-sideband && 103 + test-tool pkt-line unpack-sideband \ 104 + --reader-use-sideband \ 105 + --chomp-newline <split-sideband >out 2>err && 106 + printf "primary: regular output" >expect-out && 107 + printf "remote: Foo. \n" >expect-err && 108 + printf "remote: Bar. \n" >>expect-err && 109 + printf "remote: Hello, world! \n" >>expect-err && 110 + test_cmp expect-out out && 111 + test_cmp expect-err err 112 + ' 113 + 56 114 test_done