git
/
sideband.c
285 строк · 7.0 Кб
1#define USE_THE_REPOSITORY_VARIABLE2
3#include "git-compat-util.h"4#include "color.h"5#include "config.h"6#include "editor.h"7#include "gettext.h"8#include "sideband.h"9#include "help.h"10#include "pkt-line.h"11#include "write-or-die.h"12
13struct keyword_entry {14/*15* We use keyword as config key so it should be a single alphanumeric word.
16*/
17const char *keyword;18char color[COLOR_MAXLEN];19};20
21static struct keyword_entry keywords[] = {22{ "hint", GIT_COLOR_YELLOW },23{ "warning", GIT_COLOR_BOLD_YELLOW },24{ "success", GIT_COLOR_BOLD_GREEN },25{ "error", GIT_COLOR_BOLD_RED },26};27
28/* Returns a color setting (GIT_COLOR_NEVER, etc). */
29static int use_sideband_colors(void)30{
31static int use_sideband_colors_cached = -1;32
33const char *key = "color.remote";34struct strbuf sb = STRBUF_INIT;35char *value;36int i;37
38if (use_sideband_colors_cached >= 0)39return use_sideband_colors_cached;40
41if (!git_config_get_string(key, &value)) {42use_sideband_colors_cached = git_config_colorbool(key, value);43} else if (!git_config_get_string("color.ui", &value)) {44use_sideband_colors_cached = git_config_colorbool("color.ui", value);45} else {46use_sideband_colors_cached = GIT_COLOR_AUTO;47}48
49for (i = 0; i < ARRAY_SIZE(keywords); i++) {50strbuf_reset(&sb);51strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword);52if (git_config_get_string(sb.buf, &value))53continue;54if (color_parse(value, keywords[i].color))55continue;56}57strbuf_release(&sb);58return use_sideband_colors_cached;59}
60
61void list_config_color_sideband_slots(struct string_list *list, const char *prefix)62{
63int i;64
65for (i = 0; i < ARRAY_SIZE(keywords); i++)66list_config_item(list, prefix, keywords[i].keyword);67}
68
69/*
70* Optionally highlight one keyword in remote output if it appears at the start
71* of the line. This should be called for a single line only, which is
72* passed as the first N characters of the SRC array.
73*
74* It is fine to use "int n" here instead of "size_t n" as all calls to this
75* function pass an 'int' parameter. Additionally, the buffer involved in
76* storing these 'int' values takes input from a packet via the pkt-line
77* interface, which is capable of transferring only 64kB at a time.
78*/
79static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)80{
81int i;82
83if (!want_color_stderr(use_sideband_colors())) {84strbuf_add(dest, src, n);85return;86}87
88while (0 < n && isspace(*src)) {89strbuf_addch(dest, *src);90src++;91n--;92}93
94for (i = 0; i < ARRAY_SIZE(keywords); i++) {95struct keyword_entry *p = keywords + i;96int len = strlen(p->keyword);97
98if (n < len)99continue;100/*101* Match case insensitively, so we colorize output from existing
102* servers regardless of the case that they use for their
103* messages. We only highlight the word precisely, so
104* "successful" stays uncolored.
105*/
106if (!strncasecmp(p->keyword, src, len) &&107(len == n || !isalnum(src[len]))) {108strbuf_addstr(dest, p->color);109strbuf_add(dest, src, len);110strbuf_addstr(dest, GIT_COLOR_RESET);111n -= len;112src += len;113break;114}115}116
117strbuf_add(dest, src, n);118}
119
120
121#define DISPLAY_PREFIX "remote: "122
123#define ANSI_SUFFIX "\033[K"124#define DUMB_SUFFIX " "125
126int demultiplex_sideband(const char *me, int status,127char *buf, int len,128int die_on_error,129struct strbuf *scratch,130enum sideband_type *sideband_type)131{
132static const char *suffix;133const char *b, *brk;134int band;135
136if (!suffix) {137if (isatty(2) && !is_terminal_dumb())138suffix = ANSI_SUFFIX;139else140suffix = DUMB_SUFFIX;141}142
143if (status == PACKET_READ_EOF) {144strbuf_addf(scratch,145"%s%s: unexpected disconnect while reading sideband packet",146scratch->len ? "\n" : "", me);147*sideband_type = SIDEBAND_PROTOCOL_ERROR;148goto cleanup;149}150
151if (len < 0)152BUG("negative length on non-eof packet read");153
154if (len == 0) {155if (status == PACKET_READ_NORMAL) {156strbuf_addf(scratch,157"%s%s: protocol error: missing sideband designator",158scratch->len ? "\n" : "", me);159*sideband_type = SIDEBAND_PROTOCOL_ERROR;160} else {161/* covers flush, delim, etc */162*sideband_type = SIDEBAND_FLUSH;163}164goto cleanup;165}166
167band = buf[0] & 0xff;168buf[len] = '\0';169len--;170switch (band) {171case 3:172if (die_on_error)173die(_("remote error: %s"), buf + 1);174strbuf_addf(scratch, "%s%s", scratch->len ? "\n" : "",175DISPLAY_PREFIX);176maybe_colorize_sideband(scratch, buf + 1, len);177
178*sideband_type = SIDEBAND_REMOTE_ERROR;179break;180case 2:181b = buf + 1;182
183/*184* Append a suffix to each nonempty line to clear the
185* end of the screen line.
186*
187* The output is accumulated in a buffer and
188* each line is printed to stderr using
189* write(2) to ensure inter-process atomicity.
190*/
191while ((brk = strpbrk(b, "\n\r"))) {192int linelen = brk - b;193
194/*195* For message accross packet boundary, there would have
196* a nonempty "scratch" buffer from last call of this
197* function, and there may have a leading CR/LF in "buf".
198* For this case we should add a clear-to-eol suffix to
199* clean leftover letters we previously have written on
200* the same line.
201*/
202if (scratch->len && !linelen)203strbuf_addstr(scratch, suffix);204
205if (!scratch->len)206strbuf_addstr(scratch, DISPLAY_PREFIX);207
208/*209* A use case that we should not add clear-to-eol suffix
210* to empty lines:
211*
212* For progress reporting we may receive a bunch of
213* percentage updates followed by '\r' to remain on the
214* same line, and at the end receive a single '\n' to
215* move to the next line. We should preserve the final
216* status report line by not appending clear-to-eol
217* suffix to this single line break.
218*/
219if (linelen > 0) {220maybe_colorize_sideband(scratch, b, linelen);221strbuf_addstr(scratch, suffix);222}223
224strbuf_addch(scratch, *brk);225write_in_full(2, scratch->buf, scratch->len);226strbuf_reset(scratch);227
228b = brk + 1;229}230
231if (*b) {232strbuf_addstr(scratch, scratch->len ?233"" : DISPLAY_PREFIX);234maybe_colorize_sideband(scratch, b, strlen(b));235}236return 0;237case 1:238*sideband_type = SIDEBAND_PRIMARY;239return 1;240default:241strbuf_addf(scratch, "%s%s: protocol error: bad band #%d",242scratch->len ? "\n" : "", me, band);243*sideband_type = SIDEBAND_PROTOCOL_ERROR;244break;245}246
247cleanup:248if (die_on_error && *sideband_type == SIDEBAND_PROTOCOL_ERROR)249die("%s", scratch->buf);250if (scratch->len) {251strbuf_addch(scratch, '\n');252write_in_full(2, scratch->buf, scratch->len);253}254strbuf_release(scratch);255return 1;256}
257
258/*
259* fd is connected to the remote side; send the sideband data
260* over multiplexed packet stream.
261*/
262void send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max)263{
264const char *p = data;265
266while (sz) {267unsigned n;268char hdr[5];269
270n = sz;271if (packet_max - 5 < n)272n = packet_max - 5;273if (0 <= band) {274xsnprintf(hdr, sizeof(hdr), "%04x", n + 5);275hdr[4] = band;276write_or_die(fd, hdr, 5);277} else {278xsnprintf(hdr, sizeof(hdr), "%04x", n + 4);279write_or_die(fd, hdr, 4);280}281write_or_die(fd, p, n);282p += n;283sz -= n;284}285}
286