git

Форк
0
/
interpret-trailers.c 
242 строки · 6.8 Кб
1
/*
2
 * Builtin "git interpret-trailers"
3
 *
4
 * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
5
 *
6
 */
7

8
#include "builtin.h"
9
#include "gettext.h"
10
#include "parse-options.h"
11
#include "string-list.h"
12
#include "tempfile.h"
13
#include "trailer.h"
14
#include "config.h"
15

16
static const char * const git_interpret_trailers_usage[] = {
17
	N_("git interpret-trailers [--in-place] [--trim-empty]\n"
18
	   "                       [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
19
	   "                       [--parse] [<file>...]"),
20
	NULL
21
};
22

23
static enum trailer_where where;
24
static enum trailer_if_exists if_exists;
25
static enum trailer_if_missing if_missing;
26

27
static int option_parse_where(const struct option *opt,
28
			      const char *arg, int unset UNUSED)
29
{
30
	/* unset implies NULL arg, which is handled in our helper */
31
	return trailer_set_where(opt->value, arg);
32
}
33

34
static int option_parse_if_exists(const struct option *opt,
35
				  const char *arg, int unset UNUSED)
36
{
37
	/* unset implies NULL arg, which is handled in our helper */
38
	return trailer_set_if_exists(opt->value, arg);
39
}
40

41
static int option_parse_if_missing(const struct option *opt,
42
				   const char *arg, int unset UNUSED)
43
{
44
	/* unset implies NULL arg, which is handled in our helper */
45
	return trailer_set_if_missing(opt->value, arg);
46
}
47

48
static void new_trailers_clear(struct list_head *trailers)
49
{
50
	struct list_head *pos, *tmp;
51
	struct new_trailer_item *item;
52

53
	list_for_each_safe(pos, tmp, trailers) {
54
		item = list_entry(pos, struct new_trailer_item, list);
55
		list_del(pos);
56
		free(item);
57
	}
58
}
59

60
static int option_parse_trailer(const struct option *opt,
61
				   const char *arg, int unset)
62
{
63
	struct list_head *trailers = opt->value;
64
	struct new_trailer_item *item;
65

66
	if (unset) {
67
		new_trailers_clear(trailers);
68
		return 0;
69
	}
70

71
	if (!arg)
72
		return -1;
73

74
	item = xmalloc(sizeof(*item));
75
	item->text = arg;
76
	item->where = where;
77
	item->if_exists = if_exists;
78
	item->if_missing = if_missing;
79
	list_add_tail(&item->list, trailers);
80
	return 0;
81
}
82

83
static int parse_opt_parse(const struct option *opt, const char *arg,
84
			   int unset)
85
{
86
	struct process_trailer_options *v = opt->value;
87
	v->only_trailers = 1;
88
	v->only_input = 1;
89
	v->unfold = 1;
90
	BUG_ON_OPT_NEG(unset);
91
	BUG_ON_OPT_ARG(arg);
92
	return 0;
93
}
94

95
static struct tempfile *trailers_tempfile;
96

97
static FILE *create_in_place_tempfile(const char *file)
98
{
99
	struct stat st;
100
	struct strbuf filename_template = STRBUF_INIT;
101
	const char *tail;
102
	FILE *outfile;
103

104
	if (stat(file, &st))
105
		die_errno(_("could not stat %s"), file);
106
	if (!S_ISREG(st.st_mode))
107
		die(_("file %s is not a regular file"), file);
108
	if (!(st.st_mode & S_IWUSR))
109
		die(_("file %s is not writable by user"), file);
110

111
	/* Create temporary file in the same directory as the original */
112
	tail = strrchr(file, '/');
113
	if (tail)
114
		strbuf_add(&filename_template, file, tail - file + 1);
115
	strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
116

117
	trailers_tempfile = xmks_tempfile_m(filename_template.buf, st.st_mode);
118
	strbuf_release(&filename_template);
119
	outfile = fdopen_tempfile(trailers_tempfile, "w");
120
	if (!outfile)
121
		die_errno(_("could not open temporary file"));
122

123
	return outfile;
124
}
125

126
static void read_input_file(struct strbuf *sb, const char *file)
127
{
128
	if (file) {
129
		if (strbuf_read_file(sb, file, 0) < 0)
130
			die_errno(_("could not read input file '%s'"), file);
131
	} else {
132
		if (strbuf_read(sb, fileno(stdin), 0) < 0)
133
			die_errno(_("could not read from stdin"));
134
	}
135
}
136

137
static void interpret_trailers(const struct process_trailer_options *opts,
138
			       struct list_head *new_trailer_head,
139
			       const char *file)
140
{
141
	LIST_HEAD(head);
142
	struct strbuf sb = STRBUF_INIT;
143
	struct strbuf trailer_block = STRBUF_INIT;
144
	struct trailer_info *info;
145
	FILE *outfile = stdout;
146

147
	trailer_config_init();
148

149
	read_input_file(&sb, file);
150

151
	if (opts->in_place)
152
		outfile = create_in_place_tempfile(file);
153

154
	info = parse_trailers(opts, sb.buf, &head);
155

156
	/* Print the lines before the trailers */
157
	if (!opts->only_trailers)
158
		fwrite(sb.buf, 1, trailer_block_start(info), outfile);
159

160
	if (!opts->only_trailers && !blank_line_before_trailer_block(info))
161
		fprintf(outfile, "\n");
162

163

164
	if (!opts->only_input) {
165
		LIST_HEAD(config_head);
166
		LIST_HEAD(arg_head);
167
		parse_trailers_from_config(&config_head);
168
		parse_trailers_from_command_line_args(&arg_head, new_trailer_head);
169
		list_splice(&config_head, &arg_head);
170
		process_trailers_lists(&head, &arg_head);
171
	}
172

173
	/* Print trailer block. */
174
	format_trailers(opts, &head, &trailer_block);
175
	free_trailers(&head);
176
	fwrite(trailer_block.buf, 1, trailer_block.len, outfile);
177
	strbuf_release(&trailer_block);
178

179
	/* Print the lines after the trailers as is */
180
	if (!opts->only_trailers)
181
		fwrite(sb.buf + trailer_block_end(info), 1, sb.len - trailer_block_end(info), outfile);
182
	trailer_info_release(info);
183

184
	if (opts->in_place)
185
		if (rename_tempfile(&trailers_tempfile, file))
186
			die_errno(_("could not rename temporary file to %s"), file);
187

188
	strbuf_release(&sb);
189
}
190

191
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
192
{
193
	struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
194
	LIST_HEAD(trailers);
195

196
	struct option options[] = {
197
		OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")),
198
		OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),
199

200
		OPT_CALLBACK(0, "where", &where, N_("placement"),
201
			     N_("where to place the new trailer"), option_parse_where),
202
		OPT_CALLBACK(0, "if-exists", &if_exists, N_("action"),
203
			     N_("action if trailer already exists"), option_parse_if_exists),
204
		OPT_CALLBACK(0, "if-missing", &if_missing, N_("action"),
205
			     N_("action if trailer is missing"), option_parse_if_missing),
206

207
		OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")),
208
		OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply trailer.* configuration variables")),
209
		OPT_BOOL(0, "unfold", &opts.unfold, N_("reformat multiline trailer values as single-line values")),
210
		OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("alias for --only-trailers --only-input --unfold"),
211
			PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse),
212
		OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat \"---\" as the end of input")),
213
		OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
214
				N_("trailer(s) to add"), option_parse_trailer),
215
		OPT_END()
216
	};
217

218
	git_config(git_default_config, NULL);
219

220
	argc = parse_options(argc, argv, prefix, options,
221
			     git_interpret_trailers_usage, 0);
222

223
	if (opts.only_input && !list_empty(&trailers))
224
		usage_msg_opt(
225
			_("--trailer with --only-input does not make sense"),
226
			git_interpret_trailers_usage,
227
			options);
228

229
	if (argc) {
230
		int i;
231
		for (i = 0; i < argc; i++)
232
			interpret_trailers(&opts, &trailers, argv[i]);
233
	} else {
234
		if (opts.in_place)
235
			die(_("no input file given for in-place editing"));
236
		interpret_trailers(&opts, &trailers, NULL);
237
	}
238

239
	new_trailers_clear(&trailers);
240

241
	return 0;
242
}
243

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

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

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

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