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