]>
Commit | Line | Data |
---|---|---|
368aa529 AS |
1 | #include "builtin.h" |
2 | #include "cache.h" | |
3 | #include "dir.h" | |
4 | #include "quote.h" | |
5 | #include "pathspec.h" | |
6 | #include "parse-options.h" | |
7 | ||
8 | static int quiet, verbose, stdin_paths; | |
9 | static const char * const check_ignore_usage[] = { | |
10 | "git check-ignore [options] pathname...", | |
11 | "git check-ignore [options] --stdin < <list-of-paths>", | |
12 | NULL | |
13 | }; | |
14 | ||
15 | static int null_term_line; | |
16 | ||
17 | static const struct option check_ignore_options[] = { | |
18 | OPT__QUIET(&quiet, N_("suppress progress reporting")), | |
19 | OPT__VERBOSE(&verbose, N_("be verbose")), | |
20 | OPT_GROUP(""), | |
21 | OPT_BOOLEAN(0, "stdin", &stdin_paths, | |
22 | N_("read file names from stdin")), | |
23 | OPT_BOOLEAN('z', NULL, &null_term_line, | |
24 | N_("input paths are terminated by a null character")), | |
25 | OPT_END() | |
26 | }; | |
27 | ||
28 | static void output_exclude(const char *path, struct exclude *exclude) | |
29 | { | |
30 | char *bang = exclude->flags & EXC_FLAG_NEGATIVE ? "!" : ""; | |
31 | char *slash = exclude->flags & EXC_FLAG_MUSTBEDIR ? "/" : ""; | |
32 | if (!null_term_line) { | |
33 | if (!verbose) { | |
34 | write_name_quoted(path, stdout, '\n'); | |
35 | } else { | |
36 | quote_c_style(exclude->el->src, NULL, stdout, 0); | |
37 | printf(":%d:%s%s%s\t", | |
38 | exclude->srcpos, | |
39 | bang, exclude->pattern, slash); | |
40 | quote_c_style(path, NULL, stdout, 0); | |
41 | fputc('\n', stdout); | |
42 | } | |
43 | } else { | |
44 | if (!verbose) { | |
45 | printf("%s%c", path, '\0'); | |
46 | } else { | |
47 | printf("%s%c%d%c%s%s%s%c%s%c", | |
48 | exclude->el->src, '\0', | |
49 | exclude->srcpos, '\0', | |
50 | bang, exclude->pattern, slash, '\0', | |
51 | path, '\0'); | |
52 | } | |
53 | } | |
54 | } | |
55 | ||
56 | static int check_ignore(const char *prefix, const char **pathspec) | |
57 | { | |
58 | struct dir_struct dir; | |
59 | const char *path, *full_path; | |
60 | char *seen; | |
61 | int num_ignored = 0, dtype = DT_UNKNOWN, i; | |
62 | struct path_exclude_check check; | |
63 | struct exclude *exclude; | |
64 | ||
65 | /* read_cache() is only necessary so we can watch out for submodules. */ | |
66 | if (read_cache() < 0) | |
67 | die(_("index file corrupt")); | |
68 | ||
69 | memset(&dir, 0, sizeof(dir)); | |
70 | dir.flags |= DIR_COLLECT_IGNORED; | |
71 | setup_standard_excludes(&dir); | |
72 | ||
73 | if (!pathspec || !*pathspec) { | |
74 | if (!quiet) | |
75 | fprintf(stderr, "no pathspec given.\n"); | |
76 | return 0; | |
77 | } | |
78 | ||
79 | path_exclude_check_init(&check, &dir); | |
80 | /* | |
81 | * look for pathspecs matching entries in the index, since these | |
82 | * should not be ignored, in order to be consistent with | |
83 | * 'git status', 'git add' etc. | |
84 | */ | |
85 | seen = find_pathspecs_matching_against_index(pathspec); | |
86 | for (i = 0; pathspec[i]; i++) { | |
87 | path = pathspec[i]; | |
88 | full_path = prefix_path(prefix, prefix | |
89 | ? strlen(prefix) : 0, path); | |
90 | full_path = check_path_for_gitlink(full_path); | |
91 | die_if_path_beyond_symlink(full_path, prefix); | |
c19387e7 | 92 | if (!seen[i]) { |
368aa529 AS |
93 | exclude = last_exclude_matching_path(&check, full_path, |
94 | -1, &dtype); | |
95 | if (exclude) { | |
96 | if (!quiet) | |
97 | output_exclude(path, exclude); | |
98 | num_ignored++; | |
99 | } | |
100 | } | |
101 | } | |
102 | free(seen); | |
103 | clear_directory(&dir); | |
104 | path_exclude_check_clear(&check); | |
105 | ||
106 | return num_ignored; | |
107 | } | |
108 | ||
109 | static int check_ignore_stdin_paths(const char *prefix) | |
110 | { | |
111 | struct strbuf buf, nbuf; | |
112 | char **pathspec = NULL; | |
113 | size_t nr = 0, alloc = 0; | |
114 | int line_termination = null_term_line ? 0 : '\n'; | |
115 | int num_ignored; | |
116 | ||
117 | strbuf_init(&buf, 0); | |
118 | strbuf_init(&nbuf, 0); | |
119 | while (strbuf_getline(&buf, stdin, line_termination) != EOF) { | |
120 | if (line_termination && buf.buf[0] == '"') { | |
121 | strbuf_reset(&nbuf); | |
122 | if (unquote_c_style(&nbuf, buf.buf, NULL)) | |
123 | die("line is badly quoted"); | |
124 | strbuf_swap(&buf, &nbuf); | |
125 | } | |
126 | ALLOC_GROW(pathspec, nr + 1, alloc); | |
127 | pathspec[nr] = xcalloc(strlen(buf.buf) + 1, sizeof(*buf.buf)); | |
128 | strcpy(pathspec[nr++], buf.buf); | |
129 | } | |
130 | ALLOC_GROW(pathspec, nr + 1, alloc); | |
131 | pathspec[nr] = NULL; | |
132 | num_ignored = check_ignore(prefix, (const char **)pathspec); | |
133 | maybe_flush_or_die(stdout, "attribute to stdout"); | |
134 | strbuf_release(&buf); | |
135 | strbuf_release(&nbuf); | |
136 | free(pathspec); | |
137 | return num_ignored; | |
138 | } | |
139 | ||
140 | int cmd_check_ignore(int argc, const char **argv, const char *prefix) | |
141 | { | |
142 | int num_ignored; | |
143 | ||
144 | git_config(git_default_config, NULL); | |
145 | ||
146 | argc = parse_options(argc, argv, prefix, check_ignore_options, | |
147 | check_ignore_usage, 0); | |
148 | ||
149 | if (stdin_paths) { | |
150 | if (argc > 0) | |
151 | die(_("cannot specify pathnames with --stdin")); | |
152 | } else { | |
153 | if (null_term_line) | |
154 | die(_("-z only makes sense with --stdin")); | |
155 | if (argc == 0) | |
156 | die(_("no path specified")); | |
157 | } | |
158 | if (quiet) { | |
159 | if (argc > 1) | |
160 | die(_("--quiet is only valid with a single pathname")); | |
161 | if (verbose) | |
162 | die(_("cannot have both --quiet and --verbose")); | |
163 | } | |
164 | ||
165 | if (stdin_paths) { | |
166 | num_ignored = check_ignore_stdin_paths(prefix); | |
167 | } else { | |
168 | num_ignored = check_ignore(prefix, argv); | |
169 | maybe_flush_or_die(stdout, "ignore to stdout"); | |
170 | } | |
171 | ||
172 | return !num_ignored; | |
173 | } |