Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 1 | /* |
| 2 | * "git clean" builtin command |
| 3 | * |
| 4 | * Copyright (C) 2007 Shawn Bohrer |
| 5 | * |
| 6 | * Based on git-clean.sh by Pavel Roskin |
| 7 | */ |
| 8 | |
| 9 | #include "builtin.h" |
| 10 | #include "cache.h" |
| 11 | #include "dir.h" |
| 12 | #include "parse-options.h" |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 13 | #include "refs.h" |
Jared Hance | 07de4eb | 2010-07-20 15:35:56 -0400 | [diff] [blame] | 14 | #include "string-list.h" |
Dmitry Potapov | 1fb3289 | 2008-03-07 04:13:17 +0300 | [diff] [blame] | 15 | #include "quote.h" |
Jiang Xin | 1b8fd46 | 2013-06-25 23:53:49 +0800 | [diff] [blame^] | 16 | #include "column.h" |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 17 | |
Junio C Hamano | 625db1b | 2007-11-12 21:13:05 -0800 | [diff] [blame] | 18 | static int force = -1; /* unset */ |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 19 | static int interactive; |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 20 | static struct string_list del_list = STRING_LIST_INIT_DUP; |
Jiang Xin | 1b8fd46 | 2013-06-25 23:53:49 +0800 | [diff] [blame^] | 21 | static unsigned int colopts; |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 22 | |
| 23 | static const char *const builtin_clean_usage[] = { |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 24 | N_("git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."), |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 25 | NULL |
| 26 | }; |
| 27 | |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 28 | static const char *msg_remove = N_("Removing %s\n"); |
| 29 | static const char *msg_would_remove = N_("Would remove %s\n"); |
| 30 | static const char *msg_skip_git_dir = N_("Skipping repository %s\n"); |
| 31 | static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n"); |
| 32 | static const char *msg_warn_remove_failed = N_("failed to remove %s"); |
| 33 | |
Johannes Schindelin | ef90d6d | 2008-05-14 18:46:53 +0100 | [diff] [blame] | 34 | static int git_clean_config(const char *var, const char *value, void *cb) |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 35 | { |
Jiang Xin | 1b8fd46 | 2013-06-25 23:53:49 +0800 | [diff] [blame^] | 36 | if (!prefixcmp(var, "column.")) |
| 37 | return git_column_config(var, value, "clean", &colopts); |
| 38 | |
| 39 | if (!strcmp(var, "clean.requireforce")) { |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 40 | force = !git_config_bool(var, value); |
Jiang Xin | 1b8fd46 | 2013-06-25 23:53:49 +0800 | [diff] [blame^] | 41 | return 0; |
| 42 | } |
Johannes Schindelin | ef90d6d | 2008-05-14 18:46:53 +0100 | [diff] [blame] | 43 | return git_default_config(var, value, cb); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 44 | } |
| 45 | |
Jared Hance | 07de4eb | 2010-07-20 15:35:56 -0400 | [diff] [blame] | 46 | static int exclude_cb(const struct option *opt, const char *arg, int unset) |
| 47 | { |
| 48 | struct string_list *exclude_list = opt->value; |
| 49 | string_list_append(exclude_list, arg); |
| 50 | return 0; |
| 51 | } |
| 52 | |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 53 | static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag, |
| 54 | int dry_run, int quiet, int *dir_gone) |
| 55 | { |
| 56 | DIR *dir; |
| 57 | struct strbuf quoted = STRBUF_INIT; |
| 58 | struct dirent *e; |
| 59 | int res = 0, ret = 0, gone = 1, original_len = path->len, len, i; |
| 60 | unsigned char submodule_head[20]; |
| 61 | struct string_list dels = STRING_LIST_INIT_DUP; |
| 62 | |
| 63 | *dir_gone = 1; |
| 64 | |
| 65 | if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && |
| 66 | !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) { |
| 67 | if (!quiet) { |
Jiang Xin | 39598f9 | 2013-06-25 23:53:45 +0800 | [diff] [blame] | 68 | quote_path_relative(path->buf, prefix, "ed); |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 69 | printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir), |
| 70 | quoted.buf); |
| 71 | } |
| 72 | |
| 73 | *dir_gone = 0; |
| 74 | return 0; |
| 75 | } |
| 76 | |
| 77 | dir = opendir(path->buf); |
| 78 | if (!dir) { |
| 79 | /* an empty dir could be removed even if it is unreadble */ |
| 80 | res = dry_run ? 0 : rmdir(path->buf); |
| 81 | if (res) { |
Jiang Xin | 39598f9 | 2013-06-25 23:53:45 +0800 | [diff] [blame] | 82 | quote_path_relative(path->buf, prefix, "ed); |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 83 | warning(_(msg_warn_remove_failed), quoted.buf); |
| 84 | *dir_gone = 0; |
| 85 | } |
| 86 | return res; |
| 87 | } |
| 88 | |
| 89 | if (path->buf[original_len - 1] != '/') |
| 90 | strbuf_addch(path, '/'); |
| 91 | |
| 92 | len = path->len; |
| 93 | while ((e = readdir(dir)) != NULL) { |
| 94 | struct stat st; |
| 95 | if (is_dot_or_dotdot(e->d_name)) |
| 96 | continue; |
| 97 | |
| 98 | strbuf_setlen(path, len); |
| 99 | strbuf_addstr(path, e->d_name); |
| 100 | if (lstat(path->buf, &st)) |
| 101 | ; /* fall thru */ |
| 102 | else if (S_ISDIR(st.st_mode)) { |
| 103 | if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone)) |
| 104 | ret = 1; |
| 105 | if (gone) { |
Jiang Xin | 39598f9 | 2013-06-25 23:53:45 +0800 | [diff] [blame] | 106 | quote_path_relative(path->buf, prefix, "ed); |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 107 | string_list_append(&dels, quoted.buf); |
| 108 | } else |
| 109 | *dir_gone = 0; |
| 110 | continue; |
| 111 | } else { |
| 112 | res = dry_run ? 0 : unlink(path->buf); |
| 113 | if (!res) { |
Jiang Xin | 39598f9 | 2013-06-25 23:53:45 +0800 | [diff] [blame] | 114 | quote_path_relative(path->buf, prefix, "ed); |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 115 | string_list_append(&dels, quoted.buf); |
| 116 | } else { |
Jiang Xin | 39598f9 | 2013-06-25 23:53:45 +0800 | [diff] [blame] | 117 | quote_path_relative(path->buf, prefix, "ed); |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 118 | warning(_(msg_warn_remove_failed), quoted.buf); |
| 119 | *dir_gone = 0; |
| 120 | ret = 1; |
| 121 | } |
| 122 | continue; |
| 123 | } |
| 124 | |
| 125 | /* path too long, stat fails, or non-directory still exists */ |
| 126 | *dir_gone = 0; |
| 127 | ret = 1; |
| 128 | break; |
| 129 | } |
| 130 | closedir(dir); |
| 131 | |
| 132 | strbuf_setlen(path, original_len); |
| 133 | |
| 134 | if (*dir_gone) { |
| 135 | res = dry_run ? 0 : rmdir(path->buf); |
| 136 | if (!res) |
| 137 | *dir_gone = 1; |
| 138 | else { |
Jiang Xin | 39598f9 | 2013-06-25 23:53:45 +0800 | [diff] [blame] | 139 | quote_path_relative(path->buf, prefix, "ed); |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 140 | warning(_(msg_warn_remove_failed), quoted.buf); |
| 141 | *dir_gone = 0; |
| 142 | ret = 1; |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | if (!*dir_gone && !quiet) { |
| 147 | for (i = 0; i < dels.nr; i++) |
| 148 | printf(dry_run ? _(msg_would_remove) : _(msg_remove), dels.items[i].string); |
| 149 | } |
| 150 | string_list_clear(&dels, 0); |
| 151 | return ret; |
| 152 | } |
| 153 | |
Jiang Xin | 1b8fd46 | 2013-06-25 23:53:49 +0800 | [diff] [blame^] | 154 | static void pretty_print_dels(void) |
| 155 | { |
| 156 | struct string_list list = STRING_LIST_INIT_DUP; |
| 157 | struct string_list_item *item; |
| 158 | struct strbuf buf = STRBUF_INIT; |
| 159 | const char *qname; |
| 160 | struct column_options copts; |
| 161 | |
| 162 | for_each_string_list_item(item, &del_list) { |
| 163 | qname = quote_path_relative(item->string, NULL, &buf); |
| 164 | string_list_append(&list, qname); |
| 165 | } |
| 166 | |
| 167 | /* |
| 168 | * always enable column display, we only consult column.* |
| 169 | * about layout strategy and stuff |
| 170 | */ |
| 171 | colopts = (colopts & ~COL_ENABLE_MASK) | COL_ENABLED; |
| 172 | memset(&copts, 0, sizeof(copts)); |
| 173 | copts.indent = " "; |
| 174 | copts.padding = 2; |
| 175 | print_columns(&list, colopts, &copts); |
| 176 | putchar('\n'); |
| 177 | strbuf_release(&buf); |
| 178 | string_list_clear(&list, 0); |
| 179 | } |
| 180 | |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 181 | static void interactive_main_loop(void) |
| 182 | { |
| 183 | struct strbuf confirm = STRBUF_INIT; |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 184 | |
| 185 | while (del_list.nr) { |
| 186 | putchar('\n'); |
Jiang Xin | 1b8fd46 | 2013-06-25 23:53:49 +0800 | [diff] [blame^] | 187 | printf_ln(Q_("Would remove the following item:", |
| 188 | "Would remove the following items:", |
| 189 | del_list.nr)); |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 190 | putchar('\n'); |
| 191 | |
Jiang Xin | 1b8fd46 | 2013-06-25 23:53:49 +0800 | [diff] [blame^] | 192 | pretty_print_dels(); |
| 193 | |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 194 | printf(_("Remove [y/n]? ")); |
| 195 | if (strbuf_getline(&confirm, stdin, '\n') != EOF) { |
| 196 | strbuf_trim(&confirm); |
| 197 | } else { |
| 198 | /* Ctrl-D is the same as "quit" */ |
| 199 | string_list_clear(&del_list, 0); |
| 200 | putchar('\n'); |
| 201 | printf_ln("Bye."); |
| 202 | break; |
| 203 | } |
| 204 | |
| 205 | if (confirm.len) { |
| 206 | if (!strncasecmp(confirm.buf, "yes", confirm.len)) { |
| 207 | break; |
| 208 | } else if (!strncasecmp(confirm.buf, "no", confirm.len) || |
| 209 | !strncasecmp(confirm.buf, "quit", confirm.len)) { |
| 210 | string_list_clear(&del_list, 0); |
| 211 | printf_ln("Bye."); |
| 212 | break; |
| 213 | } else { |
| 214 | continue; |
| 215 | } |
| 216 | } |
| 217 | } |
| 218 | |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 219 | strbuf_release(&confirm); |
| 220 | } |
| 221 | |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 222 | int cmd_clean(int argc, const char **argv, const char *prefix) |
| 223 | { |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 224 | int i, res; |
| 225 | int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0; |
| 226 | int ignored_only = 0, config_set = 0, errors = 0, gone = 1; |
Junio C Hamano | a0f4afb | 2009-06-30 15:33:45 -0700 | [diff] [blame] | 227 | int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT; |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 228 | struct strbuf abs_path = STRBUF_INIT; |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 229 | struct dir_struct dir; |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 230 | static const char **pathspec; |
Brandon Casey | f285a2d | 2008-10-09 14:12:12 -0500 | [diff] [blame] | 231 | struct strbuf buf = STRBUF_INIT; |
Thiago Farina | bdab6a5 | 2010-09-06 20:32:55 -0300 | [diff] [blame] | 232 | struct string_list exclude_list = STRING_LIST_INIT_NODUP; |
Adam Spiers | 72aeb18 | 2013-01-16 13:25:58 +0000 | [diff] [blame] | 233 | struct exclude_list *el; |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 234 | struct string_list_item *item; |
Dmitry Potapov | 1fb3289 | 2008-03-07 04:13:17 +0300 | [diff] [blame] | 235 | const char *qname; |
Junio C Hamano | d871c86 | 2007-12-04 23:55:41 -0800 | [diff] [blame] | 236 | char *seen = NULL; |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 237 | struct option options[] = { |
Nguyễn Thái Ngọc Duy | 145f9c8 | 2012-08-20 19:32:01 +0700 | [diff] [blame] | 238 | OPT__QUIET(&quiet, N_("do not print names of files removed")), |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 239 | OPT__DRY_RUN(&dry_run, N_("dry run")), |
Nguyễn Thái Ngọc Duy | 145f9c8 | 2012-08-20 19:32:01 +0700 | [diff] [blame] | 240 | OPT__FORCE(&force, N_("force")), |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 241 | OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")), |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 242 | OPT_BOOLEAN('d', NULL, &remove_directories, |
Nguyễn Thái Ngọc Duy | 145f9c8 | 2012-08-20 19:32:01 +0700 | [diff] [blame] | 243 | N_("remove whole directories")), |
| 244 | { OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"), |
| 245 | N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb }, |
| 246 | OPT_BOOLEAN('x', NULL, &ignored, N_("remove ignored files, too")), |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 247 | OPT_BOOLEAN('X', NULL, &ignored_only, |
Nguyễn Thái Ngọc Duy | 145f9c8 | 2012-08-20 19:32:01 +0700 | [diff] [blame] | 248 | N_("remove only ignored files")), |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 249 | OPT_END() |
| 250 | }; |
| 251 | |
Johannes Schindelin | ef90d6d | 2008-05-14 18:46:53 +0100 | [diff] [blame] | 252 | git_config(git_clean_config, NULL); |
Junio C Hamano | 625db1b | 2007-11-12 21:13:05 -0800 | [diff] [blame] | 253 | if (force < 0) |
| 254 | force = 0; |
| 255 | else |
| 256 | config_set = 1; |
| 257 | |
Stephen Boyd | 3778292 | 2009-05-23 11:53:12 -0700 | [diff] [blame] | 258 | argc = parse_options(argc, argv, prefix, options, builtin_clean_usage, |
| 259 | 0); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 260 | |
| 261 | memset(&dir, 0, sizeof(dir)); |
Shawn Bohrer | 1617adc | 2007-11-14 23:00:54 -0600 | [diff] [blame] | 262 | if (ignored_only) |
Johannes Schindelin | 7c4c97c | 2009-02-16 13:20:25 +0100 | [diff] [blame] | 263 | dir.flags |= DIR_SHOW_IGNORED; |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 264 | |
| 265 | if (ignored && ignored_only) |
Ævar Arnfjörð Bjarmason | 2da57ad | 2011-02-22 23:42:21 +0000 | [diff] [blame] | 266 | die(_("-x and -X cannot be used together")); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 267 | |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 268 | if (!interactive && !dry_run && !force) { |
Ævar Arnfjörð Bjarmason | a66f9b2 | 2011-02-22 23:42:22 +0000 | [diff] [blame] | 269 | if (config_set) |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 270 | die(_("clean.requireForce set to true and neither -i, -n nor -f given; " |
Ævar Arnfjörð Bjarmason | a66f9b2 | 2011-02-22 23:42:22 +0000 | [diff] [blame] | 271 | "refusing to clean")); |
| 272 | else |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 273 | die(_("clean.requireForce defaults to true and neither -i, -n nor -f given; " |
Ævar Arnfjörð Bjarmason | a66f9b2 | 2011-02-22 23:42:22 +0000 | [diff] [blame] | 274 | "refusing to clean")); |
| 275 | } |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 276 | |
Junio C Hamano | a0f4afb | 2009-06-30 15:33:45 -0700 | [diff] [blame] | 277 | if (force > 1) |
| 278 | rm_flags = 0; |
| 279 | |
Johannes Schindelin | 7c4c97c | 2009-02-16 13:20:25 +0100 | [diff] [blame] | 280 | dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 281 | |
Nguyễn Thái Ngọc Duy | c28b3d6 | 2009-08-20 20:47:01 +0700 | [diff] [blame] | 282 | if (read_cache() < 0) |
Ævar Arnfjörð Bjarmason | 2da57ad | 2011-02-22 23:42:21 +0000 | [diff] [blame] | 283 | die(_("index file corrupt")); |
Nguyễn Thái Ngọc Duy | c28b3d6 | 2009-08-20 20:47:01 +0700 | [diff] [blame] | 284 | |
Shawn Bohrer | 1617adc | 2007-11-14 23:00:54 -0600 | [diff] [blame] | 285 | if (!ignored) |
| 286 | setup_standard_excludes(&dir); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 287 | |
Adam Spiers | 72aeb18 | 2013-01-16 13:25:58 +0000 | [diff] [blame] | 288 | el = add_exclude_list(&dir, EXC_CMDL, "--exclude option"); |
Jared Hance | 07de4eb | 2010-07-20 15:35:56 -0400 | [diff] [blame] | 289 | for (i = 0; i < exclude_list.nr; i++) |
Adam Spiers | 72aeb18 | 2013-01-16 13:25:58 +0000 | [diff] [blame] | 290 | add_exclude(exclude_list.items[i].string, "", 0, el, -(i+1)); |
Jared Hance | 07de4eb | 2010-07-20 15:35:56 -0400 | [diff] [blame] | 291 | |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 292 | pathspec = get_pathspec(prefix, argv); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 293 | |
Linus Torvalds | 1d8842d | 2009-05-14 13:22:36 -0700 | [diff] [blame] | 294 | fill_directory(&dir, pathspec); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 295 | |
Junio C Hamano | d871c86 | 2007-12-04 23:55:41 -0800 | [diff] [blame] | 296 | if (pathspec) |
Jeff King | a8db80c | 2008-01-12 04:04:32 -0500 | [diff] [blame] | 297 | seen = xmalloc(argc > 0 ? argc : 1); |
Junio C Hamano | d871c86 | 2007-12-04 23:55:41 -0800 | [diff] [blame] | 298 | |
| 299 | for (i = 0; i < dir.nr; i++) { |
| 300 | struct dir_entry *ent = dir.entries[i]; |
Shawn Bohrer | f2d0df7 | 2008-04-14 22:14:09 -0500 | [diff] [blame] | 301 | int len, pos; |
| 302 | int matches = 0; |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 303 | struct cache_entry *ce; |
| 304 | struct stat st; |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 305 | const char *rel; |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 306 | |
| 307 | /* |
| 308 | * Remove the '/' at the end that directory |
| 309 | * walking adds for directory entries. |
| 310 | */ |
| 311 | len = ent->len; |
| 312 | if (len && ent->name[len-1] == '/') |
| 313 | len--; |
| 314 | pos = cache_name_pos(ent->name, len); |
| 315 | if (0 <= pos) |
| 316 | continue; /* exact match */ |
| 317 | pos = -pos - 1; |
| 318 | if (pos < active_nr) { |
| 319 | ce = active_cache[pos]; |
| 320 | if (ce_namelen(ce) == len && |
| 321 | !memcmp(ce->name, ent->name, len)) |
| 322 | continue; /* Yup, this one exists unmerged */ |
| 323 | } |
| 324 | |
Junio C Hamano | d871c86 | 2007-12-04 23:55:41 -0800 | [diff] [blame] | 325 | if (lstat(ent->name, &st)) |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 326 | die_errno("Cannot lstat '%s'", ent->name); |
Junio C Hamano | d871c86 | 2007-12-04 23:55:41 -0800 | [diff] [blame] | 327 | |
| 328 | if (pathspec) { |
Jeff King | a8db80c | 2008-01-12 04:04:32 -0500 | [diff] [blame] | 329 | memset(seen, 0, argc > 0 ? argc : 1); |
Shawn Bohrer | f2d0df7 | 2008-04-14 22:14:09 -0500 | [diff] [blame] | 330 | matches = match_pathspec(pathspec, ent->name, len, |
Nguyễn Thái Ngọc Duy | 1c7d402 | 2010-11-15 13:42:44 +0700 | [diff] [blame] | 331 | 0, seen); |
Junio C Hamano | d871c86 | 2007-12-04 23:55:41 -0800 | [diff] [blame] | 332 | } |
| 333 | |
| 334 | if (S_ISDIR(st.st_mode)) { |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 335 | if (remove_directories || (matches == MATCHED_EXACTLY)) { |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 336 | rel = relative_path(ent->name, prefix, &buf); |
| 337 | string_list_append(&del_list, rel); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 338 | } |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 339 | } else { |
Junio C Hamano | d871c86 | 2007-12-04 23:55:41 -0800 | [diff] [blame] | 340 | if (pathspec && !matches) |
| 341 | continue; |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 342 | rel = relative_path(ent->name, prefix, &buf); |
| 343 | string_list_append(&del_list, rel); |
| 344 | } |
| 345 | } |
| 346 | |
Jiang Xin | 1769600 | 2013-06-25 23:53:48 +0800 | [diff] [blame] | 347 | if (interactive && del_list.nr > 0) |
| 348 | interactive_main_loop(); |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 349 | |
| 350 | for_each_string_list_item(item, &del_list) { |
| 351 | struct stat st; |
| 352 | |
| 353 | if (prefix) |
| 354 | strbuf_addstr(&abs_path, prefix); |
| 355 | |
| 356 | strbuf_addstr(&abs_path, item->string); |
| 357 | |
| 358 | /* |
| 359 | * we might have removed this as part of earlier |
| 360 | * recursive directory removal, so lstat() here could |
| 361 | * fail with ENOENT. |
| 362 | */ |
| 363 | if (lstat(abs_path.buf, &st)) |
| 364 | continue; |
| 365 | |
| 366 | if (S_ISDIR(st.st_mode)) { |
| 367 | if (remove_dirs(&abs_path, prefix, rm_flags, dry_run, quiet, &gone)) |
| 368 | errors++; |
| 369 | if (gone && !quiet) { |
| 370 | qname = quote_path_relative(item->string, NULL, &buf); |
| 371 | printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname); |
| 372 | } |
| 373 | } else { |
| 374 | res = dry_run ? 0 : unlink(abs_path.buf); |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 375 | if (res) { |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 376 | qname = quote_path_relative(item->string, NULL, &buf); |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 377 | warning(_(msg_warn_remove_failed), qname); |
Miklos Vajna | aa9c83c | 2008-02-21 02:44:46 +0100 | [diff] [blame] | 378 | errors++; |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 379 | } else if (!quiet) { |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 380 | qname = quote_path_relative(item->string, NULL, &buf); |
Zoltan Klinger | f538a91 | 2013-01-11 09:53:46 +1100 | [diff] [blame] | 381 | printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname); |
Miklos Vajna | aa9c83c | 2008-02-21 02:44:46 +0100 | [diff] [blame] | 382 | } |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 383 | } |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 384 | strbuf_reset(&abs_path); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 385 | } |
Junio C Hamano | d871c86 | 2007-12-04 23:55:41 -0800 | [diff] [blame] | 386 | free(seen); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 387 | |
Jiang Xin | 396049e | 2013-06-25 23:53:47 +0800 | [diff] [blame] | 388 | strbuf_release(&abs_path); |
| 389 | strbuf_release(&buf); |
| 390 | string_list_clear(&del_list, 0); |
Jared Hance | 07de4eb | 2010-07-20 15:35:56 -0400 | [diff] [blame] | 391 | string_list_clear(&exclude_list, 0); |
Miklos Vajna | aa9c83c | 2008-02-21 02:44:46 +0100 | [diff] [blame] | 392 | return (errors != 0); |
Shawn Bohrer | 113f10f | 2007-11-11 19:48:47 -0600 | [diff] [blame] | 393 | } |