]> git.ipfire.org Git - thirdparty/git.git/blob - builtin/ls-tree.c
Merge branch 'mp/rebase-label-length-limit' into maint-2.42
[thirdparty/git.git] / builtin / ls-tree.c
1 /*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
6 #include "builtin.h"
7 #include "config.h"
8 #include "gettext.h"
9 #include "hex.h"
10 #include "object-name.h"
11 #include "object-store-ll.h"
12 #include "blob.h"
13 #include "tree.h"
14 #include "commit.h"
15 #include "path.h"
16 #include "quote.h"
17 #include "parse-options.h"
18 #include "pathspec.h"
19
20 static const char * const ls_tree_usage[] = {
21 N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
22 NULL
23 };
24
25 static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
26 const enum object_type type, unsigned int padded)
27 {
28 if (type == OBJ_BLOB) {
29 unsigned long size;
30 if (oid_object_info(the_repository, oid, &size) < 0)
31 die(_("could not get object info about '%s'"),
32 oid_to_hex(oid));
33 if (padded)
34 strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
35 else
36 strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
37 } else if (padded) {
38 strbuf_addf(line, "%7s", "-");
39 } else {
40 strbuf_addstr(line, "-");
41 }
42 }
43
44 struct ls_tree_options {
45 unsigned null_termination:1;
46 int abbrev;
47 enum ls_tree_path_options {
48 LS_RECURSIVE = 1 << 0,
49 LS_TREE_ONLY = 1 << 1,
50 LS_SHOW_TREES = 1 << 2,
51 } ls_options;
52 struct pathspec pathspec;
53 const char *prefix;
54 const char *format;
55 };
56
57 static int show_recursive(struct ls_tree_options *options, const char *base,
58 size_t baselen, const char *pathname)
59 {
60 int i;
61
62 if (options->ls_options & LS_RECURSIVE)
63 return 1;
64
65 if (!options->pathspec.nr)
66 return 0;
67
68 for (i = 0; i < options->pathspec.nr; i++) {
69 const char *spec = options->pathspec.items[i].match;
70 size_t len, speclen;
71
72 if (strncmp(base, spec, baselen))
73 continue;
74 len = strlen(pathname);
75 spec += baselen;
76 speclen = strlen(spec);
77 if (speclen <= len)
78 continue;
79 if (spec[len] && spec[len] != '/')
80 continue;
81 if (memcmp(pathname, spec, len))
82 continue;
83 return 1;
84 }
85 return 0;
86 }
87
88 static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
89 const char *pathname, unsigned mode, void *context)
90 {
91 struct ls_tree_options *options = context;
92 int recurse = 0;
93 struct strbuf sb = STRBUF_INIT;
94 enum object_type type = object_type(mode);
95 const char *format = options->format;
96
97 if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
98 recurse = READ_TREE_RECURSIVE;
99 if (type == OBJ_TREE && recurse && !(options->ls_options & LS_SHOW_TREES))
100 return recurse;
101 if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
102 return 0;
103
104 while (strbuf_expand_step(&sb, &format)) {
105 const char *end;
106 size_t len;
107
108 if (skip_prefix(format, "%", &format))
109 strbuf_addch(&sb, '%');
110 else if ((len = strbuf_expand_literal(&sb, format)))
111 format += len;
112 else if (*format != '(')
113 die(_("bad ls-tree format: element '%s' "
114 "does not start with '('"), format);
115 else if (!(end = strchr(format + 1, ')')))
116 die(_("bad ls-tree format: element '%s' "
117 "does not end in ')'"), format);
118 else if (skip_prefix(format, "(objectmode)", &format))
119 strbuf_addf(&sb, "%06o", mode);
120 else if (skip_prefix(format, "(objecttype)", &format))
121 strbuf_addstr(&sb, type_name(type));
122 else if (skip_prefix(format, "(objectsize:padded)", &format))
123 expand_objectsize(&sb, oid, type, 1);
124 else if (skip_prefix(format, "(objectsize)", &format))
125 expand_objectsize(&sb, oid, type, 0);
126 else if (skip_prefix(format, "(objectname)", &format))
127 strbuf_add_unique_abbrev(&sb, oid, options->abbrev);
128 else if (skip_prefix(format, "(path)", &format)) {
129 const char *name;
130 const char *prefix = options->prefix;
131 struct strbuf sbuf = STRBUF_INIT;
132 size_t baselen = base->len;
133
134 strbuf_addstr(base, pathname);
135 name = relative_path(base->buf, prefix, &sbuf);
136 quote_c_style(name, &sb, NULL, 0);
137 strbuf_setlen(base, baselen);
138 strbuf_release(&sbuf);
139 } else
140 die(_("bad ls-tree format: %%%.*s"),
141 (int)(end - format + 1), format);
142 }
143 strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
144 fwrite(sb.buf, sb.len, 1, stdout);
145 strbuf_release(&sb);
146 return recurse;
147 }
148
149 static int show_tree_common(struct ls_tree_options *options, int *recurse,
150 struct strbuf *base, const char *pathname,
151 enum object_type type)
152 {
153 int ret = -1;
154 *recurse = 0;
155
156 if (type == OBJ_BLOB) {
157 if (options->ls_options & LS_TREE_ONLY)
158 ret = 0;
159 } else if (type == OBJ_TREE &&
160 show_recursive(options, base->buf, base->len, pathname)) {
161 *recurse = READ_TREE_RECURSIVE;
162 if (!(options->ls_options & LS_SHOW_TREES))
163 ret = *recurse;
164 }
165
166 return ret;
167 }
168
169 static void show_tree_common_default_long(struct ls_tree_options *options,
170 struct strbuf *base,
171 const char *pathname,
172 const size_t baselen)
173 {
174 const char *prefix = options->prefix;
175
176 strbuf_addstr(base, pathname);
177
178 if (options->null_termination) {
179 struct strbuf sb = STRBUF_INIT;
180 const char *name = relative_path(base->buf, prefix, &sb);
181
182 fputs(name, stdout);
183 fputc('\0', stdout);
184
185 strbuf_release(&sb);
186 } else {
187 write_name_quoted_relative(base->buf, prefix, stdout, '\n');
188 }
189
190 strbuf_setlen(base, baselen);
191 }
192
193 static int show_tree_default(const struct object_id *oid, struct strbuf *base,
194 const char *pathname, unsigned mode,
195 void *context)
196 {
197 struct ls_tree_options *options = context;
198 int early;
199 int recurse;
200 enum object_type type = object_type(mode);
201
202 early = show_tree_common(options, &recurse, base, pathname, type);
203 if (early >= 0)
204 return early;
205
206 printf("%06o %s %s\t", mode, type_name(object_type(mode)),
207 repo_find_unique_abbrev(the_repository, oid, options->abbrev));
208 show_tree_common_default_long(options, base, pathname, base->len);
209 return recurse;
210 }
211
212 static int show_tree_long(const struct object_id *oid, struct strbuf *base,
213 const char *pathname, unsigned mode,
214 void *context)
215 {
216 struct ls_tree_options *options = context;
217 int early;
218 int recurse;
219 char size_text[24];
220 enum object_type type = object_type(mode);
221
222 early = show_tree_common(options, &recurse, base, pathname, type);
223 if (early >= 0)
224 return early;
225
226 if (type == OBJ_BLOB) {
227 unsigned long size;
228 if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
229 xsnprintf(size_text, sizeof(size_text), "BAD");
230 else
231 xsnprintf(size_text, sizeof(size_text),
232 "%" PRIuMAX, (uintmax_t)size);
233 } else {
234 xsnprintf(size_text, sizeof(size_text), "-");
235 }
236
237 printf("%06o %s %s %7s\t", mode, type_name(type),
238 repo_find_unique_abbrev(the_repository, oid, options->abbrev),
239 size_text);
240 show_tree_common_default_long(options, base, pathname, base->len);
241 return recurse;
242 }
243
244 static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
245 const char *pathname, unsigned mode,
246 void *context)
247 {
248 struct ls_tree_options *options = context;
249 int early;
250 int recurse;
251 const size_t baselen = base->len;
252 enum object_type type = object_type(mode);
253 const char *prefix;
254
255 early = show_tree_common(options, &recurse, base, pathname, type);
256 if (early >= 0)
257 return early;
258
259 prefix = options->prefix;
260 strbuf_addstr(base, pathname);
261 if (options->null_termination) {
262 struct strbuf sb = STRBUF_INIT;
263 const char *name = relative_path(base->buf, prefix, &sb);
264
265 fputs(name, stdout);
266 fputc('\0', stdout);
267
268 strbuf_release(&sb);
269 } else {
270 write_name_quoted_relative(base->buf, prefix, stdout, '\n');
271 }
272 strbuf_setlen(base, baselen);
273 return recurse;
274 }
275
276 static int show_tree_object(const struct object_id *oid, struct strbuf *base,
277 const char *pathname, unsigned mode,
278 void *context)
279 {
280 struct ls_tree_options *options = context;
281 int early;
282 int recurse;
283 enum object_type type = object_type(mode);
284 const char *str;
285
286 early = show_tree_common(options, &recurse, base, pathname, type);
287 if (early >= 0)
288 return early;
289
290 str = repo_find_unique_abbrev(the_repository, oid, options->abbrev);
291 if (options->null_termination) {
292 fputs(str, stdout);
293 fputc('\0', stdout);
294 } else {
295 puts(str);
296 }
297 return recurse;
298 }
299
300 enum ls_tree_cmdmode {
301 MODE_DEFAULT = 0,
302 MODE_LONG,
303 MODE_NAME_ONLY,
304 MODE_NAME_STATUS,
305 MODE_OBJECT_ONLY,
306 };
307
308 struct ls_tree_cmdmode_to_fmt {
309 enum ls_tree_cmdmode mode;
310 const char *const fmt;
311 read_tree_fn_t fn;
312 };
313
314 static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
315 {
316 .mode = MODE_DEFAULT,
317 .fmt = "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
318 .fn = show_tree_default,
319 },
320 {
321 .mode = MODE_LONG,
322 .fmt = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
323 .fn = show_tree_long,
324 },
325 {
326 .mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
327 .fmt = "%(path)",
328 .fn = show_tree_name_only,
329 },
330 {
331 .mode = MODE_OBJECT_ONLY,
332 .fmt = "%(objectname)",
333 .fn = show_tree_object
334 },
335 {
336 /* fallback */
337 .fn = show_tree_default,
338 },
339 };
340
341 int cmd_ls_tree(int argc, const char **argv, const char *prefix)
342 {
343 struct object_id oid;
344 struct tree *tree;
345 int i, full_tree = 0;
346 int full_name = !prefix || !*prefix;
347 read_tree_fn_t fn = NULL;
348 enum ls_tree_cmdmode cmdmode = MODE_DEFAULT;
349 int null_termination = 0;
350 struct ls_tree_options options = { 0 };
351 const struct option ls_tree_options[] = {
352 OPT_BIT('d', NULL, &options.ls_options, N_("only show trees"),
353 LS_TREE_ONLY),
354 OPT_BIT('r', NULL, &options.ls_options, N_("recurse into subtrees"),
355 LS_RECURSIVE),
356 OPT_BIT('t', NULL, &options.ls_options, N_("show trees when recursing"),
357 LS_SHOW_TREES),
358 OPT_BOOL('z', NULL, &null_termination,
359 N_("terminate entries with NUL byte")),
360 OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
361 MODE_LONG),
362 OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
363 MODE_NAME_ONLY),
364 OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
365 MODE_NAME_STATUS),
366 OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
367 MODE_OBJECT_ONLY),
368 OPT_BOOL(0, "full-name", &full_name, N_("use full path names")),
369 OPT_BOOL(0, "full-tree", &full_tree,
370 N_("list entire tree; not just current directory "
371 "(implies --full-name)")),
372 OPT_STRING_F(0, "format", &options.format, N_("format"),
373 N_("format to use for the output"),
374 PARSE_OPT_NONEG),
375 OPT__ABBREV(&options.abbrev),
376 OPT_END()
377 };
378 struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
379 int ret;
380
381 git_config(git_default_config, NULL);
382
383 argc = parse_options(argc, argv, prefix, ls_tree_options,
384 ls_tree_usage, 0);
385 options.null_termination = null_termination;
386
387 if (full_tree)
388 prefix = NULL;
389 options.prefix = full_name ? NULL : prefix;
390
391 /*
392 * We wanted to detect conflicts between --name-only and
393 * --name-status, but once we're done with that subsequent
394 * code should only need to check the primary name.
395 */
396 if (cmdmode == MODE_NAME_STATUS)
397 cmdmode = MODE_NAME_ONLY;
398
399 /* -d -r should imply -t, but -d by itself should not have to. */
400 if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
401 ((LS_TREE_ONLY|LS_RECURSIVE) & options.ls_options))
402 options.ls_options |= LS_SHOW_TREES;
403
404 if (options.format && cmdmode)
405 usage_msg_opt(
406 _("--format can't be combined with other format-altering options"),
407 ls_tree_usage, ls_tree_options);
408 if (argc < 1)
409 usage_with_options(ls_tree_usage, ls_tree_options);
410 if (repo_get_oid(the_repository, argv[0], &oid))
411 die("Not a valid object name %s", argv[0]);
412
413 /*
414 * show_recursive() rolls its own matching code and is
415 * generally ignorant of 'struct pathspec'. The magic mask
416 * cannot be lifted until it is converted to use
417 * match_pathspec() or tree_entry_interesting()
418 */
419 parse_pathspec(&options.pathspec, PATHSPEC_ALL_MAGIC &
420 ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
421 PATHSPEC_PREFER_CWD,
422 prefix, argv + 1);
423 for (i = 0; i < options.pathspec.nr; i++)
424 options.pathspec.items[i].nowildcard_len = options.pathspec.items[i].len;
425 options.pathspec.has_wildcard = 0;
426 tree = parse_tree_indirect(&oid);
427 if (!tree)
428 die("not a tree object");
429 /*
430 * The generic show_tree_fmt() is slower than show_tree(), so
431 * take the fast path if possible.
432 */
433 while (m2f) {
434 if (!m2f->fmt) {
435 fn = options.format ? show_tree_fmt : show_tree_default;
436 } else if (options.format && !strcmp(options.format, m2f->fmt)) {
437 cmdmode = m2f->mode;
438 fn = m2f->fn;
439 } else if (!options.format && cmdmode == m2f->mode) {
440 fn = m2f->fn;
441 } else {
442 m2f++;
443 continue;
444 }
445 break;
446 }
447
448 ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options);
449 clear_pathspec(&options.pathspec);
450 return ret;
451 }