com.microsoft.alm.plugin.idea.tfvc.core.TFSChangeProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.alm.plugin.idea.tfvc.core.TFSChangeProvider.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root.

package com.microsoft.alm.plugin.idea.tfvc.core;

import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.ChangeListManagerGate;
import com.intellij.openapi.vcs.changes.ChangeProvider;
import com.intellij.openapi.vcs.changes.ChangelistBuilder;
import com.intellij.openapi.vcs.changes.VcsDirtyScope;
import com.intellij.openapi.vfs.VirtualFile;
import com.microsoft.alm.plugin.context.ServerContext;
import com.microsoft.alm.plugin.external.commands.Command;
import com.microsoft.alm.plugin.external.commands.StatusCommand;
import com.microsoft.alm.plugin.external.models.PendingChange;
import com.microsoft.alm.plugin.idea.tfvc.core.tfs.RootsCollection;
import com.microsoft.alm.plugin.idea.tfvc.core.tfs.StatusProvider;
import com.microsoft.alm.plugin.idea.tfvc.exceptions.TfsException;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.List;

/**
 * Extends the VCS change provider to execture the correct events to find out the local changes in the workspace
 * <p/>
 * TODO (Jetbrains) important cases
 * 1. when folder1 is unversioned and folder1/file1 is scheduled for addition, team explorer effectively shows folder1 as scheduled for addition
 */

public class TFSChangeProvider implements ChangeProvider {
    private static final Logger logger = LoggerFactory.getLogger(TFSChangeProvider.class);

    private final Project myProject;

    public TFSChangeProvider(final Project project) {
        myProject = project;
    }

    public boolean isModifiedDocumentTrackingRequired() {
        return true;
    }

    public void doCleanup(final List<VirtualFile> files) {
    }

    public void getChanges(@NotNull final VcsDirtyScope dirtyScope, @NotNull final ChangelistBuilder builder,
            @NotNull final ProgressIndicator progress, @NotNull final ChangeListManagerGate addGate)
            throws VcsException {

        if (myProject.isDisposed()) {
            return;
        }
        if (builder == null) {
            return;
        }

        progress.setText("Processing changes");

        // Get server context for this project
        final ServerContext serverContext = TFSVcs.getInstance(myProject).getServerContext(false);

        // process only roots, filter out child items since requests are recursive anyway
        RootsCollection.FilePathRootsCollection roots = new RootsCollection.FilePathRootsCollection();
        roots.addAll(dirtyScope.getRecursivelyDirtyDirectories());

        final ChangeListManager changeListManager = ChangeListManager.getInstance(myProject);
        for (FilePath dirtyFile : dirtyScope.getDirtyFiles()) {
            // workaround for IDEADEV-31511 and IDEADEV-31721
            if (dirtyFile.getVirtualFile() == null
                    || !changeListManager.isIgnoredFile(dirtyFile.getVirtualFile())) {
                roots.add(dirtyFile);
            }
        }

        if (roots.isEmpty()) {
            return;
        }

        final ChangelistBuilderStatusVisitor changelistBuilderStatusVisitor = new ChangelistBuilderStatusVisitor(
                myProject, serverContext, builder);

        for (final FilePath root : roots) {
            // if we get a change notification in the $tf folder, we need to just ignore it
            if (StringUtils.containsIgnoreCase(root.getPath(), "$tf")
                    || StringUtils.containsIgnoreCase(root.getPath(), ".tf")) {
                continue;
            }

            List<PendingChange> changes;
            try {
                // TODO: add the ability to pass multiple roots to the command line
                final Command<List<PendingChange>> command = new StatusCommand(serverContext, root.getPath());
                changes = command.runSynchronously();
            } catch (final Throwable t) {
                logger.warn("Failed to get changes from command line. root=" + root.getPath(), t);
                changes = Collections.emptyList();
            }

            // for each change, find out the status of the changes and then add to the list
            for (final PendingChange change : changes) {
                try {
                    StatusProvider.visitByStatus(changelistBuilderStatusVisitor, change);
                } catch (TfsException e) {
                    throw new VcsException(e.getMessage(), e);
                }
            }
        }
    }

}