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