in plugin/src/com/microsoft/alm/plugin/idea/tfvc/core/TFSFileSystemListener.java [65:225]
public boolean delete(@NotNull final VirtualFile virtualFile) throws IOException {
long startTime = System.nanoTime();
ourLogger.trace("Delete command started for file " + virtualFile);
final TFSVcs vcs = VcsHelper.getTFSVcsByPath(virtualFile);
// no TFSVcs so not a TFVC project so do nothing
if (vcs == null) {
ourLogger.info("Not a TFVC project so not doing a TFVC delete");
return false;
}
if (TFVCUtil.isInvalidTFVCPath(vcs, new LocalFilePath(virtualFile.getPath(), virtualFile.isDirectory()))) {
ourLogger.warn("Invalid file name for TFVC, so not performing TFVC delete: {}", virtualFile.getPath());
return false;
}
// do nothing with TFVC if the user chooses not to
final VcsShowConfirmationOption.Value value = vcs.getDeleteConfirmation().getValue();
if (VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY.equals(value)) {
ourLogger.info("Don't delete file from TFVC: " + virtualFile.getPath());
return false;
}
ourLogger.info("Deleting file with TFVC: " + virtualFile.getPath());
final Project currentProject = vcs.getProject();
// TODO: Currently, we cannot allow the users to undo directory deletion, because there's no non-recursive
// `tf undo` command. In future, we may allow this after we drop legacy client support and add a undo command
// that won't touch the disk at all.
//
// Currently, `tf undo` will always try to restore the whole directory (with ALL the files) which breaks the
// undo behavior.
if (virtualFile.isDirectory()) {
ourLogger.info("Marking operation as non-undoable since directory \"{}\" is deleted", virtualFile);
DocumentReference ref = DocumentReferenceManager.getInstance().create(virtualFile);
UndoManager.getInstance(currentProject).nonundoableActionPerformed(ref, false);
}
TfvcClient tfvcClient = TfvcClient.getInstance();
ServerContext serverContext = vcs.getServerContext(true);
List<PendingChange> pendingChanges = tfvcClient.getStatusForFiles(
currentProject,
serverContext,
Collections.singletonList(virtualFile.getPath()));
// if 0 pending changes then just delete the file and return
if (pendingChanges.isEmpty()) {
ourLogger.info("No changes to file so deleting though TFVC");
TfvcDeleteResult operationResult = tfvcClient.deleteFilesRecursively(
currentProject,
serverContext,
Collections.singletonList(TfsFileUtil.createLocalPath(virtualFile)));
operationResult.throwIfErrorMessagesAreNotEmpty();
long time = System.nanoTime() - startTime;
ourLogger.trace("Delete command finished in " + time / 1_000_000_000.0 + "s");
// There's a possibility that the path in question was explicitly ignored using .tfignore. In such case,
// TFVC client will report that the file wasn't found and won't do anything with it. If this happened, then
// we'll delegate the operation to IDEA (i.e. return false).
List<TfsPath> notFoundPaths = operationResult.getNotFoundPaths();
return notFoundPaths.isEmpty();
}
// start with assuming you don't need to revert but look at the pending changes to see if that's incorrect
final AtomicBoolean revert = new AtomicBoolean(false);
// assume false until we know we need to delete from TFVC
final AtomicBoolean success = new AtomicBoolean(false);
final AtomicBoolean isUndelete = new AtomicBoolean(false);
for (final PendingChange pendingChange : pendingChanges) {
StatusProvider.visitByStatus(new StatusVisitor() {
public void scheduledForAddition(final @NotNull FilePath localPath,
final boolean localItemExists,
final @NotNull ServerStatus serverStatus) {
// revert the file and then let the IDE delete it
revert.set(true);
success.set(false);
}
public void unversioned(final @NotNull FilePath localPath,
final boolean localItemExists,
final @NotNull ServerStatus serverStatus) {
// only do something if it's an unversioned delete, the IDE will take care of it otherwise
if (pendingChange.getChangeTypes().contains(ServerStatusType.DELETE)) {
revert.set(true);
success.set(true);
}
}
public void scheduledForDeletion(final @NotNull FilePath localPath,
final boolean localItemExists,
final @NotNull ServerStatus serverStatus) {
// already deleted on server so let IDE take care of it
success.set(false);
}
public void checkedOutForEdit(final @NotNull FilePath localPath,
final boolean localItemExists,
final @NotNull ServerStatus serverStatus) {
// revert it and then delete it
revert.set(true);
success.set(true);
}
@Override
public void locked(@NotNull FilePath localPath, boolean localItemExists, @NotNull ServerStatus serverStatus) {
// nothing to do if it's locked
success.set(false);
}
public void renamed(final @NotNull FilePath localPath, final boolean localItemExists, final @NotNull ServerStatus serverStatus) {
// revert it and then delete it
revert.set(true);
success.set(true);
}
public void renamedCheckedOut(final @NotNull FilePath localPath,
final boolean localItemExists,
final @NotNull ServerStatus serverStatus) {
// revert it and then delete it
revert.set(true);
success.set(true);
}
public void undeleted(final @NotNull FilePath localPath,
final boolean localItemExists,
final @NotNull ServerStatus serverStatus) {
// revert it and it will be deleted
revert.set(true);
isUndelete.set(true);
}
}, pendingChange);
}
if (revert.get()) {
TfsPath filePath = TfsFileUtil.createLocalPath(virtualFile);
tfvcClient.undoLocalChanges(currentProject, serverContext, Collections.singletonList(filePath));
}
if (success.get() && !isUndelete.get()) {
ourLogger.info("Deleting file with TFVC after undoing pending changes");
// PendingChanges will always have at least 1 element or else we wouldn't have gotten this far
PendingChange pendingChange = pendingChanges.get(0);
TfsPath itemToDelete = StringUtils.isNotEmpty(pendingChange.getSourceItem())
? new TfsServerPath(pendingChange.getWorkspace(), pendingChange.getSourceItem())
: TfsFileUtil.createLocalPath(pendingChange.getLocalItem());
TfvcDeleteResult operationResult = tfvcClient.deleteFilesRecursively(
currentProject,
serverContext,
Collections.singletonList(itemToDelete));
operationResult.throwIfErrorMessagesAreNotEmpty();
operationResult.throwIfNotFoundPathsAreNotEmpty();
}
ourLogger.info("File was deleted using TFVC: " + success.get());
long time = System.nanoTime() - startTime;
ourLogger.trace("Delete command finished in " + time / 1_000_000_000.0 + "s");
return success.get();
}