Git Import Wizard
[egit.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / repository / RepositoriesViewContentProvider.java
blob2d30bf4a2b36d578be1506a9c0271caeb6676f03
1 /*******************************************************************************
2 * Copyright (c) 2010 SAP AG.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
8 * Contributors:
9 * Mathias Kinzler (SAP AG) - initial implementation
10 *******************************************************************************/
11 package org.eclipse.egit.ui.internal.repository;
13 import java.io.File;
14 import java.io.IOException;
15 import java.net.URISyntaxException;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.Comparator;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Set;
24 import java.util.Map.Entry;
26 import org.eclipse.core.resources.IProjectDescription;
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.core.runtime.NullProgressMonitor;
29 import org.eclipse.egit.ui.Activator;
30 import org.eclipse.egit.ui.UIText;
31 import org.eclipse.egit.ui.internal.clone.GitProjectsImportPage;
32 import org.eclipse.egit.ui.internal.repository.RepositoryTreeNode.RepositoryTreeNodeType;
33 import org.eclipse.jface.viewers.ITreeContentProvider;
34 import org.eclipse.jface.viewers.Viewer;
35 import org.eclipse.jgit.lib.Constants;
36 import org.eclipse.jgit.lib.Ref;
37 import org.eclipse.jgit.lib.RefDatabase;
38 import org.eclipse.jgit.lib.Repository;
39 import org.eclipse.jgit.transport.RemoteConfig;
40 import org.eclipse.osgi.util.NLS;
42 /**
43 * Content Provider for the Git Repositories View
45 public class RepositoriesViewContentProvider implements ITreeContentProvider {
47 @SuppressWarnings("unchecked")
48 public Object[] getElements(Object inputElement) {
50 List<RepositoryTreeNode> nodes = (List<RepositoryTreeNode>) inputElement;
51 Collections.sort(nodes);
52 return nodes.toArray();
55 public void dispose() {
56 // nothing
59 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
60 // nothing
63 public Object[] getChildren(Object parentElement) {
65 RepositoryTreeNode node = (RepositoryTreeNode) parentElement;
66 Repository repo = node.getRepository();
68 switch (node.getType()) {
70 case BRANCHES: {
72 List<RepositoryTreeNode<Repository>> nodes = new ArrayList<RepositoryTreeNode<Repository>>();
74 nodes.add(new RepositoryTreeNode<Repository>(node,
75 RepositoryTreeNodeType.LOCALBRANCHES, repo, repo));
76 nodes.add(new RepositoryTreeNode<Repository>(node,
77 RepositoryTreeNodeType.REMOTEBRANCHES, repo, repo));
79 return nodes.toArray();
82 case LOCALBRANCHES: {
83 List<RepositoryTreeNode<Ref>> refs = new ArrayList<RepositoryTreeNode<Ref>>();
85 try {
86 for (Entry<String, Ref> refEntry : repo.getRefDatabase()
87 .getRefs(Constants.R_HEADS).entrySet()) {
88 if (!refEntry.getValue().isSymbolic())
89 refs.add(new RepositoryTreeNode<Ref>(node,
90 RepositoryTreeNodeType.REF, repo, refEntry
91 .getValue()));
93 } catch (IOException e) {
94 handleException(e, node);
97 return refs.toArray();
100 case REMOTEBRANCHES: {
101 List<RepositoryTreeNode<Ref>> refs = new ArrayList<RepositoryTreeNode<Ref>>();
103 try {
104 for (Entry<String, Ref> refEntry : repo.getRefDatabase()
105 .getRefs(Constants.R_REMOTES).entrySet()) {
106 if (!refEntry.getValue().isSymbolic())
107 refs.add(new RepositoryTreeNode<Ref>(node,
108 RepositoryTreeNodeType.REF, repo, refEntry
109 .getValue()));
111 } catch (IOException e) {
112 handleException(e, node);
115 return refs.toArray();
117 case TAGS: {
118 List<RepositoryTreeNode<Ref>> refs = new ArrayList<RepositoryTreeNode<Ref>>();
120 try {
121 for (Entry<String, Ref> refEntry : repo.getRefDatabase()
122 .getRefs(Constants.R_TAGS).entrySet()) {
123 refs.add(new RepositoryTreeNode<Ref>(node,
124 RepositoryTreeNodeType.TAG, repo, refEntry
125 .getValue()));
127 } catch (IOException e) {
128 handleException(e, node);
131 return refs.toArray();
134 case SYMBOLICREFS: {
135 List<RepositoryTreeNode<Ref>> refs = new ArrayList<RepositoryTreeNode<Ref>>();
137 try {
138 for (Entry<String, Ref> refEntry : repo.getRefDatabase()
139 .getRefs(RefDatabase.ALL).entrySet()) {
140 if (refEntry.getValue().isSymbolic())
141 refs.add(new RepositoryTreeNode<Ref>(node,
142 RepositoryTreeNodeType.SYMBOLICREF, repo,
143 refEntry.getValue()));
145 } catch (IOException e) {
146 handleException(e, node);
149 return refs.toArray();
152 case REMOTES: {
153 List<RepositoryTreeNode<String>> remotes = new ArrayList<RepositoryTreeNode<String>>();
155 Repository rep = node.getRepository();
157 Set<String> configNames = rep.getConfig().getSubsections(
158 RepositoriesView.REMOTE);
160 for (String configName : configNames) {
161 remotes.add(new RepositoryTreeNode<String>(node,
162 RepositoryTreeNodeType.REMOTE, repo, configName));
165 return remotes.toArray();
168 case REPO: {
170 List<RepositoryTreeNode<? extends Object>> nodeList = new ArrayList<RepositoryTreeNode<? extends Object>>();
172 nodeList.add(new RepositoryTreeNode<Repository>(node,
173 RepositoryTreeNodeType.BRANCHES, node.getRepository(), node
174 .getRepository()));
176 nodeList.add(new RepositoryTreeNode<Repository>(node,
177 RepositoryTreeNodeType.TAGS, repo, repo));
179 nodeList.add(new RepositoryTreeNode<Repository>(node,
180 RepositoryTreeNodeType.SYMBOLICREFS, repo, repo));
182 nodeList.add(new RepositoryTreeNode<Repository>(node,
183 RepositoryTreeNodeType.WORKINGDIR, node.getRepository(),
184 node.getRepository()));
186 nodeList.add(new RepositoryTreeNode<Repository>(node,
187 RepositoryTreeNodeType.PROJECTS, node.getRepository(), node
188 .getRepository()));
190 nodeList.add(new RepositoryTreeNode<Repository>(node,
191 RepositoryTreeNodeType.REMOTES, node.getRepository(), node
192 .getRepository()));
194 return nodeList.toArray();
197 case PROJECTS: {
198 List<RepositoryTreeNode<File>> projects = new ArrayList<RepositoryTreeNode<File>>();
200 // TODO do we want to show the projects here?
201 Collection<File> result = new HashSet<File>();
202 Set<String> traversed = new HashSet<String>();
203 collectProjectFilesFromDirectory(result, repo.getDirectory()
204 .getParentFile(), traversed, new NullProgressMonitor());
205 for (File file : result) {
206 projects.add(new RepositoryTreeNode<File>(node,
207 RepositoryTreeNodeType.PROJ, repo, file));
210 Comparator<RepositoryTreeNode<File>> sorter = new Comparator<RepositoryTreeNode<File>>() {
212 public int compare(RepositoryTreeNode<File> o1,
213 RepositoryTreeNode<File> o2) {
214 return o1.getObject().getName().compareTo(
215 o2.getObject().getName());
218 Collections.sort(projects, sorter);
220 return projects.toArray();
223 case WORKINGDIR: {
224 List<RepositoryTreeNode<File>> children = new ArrayList<RepositoryTreeNode<File>>();
226 File workingDir = repo.getWorkDir();
227 if (workingDir == null || !workingDir.exists())
228 return null;
230 File[] childFiles = workingDir.listFiles();
231 Arrays.sort(childFiles, new Comparator<File>() {
232 public int compare(File o1, File o2) {
233 if (o1.isDirectory()) {
234 if (o2.isDirectory()) {
235 return o1.compareTo(o2);
237 return -1;
238 } else if (o2.isDirectory()) {
239 return 1;
241 return o1.compareTo(o2);
244 for (File file : childFiles) {
245 if (file.isDirectory()) {
246 children.add(new RepositoryTreeNode<File>(node,
247 RepositoryTreeNodeType.FOLDER, repo, file));
248 } else {
249 children.add(new RepositoryTreeNode<File>(node,
250 RepositoryTreeNodeType.FILE, repo, file));
254 return children.toArray();
257 case FOLDER: {
258 List<RepositoryTreeNode<File>> children = new ArrayList<RepositoryTreeNode<File>>();
260 File parent = ((File) node.getObject());
262 File[] childFiles = parent.listFiles();
263 Arrays.sort(childFiles, new Comparator<File>() {
264 public int compare(File o1, File o2) {
265 if (o1.isDirectory()) {
266 if (o2.isDirectory()) {
267 return o1.compareTo(o2);
269 return -1;
270 } else if (o2.isDirectory()) {
271 return 1;
273 return o1.compareTo(o2);
276 for (File file : childFiles) {
277 if (file.isDirectory()) {
278 children.add(new RepositoryTreeNode<File>(node,
279 RepositoryTreeNodeType.FOLDER, repo, file));
280 } else {
281 children.add(new RepositoryTreeNode<File>(node,
282 RepositoryTreeNodeType.FILE, repo, file));
286 return children.toArray();
289 case REMOTE: {
291 List<RepositoryTreeNode<String>> children = new ArrayList<RepositoryTreeNode<String>>();
293 String remoteName = (String) node.getObject();
294 RemoteConfig rc;
295 try {
296 rc = new RemoteConfig(node.getRepository().getConfig(),
297 remoteName);
298 } catch (URISyntaxException e) {
299 handleException(e, node);
300 return children.toArray();
303 if (!rc.getURIs().isEmpty())
304 children.add(new RepositoryTreeNode<String>(node,
305 RepositoryTreeNodeType.FETCH, node.getRepository(), rc
306 .getURIs().get(0).toPrivateString()));
308 if (!rc.getPushURIs().isEmpty())
309 if (rc.getPushURIs().size() == 1)
310 children.add(new RepositoryTreeNode<String>(node,
311 RepositoryTreeNodeType.PUSH, node.getRepository(),
312 rc.getPushURIs().get(0).toPrivateString()));
313 else
314 children.add(new RepositoryTreeNode<String>(node,
315 RepositoryTreeNodeType.PUSH, node.getRepository(),
316 rc.getPushURIs().get(0).toPrivateString() + "...")); //$NON-NLS-1$
318 return children.toArray();
322 case FILE:
323 // fall through
324 case REF:
325 // fall through
326 case PUSH:
327 // fall through
328 case PROJ:
329 // fall through
330 case HEAD:
331 // fall through
332 case TAG:
333 // fall through
334 case FETCH:
335 // fall through
336 case ERROR:
337 // fall through
338 case SYMBOLICREF:
339 return null;
343 return null;
347 private void handleException(Exception e, RepositoryTreeNode parentNode) {
348 Activator.handleError(e.getMessage(), e, false);
349 // add a node indicating that there was an Exception
350 new RepositoryTreeNode<String>(parentNode,
351 RepositoryTreeNodeType.ERROR, parentNode.getRepository(),
352 UIText.RepositoriesViewContentProvider_ExceptionNodeText);
355 public Object getParent(Object element) {
357 return ((RepositoryTreeNode) element).getParent();
360 public boolean hasChildren(Object element) {
361 Object[] children = getChildren(element);
362 return children != null && children.length > 0;
365 private boolean collectProjectFilesFromDirectory(Collection<File> files,
366 File directory, Set<String> directoriesVisited,
367 IProgressMonitor monitor) {
369 // stolen from the GitCloneWizard; perhaps we should completely drop
370 // the projects from this view, though
371 if (monitor.isCanceled()) {
372 return false;
374 monitor.subTask(NLS.bind(UIText.RepositoriesView_Checking_Message,
375 directory.getPath()));
376 File[] contents = directory.listFiles();
377 if (contents == null)
378 return false;
380 // first look for project description files
381 final String dotProject = IProjectDescription.DESCRIPTION_FILE_NAME;
382 for (int i = 0; i < contents.length; i++) {
383 File file = contents[i];
384 if (file.isFile() && file.getName().equals(dotProject)) {
385 files.add(file.getParentFile());
386 // don't search sub-directories since we can't have nested
387 // projects
388 return true;
391 // no project description found, so recurse into sub-directories
392 for (int i = 0; i < contents.length; i++) {
393 if (contents[i].isDirectory()) {
394 if (!contents[i].getName().equals(
395 GitProjectsImportPage.METADATA_FOLDER)) {
396 try {
397 String canonicalPath = contents[i].getCanonicalPath();
398 if (!directoriesVisited.add(canonicalPath)) {
399 // already been here --> do not recurse
400 continue;
402 } catch (IOException e) {
403 Activator.handleError(e.getMessage(), e, false);
405 collectProjectFilesFromDirectory(files, contents[i],
406 directoriesVisited, monitor);
410 return true;