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