]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/ls-tree.c
ls-tree: fix expansion of repeated %(path)
[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
ÆAB
26static const char *format;
27
e8151715
ÆAB
28struct show_tree_data {
29 unsigned mode;
30 enum object_type type;
31 const struct object_id *oid;
32 const char *pathname;
33 struct strbuf *base;
34};
aa1c48df 35
61fdbcf9 36static const char * const ls_tree_usage[] = {
373f9221 37 N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
61fdbcf9
SB
38 NULL
39};
0f8f45cb 40
315f22c8 41static enum ls_tree_cmdmode {
455923e0
ÆAB
42 MODE_DEFAULT = 0,
43 MODE_LONG,
315f22c8
TL
44 MODE_NAME_ONLY,
45} cmdmode;
46
455923e0
ÆAB
47static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
48 const enum object_type type, unsigned int padded)
49{
50 if (type == OBJ_BLOB) {
51 unsigned long size;
52 if (oid_object_info(the_repository, oid, &size) < 0)
53 die(_("could not get object info about '%s'"),
54 oid_to_hex(oid));
55 if (padded)
56 strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
57 else
58 strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
59 } else if (padded) {
60 strbuf_addf(line, "%7s", "-");
61 } else {
62 strbuf_addstr(line, "-");
63 }
64}
65
66static size_t expand_show_tree(struct strbuf *sb, const char *start,
67 void *context)
68{
69 struct show_tree_data *data = context;
70 const char *end;
71 const char *p;
72 unsigned int errlen;
73 size_t len = strbuf_expand_literal_cb(sb, start, NULL);
74
75 if (len)
76 return len;
77 if (*start != '(')
78 die(_("bad ls-tree format: element '%s' does not start with '('"), start);
79
80 end = strchr(start + 1, ')');
81 if (!end)
82 die(_("bad ls-tree format: element '%s' does not end in ')'"), start);
83
84 len = end - start + 1;
85 if (skip_prefix(start, "(objectmode)", &p)) {
86 strbuf_addf(sb, "%06o", data->mode);
87 } else if (skip_prefix(start, "(objecttype)", &p)) {
88 strbuf_addstr(sb, type_name(data->type));
89 } else if (skip_prefix(start, "(objectsize:padded)", &p)) {
90 expand_objectsize(sb, data->oid, data->type, 1);
91 } else if (skip_prefix(start, "(objectsize)", &p)) {
92 expand_objectsize(sb, data->oid, data->type, 0);
93 } else if (skip_prefix(start, "(objectname)", &p)) {
94 strbuf_add_unique_abbrev(sb, data->oid, abbrev);
95 } else if (skip_prefix(start, "(path)", &p)) {
96 const char *name = data->base->buf;
97 const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
98 struct strbuf quoted = STRBUF_INIT;
99 struct strbuf sbuf = STRBUF_INIT;
16fb5c54
RS
100 size_t baselen = data->base->len;
101
455923e0
ÆAB
102 strbuf_addstr(data->base, data->pathname);
103 name = relative_path(data->base->buf, prefix, &sbuf);
104 quote_c_style(name, &quoted, NULL, 0);
16fb5c54 105 strbuf_setlen(data->base, baselen);
455923e0
ÆAB
106 strbuf_addbuf(sb, &quoted);
107 strbuf_release(&sbuf);
108 strbuf_release(&quoted);
109 } else {
110 errlen = (unsigned long)len;
111 die(_("bad ls-tree format: %%%.*s"), errlen, start);
112 }
113 return len;
114}
115
132ceda4 116static int show_recursive(const char *base, size_t baselen, const char *pathname)
0f8f45cb 117{
e1e24edc 118 int i;
0f8f45cb
LT
119
120 if (ls_options & LS_RECURSIVE)
121 return 1;
122
e1e24edc 123 if (!pathspec.nr)
0f8f45cb
LT
124 return 0;
125
e1e24edc
BW
126 for (i = 0; i < pathspec.nr; i++) {
127 const char *spec = pathspec.items[i].match;
132ceda4 128 size_t len, speclen;
0f8f45cb 129
0f8f45cb
LT
130 if (strncmp(base, spec, baselen))
131 continue;
132 len = strlen(pathname);
133 spec += baselen;
134 speclen = strlen(spec);
135 if (speclen <= len)
136 continue;
b294ed63
JH
137 if (spec[len] && spec[len] != '/')
138 continue;
0f8f45cb
LT
139 if (memcmp(pathname, spec, len))
140 continue;
141 return 1;
142 }
e1e24edc 143 return 0;
0f8f45cb 144}
aa1c48df 145
455923e0
ÆAB
146static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
147 const char *pathname, unsigned mode, void *context)
148{
455923e0
ÆAB
149 int recurse = 0;
150 struct strbuf sb = STRBUF_INIT;
151 enum object_type type = object_type(mode);
152
153 struct show_tree_data data = {
154 .mode = mode,
155 .type = type,
156 .oid = oid,
157 .pathname = pathname,
158 .base = base,
159 };
160
161 if (type == OBJ_TREE && show_recursive(base->buf, base->len, pathname))
162 recurse = READ_TREE_RECURSIVE;
163 if (type == OBJ_TREE && recurse && !(ls_options & LS_SHOW_TREES))
164 return recurse;
165 if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY))
166 return 0;
167
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);
455923e0
ÆAB
172 return recurse;
173}
174
e8151715 175static int show_default(struct show_tree_data *data)
315f22c8 176{
e8151715 177 size_t baselen = data->base->len;
315f22c8
TL
178
179 if (cmdmode == MODE_LONG) {
180 char size_text[24];
e8151715 181 if (data->type == OBJ_BLOB) {
315f22c8 182 unsigned long size;
e8151715 183 if (oid_object_info(the_repository, data->oid, &size) == OBJ_BAD)
315f22c8
TL
184 xsnprintf(size_text, sizeof(size_text), "BAD");
185 else
186 xsnprintf(size_text, sizeof(size_text),
187 "%" PRIuMAX, (uintmax_t)size);
188 } else {
189 xsnprintf(size_text, sizeof(size_text), "-");
190 }
e8151715
ÆAB
191 printf("%06o %s %s %7s\t", data->mode, type_name(data->type),
192 find_unique_abbrev(data->oid, abbrev), size_text);
315f22c8 193 } else {
e8151715
ÆAB
194 printf("%06o %s %s\t", data->mode, type_name(data->type),
195 find_unique_abbrev(data->oid, abbrev));
315f22c8 196 }
e8151715
ÆAB
197 baselen = data->base->len;
198 strbuf_addstr(data->base, data->pathname);
199 write_name_quoted_relative(data->base->buf,
315f22c8
TL
200 chomp_prefix ? ls_tree_prefix : NULL, stdout,
201 line_termination);
e8151715 202 strbuf_setlen(data->base, baselen);
315f22c8
TL
203 return 1;
204}
205
df46d77e 206static int show_tree(const struct object_id *oid, struct strbuf *base,
47957485 207 const char *pathname, unsigned mode, void *context)
6af1f019 208{
889f7838 209 int recurse = 0;
132ceda4 210 size_t baselen;
87af0ddf 211 enum object_type type = object_type(mode);
e8151715
ÆAB
212 struct show_tree_data data = {
213 .mode = mode,
214 .type = type,
215 .oid = oid,
216 .pathname = pathname,
217 .base = base,
218 };
ab1630a3 219
87af0ddf
TL
220 if (type == OBJ_BLOB) {
221 if (ls_options & LS_TREE_ONLY)
222 return 0;
223 } else if (type == OBJ_TREE &&
224 show_recursive(base->buf, base->len, pathname)) {
225 recurse = READ_TREE_RECURSIVE;
226 if (!(ls_options & LS_SHOW_TREES))
227 return recurse;
6af1f019 228 }
ab1630a3 229
315f22c8
TL
230 if (cmdmode == MODE_NAME_ONLY) {
231 baselen = base->len;
232 strbuf_addstr(base, pathname);
233 write_name_quoted_relative(base->buf,
234 chomp_prefix ? ls_tree_prefix : NULL,
235 stdout, line_termination);
236 strbuf_setlen(base, baselen);
237 return recurse;
a5bbda8b 238 }
315f22c8
TL
239
240 if (cmdmode == MODE_LONG ||
241 (!ls_options || (ls_options & LS_RECURSIVE)
242 || (ls_options & LS_SHOW_TREES)
243 || (ls_options & LS_TREE_ONLY)))
e8151715 244 show_default(&data);
315f22c8 245
889f7838 246 return recurse;
6af1f019 247}
0f2303f7 248
455923e0
ÆAB
249struct ls_tree_cmdmode_to_fmt {
250 enum ls_tree_cmdmode mode;
251 const char *const fmt;
252};
253
254static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
255 {
256 .mode = MODE_DEFAULT,
257 .fmt = "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
258 },
259 {
260 .mode = MODE_LONG,
261 .fmt = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
262 },
263 {
264 .mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
265 .fmt = "%(path)",
266 },
267 { 0 },
268};
269
a633fca0 270int cmd_ls_tree(int argc, const char **argv, const char *prefix)
6af1f019 271{
a9b5f5bf 272 struct object_id oid;
521698b1 273 struct tree *tree;
f0096c06 274 int i, full_tree = 0;
455923e0 275 read_tree_fn_t fn = show_tree;
61fdbcf9 276 const struct option ls_tree_options[] = {
373f9221 277 OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
61fdbcf9 278 LS_TREE_ONLY),
373f9221 279 OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"),
61fdbcf9 280 LS_RECURSIVE),
373f9221 281 OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"),
61fdbcf9
SB
282 LS_SHOW_TREES),
283 OPT_SET_INT('z', NULL, &line_termination,
373f9221 284 N_("terminate entries with NUL byte"), 0),
315f22c8
TL
285 OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
286 MODE_LONG),
287 OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
288 MODE_NAME_ONLY),
289 OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
290 MODE_NAME_ONLY),
61fdbcf9 291 OPT_SET_INT(0, "full-name", &chomp_prefix,
373f9221 292 N_("use full path names"), 0),
d5d09d47
SB
293 OPT_BOOL(0, "full-tree", &full_tree,
294 N_("list entire tree; not just current directory "
295 "(implies --full-name)")),
455923e0
ÆAB
296 OPT_STRING_F(0, "format", &format, N_("format"),
297 N_("format to use for the output"),
298 PARSE_OPT_NONEG),
61fdbcf9
SB
299 OPT__ABBREV(&abbrev),
300 OPT_END()
301 };
7912c070 302
ef90d6d4 303 git_config(git_default_config, NULL);
a633fca0 304 ls_tree_prefix = prefix;
a69dd585
JH
305 if (prefix && *prefix)
306 chomp_prefix = strlen(prefix);
61fdbcf9
SB
307
308 argc = parse_options(argc, argv, prefix, ls_tree_options,
309 ls_tree_usage, 0);
310 if (full_tree) {
311 ls_tree_prefix = prefix = NULL;
312 chomp_prefix = 0;
aa1c48df 313 }
f5984671
JH
314 /* -d -r should imply -t, but -d by itself should not have to. */
315 if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
316 ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
317 ls_options |= LS_SHOW_TREES;
aa1c48df 318
455923e0
ÆAB
319 if (format && cmdmode)
320 usage_msg_opt(
321 _("--format can't be combined with other format-altering options"),
322 ls_tree_usage, ls_tree_options);
61fdbcf9
SB
323 if (argc < 1)
324 usage_with_options(ls_tree_usage, ls_tree_options);
a9b5f5bf 325 if (get_oid(argv[0], &oid))
61fdbcf9 326 die("Not a valid object name %s", argv[0]);
6af1f019 327
0fdc2ae5
NTND
328 /*
329 * show_recursive() rolls its own matching code and is
330 * generally ignorant of 'struct pathspec'. The magic mask
331 * cannot be lifted until it is converted to use
854b0959 332 * match_pathspec() or tree_entry_interesting()
0fdc2ae5 333 */
e1e24edc
BW
334 parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &
335 ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
0fdc2ae5
NTND
336 PATHSPEC_PREFER_CWD,
337 prefix, argv + 1);
f0096c06 338 for (i = 0; i < pathspec.nr; i++)
170260ae 339 pathspec.items[i].nowildcard_len = pathspec.items[i].len;
33e0f62b 340 pathspec.has_wildcard = 0;
a9dbc179 341 tree = parse_tree_indirect(&oid);
521698b1 342 if (!tree)
3c5e8468 343 die("not a tree object");
455923e0
ÆAB
344 /*
345 * The generic show_tree_fmt() is slower than show_tree(), so
346 * take the fast path if possible.
347 */
348 if (format) {
349 struct ls_tree_cmdmode_to_fmt *m2f;
350
351 fn = show_tree_fmt;
352 for (m2f = ls_tree_cmdmode_format; m2f->fmt; m2f++) {
353 if (strcmp(format, m2f->fmt))
354 continue;
355
356 cmdmode = m2f->mode;
357 fn = show_tree;
358 break;
359 }
360 }
361
362 return !!read_tree(the_repository, tree, &pathspec, fn, NULL);
7912c070 363}