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