2 * GIT - The information manager from hell
4 * Copyright (C) Linus Torvalds, 2005
10 #include "object-store.h"
16 #include "parse-options.h"
19 static const char * const ls_tree_usage
[] = {
20 N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
24 static void expand_objectsize(struct strbuf
*line
, const struct object_id
*oid
,
25 const enum object_type type
, unsigned int padded
)
27 if (type
== OBJ_BLOB
) {
29 if (oid_object_info(the_repository
, oid
, &size
) < 0)
30 die(_("could not get object info about '%s'"),
33 strbuf_addf(line
, "%7"PRIuMAX
, (uintmax_t)size
);
35 strbuf_addf(line
, "%"PRIuMAX
, (uintmax_t)size
);
37 strbuf_addf(line
, "%7s", "-");
39 strbuf_addstr(line
, "-");
43 struct ls_tree_options
{
44 unsigned null_termination
:1;
46 enum ls_tree_path_options
{
47 LS_RECURSIVE
= 1 << 0,
48 LS_TREE_ONLY
= 1 << 1,
49 LS_SHOW_TREES
= 1 << 2,
51 struct pathspec pathspec
;
53 const char *ls_tree_prefix
;
57 struct show_tree_data
{
58 struct ls_tree_options
*options
;
60 enum object_type type
;
61 const struct object_id
*oid
;
66 static size_t expand_show_tree(struct strbuf
*sb
, const char *start
,
69 struct show_tree_data
*data
= context
;
70 struct ls_tree_options
*options
= data
->options
;
74 size_t len
= strbuf_expand_literal_cb(sb
, start
, NULL
);
79 die(_("bad ls-tree format: element '%s' does not start with '('"), start
);
81 end
= strchr(start
+ 1, ')');
83 die(_("bad ls-tree format: element '%s' does not end in ')'"), start
);
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
, options
->abbrev
);
96 } else if (skip_prefix(start
, "(path)", &p
)) {
97 const char *name
= data
->base
->buf
;
98 const char *prefix
= options
->chomp_prefix
? options
->ls_tree_prefix
: NULL
;
99 struct strbuf sbuf
= STRBUF_INIT
;
100 size_t baselen
= data
->base
->len
;
102 strbuf_addstr(data
->base
, data
->pathname
);
103 name
= relative_path(data
->base
->buf
, prefix
, &sbuf
);
104 quote_c_style(name
, sb
, NULL
, 0);
105 strbuf_setlen(data
->base
, baselen
);
106 strbuf_release(&sbuf
);
108 errlen
= (unsigned long)len
;
109 die(_("bad ls-tree format: %%%.*s"), errlen
, start
);
114 static int show_recursive(struct ls_tree_options
*options
, const char *base
,
115 size_t baselen
, const char *pathname
)
119 if (options
->ls_options
& LS_RECURSIVE
)
122 if (!options
->pathspec
.nr
)
125 for (i
= 0; i
< options
->pathspec
.nr
; i
++) {
126 const char *spec
= options
->pathspec
.items
[i
].match
;
129 if (strncmp(base
, spec
, baselen
))
131 len
= strlen(pathname
);
133 speclen
= strlen(spec
);
136 if (spec
[len
] && spec
[len
] != '/')
138 if (memcmp(pathname
, spec
, len
))
145 static int show_tree_fmt(const struct object_id
*oid
, struct strbuf
*base
,
146 const char *pathname
, unsigned mode
, void *context
)
148 struct ls_tree_options
*options
= context
;
150 struct strbuf sb
= STRBUF_INIT
;
151 enum object_type type
= object_type(mode
);
152 struct show_tree_data cb_data
= {
157 .pathname
= pathname
,
161 if (type
== OBJ_TREE
&& show_recursive(options
, base
->buf
, base
->len
, pathname
))
162 recurse
= READ_TREE_RECURSIVE
;
163 if (type
== OBJ_TREE
&& recurse
&& !(options
->ls_options
& LS_SHOW_TREES
))
165 if (type
== OBJ_BLOB
&& (options
->ls_options
& LS_TREE_ONLY
))
168 strbuf_expand(&sb
, options
->format
, expand_show_tree
, &cb_data
);
169 strbuf_addch(&sb
, options
->null_termination
? '\0' : '\n');
170 fwrite(sb
.buf
, sb
.len
, 1, stdout
);
175 static int show_tree_common(struct ls_tree_options
*options
, int *recurse
,
176 struct strbuf
*base
, const char *pathname
,
177 enum object_type type
)
182 if (type
== OBJ_BLOB
) {
183 if (options
->ls_options
& LS_TREE_ONLY
)
185 } else if (type
== OBJ_TREE
&&
186 show_recursive(options
, base
->buf
, base
->len
, pathname
)) {
187 *recurse
= READ_TREE_RECURSIVE
;
188 if (!(options
->ls_options
& LS_SHOW_TREES
))
195 static void show_tree_common_default_long(struct ls_tree_options
*options
,
197 const char *pathname
,
198 const size_t baselen
)
200 const char *prefix
= options
->chomp_prefix
? options
->ls_tree_prefix
: NULL
;
202 strbuf_addstr(base
, pathname
);
204 if (options
->null_termination
) {
205 struct strbuf sb
= STRBUF_INIT
;
206 const char *name
= relative_path(base
->buf
, prefix
, &sb
);
213 write_name_quoted_relative(base
->buf
, prefix
, stdout
, '\n');
216 strbuf_setlen(base
, baselen
);
219 static int show_tree_default(const struct object_id
*oid
, struct strbuf
*base
,
220 const char *pathname
, unsigned mode
,
223 struct ls_tree_options
*options
= context
;
226 enum object_type type
= object_type(mode
);
228 early
= show_tree_common(options
, &recurse
, base
, pathname
, type
);
232 printf("%06o %s %s\t", mode
, type_name(object_type(mode
)),
233 repo_find_unique_abbrev(the_repository
, oid
, options
->abbrev
));
234 show_tree_common_default_long(options
, base
, pathname
, base
->len
);
238 static int show_tree_long(const struct object_id
*oid
, struct strbuf
*base
,
239 const char *pathname
, unsigned mode
,
242 struct ls_tree_options
*options
= context
;
246 enum object_type type
= object_type(mode
);
248 early
= show_tree_common(options
, &recurse
, base
, pathname
, type
);
252 if (type
== OBJ_BLOB
) {
254 if (oid_object_info(the_repository
, oid
, &size
) == OBJ_BAD
)
255 xsnprintf(size_text
, sizeof(size_text
), "BAD");
257 xsnprintf(size_text
, sizeof(size_text
),
258 "%" PRIuMAX
, (uintmax_t)size
);
260 xsnprintf(size_text
, sizeof(size_text
), "-");
263 printf("%06o %s %s %7s\t", mode
, type_name(type
),
264 repo_find_unique_abbrev(the_repository
, oid
, options
->abbrev
),
266 show_tree_common_default_long(options
, base
, pathname
, base
->len
);
270 static int show_tree_name_only(const struct object_id
*oid
, struct strbuf
*base
,
271 const char *pathname
, unsigned mode
,
274 struct ls_tree_options
*options
= context
;
277 const size_t baselen
= base
->len
;
278 enum object_type type
= object_type(mode
);
281 early
= show_tree_common(options
, &recurse
, base
, pathname
, type
);
285 prefix
= options
->chomp_prefix
? options
->ls_tree_prefix
: NULL
;
286 strbuf_addstr(base
, pathname
);
287 if (options
->null_termination
) {
288 struct strbuf sb
= STRBUF_INIT
;
289 const char *name
= relative_path(base
->buf
, prefix
, &sb
);
296 write_name_quoted_relative(base
->buf
, prefix
, stdout
, '\n');
298 strbuf_setlen(base
, baselen
);
302 static int show_tree_object(const struct object_id
*oid
, struct strbuf
*base
,
303 const char *pathname
, unsigned mode
,
306 struct ls_tree_options
*options
= context
;
309 enum object_type type
= object_type(mode
);
312 early
= show_tree_common(options
, &recurse
, base
, pathname
, type
);
316 str
= repo_find_unique_abbrev(the_repository
, oid
, options
->abbrev
);
317 if (options
->null_termination
) {
326 enum ls_tree_cmdmode
{
334 struct ls_tree_cmdmode_to_fmt
{
335 enum ls_tree_cmdmode mode
;
336 const char *const fmt
;
340 static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format
[] = {
342 .mode
= MODE_DEFAULT
,
343 .fmt
= "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
344 .fn
= show_tree_default
,
348 .fmt
= "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
349 .fn
= show_tree_long
,
352 .mode
= MODE_NAME_ONLY
, /* And MODE_NAME_STATUS */
354 .fn
= show_tree_name_only
,
357 .mode
= MODE_OBJECT_ONLY
,
358 .fmt
= "%(objectname)",
359 .fn
= show_tree_object
363 .fn
= show_tree_default
,
367 int cmd_ls_tree(int argc
, const char **argv
, const char *prefix
)
369 struct object_id oid
;
371 int i
, full_tree
= 0;
372 read_tree_fn_t fn
= NULL
;
373 enum ls_tree_cmdmode cmdmode
= MODE_DEFAULT
;
374 int null_termination
= 0;
375 struct ls_tree_options options
= { 0 };
376 const struct option ls_tree_options
[] = {
377 OPT_BIT('d', NULL
, &options
.ls_options
, N_("only show trees"),
379 OPT_BIT('r', NULL
, &options
.ls_options
, N_("recurse into subtrees"),
381 OPT_BIT('t', NULL
, &options
.ls_options
, N_("show trees when recursing"),
383 OPT_BOOL('z', NULL
, &null_termination
,
384 N_("terminate entries with NUL byte")),
385 OPT_CMDMODE('l', "long", &cmdmode
, N_("include object size"),
387 OPT_CMDMODE(0, "name-only", &cmdmode
, N_("list only filenames"),
389 OPT_CMDMODE(0, "name-status", &cmdmode
, N_("list only filenames"),
391 OPT_CMDMODE(0, "object-only", &cmdmode
, N_("list only objects"),
393 OPT_SET_INT(0, "full-name", &options
.chomp_prefix
,
394 N_("use full path names"), 0),
395 OPT_BOOL(0, "full-tree", &full_tree
,
396 N_("list entire tree; not just current directory "
397 "(implies --full-name)")),
398 OPT_STRING_F(0, "format", &options
.format
, N_("format"),
399 N_("format to use for the output"),
401 OPT__ABBREV(&options
.abbrev
),
404 struct ls_tree_cmdmode_to_fmt
*m2f
= ls_tree_cmdmode_format
;
407 git_config(git_default_config
, NULL
);
408 options
.ls_tree_prefix
= prefix
;
410 options
.chomp_prefix
= strlen(prefix
);
412 argc
= parse_options(argc
, argv
, prefix
, ls_tree_options
,
414 options
.null_termination
= null_termination
;
417 options
.ls_tree_prefix
= prefix
= NULL
;
418 options
.chomp_prefix
= 0;
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.
425 if (cmdmode
== MODE_NAME_STATUS
)
426 cmdmode
= MODE_NAME_ONLY
;
428 /* -d -r should imply -t, but -d by itself should not have to. */
429 if ( (LS_TREE_ONLY
|LS_RECURSIVE
) ==
430 ((LS_TREE_ONLY
|LS_RECURSIVE
) & options
.ls_options
))
431 options
.ls_options
|= LS_SHOW_TREES
;
433 if (options
.format
&& cmdmode
)
435 _("--format can't be combined with other format-altering options"),
436 ls_tree_usage
, ls_tree_options
);
438 usage_with_options(ls_tree_usage
, ls_tree_options
);
439 if (repo_get_oid(the_repository
, argv
[0], &oid
))
440 die("Not a valid object name %s", argv
[0]);
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
446 * match_pathspec() or tree_entry_interesting()
448 parse_pathspec(&options
.pathspec
, PATHSPEC_ALL_MAGIC
&
449 ~(PATHSPEC_FROMTOP
| PATHSPEC_LITERAL
),
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;
455 tree
= parse_tree_indirect(&oid
);
457 die("not a tree object");
459 * The generic show_tree_fmt() is slower than show_tree(), so
460 * take the fast path if possible.
464 fn
= options
.format
? show_tree_fmt
: show_tree_default
;
465 } else if (options
.format
&& !strcmp(options
.format
, m2f
->fmt
)) {
468 } else if (!options
.format
&& cmdmode
== m2f
->mode
) {
477 ret
= !!read_tree(the_repository
, tree
, &options
.pathspec
, fn
, &options
);
478 clear_pathspec(&options
.pathspec
);