Teach GitMoveDeleteHook how to move a folder recursively
[egit.git] / org.spearce.egit.core / src / org / spearce / egit / core / GitMoveDeleteHook.java
blob2cdff7dbae382873ff1ecf2497cfef6b2c575563
1 /*******************************************************************************
2 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.org>
4 * Copyright (C) 2008, Google Inc.
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * See LICENSE for the full license text, also available.
9 *******************************************************************************/
10 package org.spearce.egit.core;
12 import java.io.IOException;
14 import org.eclipse.core.resources.IFile;
15 import org.eclipse.core.resources.IFolder;
16 import org.eclipse.core.resources.IProject;
17 import org.eclipse.core.resources.IProjectDescription;
18 import org.eclipse.core.resources.IResource;
19 import org.eclipse.core.resources.team.IMoveDeleteHook;
20 import org.eclipse.core.resources.team.IResourceTree;
21 import org.eclipse.core.runtime.Assert;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.Status;
25 import org.spearce.egit.core.project.GitProjectData;
26 import org.spearce.egit.core.project.RepositoryMapping;
27 import org.spearce.jgit.dircache.DirCache;
28 import org.spearce.jgit.dircache.DirCacheBuilder;
29 import org.spearce.jgit.dircache.DirCacheEditor;
30 import org.spearce.jgit.dircache.DirCacheEntry;
32 class GitMoveDeleteHook implements IMoveDeleteHook {
33 private static final boolean I_AM_DONE = true;
35 private static final boolean FINISH_FOR_ME = false;
37 private final GitProjectData data;
39 GitMoveDeleteHook(final GitProjectData d) {
40 Assert.isNotNull(d);
41 data = d;
44 public boolean deleteFile(final IResourceTree tree, final IFile file,
45 final int updateFlags, final IProgressMonitor monitor) {
46 final boolean force = (updateFlags & IResource.FORCE) == IResource.FORCE;
47 if (!force && !tree.isSynchronized(file, IResource.DEPTH_ZERO))
48 return false;
50 final RepositoryMapping map = RepositoryMapping.getMapping(file);
51 if (map == null)
52 return false;
54 try {
55 final DirCache dirc = DirCache.lock(map.getRepository());
56 final int first = dirc.findEntry(map.getRepoRelativePath(file));
57 if (first < 0) {
58 dirc.unlock();
59 return false;
62 final DirCacheBuilder edit = dirc.builder();
63 if (first > 0)
64 edit.keep(0, first);
65 final int next = dirc.nextEntry(first);
66 if (next < dirc.getEntryCount())
67 edit.keep(next, dirc.getEntryCount() - next);
68 if (!edit.commit())
69 tree.failed(new Status(IStatus.ERROR, Activator.getPluginId(),
70 0, CoreText.MoveDeleteHook_operationError, null));
71 tree.standardDeleteFile(file, updateFlags, monitor);
72 } catch (IOException e) {
73 tree.failed(new Status(IStatus.ERROR, Activator.getPluginId(), 0,
74 CoreText.MoveDeleteHook_operationError, e));
76 return true;
79 public boolean deleteFolder(final IResourceTree tree, final IFolder folder,
80 final int updateFlags, final IProgressMonitor monitor) {
81 // Deleting a GIT repository which is in use is a pretty bad idea. To
82 // delete disconnect the team provider first.
84 if (data.isProtected(folder)) {
85 return cannotModifyRepository(tree);
86 } else {
87 return FINISH_FOR_ME;
91 public boolean deleteProject(final IResourceTree tree,
92 final IProject project, final int updateFlags,
93 final IProgressMonitor monitor) {
94 // TODO: Note that eclipse thinks folders are real, while
95 // Git does not care.
96 return FINISH_FOR_ME;
99 public boolean moveFile(final IResourceTree tree, final IFile srcf,
100 final IFile dstf, final int updateFlags,
101 final IProgressMonitor monitor) {
102 final boolean force = (updateFlags & IResource.FORCE) == IResource.FORCE;
103 if (!force && !tree.isSynchronized(srcf, IResource.DEPTH_ZERO))
104 return false;
106 final RepositoryMapping srcm = RepositoryMapping.getMapping(srcf);
107 if (srcm == null)
108 return false;
109 final RepositoryMapping dstm = RepositoryMapping.getMapping(dstf);
111 try {
112 final DirCache sCache = DirCache.lock(srcm.getRepository());
113 final String sPath = srcm.getRepoRelativePath(srcf);
114 final DirCacheEntry sEnt = sCache.getEntry(sPath);
115 if (sEnt == null) {
116 sCache.unlock();
117 return false;
120 final DirCacheEditor sEdit = sCache.editor();
121 sEdit.add(new DirCacheEditor.DeletePath(sEnt));
122 if (dstm != null && dstm.getRepository() == srcm.getRepository()) {
123 final String dPath = srcm.getRepoRelativePath(dstf);
124 sEdit.add(new DirCacheEditor.PathEdit(dPath) {
125 @Override
126 public void apply(final DirCacheEntry dEnt) {
127 dEnt.copyMetaData(sEnt);
131 if (!sEdit.commit())
132 tree.failed(new Status(IStatus.ERROR, Activator.getPluginId(),
133 0, CoreText.MoveDeleteHook_operationError, null));
135 tree.standardMoveFile(srcf, dstf, updateFlags, monitor);
136 } catch (IOException e) {
137 tree.failed(new Status(IStatus.ERROR, Activator.getPluginId(), 0,
138 CoreText.MoveDeleteHook_operationError, e));
140 return true;
143 public boolean moveFolder(final IResourceTree tree, final IFolder srcf,
144 final IFolder dstf, final int updateFlags,
145 final IProgressMonitor monitor) {
146 final boolean force = (updateFlags & IResource.FORCE) == IResource.FORCE;
147 if (!force && !tree.isSynchronized(srcf, IResource.DEPTH_ZERO))
148 return false;
150 final RepositoryMapping srcm = RepositoryMapping.getMapping(srcf);
151 if (srcm == null)
152 return false;
153 final RepositoryMapping dstm = RepositoryMapping.getMapping(dstf);
155 try {
156 final DirCache sCache = DirCache.lock(srcm.getRepository());
157 final String sPath = srcm.getRepoRelativePath(srcf);
158 final DirCacheEntry[] sEnt = sCache.getEntriesWithin(sPath);
159 if (sEnt.length == 0) {
160 sCache.unlock();
161 return false;
164 final DirCacheEditor sEdit = sCache.editor();
165 sEdit.add(new DirCacheEditor.DeleteTree(sPath));
166 if (dstm != null && dstm.getRepository() == srcm.getRepository()) {
167 final String dPath = srcm.getRepoRelativePath(dstf) + "/";
168 final int sPathLen = sPath.length() + 1;
169 for (final DirCacheEntry se : sEnt) {
170 final String p = se.getPathString().substring(sPathLen);
171 sEdit.add(new DirCacheEditor.PathEdit(dPath + p) {
172 @Override
173 public void apply(final DirCacheEntry dEnt) {
174 dEnt.copyMetaData(se);
179 if (!sEdit.commit())
180 tree.failed(new Status(IStatus.ERROR, Activator.getPluginId(),
181 0, CoreText.MoveDeleteHook_operationError, null));
183 tree.standardMoveFolder(srcf, dstf, updateFlags, monitor);
184 } catch (IOException e) {
185 tree.failed(new Status(IStatus.ERROR, Activator.getPluginId(), 0,
186 CoreText.MoveDeleteHook_operationError, e));
188 return true;
191 public boolean moveProject(final IResourceTree tree, final IProject source,
192 final IProjectDescription description, final int updateFlags,
193 final IProgressMonitor monitor) {
194 // TODO: We should be able to do this without too much effort when the
195 // projects belong to the same Git repository.
196 return FINISH_FOR_ME;
199 private boolean cannotModifyRepository(final IResourceTree tree) {
200 tree.failed(new Status(IStatus.ERROR, Activator.getPluginId(), 0,
201 CoreText.MoveDeleteHook_cannotModifyFolder, null));
202 return I_AM_DONE;