Package org.eclipse.egit.ui.internal.merge

Source Code of org.eclipse.egit.ui.internal.merge.GitCompareEditorInput

/*******************************************************************************
* Copyright (C) 2010, 2011 Mathias Kinzler <mathias.kinzler@sap.com> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.egit.ui.internal.merge;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.compare.structuremergeviewer.IDiffContainer;
import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.egit.core.AdaptableFileTreeIterator;
import org.eclipse.egit.core.internal.CompareCoreUtils;
import org.eclipse.egit.core.internal.storage.GitFileRevision;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.CompareUtils;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.dialogs.CompareTreeView;
import org.eclipse.egit.ui.internal.revision.FileRevisionTypedElement;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.treewalk.filter.OrTreeFilter;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;

/**
* A Git-specific {@link CompareEditorInput}
*/
public class GitCompareEditorInput extends CompareEditorInput {
  private static final Image FOLDER_IMAGE = PlatformUI.getWorkbench()
      .getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);

  private final String baseVersion;

  private final String compareVersion;

  private final IResource[] resources;

  private final List<String> filterPathStrings = new ArrayList<String>();

  private final Map<IPath, IDiffContainer> diffRoots = new HashMap<IPath, IDiffContainer>();

  private Repository repository;

  /**
   * @param compareVersion
   *            (shown on the left side in compare); currently only commit IDs
   *            are supported
   * @param baseVersion
   *            (shown on the right side in compare); currently only commit
   *            IDs are supported
   * @param resources
   *            as selected by the user
   */
  public GitCompareEditorInput(String compareVersion, String baseVersion,
      IResource... resources) {
    super(new CompareConfiguration());
    this.resources = convertResourceInput(resources);
    this.baseVersion = baseVersion;
    this.compareVersion = compareVersion;
  }

  /**
   * @param compareVersion
   *            (shown on the left side in compare); currently only commit IDs
   *            are supported
   * @param baseVersion
   *            (shown on the right side in compare); currently only commit
   *            IDs are supported
   * @param repository
   *            as selected by the user
   */
  public GitCompareEditorInput(String compareVersion, String baseVersion,
      Repository repository) {
    super(new CompareConfiguration());
    this.resources = new IResource[0];
    this.baseVersion = baseVersion;
    this.compareVersion = compareVersion;
    this.repository = repository;
  }

  @Override
  protected Object prepareInput(IProgressMonitor monitor)
      throws InvocationTargetException, InterruptedException {
    // make sure all resources belong to the same repository
    RevWalk rw = null;
    try {
      monitor.beginTask(
          UIText.GitCompareEditorInput_CompareResourcesTaskName,
          IProgressMonitor.UNKNOWN);

      for (IResource resource : resources) {
        RepositoryMapping map = RepositoryMapping.getMapping(resource
            .getProject());
        if (repository != null && repository != map.getRepository())
          throw new InvocationTargetException(
              new IllegalStateException(
                  UIText.GitCompareEditorInput_ResourcesInDifferentReposMessagge));
        String repoRelativePath = map.getRepoRelativePath(resource);
        filterPathStrings.add(repoRelativePath);
        DiffNode node = new DiffNode(Differencer.NO_CHANGE) {
          @Override
          public Image getImage() {
            return FOLDER_IMAGE;
          }
        };
        diffRoots
            .put(new Path(map.getRepoRelativePath(resource)), node);
        repository = map.getRepository();
      }

      if (repository == null)
        throw new InvocationTargetException(
            new IllegalStateException(
                UIText.GitCompareEditorInput_ResourcesInDifferentReposMessagge));

      if (monitor.isCanceled())
        throw new InterruptedException();

      rw = new RevWalk(repository);

      final RevCommit baseCommit;
      try {
        baseCommit = rw.parseCommit(repository.resolve(baseVersion));
      } catch (IOException e) {
        throw new InvocationTargetException(e);
      }

      final RevCommit compareCommit;
      if (compareVersion == null)
        compareCommit = null;
      else
        try {
          compareCommit = rw.parseCommit(repository
              .resolve(compareVersion));
        } catch (IOException e) {
          throw new InvocationTargetException(e);
        }

      if (monitor.isCanceled())
        throw new InterruptedException();

      // set the labels
      CompareConfiguration config = getCompareConfiguration();
      config.setLeftLabel(compareVersion);
      config.setRightLabel(baseVersion);
      // set title and icon
      if (resources.length == 0) {
        Object[] titleParameters = new Object[] {
            Activator.getDefault().getRepositoryUtil()
                .getRepositoryName(repository),
            CompareUtils.truncatedRevision(compareVersion),
            CompareUtils.truncatedRevision(baseVersion) };
        setTitle(NLS.bind(UIText.GitCompareEditorInput_EditorTitle,
            titleParameters));
      } else if (resources.length == 1) {
        Object[] titleParameters = new Object[] {
            resources[0].getFullPath().makeRelative().toString(),
            CompareUtils.truncatedRevision(compareVersion),
            CompareUtils.truncatedRevision(baseVersion) };
        setTitle(NLS.bind(
            UIText.GitCompareEditorInput_EditorTitleSingleResource,
            titleParameters));
      } else
        setTitle(NLS
            .bind(
                UIText.GitCompareEditorInput_EditorTitleMultipleResources,
                CompareUtils.truncatedRevision(compareVersion),
                CompareUtils.truncatedRevision(baseVersion)));

      // build the nodes
      try {
        return buildDiffContainer(baseCommit, compareCommit, monitor);
      } catch (IOException e) {
        throw new InvocationTargetException(e);
      }
    } finally {
      if (rw != null)
        rw.dispose();
      monitor.done();
    }
  }

  @Override
  protected void contentsCreated() {
    super.contentsCreated();
    // select the first conflict
    getNavigator().selectChange(true);
  }

  @Override
  protected void handleDispose() {
    super.handleDispose();
    // we do NOT dispose the images, as these are shared
  }

  private IDiffContainer buildDiffContainer(RevCommit baseCommit,
      RevCommit compareCommit, IProgressMonitor monitor)
      throws IOException, InterruptedException {
    boolean useIndex = compareVersion.equals(CompareTreeView.INDEX_VERSION);
    boolean checkIgnored = false;

    IDiffContainer result = new DiffNode(Differencer.CONFLICTING);

    TreeWalk tw = new TreeWalk(repository);

    // filter by selected resources
    if (filterPathStrings.size() > 1) {
      List<TreeFilter> suffixFilters = new ArrayList<TreeFilter>();
      for (String filterPath : filterPathStrings)
        suffixFilters.add(PathFilter.create(filterPath));
      TreeFilter otf = OrTreeFilter.create(suffixFilters);
      tw.setFilter(otf);
    } else if (filterPathStrings.size() > 0) {
      String path = filterPathStrings.get(0);
      if (path.length() != 0)
        tw.setFilter(PathFilter.create(path));
    }

    tw.setRecursive(true);

    int baseTreeIndex;
    if (baseCommit == null) {
      // compare workspace with something
      checkIgnored = true;
      baseTreeIndex = tw.addTree(new AdaptableFileTreeIterator(
          repository, ResourcesPlugin.getWorkspace().getRoot()));
    } else
      baseTreeIndex = tw.addTree(new CanonicalTreeParser(null, repository
          .newObjectReader(), baseCommit.getTree()));
    int compareTreeIndex;
    if (!useIndex)
      compareTreeIndex = tw.addTree(new CanonicalTreeParser(null,
          repository.newObjectReader(), compareCommit.getTree()));
    else
      // compare something with the index
      compareTreeIndex = tw.addTree(new DirCacheIterator(repository
          .readDirCache()));

    try {
      while (tw.next()) {
        if (monitor.isCanceled())
          throw new InterruptedException();
        AbstractTreeIterator compareVersionIterator = tw.getTree(
            compareTreeIndex, AbstractTreeIterator.class);
        AbstractTreeIterator baseVersionIterator = tw.getTree(
            baseTreeIndex, AbstractTreeIterator.class);
        if (checkIgnored
            && baseVersionIterator != null
            && ((WorkingTreeIterator) baseVersionIterator)
                .isEntryIgnored())
          continue;


        if (compareVersionIterator != null
            && baseVersionIterator != null) {
          boolean equalContent = compareVersionIterator
              .getEntryObjectId().equals(
                  baseVersionIterator.getEntryObjectId());
          if (equalContent)
            continue;
        }

        String encoding = null;

        GitFileRevision compareRev = null;
        if (compareVersionIterator != null) {
          String entryPath = compareVersionIterator.getEntryPathString();
          encoding = CompareCoreUtils.getResourceEncoding(repository, entryPath);
          if (!useIndex)
            compareRev = GitFileRevision.inCommit(repository,
                compareCommit, entryPath,
                tw.getObjectId(compareTreeIndex));
          else
            compareRev = GitFileRevision.inIndex(repository,
                entryPath);
        }

        GitFileRevision baseRev = null;
        if (baseVersionIterator != null) {
          String entryPath = baseVersionIterator.getEntryPathString();
          if (encoding == null) {
            encoding = CompareCoreUtils.getResourceEncoding(repository, entryPath);
          }
          baseRev = GitFileRevision.inCommit(repository, baseCommit,
              entryPath, tw.getObjectId(baseTreeIndex));
        }

        if (compareVersionIterator != null
            && baseVersionIterator != null) {
          monitor.setTaskName(baseVersionIterator
              .getEntryPathString());
          // content exists on both sides
          add(result, baseVersionIterator.getEntryPathString(),
              new DiffNode(new FileRevisionTypedElement(compareRev, encoding),
                  new FileRevisionTypedElement(baseRev, encoding)));
        } else if (baseVersionIterator != null
            && compareVersionIterator == null) {
          monitor.setTaskName(baseVersionIterator
              .getEntryPathString());
          // only on base side
          add(result, baseVersionIterator.getEntryPathString(),
              new DiffNode(Differencer.DELETION | Differencer.RIGHT, null, null,
                  new FileRevisionTypedElement(baseRev, encoding)));
        } else if (compareVersionIterator != null
            && baseVersionIterator == null) {
          monitor.setTaskName(compareVersionIterator
              .getEntryPathString());
          // only on compare side
          add(result, compareVersionIterator.getEntryPathString(),
              new DiffNode(Differencer.ADDITION | Differencer.RIGHT, null,
                  new FileRevisionTypedElement(compareRev, encoding), null));
        }

        if (monitor.isCanceled())
          throw new InterruptedException();
      }
      return result;
    } finally {
      tw.release();
    }
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result
        + ((baseVersion == null) ? 0 : baseVersion.hashCode());
    result = prime * result
        + ((compareVersion == null) ? 0 : compareVersion.hashCode());
    result = prime
        * result
        + ((repository == null) ? 0 : repository.getDirectory()
            .hashCode());
    result = prime * result + Arrays.hashCode(resources);
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    GitCompareEditorInput other = (GitCompareEditorInput) obj;
    if (baseVersion == null) {
      if (other.baseVersion != null)
        return false;
    } else if (!baseVersion.equals(other.baseVersion))
      return false;
    if (compareVersion == null) {
      if (other.compareVersion != null)
        return false;
    } else if (!compareVersion.equals(other.compareVersion))
      return false;
    if (repository == null) {
      if (other.repository != null)
        return false;
    } else if (other.repository == null || !repository.getDirectory().equals(
        other.repository.getDirectory()))
      return false;
    if (!Arrays.equals(resources, other.resources))
      return false;
    return true;
  }

  private void add(IDiffContainer result, String filePath, DiffNode diffNode) {
    IDiffContainer container = getFileParent(result, filePath);
    container.add(diffNode);
    diffNode.setParent(container);

  }

  private IDiffContainer getFileParent(IDiffContainer root, String filePath) {
    IPath path = new Path(filePath);
    IDiffContainer child = root;
    if (diffRoots.isEmpty()) {
      for (int i = 0; i < path.segmentCount() - 1; i++)
        child = getOrCreateChild(child, path.segment(i));
      return child;
    } else {
      for (Entry<IPath, IDiffContainer> entry : diffRoots.entrySet()) {
        if (entry.getKey().isPrefixOf(path)) {
          for (int i = entry.getKey().segmentCount(); i < path
              .segmentCount() - 1; i++)
            child = getOrCreateChild(child, path.segment(i));
          return child;
        }
      }
      return null;
    }
  }

  private DiffNode getOrCreateChild(IDiffContainer parent, final String name) {
    for (IDiffElement child : parent.getChildren()) {
      if (child.getName().equals(name)) {
        return ((DiffNode) child);
      }
    }
    DiffNode child = new DiffNode(parent, Differencer.NO_CHANGE) {

      @Override
      public String getName() {
        return name;
      }

      @Override
      public Image getImage() {
        return FOLDER_IMAGE;
      }
    };
    return child;
  }

  private IResource[] convertResourceInput(final IResource[] input) {
    if (input.length > 0) {
      // we must make sure to only show the topmost resources as roots
      List<IResource> resourceList = new ArrayList<IResource>(
          input.length);
      List<IPath> allPaths = new ArrayList<IPath>(input.length);
      for (IResource originalInput : input) {
        allPaths.add(originalInput.getFullPath());
      }
      for (IResource originalInput : input) {
        boolean skip = false;
        for (IPath path : allPaths) {
          if (path.isPrefixOf(originalInput.getFullPath())
              && path.segmentCount() < originalInput
                  .getFullPath().segmentCount()) {
            skip = true;
            break;
          }
        }
        if (!skip)
          resourceList.add(originalInput);
      }
      return resourceList.toArray(new IResource[resourceList.size()]);
    } else
      return input;
  }
}
TOP

Related Classes of org.eclipse.egit.ui.internal.merge.GitCompareEditorInput

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.