X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fgit.git;a=blobdiff_plain;f=sideband.c;h=ef851113c44ee91e594734bf68567110b7ac8c6b;hp=325bf0e974ab9bd8c2c5b5483fbb619ac425531b;hb=ac140beebe11adbca5801c225e87802d706590c4;hpb=ba6f0905fdb9e65c1ac5fbc79c9a4ef0b59b3e68 diff --git a/sideband.c b/sideband.c index 325bf0e974..ef851113c4 100644 --- a/sideband.c +++ b/sideband.c @@ -1,106 +1,212 @@ #include "cache.h" -#include "pkt-line.h" +#include "color.h" +#include "config.h" #include "sideband.h" +#include "help.h" + +struct keyword_entry { + /* + * We use keyword as config key so it should be a single alphanumeric word. + */ + const char *keyword; + char color[COLOR_MAXLEN]; +}; + +static struct keyword_entry keywords[] = { + { "hint", GIT_COLOR_YELLOW }, + { "warning", GIT_COLOR_BOLD_YELLOW }, + { "success", GIT_COLOR_BOLD_GREEN }, + { "error", GIT_COLOR_BOLD_RED }, +}; + +/* Returns a color setting (GIT_COLOR_NEVER, etc). */ +static int use_sideband_colors(void) +{ + static int use_sideband_colors_cached = -1; + + const char *key = "color.remote"; + struct strbuf sb = STRBUF_INIT; + char *value; + int i; + + if (use_sideband_colors_cached >= 0) + return use_sideband_colors_cached; + + if (!git_config_get_string(key, &value)) { + use_sideband_colors_cached = git_config_colorbool(key, value); + } else if (!git_config_get_string("color.ui", &value)) { + use_sideband_colors_cached = git_config_colorbool("color.ui", value); + } else { + use_sideband_colors_cached = GIT_COLOR_AUTO; + } + + for (i = 0; i < ARRAY_SIZE(keywords); i++) { + strbuf_reset(&sb); + strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword); + if (git_config_get_string(sb.buf, &value)) + continue; + if (color_parse(value, keywords[i].color)) + continue; + } + strbuf_release(&sb); + return use_sideband_colors_cached; +} + +void list_config_color_sideband_slots(struct string_list *list, const char *prefix) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(keywords); i++) + list_config_item(list, prefix, keywords[i].keyword); +} /* - * Receive multiplexed output stream over git native protocol. - * in_stream is the input stream from the remote, which carries data - * in pkt_line format with band designator. Demultiplex it into out - * and err and return error appropriately. Band #1 carries the - * primary payload. Things coming over band #2 is not necessarily - * error; they are usually informative message on the standard error - * stream, aka "verbose"). A message over band #3 is a signal that - * the remote died unexpectedly. A flush() concludes the stream. + * Optionally highlight one keyword in remote output if it appears at the start + * of the line. This should be called for a single line only, which is + * passed as the first N characters of the SRC array. + * + * NEEDSWORK: use "size_t n" instead for clarity. */ +static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n) +{ + int i; + + if (!want_color_stderr(use_sideband_colors())) { + strbuf_add(dest, src, n); + return; + } + + while (0 < n && isspace(*src)) { + strbuf_addch(dest, *src); + src++; + n--; + } + + for (i = 0; i < ARRAY_SIZE(keywords); i++) { + struct keyword_entry *p = keywords + i; + int len = strlen(p->keyword); + + if (n < len) + continue; + /* + * Match case insensitively, so we colorize output from existing + * servers regardless of the case that they use for their + * messages. We only highlight the word precisely, so + * "successful" stays uncolored. + */ + if (!strncasecmp(p->keyword, src, len) && + (len == n || !isalnum(src[len]))) { + strbuf_addstr(dest, p->color); + strbuf_add(dest, src, len); + strbuf_addstr(dest, GIT_COLOR_RESET); + n -= len; + src += len; + break; + } + } + + strbuf_add(dest, src, n); +} + #define DISPLAY_PREFIX "remote: " #define ANSI_SUFFIX "\033[K" #define DUMB_SUFFIX " " -int recv_sideband(const char *me, int in_stream, int out) +int demultiplex_sideband(const char *me, char *buf, int len, + int die_on_error, + struct strbuf *scratch, + enum sideband_type *sideband_type) { - const char *suffix; - char buf[LARGE_PACKET_MAX + 1]; - struct strbuf outbuf = STRBUF_INIT; - int retval = 0; - - if (isatty(2) && !is_terminal_dumb()) - suffix = ANSI_SUFFIX; - else - suffix = DUMB_SUFFIX; - - while (!retval) { - const char *b, *brk; - int band, len; - len = packet_read(in_stream, NULL, NULL, buf, LARGE_PACKET_MAX, 0); - if (len == 0) - break; - if (len < 1) { - strbuf_addf(&outbuf, - "%s%s: protocol error: no band designator", - outbuf.len ? "\n" : "", me); - retval = SIDEBAND_PROTOCOL_ERROR; - break; - } - band = buf[0] & 0xff; - buf[len] = '\0'; - len--; - switch (band) { - case 3: - strbuf_addf(&outbuf, "%s%s%s", outbuf.len ? "\n" : "", - DISPLAY_PREFIX, buf + 1); - retval = SIDEBAND_REMOTE_ERROR; - break; - case 2: - b = buf + 1; - - /* - * Append a suffix to each nonempty line to clear the - * end of the screen line. - * - * The output is accumulated in a buffer and - * each line is printed to stderr using - * write(2) to ensure inter-process atomicity. - */ - while ((brk = strpbrk(b, "\n\r"))) { - int linelen = brk - b; - - if (!outbuf.len) - strbuf_addstr(&outbuf, DISPLAY_PREFIX); - if (linelen > 0) { - strbuf_addf(&outbuf, "%.*s%s%c", - linelen, b, suffix, *brk); - } else { - strbuf_addch(&outbuf, *brk); - } - xwrite(2, outbuf.buf, outbuf.len); - strbuf_reset(&outbuf); - - b = brk + 1; + static const char *suffix; + const char *b, *brk; + int band; + + if (!suffix) { + if (isatty(2) && !is_terminal_dumb()) + suffix = ANSI_SUFFIX; + else + suffix = DUMB_SUFFIX; + } + + if (len == 0) { + *sideband_type = SIDEBAND_FLUSH; + goto cleanup; + } + if (len < 1) { + strbuf_addf(scratch, + "%s%s: protocol error: no band designator", + scratch->len ? "\n" : "", me); + *sideband_type = SIDEBAND_PROTOCOL_ERROR; + goto cleanup; + } + band = buf[0] & 0xff; + buf[len] = '\0'; + len--; + switch (band) { + case 3: + if (die_on_error) + die("remote error: %s", buf + 1); + strbuf_addf(scratch, "%s%s", scratch->len ? "\n" : "", + DISPLAY_PREFIX); + maybe_colorize_sideband(scratch, buf + 1, len); + + *sideband_type = SIDEBAND_REMOTE_ERROR; + break; + case 2: + b = buf + 1; + + /* + * Append a suffix to each nonempty line to clear the + * end of the screen line. + * + * The output is accumulated in a buffer and + * each line is printed to stderr using + * write(2) to ensure inter-process atomicity. + */ + while ((brk = strpbrk(b, "\n\r"))) { + int linelen = brk - b; + + if (!scratch->len) + strbuf_addstr(scratch, DISPLAY_PREFIX); + if (linelen > 0) { + maybe_colorize_sideband(scratch, b, linelen); + strbuf_addstr(scratch, suffix); } - if (*b) - strbuf_addf(&outbuf, "%s%s", outbuf.len ? - "" : DISPLAY_PREFIX, b); - break; - case 1: - write_or_die(out, buf + 1, len); - break; - default: - strbuf_addf(&outbuf, "%s%s: protocol error: bad band #%d", - outbuf.len ? "\n" : "", me, band); - retval = SIDEBAND_PROTOCOL_ERROR; - break; + strbuf_addch(scratch, *brk); + xwrite(2, scratch->buf, scratch->len); + strbuf_reset(scratch); + + b = brk + 1; + } + + if (*b) { + strbuf_addstr(scratch, scratch->len ? + "" : DISPLAY_PREFIX); + maybe_colorize_sideband(scratch, b, strlen(b)); } + return 0; + case 1: + *sideband_type = SIDEBAND_PRIMARY; + break; + default: + strbuf_addf(scratch, "%s%s: protocol error: bad band #%d", + scratch->len ? "\n" : "", me, band); + *sideband_type = SIDEBAND_PROTOCOL_ERROR; + break; } - if (outbuf.len) { - strbuf_addch(&outbuf, '\n'); - xwrite(2, outbuf.buf, outbuf.len); +cleanup: + if (die_on_error && *sideband_type == SIDEBAND_PROTOCOL_ERROR) + die("%s", scratch->buf); + if (scratch->len) { + strbuf_addch(scratch, '\n'); + xwrite(2, scratch->buf, scratch->len); } - strbuf_release(&outbuf); - return retval; + strbuf_release(scratch); + return 1; } /*