1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.api;
12
13 import static org.eclipse.jgit.lib.Constants.DOT_GIT;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.util.Collections;
18 import java.util.Set;
19 import java.util.TreeSet;
20
21 import org.eclipse.jgit.api.errors.GitAPIException;
22 import org.eclipse.jgit.api.errors.JGitInternalException;
23 import org.eclipse.jgit.errors.NoWorkTreeException;
24 import org.eclipse.jgit.events.WorkingTreeModifiedEvent;
25 import org.eclipse.jgit.lib.Repository;
26 import org.eclipse.jgit.util.FS;
27 import org.eclipse.jgit.util.FileUtils;
28 import org.eclipse.jgit.util.Paths;
29
30
31
32
33
34
35
36
37 public class CleanCommand extends GitCommand<Set<String>> {
38
39 private Set<String> paths = Collections.emptySet();
40
41 private boolean dryRun;
42
43 private boolean directories;
44
45 private boolean ignore = true;
46
47 private boolean force = false;
48
49
50
51
52
53
54
55 protected CleanCommand(Repository repo) {
56 super(repo);
57 }
58
59
60
61
62
63
64
65
66
67 @Override
68 public Set<String> call() throws NoWorkTreeException, GitAPIException {
69 Set<String> files = new TreeSet<>();
70 try {
71 StatusCommand command = new StatusCommand(repo);
72 Status status = command.call();
73
74 Set<String> untrackedFiles = new TreeSet<>(status.getUntracked());
75 Set<String> untrackedDirs = new TreeSet<>(
76 status.getUntrackedFolders());
77
78 FS fs = getRepository().getFS();
79 for (String p : status.getIgnoredNotInIndex()) {
80 File f = new File(repo.getWorkTree(), p);
81 if (fs.isFile(f) || fs.isSymLink(f)) {
82 untrackedFiles.add(p);
83 } else if (fs.isDirectory(f)) {
84 untrackedDirs.add(p);
85 }
86 }
87
88 Set<String> filtered = filterFolders(untrackedFiles, untrackedDirs);
89
90 Set<String> notIgnoredFiles = filterIgnorePaths(filtered,
91 status.getIgnoredNotInIndex(), true);
92 Set<String> notIgnoredDirs = filterIgnorePaths(untrackedDirs,
93 status.getIgnoredNotInIndex(), false);
94
95 for (String file : notIgnoredFiles) {
96 if (paths.isEmpty() || paths.contains(file)) {
97 files = cleanPath(file, files);
98 }
99 }
100 for (String dir : notIgnoredDirs) {
101 if (paths.isEmpty() || paths.contains(dir)) {
102 files = cleanPath(dir, files);
103 }
104 }
105 } catch (IOException e) {
106 throw new JGitInternalException(e.getMessage(), e);
107 } finally {
108 if (!dryRun && !files.isEmpty()) {
109 repo.fireEvent(new WorkingTreeModifiedEvent(null, files));
110 }
111 }
112 return files;
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 private Set<String> cleanPath(String path, Set<String> inFiles)
136 throws IOException {
137 File curFile = new File(repo.getWorkTree(), path);
138 if (curFile.isDirectory()) {
139 if (directories) {
140
141 if (new File(curFile, DOT_GIT).exists()) {
142 if (force) {
143 if (!dryRun) {
144 FileUtils.delete(curFile, FileUtils.RECURSIVE
145 | FileUtils.SKIP_MISSING);
146 }
147 inFiles.add(path + '/');
148 }
149 } else {
150 if (!dryRun) {
151 FileUtils.delete(curFile,
152 FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
153 }
154 inFiles.add(path + '/');
155 }
156 }
157 } else {
158 if (!dryRun) {
159 FileUtils.delete(curFile, FileUtils.SKIP_MISSING);
160 }
161 inFiles.add(path);
162 }
163
164 return inFiles;
165 }
166
167 private Set<String> filterIgnorePaths(Set<String> inputPaths,
168 Set<String> ignoredNotInIndex, boolean exact) {
169 if (ignore) {
170 Set<String> filtered = new TreeSet<>(inputPaths);
171 for (String path : inputPaths) {
172 for (String ignored : ignoredNotInIndex) {
173 if ((exact && path.equals(ignored))
174 || (!exact
175 && Paths.isEqualOrPrefix(ignored, path))) {
176 filtered.remove(path);
177 break;
178 }
179 }
180 }
181 return filtered;
182 }
183 return inputPaths;
184 }
185
186 private Set<String> filterFolders(Set<String> untracked,
187 Set<String> untrackedFolders) {
188 Set<String> filtered = new TreeSet<>(untracked);
189 for (String file : untracked) {
190 for (String folder : untrackedFolders) {
191 if (Paths.isEqualOrPrefix(folder, file)) {
192 filtered.remove(file);
193 break;
194 }
195 }
196 }
197 return filtered;
198 }
199
200
201
202
203
204
205
206
207 public CleanCommand setPaths(Set<String> paths) {
208 this.paths = paths;
209 return this;
210 }
211
212
213
214
215
216
217
218
219 public CleanCommand setDryRun(boolean dryRun) {
220 this.dryRun = dryRun;
221 return this;
222 }
223
224
225
226
227
228
229
230
231
232
233 public CleanCommand setForce(boolean force) {
234 this.force = force;
235 return this;
236 }
237
238
239
240
241
242
243
244
245 public CleanCommand setCleanDirectories(boolean dirs) {
246 directories = dirs;
247 return this;
248 }
249
250
251
252
253
254
255
256
257
258 public CleanCommand setIgnore(boolean ignore) {
259 this.ignore = ignore;
260 return this;
261 }
262 }