blob: 913383830cd14ccc7803bd5f56dec11e8f94ea30 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Matt McCutchen - fix for bug 174492
* James Blackburn (Broadcom Corp.) - ongoing development
*******************************************************************************/
package org.eclipse.core.internal.localstore;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.filesystem.*;
import org.eclipse.core.filesystem.provider.FileInfo;
import org.eclipse.core.internal.resources.ICoreConstants;
import org.eclipse.core.internal.resources.Resource;
import org.eclipse.core.internal.utils.Messages;
import org.eclipse.core.internal.utils.Policy;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;
public class DeleteVisitor implements IUnifiedTreeVisitor, ICoreConstants {
protected boolean force;
protected boolean keepHistory;
protected IProgressMonitor monitor;
protected List<Resource> skipList;
protected MultiStatus status;
/**
* The number of tickets available on the progress monitor
*/
private int ticks;
public DeleteVisitor(List<Resource> skipList, int flags, IProgressMonitor monitor, int ticks) {
this.skipList = skipList;
this.ticks = ticks;
this.force = (flags & IResource.FORCE) != 0;
this.keepHistory = (flags & IResource.KEEP_HISTORY) != 0;
this.monitor = monitor;
status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.FAILED_DELETE_LOCAL, Messages.localstore_deleteProblem, null);
}
/**
* Deletes a file from both the workspace resource tree and the file system.
*/
protected void delete(UnifiedTreeNode node, boolean shouldKeepHistory) {
Resource target = (Resource) node.getResource();
try {
final boolean deleteLocalFile = !target.isLinked() && node.existsInFileSystem();
IFileStore localFile = deleteLocalFile ? node.getStore() : null;
if (deleteLocalFile && shouldKeepHistory)
recursiveKeepHistory(target.getLocalManager().getHistoryStore(), node);
node.removeChildrenFromTree();
//delete from disk
int work = ticks < 0 ? 0 : ticks;
ticks -= work;
if (deleteLocalFile)
localFile.delete(EFS.NONE, Policy.subMonitorFor(monitor, work));
else
monitor.worked(work);
//delete from tree
if (node.existsInWorkspace())
target.deleteResource(true, status);
} catch (CoreException e) {
status.add(e.getStatus());
// delete might have been partly successful, so refresh to ensure in sync
try {
target.refreshLocal(IResource.DEPTH_INFINITE, null);
} catch (CoreException e1) {
//ignore secondary failure - we are just trying to cleanup from first failure
}
}
}
/**
* Only consider path in equality in order to handle gender changes
*/
protected boolean equals(IResource one, IResource another) {
return one.getFullPath().equals(another.getFullPath());
}
public MultiStatus getStatus() {
return status;
}
protected boolean isAncestor(IResource one, IResource another) {
return one.getFullPath().isPrefixOf(another.getFullPath()) && !equals(one, another);
}
protected boolean isAncestorOfResourceToSkip(IResource resource) {
if (skipList == null)
return false;
for (IResource target : skipList) {
if (isAncestor(resource, target))
return true;
}
return false;
}
private void recursiveKeepHistory(IHistoryStore store, UnifiedTreeNode node) {
final IResource target = node.getResource();
//we don't delete linked content, so no need to keep history
if (target.isLinked() || target.isVirtual() || node.isSymbolicLink())
return;
if (node.isFolder()) {
monitor.subTask(NLS.bind(Messages.localstore_deleting, target.getFullPath()));
for (Iterator<UnifiedTreeNode> children = node.getChildren(); children.hasNext();)
recursiveKeepHistory(store, children.next());
} else {
IFileInfo info = node.fileInfo;
if (info == null)
info = new FileInfo(node.getLocalName());
store.addState(target.getFullPath(), node.getStore(), info, true);
}
monitor.worked(1);
ticks--;
}
protected void removeFromSkipList(IResource resource) {
if (skipList != null)
skipList.remove(resource);
}
protected boolean shouldSkip(IResource resource) {
if (skipList == null)
return false;
for (int i = 0; i < skipList.size(); i++)
if (equals(resource, skipList.get(i)))
return true;
return false;
}
@Override
public boolean visit(UnifiedTreeNode node) {
Policy.checkCanceled(monitor);
Resource target = (Resource) node.getResource();
if (shouldSkip(target)) {
removeFromSkipList(target);
int skipTicks = target.countResources(IResource.DEPTH_INFINITE, false);
monitor.worked(skipTicks);
ticks -= skipTicks;
return false;
}
if (isAncestorOfResourceToSkip(target))
return true;
delete(node, keepHistory);
return false;
}
}