Coverage Report

Created: 2024-09-08 06:23

/src/git/builtin/check-attr.c
Line
Count
Source (jump to first uncovered line)
1
#include "builtin.h"
2
#include "config.h"
3
#include "attr.h"
4
#include "environment.h"
5
#include "gettext.h"
6
#include "object-name.h"
7
#include "quote.h"
8
#include "repository.h"
9
#include "setup.h"
10
#include "parse-options.h"
11
#include "write-or-die.h"
12
13
static int all_attrs;
14
static int cached_attrs;
15
static int stdin_paths;
16
static char *source;
17
static const char * const check_attr_usage[] = {
18
N_("git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>..."),
19
N_("git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"),
20
NULL
21
};
22
23
static int nul_term_line;
24
25
static const struct option check_attr_options[] = {
26
  OPT_BOOL('a', "all", &all_attrs, N_("report all attributes set on file")),
27
  OPT_BOOL(0,  "cached", &cached_attrs, N_("use .gitattributes only from the index")),
28
  OPT_BOOL(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
29
  OPT_BOOL('z', NULL, &nul_term_line,
30
     N_("terminate input and output records by a NUL character")),
31
  OPT_STRING(0, "source", &source, N_("<tree-ish>"), N_("which tree-ish to check attributes at")),
32
  OPT_END()
33
};
34
35
static void output_attr(struct attr_check *check, const char *file)
36
0
{
37
0
  int j;
38
0
  int cnt = check->nr;
39
40
0
  for (j = 0; j < cnt; j++) {
41
0
    const char *value = check->items[j].value;
42
43
0
    if (ATTR_TRUE(value))
44
0
      value = "set";
45
0
    else if (ATTR_FALSE(value))
46
0
      value = "unset";
47
0
    else if (ATTR_UNSET(value))
48
0
      value = "unspecified";
49
50
0
    if (nul_term_line) {
51
0
      printf("%s%c" /* path */
52
0
             "%s%c" /* attrname */
53
0
             "%s%c" /* attrvalue */,
54
0
             file, 0,
55
0
             git_attr_name(check->items[j].attr), 0, value, 0);
56
0
    } else {
57
0
      quote_c_style(file, NULL, stdout, 0);
58
0
      printf(": %s: %s\n",
59
0
             git_attr_name(check->items[j].attr), value);
60
0
    }
61
0
  }
62
0
}
63
64
static void check_attr(const char *prefix, struct attr_check *check,
65
           int collect_all,
66
           const char *file)
67
68
0
{
69
0
  char *full_path =
70
0
    prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
71
72
0
  if (collect_all) {
73
0
    git_all_attrs(the_repository->index, full_path, check);
74
0
  } else {
75
0
    git_check_attr(the_repository->index, full_path, check);
76
0
  }
77
0
  output_attr(check, file);
78
79
0
  free(full_path);
80
0
}
81
82
static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
83
           int collect_all)
84
0
{
85
0
  struct strbuf buf = STRBUF_INIT;
86
0
  struct strbuf unquoted = STRBUF_INIT;
87
0
  strbuf_getline_fn getline_fn;
88
89
0
  getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
90
0
  while (getline_fn(&buf, stdin) != EOF) {
91
0
    if (!nul_term_line && buf.buf[0] == '"') {
92
0
      strbuf_reset(&unquoted);
93
0
      if (unquote_c_style(&unquoted, buf.buf, NULL))
94
0
        die("line is badly quoted");
95
0
      strbuf_swap(&buf, &unquoted);
96
0
    }
97
0
    check_attr(prefix, check, collect_all, buf.buf);
98
0
    maybe_flush_or_die(stdout, "attribute to stdout");
99
0
  }
100
0
  strbuf_release(&buf);
101
0
  strbuf_release(&unquoted);
102
0
}
103
104
static NORETURN void error_with_usage(const char *msg)
105
0
{
106
0
  error("%s", msg);
107
0
  usage_with_options(check_attr_usage, check_attr_options);
108
0
}
109
110
int cmd_check_attr(int argc, const char **argv, const char *prefix)
111
0
{
112
0
  struct attr_check *check;
113
0
  struct object_id initialized_oid;
114
0
  int cnt, i, doubledash, filei;
115
116
0
  if (!is_bare_repository())
117
0
    setup_work_tree();
118
119
0
  git_config(git_default_config, NULL);
120
121
0
  argc = parse_options(argc, argv, prefix, check_attr_options,
122
0
           check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
123
124
0
  prepare_repo_settings(the_repository);
125
0
  the_repository->settings.command_requires_full_index = 0;
126
127
0
  if (repo_read_index(the_repository) < 0) {
128
0
    die("invalid cache");
129
0
  }
130
131
0
  if (cached_attrs)
132
0
    git_attr_set_direction(GIT_ATTR_INDEX);
133
134
0
  doubledash = -1;
135
0
  for (i = 0; doubledash < 0 && i < argc; i++) {
136
0
    if (!strcmp(argv[i], "--"))
137
0
      doubledash = i;
138
0
  }
139
140
  /* Process --all and/or attribute arguments: */
141
0
  if (all_attrs) {
142
0
    if (doubledash >= 1)
143
0
      error_with_usage("Attributes and --all both specified");
144
145
0
    cnt = 0;
146
0
    filei = doubledash + 1;
147
0
  } else if (doubledash == 0) {
148
0
    error_with_usage("No attribute specified");
149
0
  } else if (doubledash < 0) {
150
0
    if (!argc)
151
0
      error_with_usage("No attribute specified");
152
153
0
    if (stdin_paths) {
154
      /* Treat all arguments as attribute names. */
155
0
      cnt = argc;
156
0
      filei = argc;
157
0
    } else {
158
      /* Treat exactly one argument as an attribute name. */
159
0
      cnt = 1;
160
0
      filei = 1;
161
0
    }
162
0
  } else {
163
0
    cnt = doubledash;
164
0
    filei = doubledash + 1;
165
0
  }
166
167
  /* Check file argument(s): */
168
0
  if (stdin_paths) {
169
0
    if (filei < argc)
170
0
      error_with_usage("Can't specify files with --stdin");
171
0
  } else {
172
0
    if (filei >= argc)
173
0
      error_with_usage("No file specified");
174
0
  }
175
176
0
  check = attr_check_alloc();
177
0
  if (!all_attrs) {
178
0
    for (i = 0; i < cnt; i++) {
179
0
      const struct git_attr *a = git_attr(argv[i]);
180
181
0
      if (!a)
182
0
        return error("%s: not a valid attribute name",
183
0
               argv[i]);
184
0
      attr_check_append(check, a);
185
0
    }
186
0
  }
187
188
0
  if (source) {
189
0
    if (repo_get_oid_tree(the_repository, source, &initialized_oid))
190
0
      die("%s: not a valid tree-ish source", source);
191
0
    set_git_attr_source(source);
192
0
  }
193
194
0
  if (stdin_paths)
195
0
    check_attr_stdin_paths(prefix, check, all_attrs);
196
0
  else {
197
0
    for (i = filei; i < argc; i++)
198
0
      check_attr(prefix, check, all_attrs, argv[i]);
199
0
    maybe_flush_or_die(stdout, "attribute to stdout");
200
0
  }
201
202
0
  attr_check_free(check);
203
0
  return 0;
204
0
}