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