Use the Git sort order.
[egit.git] / org.spearce.egit.core / src / org / spearce / egit / core / op / TrackOperation.java
blob687fa14002118fb828a591c871db13d7d927eade
1 /*
2 * Copyright (C) 2006 Shawn Pearce <spearce@spearce.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License, version 2.1, as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
17 package org.spearce.egit.core.op;
19 import java.io.IOException;
20 import java.util.Collection;
21 import java.util.IdentityHashMap;
22 import java.util.Iterator;
23 import java.util.Map;
25 import org.eclipse.core.resources.IContainer;
26 import org.eclipse.core.resources.IFile;
27 import org.eclipse.core.resources.IResource;
28 import org.eclipse.core.resources.IWorkspaceRunnable;
29 import org.eclipse.core.runtime.CoreException;
30 import org.eclipse.core.runtime.IProgressMonitor;
31 import org.eclipse.core.runtime.NullProgressMonitor;
32 import org.spearce.egit.core.Activator;
33 import org.spearce.egit.core.CoreText;
34 import org.spearce.egit.core.project.GitProjectData;
35 import org.spearce.egit.core.project.RepositoryMapping;
36 import org.spearce.jgit.lib.Tree;
37 import org.spearce.jgit.lib.TreeEntry;
39 /**
40 * Add one or more new files/folders to the Git repository.
41 * <p>
42 * Accepts a collection of resources (files and/or directories) which should be
43 * added to the their corresponding Git repositories. Resources in the
44 * collection can be associated with multiple repositories. The operation will
45 * automatically associate each resource with the nearest containing Git
46 * repository.
47 * </p>
48 * <p>
49 * Resources are only scheduled for addition in the cache-tree. Their backing
50 * object in the object database is not built yet (as that can be a time
51 * consuming operation, depending on file size) and the cache-tree will be dirty
52 * in memory, needing a checkpoint.
53 * </p>
55 public class TrackOperation implements IWorkspaceRunnable {
56 private final Collection rsrcList;
58 /**
59 * Create a new operation to track additional files/folders.
61 * @param rsrcs
62 * collection of {@link IResource}s which should be added to the
63 * relevant Git repositories.
65 public TrackOperation(final Collection rsrcs) {
66 rsrcList = rsrcs;
69 public void run(IProgressMonitor m) throws CoreException {
70 if (m == null) {
71 m = new NullProgressMonitor();
74 final IdentityHashMap tomerge = new IdentityHashMap();
75 m.beginTask(CoreText.AddOperation_adding, rsrcList.size() * 200);
76 try {
77 final Iterator i = rsrcList.iterator();
78 while (i.hasNext()) {
79 final Object obj = i.next();
80 if (obj instanceof IResource) {
81 add(tomerge, (IResource) obj);
83 m.worked(200);
85 } finally {
86 try {
87 final Iterator i = tomerge.keySet().iterator();
88 while (i.hasNext()) {
89 final RepositoryMapping r = (RepositoryMapping) i.next();
90 r.recomputeMerge();
92 } catch (IOException ioe) {
93 throw Activator.error(CoreText.AddOperation_failed, ioe);
94 } finally {
95 m.done();
100 private void add(final Map tomerge, final IResource toAdd)
101 throws CoreException {
102 final GitProjectData pd = GitProjectData.get(toAdd.getProject());
103 IResource r = toAdd;
104 String s = null;
105 RepositoryMapping m = null;
107 while (r != null) {
108 m = pd.getRepositoryMapping(r);
109 if (m != null) {
110 break;
113 if (s != null) {
114 s = r.getName() + "/" + s;
115 } else {
116 s = r.getName();
119 r = r.getParent();
122 if (s == null || m == null || m.getCacheTree() == null) {
123 return;
126 try {
127 tomerge.put(m, m);
128 add(m.getCacheTree(), s, toAdd);
129 } catch (IOException ioe) {
130 throw Activator.error(CoreText.AddOperation_failed, ioe);
134 private void add(final Tree t, final String path, final IResource toAdd)
135 throws IOException, CoreException {
136 if (!toAdd.exists()) {
137 // Uh, what? Why are we adding a phantom resource? Just say no!
139 } else if (toAdd instanceof IFile) {
140 if (!t.existsTree(path)) {
141 if (!t.existsBlob(path)) {
142 t.addFile(path);
145 } else if (toAdd instanceof IContainer) {
146 final IResource[] m = ((IContainer) toAdd).members();
147 final TreeEntry e = t.findTreeMember(path);
148 final Tree c;
149 c = e instanceof Tree ? (Tree) e : e == null ? t.addTree(path)
150 : null;
151 if (c != null) {
152 for (int k = 0; k < m.length; k++) {
153 add(c, m[k].getName(), m[k]);
156 // GIT does not take kindly to empty trees. If we just created
157 // such a thing remove it. We do the detection after-the-fact
158 // as its hard to know if all of our children were also empty
159 // subtrees.
161 if (c.memberCount() == 0) {
162 c.delete();