]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/ls-tree.c
Merge branch 'eg/config-type-path-docfix'
[thirdparty/git.git] / builtin / ls-tree.c
CommitLineData
7912c070
PB
1/*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
bc5c5ec0 6#include "builtin.h"
b2141fc1 7#include "config.h"
f394e093 8#include "gettext.h"
41771fa4 9#include "hex.h"
dabab1d6 10#include "object-name.h"
a034e910 11#include "object-store-ll.h"
6af1f019
JH
12#include "blob.h"
13#include "tree.h"
f35a6d3b 14#include "commit.h"
c339932b 15#include "path.h"
22ddf719 16#include "quote.h"
61fdbcf9 17#include "parse-options.h"
64acde94 18#include "pathspec.h"
7912c070 19
925a7c6b 20static const char * const ls_tree_usage[] = {
373f9221 21 N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
61fdbcf9
SB
22 NULL
23};
0f8f45cb 24
455923e0
ÆAB
25static 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
030a3d5d 44struct ls_tree_options {
e6c75d8d 45 unsigned null_termination:1;
030a3d5d
ÆAB
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;
7b7203e7 53 const char *prefix;
030a3d5d
ÆAB
54 const char *format;
55};
56
030a3d5d
ÆAB
57static int show_recursive(struct ls_tree_options *options, const char *base,
58 size_t baselen, const char *pathname)
0f8f45cb 59{
e1e24edc 60 int i;
0f8f45cb 61
030a3d5d 62 if (options->ls_options & LS_RECURSIVE)
0f8f45cb
LT
63 return 1;
64
030a3d5d 65 if (!options->pathspec.nr)
0f8f45cb
LT
66 return 0;
67
030a3d5d
ÆAB
68 for (i = 0; i < options->pathspec.nr; i++) {
69 const char *spec = options->pathspec.items[i].match;
132ceda4 70 size_t len, speclen;
0f8f45cb 71
0f8f45cb
LT
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;
b294ed63
JH
79 if (spec[len] && spec[len] != '/')
80 continue;
0f8f45cb
LT
81 if (memcmp(pathname, spec, len))
82 continue;
83 return 1;
84 }
e1e24edc 85 return 0;
0f8f45cb 86}
aa1c48df 87
455923e0 88static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
030a3d5d 89 const char *pathname, unsigned mode, void *context)
6af1f019 90{
030a3d5d 91 struct ls_tree_options *options = context;
455923e0
ÆAB
92 int recurse = 0;
93 struct strbuf sb = STRBUF_INIT;
94 enum object_type type = object_type(mode);
6f1e2d52 95 const char *format = options->format;
455923e0 96
030a3d5d 97 if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
455923e0 98 recurse = READ_TREE_RECURSIVE;
030a3d5d 99 if (type == OBJ_TREE && recurse && !(options->ls_options & LS_SHOW_TREES))
455923e0 100 return recurse;
030a3d5d 101 if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
f5984671 102 return 0;
ab1630a3 103
6f1e2d52
RS
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, '%');
4416b86c 110 else if ((len = strbuf_expand_literal(&sb, format)))
6f1e2d52
RS
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;
7b7203e7 130 const char *prefix = options->prefix;
6f1e2d52
RS
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 }
e6c75d8d 143 strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
455923e0
ÆAB
144 fwrite(sb.buf, sb.len, 1, stdout);
145 strbuf_release(&sb);
455923e0
ÆAB
146 return recurse;
147}
148
030a3d5d
ÆAB
149static int show_tree_common(struct ls_tree_options *options, int *recurse,
150 struct strbuf *base, const char *pathname,
151 enum object_type type)
315f22c8 152{
9c4d58ff 153 int ret = -1;
9c4d58ff 154 *recurse = 0;
ab1630a3 155
87af0ddf 156 if (type == OBJ_BLOB) {
030a3d5d 157 if (options->ls_options & LS_TREE_ONLY)
9c4d58ff 158 ret = 0;
87af0ddf 159 } else if (type == OBJ_TREE &&
030a3d5d 160 show_recursive(options, base->buf, base->len, pathname)) {
9c4d58ff 161 *recurse = READ_TREE_RECURSIVE;
030a3d5d 162 if (!(options->ls_options & LS_SHOW_TREES))
9c4d58ff 163 ret = *recurse;
6af1f019 164 }
ab1630a3 165
9c4d58ff
ÆAB
166 return ret;
167}
cab851c2 168
030a3d5d
ÆAB
169static void show_tree_common_default_long(struct ls_tree_options *options,
170 struct strbuf *base,
9c4d58ff
ÆAB
171 const char *pathname,
172 const size_t baselen)
173{
7b7203e7 174 const char *prefix = options->prefix;
e6c75d8d 175
9c4d58ff 176 strbuf_addstr(base, pathname);
e6c75d8d
ÆAB
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
9c4d58ff
ÆAB
190 strbuf_setlen(base, baselen);
191}
192
193static int show_tree_default(const struct object_id *oid, struct strbuf *base,
194 const char *pathname, unsigned mode,
030a3d5d 195 void *context)
9c4d58ff 196{
030a3d5d 197 struct ls_tree_options *options = context;
9c4d58ff
ÆAB
198 int early;
199 int recurse;
7677417b 200 enum object_type type = object_type(mode);
9c4d58ff 201
030a3d5d 202 early = show_tree_common(options, &recurse, base, pathname, type);
9c4d58ff
ÆAB
203 if (early >= 0)
204 return early;
205
7677417b 206 printf("%06o %s %s\t", mode, type_name(object_type(mode)),
d850b7a5 207 repo_find_unique_abbrev(the_repository, oid, options->abbrev));
030a3d5d 208 show_tree_common_default_long(options, base, pathname, base->len);
9c4d58ff
ÆAB
209 return recurse;
210}
211
212static int show_tree_long(const struct object_id *oid, struct strbuf *base,
555ff1c8 213 const char *pathname, unsigned mode,
030a3d5d 214 void *context)
9c4d58ff 215{
030a3d5d 216 struct ls_tree_options *options = context;
9c4d58ff
ÆAB
217 int early;
218 int recurse;
9c4d58ff 219 char size_text[24];
7677417b 220 enum object_type type = object_type(mode);
9c4d58ff 221
030a3d5d 222 early = show_tree_common(options, &recurse, base, pathname, type);
9c4d58ff
ÆAB
223 if (early >= 0)
224 return early;
225
7677417b 226 if (type == OBJ_BLOB) {
9c4d58ff 227 unsigned long size;
7677417b 228 if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
9c4d58ff
ÆAB
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), "-");
a5bbda8b 235 }
315f22c8 236
7677417b 237 printf("%06o %s %s %7s\t", mode, type_name(type),
d850b7a5
ÆAB
238 repo_find_unique_abbrev(the_repository, oid, options->abbrev),
239 size_text);
030a3d5d 240 show_tree_common_default_long(options, base, pathname, base->len);
350296cc 241 return recurse;
9c4d58ff 242}
315f22c8 243
c5cb97cb
JK
244static int show_tree_name_only(const struct object_id *oid UNUSED,
245 struct strbuf *base,
555ff1c8 246 const char *pathname, unsigned mode,
030a3d5d 247 void *context)
9c4d58ff 248{
030a3d5d 249 struct ls_tree_options *options = context;
9c4d58ff
ÆAB
250 int early;
251 int recurse;
252 const size_t baselen = base->len;
7677417b 253 enum object_type type = object_type(mode);
e6c75d8d 254 const char *prefix;
9c4d58ff 255
030a3d5d 256 early = show_tree_common(options, &recurse, base, pathname, type);
9c4d58ff
ÆAB
257 if (early >= 0)
258 return early;
259
7b7203e7 260 prefix = options->prefix;
1cf9952d 261 strbuf_addstr(base, pathname);
e6c75d8d
ÆAB
262 if (options->null_termination) {
263 struct strbuf sb = STRBUF_INIT;
264 const char *name = relative_path(base->buf, prefix, &sb);
265
266 fputs(name, stdout);
267 fputc('\0', stdout);
268
269 strbuf_release(&sb);
270 } else {
271 write_name_quoted_relative(base->buf, prefix, stdout, '\n');
272 }
1cf9952d 273 strbuf_setlen(base, baselen);
9c4d58ff
ÆAB
274 return recurse;
275}
276
277static int show_tree_object(const struct object_id *oid, struct strbuf *base,
555ff1c8 278 const char *pathname, unsigned mode,
030a3d5d 279 void *context)
9c4d58ff 280{
030a3d5d 281 struct ls_tree_options *options = context;
9c4d58ff
ÆAB
282 int early;
283 int recurse;
7677417b 284 enum object_type type = object_type(mode);
e6c75d8d 285 const char *str;
9c4d58ff 286
030a3d5d 287 early = show_tree_common(options, &recurse, base, pathname, type);
9c4d58ff
ÆAB
288 if (early >= 0)
289 return early;
290
d850b7a5 291 str = repo_find_unique_abbrev(the_repository, oid, options->abbrev);
e6c75d8d
ÆAB
292 if (options->null_termination) {
293 fputs(str, stdout);
294 fputc('\0', stdout);
295 } else {
296 puts(str);
297 }
889f7838 298 return recurse;
6af1f019 299}
0f2303f7 300
030a3d5d
ÆAB
301enum ls_tree_cmdmode {
302 MODE_DEFAULT = 0,
303 MODE_LONG,
304 MODE_NAME_ONLY,
305 MODE_NAME_STATUS,
306 MODE_OBJECT_ONLY,
307};
308
455923e0
ÆAB
309struct ls_tree_cmdmode_to_fmt {
310 enum ls_tree_cmdmode mode;
311 const char *const fmt;
9c4d58ff 312 read_tree_fn_t fn;
455923e0
ÆAB
313};
314
315static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
316 {
317 .mode = MODE_DEFAULT,
318 .fmt = "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
9c4d58ff 319 .fn = show_tree_default,
455923e0
ÆAB
320 },
321 {
322 .mode = MODE_LONG,
323 .fmt = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
9c4d58ff 324 .fn = show_tree_long,
455923e0
ÆAB
325 },
326 {
327 .mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
328 .fmt = "%(path)",
9c4d58ff 329 .fn = show_tree_name_only,
455923e0 330 },
cab851c2
TL
331 {
332 .mode = MODE_OBJECT_ONLY,
333 .fmt = "%(objectname)",
9c4d58ff
ÆAB
334 .fn = show_tree_object
335 },
336 {
337 /* fallback */
338 .fn = show_tree_default,
cab851c2 339 },
455923e0
ÆAB
340};
341
a633fca0 342int cmd_ls_tree(int argc, const char **argv, const char *prefix)
6af1f019 343{
a9b5f5bf 344 struct object_id oid;
521698b1 345 struct tree *tree;
f0096c06 346 int i, full_tree = 0;
991c5529 347 int full_name = !prefix || !*prefix;
9c4d58ff 348 read_tree_fn_t fn = NULL;
030a3d5d 349 enum ls_tree_cmdmode cmdmode = MODE_DEFAULT;
e6c75d8d
ÆAB
350 int null_termination = 0;
351 struct ls_tree_options options = { 0 };
61fdbcf9 352 const struct option ls_tree_options[] = {
030a3d5d 353 OPT_BIT('d', NULL, &options.ls_options, N_("only show trees"),
61fdbcf9 354 LS_TREE_ONLY),
030a3d5d 355 OPT_BIT('r', NULL, &options.ls_options, N_("recurse into subtrees"),
61fdbcf9 356 LS_RECURSIVE),
030a3d5d 357 OPT_BIT('t', NULL, &options.ls_options, N_("show trees when recursing"),
61fdbcf9 358 LS_SHOW_TREES),
e6c75d8d
ÆAB
359 OPT_BOOL('z', NULL, &null_termination,
360 N_("terminate entries with NUL byte")),
315f22c8
TL
361 OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
362 MODE_LONG),
363 OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
364 MODE_NAME_ONLY),
365 OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
0f887835 366 MODE_NAME_STATUS),
cab851c2
TL
367 OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
368 MODE_OBJECT_ONLY),
991c5529 369 OPT_BOOL(0, "full-name", &full_name, N_("use full path names")),
d5d09d47
SB
370 OPT_BOOL(0, "full-tree", &full_tree,
371 N_("list entire tree; not just current directory "
372 "(implies --full-name)")),
030a3d5d 373 OPT_STRING_F(0, "format", &options.format, N_("format"),
455923e0
ÆAB
374 N_("format to use for the output"),
375 PARSE_OPT_NONEG),
030a3d5d 376 OPT__ABBREV(&options.abbrev),
61fdbcf9
SB
377 OPT_END()
378 };
9c4d58ff 379 struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
030a3d5d 380 int ret;
7912c070 381
ef90d6d4 382 git_config(git_default_config, NULL);
61fdbcf9
SB
383
384 argc = parse_options(argc, argv, prefix, ls_tree_options,
385 ls_tree_usage, 0);
e6c75d8d
ÆAB
386 options.null_termination = null_termination;
387
7b7203e7
RS
388 if (full_tree)
389 prefix = NULL;
991c5529 390 options.prefix = full_name ? NULL : prefix;
7b7203e7 391
0f887835
ÆAB
392 /*
393 * We wanted to detect conflicts between --name-only and
394 * --name-status, but once we're done with that subsequent
395 * code should only need to check the primary name.
396 */
397 if (cmdmode == MODE_NAME_STATUS)
398 cmdmode = MODE_NAME_ONLY;
399
f5984671
JH
400 /* -d -r should imply -t, but -d by itself should not have to. */
401 if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
030a3d5d
ÆAB
402 ((LS_TREE_ONLY|LS_RECURSIVE) & options.ls_options))
403 options.ls_options |= LS_SHOW_TREES;
aa1c48df 404
030a3d5d 405 if (options.format && cmdmode)
455923e0
ÆAB
406 usage_msg_opt(
407 _("--format can't be combined with other format-altering options"),
408 ls_tree_usage, ls_tree_options);
61fdbcf9
SB
409 if (argc < 1)
410 usage_with_options(ls_tree_usage, ls_tree_options);
d850b7a5 411 if (repo_get_oid(the_repository, argv[0], &oid))
61fdbcf9 412 die("Not a valid object name %s", argv[0]);
6af1f019 413
0fdc2ae5
NTND
414 /*
415 * show_recursive() rolls its own matching code and is
416 * generally ignorant of 'struct pathspec'. The magic mask
417 * cannot be lifted until it is converted to use
854b0959 418 * match_pathspec() or tree_entry_interesting()
0fdc2ae5 419 */
030a3d5d
ÆAB
420 parse_pathspec(&options.pathspec, PATHSPEC_ALL_MAGIC &
421 ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
0fdc2ae5
NTND
422 PATHSPEC_PREFER_CWD,
423 prefix, argv + 1);
030a3d5d
ÆAB
424 for (i = 0; i < options.pathspec.nr; i++)
425 options.pathspec.items[i].nowildcard_len = options.pathspec.items[i].len;
426 options.pathspec.has_wildcard = 0;
a9dbc179 427 tree = parse_tree_indirect(&oid);
521698b1 428 if (!tree)
3c5e8468 429 die("not a tree object");
455923e0
ÆAB
430 /*
431 * The generic show_tree_fmt() is slower than show_tree(), so
432 * take the fast path if possible.
433 */
9c4d58ff
ÆAB
434 while (m2f) {
435 if (!m2f->fmt) {
030a3d5d
ÆAB
436 fn = options.format ? show_tree_fmt : show_tree_default;
437 } else if (options.format && !strcmp(options.format, m2f->fmt)) {
455923e0 438 cmdmode = m2f->mode;
9c4d58ff 439 fn = m2f->fn;
030a3d5d 440 } else if (!options.format && cmdmode == m2f->mode) {
9c4d58ff
ÆAB
441 fn = m2f->fn;
442 } else {
443 m2f++;
444 continue;
455923e0 445 }
9c4d58ff 446 break;
455923e0
ÆAB
447 }
448
030a3d5d
ÆAB
449 ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options);
450 clear_pathspec(&options.pathspec);
451 return ret;
7912c070 452}