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