sideband.con commit {fetch,upload}-pack: sideband v2 fetch response (0bbc0bc)
   1#include "cache.h"
   2#include "color.h"
   3#include "config.h"
   4#include "sideband.h"
   5#include "help.h"
   6
   7struct keyword_entry {
   8        /*
   9         * We use keyword as config key so it should be a single alphanumeric word.
  10         */
  11        const char *keyword;
  12        char color[COLOR_MAXLEN];
  13};
  14
  15static struct keyword_entry keywords[] = {
  16        { "hint",       GIT_COLOR_YELLOW },
  17        { "warning",    GIT_COLOR_BOLD_YELLOW },
  18        { "success",    GIT_COLOR_BOLD_GREEN },
  19        { "error",      GIT_COLOR_BOLD_RED },
  20};
  21
  22/* Returns a color setting (GIT_COLOR_NEVER, etc). */
  23static int use_sideband_colors(void)
  24{
  25        static int use_sideband_colors_cached = -1;
  26
  27        const char *key = "color.remote";
  28        struct strbuf sb = STRBUF_INIT;
  29        char *value;
  30        int i;
  31
  32        if (use_sideband_colors_cached >= 0)
  33                return use_sideband_colors_cached;
  34
  35        if (!git_config_get_string(key, &value)) {
  36                use_sideband_colors_cached = git_config_colorbool(key, value);
  37        } else if (!git_config_get_string("color.ui", &value)) {
  38                use_sideband_colors_cached = git_config_colorbool("color.ui", value);
  39        } else {
  40                use_sideband_colors_cached = GIT_COLOR_AUTO;
  41        }
  42
  43        for (i = 0; i < ARRAY_SIZE(keywords); i++) {
  44                strbuf_reset(&sb);
  45                strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword);
  46                if (git_config_get_string(sb.buf, &value))
  47                        continue;
  48                if (color_parse(value, keywords[i].color))
  49                        continue;
  50        }
  51        strbuf_release(&sb);
  52        return use_sideband_colors_cached;
  53}
  54
  55void list_config_color_sideband_slots(struct string_list *list, const char *prefix)
  56{
  57        int i;
  58
  59        for (i = 0; i < ARRAY_SIZE(keywords); i++)
  60                list_config_item(list, prefix, keywords[i].keyword);
  61}
  62
  63/*
  64 * Optionally highlight one keyword in remote output if it appears at the start
  65 * of the line. This should be called for a single line only, which is
  66 * passed as the first N characters of the SRC array.
  67 *
  68 * NEEDSWORK: use "size_t n" instead for clarity.
  69 */
  70static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
  71{
  72        int i;
  73
  74        if (!want_color_stderr(use_sideband_colors())) {
  75                strbuf_add(dest, src, n);
  76                return;
  77        }
  78
  79        while (0 < n && isspace(*src)) {
  80                strbuf_addch(dest, *src);
  81                src++;
  82                n--;
  83        }
  84
  85        for (i = 0; i < ARRAY_SIZE(keywords); i++) {
  86                struct keyword_entry *p = keywords + i;
  87                int len = strlen(p->keyword);
  88
  89                if (n <= len)
  90                        continue;
  91                /*
  92                 * Match case insensitively, so we colorize output from existing
  93                 * servers regardless of the case that they use for their
  94                 * messages. We only highlight the word precisely, so
  95                 * "successful" stays uncolored.
  96                 */
  97                if (!strncasecmp(p->keyword, src, len) && !isalnum(src[len])) {
  98                        strbuf_addstr(dest, p->color);
  99                        strbuf_add(dest, src, len);
 100                        strbuf_addstr(dest, GIT_COLOR_RESET);
 101                        n -= len;
 102                        src += len;
 103                        break;
 104                }
 105        }
 106
 107        strbuf_add(dest, src, n);
 108}
 109
 110
 111#define DISPLAY_PREFIX "remote: "
 112
 113#define ANSI_SUFFIX "\033[K"
 114#define DUMB_SUFFIX "        "
 115
 116int demultiplex_sideband(const char *me, char *buf, int len,
 117                         int die_on_error,
 118                         struct strbuf *scratch,
 119                         enum sideband_type *sideband_type)
 120{
 121        static const char *suffix;
 122        const char *b, *brk;
 123        int band;
 124
 125        if (!suffix) {
 126                if (isatty(2) && !is_terminal_dumb())
 127                        suffix = ANSI_SUFFIX;
 128                else
 129                        suffix = DUMB_SUFFIX;
 130        }
 131
 132        if (len == 0) {
 133                *sideband_type = SIDEBAND_FLUSH;
 134                goto cleanup;
 135        }
 136        if (len < 1) {
 137                strbuf_addf(scratch,
 138                            "%s%s: protocol error: no band designator",
 139                            scratch->len ? "\n" : "", me);
 140                *sideband_type = SIDEBAND_PROTOCOL_ERROR;
 141                goto cleanup;
 142        }
 143        band = buf[0] & 0xff;
 144        buf[len] = '\0';
 145        len--;
 146        switch (band) {
 147        case 3:
 148                if (die_on_error)
 149                        die("remote error: %s", buf + 1);
 150                strbuf_addf(scratch, "%s%s", scratch->len ? "\n" : "",
 151                            DISPLAY_PREFIX);
 152                maybe_colorize_sideband(scratch, buf + 1, len);
 153
 154                *sideband_type = SIDEBAND_REMOTE_ERROR;
 155                break;
 156        case 2:
 157                b = buf + 1;
 158
 159                /*
 160                 * Append a suffix to each nonempty line to clear the
 161                 * end of the screen line.
 162                 *
 163                 * The output is accumulated in a buffer and
 164                 * each line is printed to stderr using
 165                 * write(2) to ensure inter-process atomicity.
 166                 */
 167                while ((brk = strpbrk(b, "\n\r"))) {
 168                        int linelen = brk - b;
 169
 170                        if (!scratch->len)
 171                                strbuf_addstr(scratch, DISPLAY_PREFIX);
 172                        if (linelen > 0) {
 173                                maybe_colorize_sideband(scratch, b, linelen);
 174                                strbuf_addstr(scratch, suffix);
 175                        }
 176
 177                        strbuf_addch(scratch, *brk);
 178                        xwrite(2, scratch->buf, scratch->len);
 179                        strbuf_reset(scratch);
 180
 181                        b = brk + 1;
 182                }
 183
 184                if (*b) {
 185                        strbuf_addstr(scratch, scratch->len ?
 186                                    "" : DISPLAY_PREFIX);
 187                        maybe_colorize_sideband(scratch, b, strlen(b));
 188                }
 189                return 0;
 190        case 1:
 191                *sideband_type = SIDEBAND_PRIMARY;
 192                break;
 193        default:
 194                strbuf_addf(scratch, "%s%s: protocol error: bad band #%d",
 195                            scratch->len ? "\n" : "", me, band);
 196                *sideband_type = SIDEBAND_PROTOCOL_ERROR;
 197                break;
 198        }
 199
 200cleanup:
 201        if (die_on_error && *sideband_type == SIDEBAND_PROTOCOL_ERROR)
 202                die("%s", scratch->buf);
 203        if (scratch->len) {
 204                strbuf_addch(scratch, '\n');
 205                xwrite(2, scratch->buf, scratch->len);
 206        }
 207        strbuf_release(scratch);
 208        return 1;
 209}
 210
 211/*
 212 * fd is connected to the remote side; send the sideband data
 213 * over multiplexed packet stream.
 214 */
 215void send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max)
 216{
 217        const char *p = data;
 218
 219        while (sz) {
 220                unsigned n;
 221                char hdr[5];
 222
 223                n = sz;
 224                if (packet_max - 5 < n)
 225                        n = packet_max - 5;
 226                if (0 <= band) {
 227                        xsnprintf(hdr, sizeof(hdr), "%04x", n + 5);
 228                        hdr[4] = band;
 229                        write_or_die(fd, hdr, 5);
 230                } else {
 231                        xsnprintf(hdr, sizeof(hdr), "%04x", n + 4);
 232                        write_or_die(fd, hdr, 4);
 233                }
 234                write_or_die(fd, p, n);
 235                p += n;
 236                sz -= n;
 237        }
 238}