Git fork
at reftables-rust 285 lines 7.3 kB view raw
1#define USE_THE_REPOSITORY_VARIABLE 2#define DISABLE_SIGN_COMPARE_WARNINGS 3 4#include "git-compat-util.h" 5#include "color.h" 6#include "config.h" 7#include "editor.h" 8#include "gettext.h" 9#include "sideband.h" 10#include "help.h" 11#include "pkt-line.h" 12#include "write-or-die.h" 13 14struct keyword_entry { 15 /* 16 * We use keyword as config key so it should be a single alphanumeric word. 17 */ 18 const char *keyword; 19 char color[COLOR_MAXLEN]; 20}; 21 22static struct keyword_entry keywords[] = { 23 { "hint", GIT_COLOR_YELLOW }, 24 { "warning", GIT_COLOR_BOLD_YELLOW }, 25 { "success", GIT_COLOR_BOLD_GREEN }, 26 { "error", GIT_COLOR_BOLD_RED }, 27}; 28 29/* Returns a color setting (GIT_COLOR_NEVER, etc). */ 30static enum git_colorbool use_sideband_colors(void) 31{ 32 static enum git_colorbool use_sideband_colors_cached = GIT_COLOR_UNKNOWN; 33 34 const char *key = "color.remote"; 35 struct strbuf sb = STRBUF_INIT; 36 const char *value; 37 int i; 38 39 if (use_sideband_colors_cached != GIT_COLOR_UNKNOWN) 40 return use_sideband_colors_cached; 41 42 if (!repo_config_get_string_tmp(the_repository, key, &value)) 43 use_sideband_colors_cached = git_config_colorbool(key, value); 44 else if (!repo_config_get_string_tmp(the_repository, "color.ui", &value)) 45 use_sideband_colors_cached = git_config_colorbool("color.ui", value); 46 else 47 use_sideband_colors_cached = GIT_COLOR_AUTO; 48 49 for (i = 0; i < ARRAY_SIZE(keywords); i++) { 50 strbuf_reset(&sb); 51 strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword); 52 if (repo_config_get_string_tmp(the_repository, sb.buf, &value)) 53 continue; 54 color_parse(value, keywords[i].color); 55 } 56 57 strbuf_release(&sb); 58 return use_sideband_colors_cached; 59} 60 61void list_config_color_sideband_slots(struct string_list *list, const char *prefix) 62{ 63 int i; 64 65 for (i = 0; i < ARRAY_SIZE(keywords); i++) 66 list_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{ 81 int i; 82 83 if (!want_color_stderr(use_sideband_colors())) { 84 strbuf_add(dest, src, n); 85 return; 86 } 87 88 while (0 < n && isspace(*src)) { 89 strbuf_addch(dest, *src); 90 src++; 91 n--; 92 } 93 94 for (i = 0; i < ARRAY_SIZE(keywords); i++) { 95 struct keyword_entry *p = keywords + i; 96 int len = strlen(p->keyword); 97 98 if (n < len) 99 continue; 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 */ 106 if (!strncasecmp(p->keyword, src, len) && 107 (len == n || !isalnum(src[len]))) { 108 strbuf_addstr(dest, p->color); 109 strbuf_add(dest, src, len); 110 strbuf_addstr(dest, GIT_COLOR_RESET); 111 n -= len; 112 src += len; 113 break; 114 } 115 } 116 117 strbuf_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, 127 char *buf, int len, 128 int die_on_error, 129 struct strbuf *scratch, 130 enum sideband_type *sideband_type) 131{ 132 static const char *suffix; 133 const char *b, *brk; 134 int band; 135 136 if (!suffix) { 137 if (isatty(2) && !is_terminal_dumb()) 138 suffix = ANSI_SUFFIX; 139 else 140 suffix = DUMB_SUFFIX; 141 } 142 143 if (status == PACKET_READ_EOF) { 144 strbuf_addf(scratch, 145 "%s%s: unexpected disconnect while reading sideband packet", 146 scratch->len ? "\n" : "", me); 147 *sideband_type = SIDEBAND_PROTOCOL_ERROR; 148 goto cleanup; 149 } 150 151 if (len < 0) 152 BUG("negative length on non-eof packet read"); 153 154 if (len == 0) { 155 if (status == PACKET_READ_NORMAL) { 156 strbuf_addf(scratch, 157 "%s%s: protocol error: missing sideband designator", 158 scratch->len ? "\n" : "", me); 159 *sideband_type = SIDEBAND_PROTOCOL_ERROR; 160 } else { 161 /* covers flush, delim, etc */ 162 *sideband_type = SIDEBAND_FLUSH; 163 } 164 goto cleanup; 165 } 166 167 band = buf[0] & 0xff; 168 buf[len] = '\0'; 169 len--; 170 switch (band) { 171 case 3: 172 if (die_on_error) 173 die(_("remote error: %s"), buf + 1); 174 strbuf_addf(scratch, "%s%s", scratch->len ? "\n" : "", 175 DISPLAY_PREFIX); 176 maybe_colorize_sideband(scratch, buf + 1, len); 177 178 *sideband_type = SIDEBAND_REMOTE_ERROR; 179 break; 180 case 2: 181 b = 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 */ 191 while ((brk = strpbrk(b, "\n\r"))) { 192 int linelen = brk - b; 193 194 /* 195 * For message across 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 */ 202 if (scratch->len && !linelen) 203 strbuf_addstr(scratch, suffix); 204 205 if (!scratch->len) 206 strbuf_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 */ 219 if (linelen > 0) { 220 maybe_colorize_sideband(scratch, b, linelen); 221 strbuf_addstr(scratch, suffix); 222 } 223 224 strbuf_addch(scratch, *brk); 225 write_in_full(2, scratch->buf, scratch->len); 226 strbuf_reset(scratch); 227 228 b = brk + 1; 229 } 230 231 if (*b) { 232 strbuf_addstr(scratch, scratch->len ? 233 "" : DISPLAY_PREFIX); 234 maybe_colorize_sideband(scratch, b, strlen(b)); 235 } 236 return 0; 237 case 1: 238 *sideband_type = SIDEBAND_PRIMARY; 239 return 1; 240 default: 241 strbuf_addf(scratch, "%s%s: protocol error: bad band #%d", 242 scratch->len ? "\n" : "", me, band); 243 *sideband_type = SIDEBAND_PROTOCOL_ERROR; 244 break; 245 } 246 247cleanup: 248 if (die_on_error && *sideband_type == SIDEBAND_PROTOCOL_ERROR) 249 die("%s", scratch->buf); 250 if (scratch->len) { 251 strbuf_addch(scratch, '\n'); 252 write_in_full(2, scratch->buf, scratch->len); 253 } 254 strbuf_release(scratch); 255 return 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{ 264 const char *p = data; 265 266 while (sz) { 267 unsigned n; 268 char hdr[5]; 269 270 n = sz; 271 if (packet_max - 5 < n) 272 n = packet_max - 5; 273 if (0 <= band) { 274 xsnprintf(hdr, sizeof(hdr), "%04x", n + 5); 275 hdr[4] = band; 276 write_or_die(fd, hdr, 5); 277 } else { 278 xsnprintf(hdr, sizeof(hdr), "%04x", n + 4); 279 write_or_die(fd, hdr, 4); 280 } 281 write_or_die(fd, p, n); 282 p += n; 283 sz -= n; 284 } 285}