Package org.eclipse.egit.ui.internal.repository.tree.command

Source Code of org.eclipse.egit.ui.internal.repository.tree.command.RemoveCommand

/*******************************************************************************
* Copyright (c) 2010, 2013 SAP AG 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
*
* Contributors:
*    Mathias Kinzler (SAP AG) - initial implementation
*    Daniel Megert <daniel_megert@ch.ibm.com> - Delete empty working directory
*    Laurent Goubet <laurent.goubet@obeo.fr - 404121
*******************************************************************************/
package org.eclipse.egit.ui.internal.repository.tree.command;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.egit.core.RepositoryCache;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.JobFamilies;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNodeType;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.submodule.SubmoduleWalk;
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;

/**
* "Removes" one or several nodes
*/
public class RemoveCommand extends
    RepositoriesViewCommandHandler<RepositoryNode> {
  public Object execute(final ExecutionEvent event) throws ExecutionException {
    removeRepository(event, false);
    return null;
  }

  /**
   * Remove or delete the repository
   *
   * @param event
   * @param delete
   *            if <code>true</code>, the repository will be deleted from disk
   */
  protected void removeRepository(final ExecutionEvent event,
      final boolean delete) {
    IWorkbenchSite activeSite = HandlerUtil.getActiveSite(event);
    IWorkbenchSiteProgressService service = CommonUtils.getService(activeSite, IWorkbenchSiteProgressService.class);

    // get selected nodes
    final List<RepositoryNode> selectedNodes;
    try {
      selectedNodes = getSelectedNodes(event);
    } catch (ExecutionException e) {
      Activator.handleError(e.getMessage(), e, true);
      return;
    }
    boolean deleteWorkingDir = false;
    boolean removeProjects = false;
    final List<IProject> projectsToDelete = findProjectsToDelete(selectedNodes);
    if (delete) {
      if (selectedNodes.size() > 1) {
        return;
      } else if (selectedNodes.size() == 1) {
        Repository repository = selectedNodes.get(0).getObject();
        if (repository.isBare()) {
          // simple confirm dialog
          String title = UIText.RemoveCommand_ConfirmDeleteBareRepositoryTitle;
          String message = NLS
              .bind(
                  UIText.RemoveCommand_ConfirmDeleteBareRepositoryMessage,
                  repository.getDirectory().getPath());
          if (!MessageDialog.openConfirm(getShell(event), title,
              message))
            return;
        } else {
          // confirm dialog with check box
          // "delete also working directory"
          DeleteRepositoryConfirmDialog dlg = new DeleteRepositoryConfirmDialog(
              getShell(event), repository, projectsToDelete.size());
          if (dlg.open() != Window.OK)
            return;
          deleteWorkingDir = dlg.shouldDeleteWorkingDir();
          removeProjects = dlg.shouldRemoveProjects();
        }
      }
    }
    else {
      if (!projectsToDelete.isEmpty()) {
        final boolean[] confirmedCanceled = new boolean[] { false,
            false };
        Display.getDefault().syncExec(new Runnable() {

          public void run() {
            try {
              confirmedCanceled[0] = confirmProjectDeletion(
                  projectsToDelete, event);
            } catch (OperationCanceledException e) {
              confirmedCanceled[1] = true;
            }
          }
        });
        if (confirmedCanceled[1])
          return;
        removeProjects = confirmedCanceled[0];
      }
    }

    final boolean deleteWorkDir = deleteWorkingDir;
    final boolean removeProj = removeProjects;

    Job job = new WorkspaceJob(UIText.RemoveCommand_RemoveRepositoriesJob) {

      @Override
      public IStatus runInWorkspace(IProgressMonitor monitor) {

        monitor.setTaskName(UIText.RepositoriesView_DeleteRepoDeterminProjectsMessage);

        if (removeProj) {
          // confirmed deletion
          deleteProjects(delete, projectsToDelete,
              monitor);
        }
        for (RepositoryNode node : selectedNodes) {
          util.removeDir(node.getRepository().getDirectory());
        }

        if (delete) {
          try {
            deleteRepositoryContent(selectedNodes, deleteWorkDir);
          } catch (IOException e) {
            return Activator.createErrorStatus(e.getMessage(), e);
          }
        }
        return Status.OK_STATUS;
      }

      @Override
      public boolean belongsTo(Object family) {
        if (JobFamilies.REPOSITORY_DELETE.equals(family))
          return true;
        else
          return super.belongsTo(family);
      }
    };

    service.schedule(job);
  }

  private void deleteProjects(
      final boolean delete,
      final List<IProject> projectsToDelete,
      IProgressMonitor monitor) {
    IWorkspaceRunnable wsr = new IWorkspaceRunnable() {

      public void run(IProgressMonitor actMonitor)
      throws CoreException {

        for (IProject prj : projectsToDelete)
          prj.delete(delete, false, actMonitor);
      }
    };

    try {
      ResourcesPlugin.getWorkspace().run(wsr,
          ResourcesPlugin.getWorkspace().getRoot(),
          IWorkspace.AVOID_UPDATE, monitor);
    } catch (CoreException e1) {
      Activator.logError(e1.getMessage(), e1);
    }
  }

  private void deleteRepositoryContent(
      final List<RepositoryNode> selectedNodes,
      final boolean deleteWorkDir) throws IOException {
    for (RepositoryNode node : selectedNodes) {
      Repository repo = node.getRepository();
      File workTree = deleteWorkDir && !repo.isBare() ? repo.getWorkTree() : null;
      if (workTree != null) {
        File[] files = workTree.listFiles();
        if (files != null)
          for (File file : files) {
            if (isTracked(file, repo))
              FileUtils.delete(file,
                  FileUtils.RECURSIVE | FileUtils.RETRY);
          }
      }
      repo.close();

      if (!repo.isBare())
        closeSubmoduleRepositories(repo);

      FileUtils.delete(repo.getDirectory(),
          FileUtils.RECURSIVE | FileUtils.RETRY
              | FileUtils.SKIP_MISSING);

      if (workTree != null) {
        // Delete working directory if a submodule repository and refresh
        // parent repository
        if (node.getParent() != null
            && node.getParent().getType() == RepositoryTreeNodeType.SUBMODULES) {
          FileUtils.delete(workTree, FileUtils.RECURSIVE
              | FileUtils.RETRY | FileUtils.SKIP_MISSING);
          node.getParent().getRepository().notifyIndexChanged();
        }
        // Delete if empty working directory
        String[] files = workTree.list();
        boolean isWorkingDirEmpty = files != null && files.length == 0;
        if (isWorkingDirEmpty)
          FileUtils.delete(workTree, FileUtils.RETRY | FileUtils.SKIP_MISSING);
      }
    }
  }

  private static void closeSubmoduleRepositories(Repository repo)
      throws IOException {
    SubmoduleWalk walk = SubmoduleWalk.forIndex(repo);
    try {
      while (walk.next()) {
        Repository subRepo = walk.getRepository();
        if (subRepo != null) {
          RepositoryCache cache = null;
          try {
            cache = org.eclipse.egit.core.Activator.getDefault()
                .getRepositoryCache();
          } finally {
            if (cache != null)
              cache.lookupRepository(subRepo.getDirectory())
                  .close();
            subRepo.close();
          }
        }
      }
    } finally {
      walk.release();
    }
  }

  private boolean isTracked(File file, Repository repo) throws IOException {
    ObjectId objectId = repo.resolve(Constants.HEAD);
    RevTree tree;
    if (objectId != null)
      tree = new RevWalk(repo).parseTree(objectId);
    else
      tree = null;

    TreeWalk treeWalk = new TreeWalk(repo);
    treeWalk.setRecursive(true);
    if (tree != null)
      treeWalk.addTree(tree);
    else
      treeWalk.addTree(new EmptyTreeIterator());
    treeWalk.addTree(new DirCacheIterator(repo.readDirCache()));
    treeWalk.setFilter(PathFilterGroup.createFromStrings(Collections.singleton(
        Repository.stripWorkDir(repo.getWorkTree(), file))));
    return treeWalk.next();

  }

  private List<IProject> findProjectsToDelete(final List<RepositoryNode> selectedNodes) {
    final List<IProject> projectsToDelete = new ArrayList<IProject>();
    for (RepositoryNode node : selectedNodes) {
      if (node.getRepository().isBare())
        continue;
      File workDir = node.getRepository().getWorkTree();
      final IPath wdPath = new Path(workDir.getAbsolutePath());
      for (IProject prj : ResourcesPlugin.getWorkspace()
          .getRoot().getProjects()) {
        IPath location = prj.getLocation();
        if (location != null && wdPath.isPrefixOf(location)) {
          projectsToDelete.add(prj);
        }
      }
    }
    return projectsToDelete;
  }

  @SuppressWarnings("boxing")
  private boolean confirmProjectDeletion(List<IProject> projectsToDelete,
      ExecutionEvent event) throws OperationCanceledException {

    String message = NLS.bind(
        UIText.RepositoriesView_ConfirmProjectDeletion_Question,
        projectsToDelete.size());
    MessageDialog dlg = new MessageDialog(getShell(event),
        UIText.RepositoriesView_ConfirmProjectDeletion_WindowTitle,
        null, message, MessageDialog.INFORMATION, new String[] {
            IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL,
            IDialogConstants.CANCEL_LABEL }, 0);
    int index = dlg.open();
    // Return true if 'Yes' was selected
    if (index == 0)
      return true;
    // Return false if 'No' was selected
    if (index == 1)
      return false;
    // Cancel operation in all other cases
    throw new OperationCanceledException();
  }
}
TOP

Related Classes of org.eclipse.egit.ui.internal.repository.tree.command.RemoveCommand

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.