// (C) Copyright 2003-2013 Hewlett-Packard Development Company, L.P. package com.hp.alm.ali.idea.action.changeset; import com.hp.alm.ali.idea.action.EntityAction; import com.hp.alm.ali.idea.entity.EntityListener; import com.hp.alm.ali.idea.entity.EntityQuery; import com.hp.alm.ali.idea.entity.EntityRef; import com.hp.alm.ali.idea.model.Entity; import com.hp.alm.ali.idea.model.parser.EntityList; import com.hp.alm.ali.idea.revision.RevisionFactory; import com.hp.alm.ali.idea.services.EntityService; import com.hp.alm.ali.idea.util.MessagesUtil; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.PerformInBackgroundOption; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.CommittedChangesProvider; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.VcsRoot; import com.intellij.openapi.vcs.annotate.ShowAllAffectedGenericAction; import com.intellij.openapi.vcs.changes.TextRevisionNumber; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.Collections; import java.util.Set; public class ShowAffectedPathsAction extends EntityAction { private static Logger logger = Logger.getInstance(ShowAffectedPathsAction.class); public ShowAffectedPathsAction() { super("Paths", "Show Affected Paths", IconLoader.getIcon("/diff/Diff.png")); } @Override protected Set<String> getSupportedEntityTypes() { return Collections.singleton("changeset"); } @Override public void update(AnActionEvent event) { super.update(event); } @Override protected void actionPerformed(AnActionEvent event, final Project project, final Entity entity) { ProgressManager.getInstance().run(new Task.Backgroundable(project, "Show Affected Paths", true, PerformInBackgroundOption.DEAF) { @Override public void run(@NotNull final ProgressIndicator indicator) { indicator.setIndeterminate(true); EntityQuery query = new EntityQuery("changeset-file"); query.addColumn("scm-repository", 1); query.setValue("parent-id", String.valueOf(entity.getId())); EntityService entityService = project.getComponent(EntityService.class); EntityList list = entityService.query(query); if (indicator.isCanceled()) { return; } if (list.isEmpty()) { MessagesUtil.showErrorDialogLater(project, "Couldn't locate changeset, operation cannot proceed", "Failed"); return; } entityService.requestCachedEntity(new EntityRef("scm-repository", Integer.valueOf(list.get(0).getPropertyValue("scm-repository"))), Arrays.asList("location", "alias"), new EntityListener() { @Override public void entityLoaded(Entity repository, Event event) { if (indicator.isCanceled()) { return; } VcsRoot vcsRoot = findRepository(project, repository); if (vcsRoot != null) { try { if(showInVcsRoot(project, vcsRoot, entity)) { return; } } catch (VcsException e) { // shouldn't fail if exact match, report logger.error(e); } } else { VcsRoot[] vcsRoots = ProjectLevelVcsManager.getInstance(project).getAllVcsRoots(); for (VcsRoot root : vcsRoots) { try { if (showInVcsRoot(project, root, entity)) { return; } } catch (VcsException e) { // since we try all available vcs all kind of errors can happen (don't log as error) logger.debug(e); } } } MessagesUtil.showErrorDialogLater(project, "Couldn't locate revision in the project, try updating your VCS", "Failed"); } @Override public void entityNotFound(EntityRef ref, boolean removed) { MessagesUtil.showErrorDialogLater(project, "Couldn't locate repository, operation cannot proceed", "Failed"); } }); } }); } private boolean showInVcsRoot(final Project project, final VcsRoot root, Entity changeset) throws VcsException { final AbstractVcs vcs = root.getVcs(); if(vcs == null) { return false; } final VcsRevisionNumber revision = createRevision(vcs.getName(), changeset.getPropertyValue("rev")); if(revision == null) { return false; } CommittedChangesProvider committedChangesProvider = vcs.getCommittedChangesProvider(); if(committedChangesProvider == null) { return false; } Pair oneList = committedChangesProvider.getOneList(root.getPath(), revision); if(oneList != null && oneList.getFirst() != null) { UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { ShowAllAffectedGenericAction.showSubmittedFiles(project, revision, root.getPath(), vcs.getKeyInstanceMethod()); } }); return true; } else { return false; } } private VcsRoot findRepository(Project project, Entity repository) { String location = repository.getPropertyValue("location"); String alias = repository.getPropertyValue("alias"); VcsRoot[] vcsRoots = ProjectLevelVcsManager.getInstance(project).getAllVcsRoots(); for(VcsRoot root: vcsRoots) { AbstractVcs vcs = root.getVcs(); if(vcs == null) { continue; } RevisionFactory revisionFactory = findFactory(vcs.getName()); if(revisionFactory != null && revisionFactory.matches(root, location, alias)) { return root; } } return null; } private RevisionFactory findFactory(String vcsName) { RevisionFactory[] revisionFactories = Extensions.getExtensions(RevisionFactory.EXTENSION_POINT_NAME); for(RevisionFactory factory: revisionFactories) { if(factory.getType().equals(vcsName)) { return factory; } } return null; } private VcsRevisionNumber createRevision(String vcsName, String revision) { RevisionFactory revisionFactory = findFactory(vcsName); if(revisionFactory != null) { return revisionFactory.create(revision); } else { // not recommended, but it may actually work return new TextRevisionNumber(revision); } } }