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