]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/ls-tree.c
repository: remove unnecessary include of path.h
[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"
cbd53a21 11#include "object-store.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;
53 int chomp_prefix;
54 const char *ls_tree_prefix;
55 const char *format;
56};
57
58struct show_tree_data {
65d1f6c9 59 struct ls_tree_options *options;
030a3d5d
ÆAB
60 unsigned mode;
61 enum object_type type;
62 const struct object_id *oid;
63 const char *pathname;
64 struct strbuf *base;
65};
66
455923e0
ÆAB
67static size_t expand_show_tree(struct strbuf *sb, const char *start,
68 void *context)
69{
65d1f6c9
ÆAB
70 struct show_tree_data *data = context;
71 struct ls_tree_options *options = data->options;
455923e0
ÆAB
72 const char *end;
73 const char *p;
74 unsigned int errlen;
75 size_t len = strbuf_expand_literal_cb(sb, start, NULL);
76
77 if (len)
78 return len;
79 if (*start != '(')
80 die(_("bad ls-tree format: element '%s' does not start with '('"), start);
81
82 end = strchr(start + 1, ')');
83 if (!end)
84 die(_("bad ls-tree format: element '%s' does not end in ')'"), start);
85
86 len = end - start + 1;
87 if (skip_prefix(start, "(objectmode)", &p)) {
88 strbuf_addf(sb, "%06o", data->mode);
89 } else if (skip_prefix(start, "(objecttype)", &p)) {
90 strbuf_addstr(sb, type_name(data->type));
91 } else if (skip_prefix(start, "(objectsize:padded)", &p)) {
92 expand_objectsize(sb, data->oid, data->type, 1);
93 } else if (skip_prefix(start, "(objectsize)", &p)) {
94 expand_objectsize(sb, data->oid, data->type, 0);
95 } else if (skip_prefix(start, "(objectname)", &p)) {
030a3d5d 96 strbuf_add_unique_abbrev(sb, data->oid, options->abbrev);
455923e0
ÆAB
97 } else if (skip_prefix(start, "(path)", &p)) {
98 const char *name = data->base->buf;
030a3d5d 99 const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
455923e0 100 struct strbuf sbuf = STRBUF_INIT;
16fb5c54
RS
101 size_t baselen = data->base->len;
102
455923e0
ÆAB
103 strbuf_addstr(data->base, data->pathname);
104 name = relative_path(data->base->buf, prefix, &sbuf);
c388fcda 105 quote_c_style(name, sb, NULL, 0);
16fb5c54 106 strbuf_setlen(data->base, baselen);
455923e0 107 strbuf_release(&sbuf);
455923e0
ÆAB
108 } else {
109 errlen = (unsigned long)len;
110 die(_("bad ls-tree format: %%%.*s"), errlen, start);
111 }
112 return len;
113}
114
030a3d5d
ÆAB
115static int show_recursive(struct ls_tree_options *options, const char *base,
116 size_t baselen, const char *pathname)
0f8f45cb 117{
e1e24edc 118 int i;
0f8f45cb 119
030a3d5d 120 if (options->ls_options & LS_RECURSIVE)
0f8f45cb
LT
121 return 1;
122
030a3d5d 123 if (!options->pathspec.nr)
0f8f45cb
LT
124 return 0;
125
030a3d5d
ÆAB
126 for (i = 0; i < options->pathspec.nr; i++) {
127 const char *spec = options->pathspec.items[i].match;
132ceda4 128 size_t len, speclen;
0f8f45cb 129
0f8f45cb
LT
130 if (strncmp(base, spec, baselen))
131 continue;
132 len = strlen(pathname);
133 spec += baselen;
134 speclen = strlen(spec);
135 if (speclen <= len)
136 continue;
b294ed63
JH
137 if (spec[len] && spec[len] != '/')
138 continue;
0f8f45cb
LT
139 if (memcmp(pathname, spec, len))
140 continue;
141 return 1;
142 }
e1e24edc 143 return 0;
0f8f45cb 144}
aa1c48df 145
455923e0 146static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
030a3d5d 147 const char *pathname, unsigned mode, void *context)
6af1f019 148{
030a3d5d 149 struct ls_tree_options *options = context;
455923e0
ÆAB
150 int recurse = 0;
151 struct strbuf sb = STRBUF_INIT;
152 enum object_type type = object_type(mode);
65d1f6c9
ÆAB
153 struct show_tree_data cb_data = {
154 .options = options,
455923e0
ÆAB
155 .mode = mode,
156 .type = type,
157 .oid = oid,
158 .pathname = pathname,
159 .base = base,
160 };
161
030a3d5d 162 if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
455923e0 163 recurse = READ_TREE_RECURSIVE;
030a3d5d 164 if (type == OBJ_TREE && recurse && !(options->ls_options & LS_SHOW_TREES))
455923e0 165 return recurse;
030a3d5d 166 if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
f5984671 167 return 0;
ab1630a3 168
030a3d5d 169 strbuf_expand(&sb, options->format, expand_show_tree, &cb_data);
e6c75d8d 170 strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
455923e0
ÆAB
171 fwrite(sb.buf, sb.len, 1, stdout);
172 strbuf_release(&sb);
455923e0
ÆAB
173 return recurse;
174}
175
030a3d5d
ÆAB
176static int show_tree_common(struct ls_tree_options *options, int *recurse,
177 struct strbuf *base, const char *pathname,
178 enum object_type type)
315f22c8 179{
9c4d58ff 180 int ret = -1;
9c4d58ff 181 *recurse = 0;
ab1630a3 182
87af0ddf 183 if (type == OBJ_BLOB) {
030a3d5d 184 if (options->ls_options & LS_TREE_ONLY)
9c4d58ff 185 ret = 0;
87af0ddf 186 } else if (type == OBJ_TREE &&
030a3d5d 187 show_recursive(options, base->buf, base->len, pathname)) {
9c4d58ff 188 *recurse = READ_TREE_RECURSIVE;
030a3d5d 189 if (!(options->ls_options & LS_SHOW_TREES))
9c4d58ff 190 ret = *recurse;
6af1f019 191 }
ab1630a3 192
9c4d58ff
ÆAB
193 return ret;
194}
cab851c2 195
030a3d5d
ÆAB
196static void show_tree_common_default_long(struct ls_tree_options *options,
197 struct strbuf *base,
9c4d58ff
ÆAB
198 const char *pathname,
199 const size_t baselen)
200{
e6c75d8d
ÆAB
201 const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
202
9c4d58ff 203 strbuf_addstr(base, pathname);
e6c75d8d
ÆAB
204
205 if (options->null_termination) {
206 struct strbuf sb = STRBUF_INIT;
207 const char *name = relative_path(base->buf, prefix, &sb);
208
209 fputs(name, stdout);
210 fputc('\0', stdout);
211
212 strbuf_release(&sb);
213 } else {
214 write_name_quoted_relative(base->buf, prefix, stdout, '\n');
215 }
216
9c4d58ff
ÆAB
217 strbuf_setlen(base, baselen);
218}
219
220static int show_tree_default(const struct object_id *oid, struct strbuf *base,
221 const char *pathname, unsigned mode,
030a3d5d 222 void *context)
9c4d58ff 223{
030a3d5d 224 struct ls_tree_options *options = context;
9c4d58ff
ÆAB
225 int early;
226 int recurse;
7677417b 227 enum object_type type = object_type(mode);
9c4d58ff 228
030a3d5d 229 early = show_tree_common(options, &recurse, base, pathname, type);
9c4d58ff
ÆAB
230 if (early >= 0)
231 return early;
232
7677417b 233 printf("%06o %s %s\t", mode, type_name(object_type(mode)),
d850b7a5 234 repo_find_unique_abbrev(the_repository, oid, options->abbrev));
030a3d5d 235 show_tree_common_default_long(options, base, pathname, base->len);
9c4d58ff
ÆAB
236 return recurse;
237}
238
239static int show_tree_long(const struct object_id *oid, struct strbuf *base,
555ff1c8 240 const char *pathname, unsigned mode,
030a3d5d 241 void *context)
9c4d58ff 242{
030a3d5d 243 struct ls_tree_options *options = context;
9c4d58ff
ÆAB
244 int early;
245 int recurse;
9c4d58ff 246 char size_text[24];
7677417b 247 enum object_type type = object_type(mode);
9c4d58ff 248
030a3d5d 249 early = show_tree_common(options, &recurse, base, pathname, type);
9c4d58ff
ÆAB
250 if (early >= 0)
251 return early;
252
7677417b 253 if (type == OBJ_BLOB) {
9c4d58ff 254 unsigned long size;
7677417b 255 if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
9c4d58ff
ÆAB
256 xsnprintf(size_text, sizeof(size_text), "BAD");
257 else
258 xsnprintf(size_text, sizeof(size_text),
259 "%" PRIuMAX, (uintmax_t)size);
260 } else {
261 xsnprintf(size_text, sizeof(size_text), "-");
a5bbda8b 262 }
315f22c8 263
7677417b 264 printf("%06o %s %s %7s\t", mode, type_name(type),
d850b7a5
ÆAB
265 repo_find_unique_abbrev(the_repository, oid, options->abbrev),
266 size_text);
030a3d5d 267 show_tree_common_default_long(options, base, pathname, base->len);
350296cc 268 return recurse;
9c4d58ff 269}
315f22c8 270
9c4d58ff 271static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
555ff1c8 272 const char *pathname, unsigned mode,
030a3d5d 273 void *context)
9c4d58ff 274{
030a3d5d 275 struct ls_tree_options *options = context;
9c4d58ff
ÆAB
276 int early;
277 int recurse;
278 const size_t baselen = base->len;
7677417b 279 enum object_type type = object_type(mode);
e6c75d8d 280 const char *prefix;
9c4d58ff 281
030a3d5d 282 early = show_tree_common(options, &recurse, base, pathname, type);
9c4d58ff
ÆAB
283 if (early >= 0)
284 return early;
285
e6c75d8d 286 prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
1cf9952d 287 strbuf_addstr(base, pathname);
e6c75d8d
ÆAB
288 if (options->null_termination) {
289 struct strbuf sb = STRBUF_INIT;
290 const char *name = relative_path(base->buf, prefix, &sb);
291
292 fputs(name, stdout);
293 fputc('\0', stdout);
294
295 strbuf_release(&sb);
296 } else {
297 write_name_quoted_relative(base->buf, prefix, stdout, '\n');
298 }
1cf9952d 299 strbuf_setlen(base, baselen);
9c4d58ff
ÆAB
300 return recurse;
301}
302
303static int show_tree_object(const struct object_id *oid, struct strbuf *base,
555ff1c8 304 const char *pathname, unsigned mode,
030a3d5d 305 void *context)
9c4d58ff 306{
030a3d5d 307 struct ls_tree_options *options = context;
9c4d58ff
ÆAB
308 int early;
309 int recurse;
7677417b 310 enum object_type type = object_type(mode);
e6c75d8d 311 const char *str;
9c4d58ff 312
030a3d5d 313 early = show_tree_common(options, &recurse, base, pathname, type);
9c4d58ff
ÆAB
314 if (early >= 0)
315 return early;
316
d850b7a5 317 str = repo_find_unique_abbrev(the_repository, oid, options->abbrev);
e6c75d8d
ÆAB
318 if (options->null_termination) {
319 fputs(str, stdout);
320 fputc('\0', stdout);
321 } else {
322 puts(str);
323 }
889f7838 324 return recurse;
6af1f019 325}
0f2303f7 326
030a3d5d
ÆAB
327enum ls_tree_cmdmode {
328 MODE_DEFAULT = 0,
329 MODE_LONG,
330 MODE_NAME_ONLY,
331 MODE_NAME_STATUS,
332 MODE_OBJECT_ONLY,
333};
334
455923e0
ÆAB
335struct ls_tree_cmdmode_to_fmt {
336 enum ls_tree_cmdmode mode;
337 const char *const fmt;
9c4d58ff 338 read_tree_fn_t fn;
455923e0
ÆAB
339};
340
341static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
342 {
343 .mode = MODE_DEFAULT,
344 .fmt = "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
9c4d58ff 345 .fn = show_tree_default,
455923e0
ÆAB
346 },
347 {
348 .mode = MODE_LONG,
349 .fmt = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
9c4d58ff 350 .fn = show_tree_long,
455923e0
ÆAB
351 },
352 {
353 .mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
354 .fmt = "%(path)",
9c4d58ff 355 .fn = show_tree_name_only,
455923e0 356 },
cab851c2
TL
357 {
358 .mode = MODE_OBJECT_ONLY,
359 .fmt = "%(objectname)",
9c4d58ff
ÆAB
360 .fn = show_tree_object
361 },
362 {
363 /* fallback */
364 .fn = show_tree_default,
cab851c2 365 },
455923e0
ÆAB
366};
367
a633fca0 368int cmd_ls_tree(int argc, const char **argv, const char *prefix)
6af1f019 369{
a9b5f5bf 370 struct object_id oid;
521698b1 371 struct tree *tree;
f0096c06 372 int i, full_tree = 0;
9c4d58ff 373 read_tree_fn_t fn = NULL;
030a3d5d 374 enum ls_tree_cmdmode cmdmode = MODE_DEFAULT;
e6c75d8d
ÆAB
375 int null_termination = 0;
376 struct ls_tree_options options = { 0 };
61fdbcf9 377 const struct option ls_tree_options[] = {
030a3d5d 378 OPT_BIT('d', NULL, &options.ls_options, N_("only show trees"),
61fdbcf9 379 LS_TREE_ONLY),
030a3d5d 380 OPT_BIT('r', NULL, &options.ls_options, N_("recurse into subtrees"),
61fdbcf9 381 LS_RECURSIVE),
030a3d5d 382 OPT_BIT('t', NULL, &options.ls_options, N_("show trees when recursing"),
61fdbcf9 383 LS_SHOW_TREES),
e6c75d8d
ÆAB
384 OPT_BOOL('z', NULL, &null_termination,
385 N_("terminate entries with NUL byte")),
315f22c8
TL
386 OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
387 MODE_LONG),
388 OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
389 MODE_NAME_ONLY),
390 OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
0f887835 391 MODE_NAME_STATUS),
cab851c2
TL
392 OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
393 MODE_OBJECT_ONLY),
030a3d5d 394 OPT_SET_INT(0, "full-name", &options.chomp_prefix,
373f9221 395 N_("use full path names"), 0),
d5d09d47
SB
396 OPT_BOOL(0, "full-tree", &full_tree,
397 N_("list entire tree; not just current directory "
398 "(implies --full-name)")),
030a3d5d 399 OPT_STRING_F(0, "format", &options.format, N_("format"),
455923e0
ÆAB
400 N_("format to use for the output"),
401 PARSE_OPT_NONEG),
030a3d5d 402 OPT__ABBREV(&options.abbrev),
61fdbcf9
SB
403 OPT_END()
404 };
9c4d58ff 405 struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
030a3d5d 406 int ret;
7912c070 407
ef90d6d4 408 git_config(git_default_config, NULL);
030a3d5d 409 options.ls_tree_prefix = prefix;
9725c8dd 410 if (prefix)
030a3d5d 411 options.chomp_prefix = strlen(prefix);
61fdbcf9
SB
412
413 argc = parse_options(argc, argv, prefix, ls_tree_options,
414 ls_tree_usage, 0);
e6c75d8d
ÆAB
415 options.null_termination = null_termination;
416
61fdbcf9 417 if (full_tree) {
030a3d5d
ÆAB
418 options.ls_tree_prefix = prefix = NULL;
419 options.chomp_prefix = 0;
aa1c48df 420 }
0f887835
ÆAB
421 /*
422 * We wanted to detect conflicts between --name-only and
423 * --name-status, but once we're done with that subsequent
424 * code should only need to check the primary name.
425 */
426 if (cmdmode == MODE_NAME_STATUS)
427 cmdmode = MODE_NAME_ONLY;
428
f5984671
JH
429 /* -d -r should imply -t, but -d by itself should not have to. */
430 if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
030a3d5d
ÆAB
431 ((LS_TREE_ONLY|LS_RECURSIVE) & options.ls_options))
432 options.ls_options |= LS_SHOW_TREES;
aa1c48df 433
030a3d5d 434 if (options.format && cmdmode)
455923e0
ÆAB
435 usage_msg_opt(
436 _("--format can't be combined with other format-altering options"),
437 ls_tree_usage, ls_tree_options);
61fdbcf9
SB
438 if (argc < 1)
439 usage_with_options(ls_tree_usage, ls_tree_options);
d850b7a5 440 if (repo_get_oid(the_repository, argv[0], &oid))
61fdbcf9 441 die("Not a valid object name %s", argv[0]);
6af1f019 442
0fdc2ae5
NTND
443 /*
444 * show_recursive() rolls its own matching code and is
445 * generally ignorant of 'struct pathspec'. The magic mask
446 * cannot be lifted until it is converted to use
854b0959 447 * match_pathspec() or tree_entry_interesting()
0fdc2ae5 448 */
030a3d5d
ÆAB
449 parse_pathspec(&options.pathspec, PATHSPEC_ALL_MAGIC &
450 ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
0fdc2ae5
NTND
451 PATHSPEC_PREFER_CWD,
452 prefix, argv + 1);
030a3d5d
ÆAB
453 for (i = 0; i < options.pathspec.nr; i++)
454 options.pathspec.items[i].nowildcard_len = options.pathspec.items[i].len;
455 options.pathspec.has_wildcard = 0;
a9dbc179 456 tree = parse_tree_indirect(&oid);
521698b1 457 if (!tree)
3c5e8468 458 die("not a tree object");
455923e0
ÆAB
459 /*
460 * The generic show_tree_fmt() is slower than show_tree(), so
461 * take the fast path if possible.
462 */
9c4d58ff
ÆAB
463 while (m2f) {
464 if (!m2f->fmt) {
030a3d5d
ÆAB
465 fn = options.format ? show_tree_fmt : show_tree_default;
466 } else if (options.format && !strcmp(options.format, m2f->fmt)) {
455923e0 467 cmdmode = m2f->mode;
9c4d58ff 468 fn = m2f->fn;
030a3d5d 469 } else if (!options.format && cmdmode == m2f->mode) {
9c4d58ff
ÆAB
470 fn = m2f->fn;
471 } else {
472 m2f++;
473 continue;
455923e0 474 }
9c4d58ff 475 break;
455923e0
ÆAB
476 }
477
030a3d5d
ÆAB
478 ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options);
479 clear_pathspec(&options.pathspec);
480 return ret;
7912c070 481}