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