]> git.ipfire.org Git - thirdparty/git.git/blob - builtin/ls-tree.c
fsck: check even zero-entry index files
[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 "cache.h"
7 #include "config.h"
8 #include "object-store.h"
9 #include "blob.h"
10 #include "tree.h"
11 #include "commit.h"
12 #include "quote.h"
13 #include "builtin.h"
14 #include "parse-options.h"
15 #include "pathspec.h"
16
17 static int line_termination = '\n';
18 #define LS_RECURSIVE 1
19 #define LS_TREE_ONLY (1 << 1)
20 #define LS_SHOW_TREES (1 << 2)
21 static int abbrev;
22 static int ls_options;
23 static struct pathspec pathspec;
24 static int chomp_prefix;
25 static const char *ls_tree_prefix;
26 static const char *format;
27 struct 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 };
34
35 static const char * const ls_tree_usage[] = {
36 N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
37 NULL
38 };
39
40 static enum ls_tree_cmdmode {
41 MODE_DEFAULT = 0,
42 MODE_LONG,
43 MODE_NAME_ONLY,
44 MODE_NAME_STATUS,
45 MODE_OBJECT_ONLY,
46 } cmdmode;
47
48 static 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
67 static 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;
98 const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
99 struct strbuf sbuf = STRBUF_INIT;
100 size_t baselen = data->base->len;
101
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);
107 } else {
108 errlen = (unsigned long)len;
109 die(_("bad ls-tree format: %%%.*s"), errlen, start);
110 }
111 return len;
112 }
113
114 static int show_recursive(const char *base, size_t baselen, const char *pathname)
115 {
116 int i;
117
118 if (ls_options & LS_RECURSIVE)
119 return 1;
120
121 if (!pathspec.nr)
122 return 0;
123
124 for (i = 0; i < pathspec.nr; i++) {
125 const char *spec = pathspec.items[i].match;
126 size_t len, speclen;
127
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;
135 if (spec[len] && spec[len] != '/')
136 continue;
137 if (memcmp(pathname, spec, len))
138 continue;
139 return 1;
140 }
141 return 0;
142 }
143
144 static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
145 const char *pathname, unsigned mode, void *context UNUSED)
146 {
147 int recurse = 0;
148 struct strbuf sb = STRBUF_INIT;
149 enum object_type type = object_type(mode);
150
151 struct show_tree_data data = {
152 .mode = mode,
153 .type = type,
154 .oid = oid,
155 .pathname = pathname,
156 .base = base,
157 };
158
159 if (type == OBJ_TREE && show_recursive(base->buf, base->len, pathname))
160 recurse = READ_TREE_RECURSIVE;
161 if (type == OBJ_TREE && recurse && !(ls_options & LS_SHOW_TREES))
162 return recurse;
163 if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY))
164 return 0;
165
166 strbuf_expand(&sb, format, expand_show_tree, &data);
167 strbuf_addch(&sb, line_termination);
168 fwrite(sb.buf, sb.len, 1, stdout);
169 strbuf_release(&sb);
170 return recurse;
171 }
172
173 static int show_tree_common(struct show_tree_data *data, int *recurse,
174 const struct object_id *oid, struct strbuf *base,
175 const char *pathname, unsigned mode)
176 {
177 enum object_type type = object_type(mode);
178 int ret = -1;
179
180 *recurse = 0;
181 data->mode = mode;
182 data->type = type;
183 data->oid = oid;
184 data->pathname = pathname;
185 data->base = base;
186
187 if (type == OBJ_BLOB) {
188 if (ls_options & LS_TREE_ONLY)
189 ret = 0;
190 } else if (type == OBJ_TREE &&
191 show_recursive(base->buf, base->len, pathname)) {
192 *recurse = READ_TREE_RECURSIVE;
193 if (!(ls_options & LS_SHOW_TREES))
194 ret = *recurse;
195 }
196
197 return ret;
198 }
199
200 static void show_tree_common_default_long(struct strbuf *base,
201 const char *pathname,
202 const size_t baselen)
203 {
204 strbuf_addstr(base, pathname);
205 write_name_quoted_relative(base->buf,
206 chomp_prefix ? ls_tree_prefix : NULL, stdout,
207 line_termination);
208 strbuf_setlen(base, baselen);
209 }
210
211 static int show_tree_default(const struct object_id *oid, struct strbuf *base,
212 const char *pathname, unsigned mode,
213 void *context UNUSED)
214 {
215 int early;
216 int recurse;
217 struct show_tree_data data = { 0 };
218
219 early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
220 if (early >= 0)
221 return early;
222
223 printf("%06o %s %s\t", data.mode, type_name(data.type),
224 find_unique_abbrev(data.oid, abbrev));
225 show_tree_common_default_long(base, pathname, data.base->len);
226 return recurse;
227 }
228
229 static int show_tree_long(const struct object_id *oid, struct strbuf *base,
230 const char *pathname, unsigned mode,
231 void *context UNUSED)
232 {
233 int early;
234 int recurse;
235 struct show_tree_data data = { 0 };
236 char size_text[24];
237
238 early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
239 if (early >= 0)
240 return early;
241
242 if (data.type == OBJ_BLOB) {
243 unsigned long size;
244 if (oid_object_info(the_repository, data.oid, &size) == OBJ_BAD)
245 xsnprintf(size_text, sizeof(size_text), "BAD");
246 else
247 xsnprintf(size_text, sizeof(size_text),
248 "%" PRIuMAX, (uintmax_t)size);
249 } else {
250 xsnprintf(size_text, sizeof(size_text), "-");
251 }
252
253 printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
254 find_unique_abbrev(data.oid, abbrev), size_text);
255 show_tree_common_default_long(base, pathname, data.base->len);
256 return recurse;
257 }
258
259 static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
260 const char *pathname, unsigned mode,
261 void *context UNUSED)
262 {
263 int early;
264 int recurse;
265 const size_t baselen = base->len;
266 struct show_tree_data data = { 0 };
267
268 early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
269 if (early >= 0)
270 return early;
271
272 strbuf_addstr(base, pathname);
273 write_name_quoted_relative(base->buf,
274 chomp_prefix ? ls_tree_prefix : NULL,
275 stdout, line_termination);
276 strbuf_setlen(base, baselen);
277 return recurse;
278 }
279
280 static int show_tree_object(const struct object_id *oid, struct strbuf *base,
281 const char *pathname, unsigned mode,
282 void *context UNUSED)
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);
293 return recurse;
294 }
295
296 struct ls_tree_cmdmode_to_fmt {
297 enum ls_tree_cmdmode mode;
298 const char *const fmt;
299 read_tree_fn_t fn;
300 };
301
302 static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
303 {
304 .mode = MODE_DEFAULT,
305 .fmt = "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
306 .fn = show_tree_default,
307 },
308 {
309 .mode = MODE_LONG,
310 .fmt = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
311 .fn = show_tree_long,
312 },
313 {
314 .mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
315 .fmt = "%(path)",
316 .fn = show_tree_name_only,
317 },
318 {
319 .mode = MODE_OBJECT_ONLY,
320 .fmt = "%(objectname)",
321 .fn = show_tree_object
322 },
323 {
324 /* fallback */
325 .fn = show_tree_default,
326 },
327 };
328
329 int cmd_ls_tree(int argc, const char **argv, const char *prefix)
330 {
331 struct object_id oid;
332 struct tree *tree;
333 int i, full_tree = 0;
334 read_tree_fn_t fn = NULL;
335 const struct option ls_tree_options[] = {
336 OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
337 LS_TREE_ONLY),
338 OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"),
339 LS_RECURSIVE),
340 OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"),
341 LS_SHOW_TREES),
342 OPT_SET_INT('z', NULL, &line_termination,
343 N_("terminate entries with NUL byte"), 0),
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"),
349 MODE_NAME_STATUS),
350 OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
351 MODE_OBJECT_ONLY),
352 OPT_SET_INT(0, "full-name", &chomp_prefix,
353 N_("use full path names"), 0),
354 OPT_BOOL(0, "full-tree", &full_tree,
355 N_("list entire tree; not just current directory "
356 "(implies --full-name)")),
357 OPT_STRING_F(0, "format", &format, N_("format"),
358 N_("format to use for the output"),
359 PARSE_OPT_NONEG),
360 OPT__ABBREV(&abbrev),
361 OPT_END()
362 };
363 struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
364
365 git_config(git_default_config, NULL);
366 ls_tree_prefix = prefix;
367 if (prefix)
368 chomp_prefix = strlen(prefix);
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;
375 }
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
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;
388
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);
393 if (argc < 1)
394 usage_with_options(ls_tree_usage, ls_tree_options);
395 if (get_oid(argv[0], &oid))
396 die("Not a valid object name %s", argv[0]);
397
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
402 * match_pathspec() or tree_entry_interesting()
403 */
404 parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &
405 ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
406 PATHSPEC_PREFER_CWD,
407 prefix, argv + 1);
408 for (i = 0; i < pathspec.nr; i++)
409 pathspec.items[i].nowildcard_len = pathspec.items[i].len;
410 pathspec.has_wildcard = 0;
411 tree = parse_tree_indirect(&oid);
412 if (!tree)
413 die("not a tree object");
414 /*
415 * The generic show_tree_fmt() is slower than show_tree(), so
416 * take the fast path if possible.
417 */
418 while (m2f) {
419 if (!m2f->fmt) {
420 fn = format ? show_tree_fmt : show_tree_default;
421 } else if (format && !strcmp(format, m2f->fmt)) {
422 cmdmode = m2f->mode;
423 fn = m2f->fn;
424 } else if (!format && cmdmode == m2f->mode) {
425 fn = m2f->fn;
426 } else {
427 m2f++;
428 continue;
429 }
430 break;
431 }
432
433 return !!read_tree(the_repository, tree, &pathspec, fn, NULL);
434 }