git

Форк
0
/
sideband.c 
285 строк · 7.0 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

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

13
struct keyword_entry {
14
	/*
15
	 * We use keyword as config key so it should be a single alphanumeric word.
16
	 */
17
	const char *keyword;
18
	char color[COLOR_MAXLEN];
19
};
20

21
static 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). */
29
static int use_sideband_colors(void)
30
{
31
	static int use_sideband_colors_cached = -1;
32

33
	const char *key = "color.remote";
34
	struct strbuf sb = STRBUF_INIT;
35
	char *value;
36
	int i;
37

38
	if (use_sideband_colors_cached >= 0)
39
		return use_sideband_colors_cached;
40

41
	if (!git_config_get_string(key, &value)) {
42
		use_sideband_colors_cached = git_config_colorbool(key, value);
43
	} else if (!git_config_get_string("color.ui", &value)) {
44
		use_sideband_colors_cached = git_config_colorbool("color.ui", value);
45
	} else {
46
		use_sideband_colors_cached = GIT_COLOR_AUTO;
47
	}
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 (git_config_get_string(sb.buf, &value))
53
			continue;
54
		if (color_parse(value, keywords[i].color))
55
			continue;
56
	}
57
	strbuf_release(&sb);
58
	return use_sideband_colors_cached;
59
}
60

61
void 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
 */
79
static 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

126
int 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 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
			 */
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

247
cleanup:
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
 */
262
void 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
}
286

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.