/******************************************************************************* * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com> * Copyright (C) 2007, Jing Xue <jingxue@digizenstudio.com> * Copyright (C) 2007, Robin Rosenberg <me@lathund.dewire.com> * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com> * Copyright (C) 2011, Jens Baumgart <jens.baumgart@sap.com> * Copyright (C) 2011, Benjamin Muskalla <benjamin.muskalla@tasktop.com> * Copyright (C) 2012, François Rey <eclipse.org_@_francois_._rey_._name> * Copyright (C) 2016, Thomas Wolf <thomas.wolf@paranor.ch> * * 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.actions; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.egit.core.internal.CoreText; import org.eclipse.egit.core.internal.indexdiff.IndexDiffCacheEntry; import org.eclipse.egit.core.internal.indexdiff.IndexDiffData; import org.eclipse.egit.core.internal.job.RuleUtil; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.JobFamilies; import org.eclipse.egit.ui.UIPreferences; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.commit.CommitUI; import org.eclipse.egit.ui.internal.operations.GitScopeUtil; import org.eclipse.egit.ui.internal.staging.StagingView; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.api.AddCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Repository; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; /** * Commit either using the {@link CommitUI} dialog or the {@link StagingView}. */ public class CommitActionHandler extends RepositoryActionHandler { @Override public Object execute(final ExecutionEvent event) throws ExecutionException { final Repository repository = getRepository(true, event); if (repository == null) { return null; } IPreferenceStore uiPreferences = Activator.getDefault() .getPreferenceStore(); boolean useStagingView = uiPreferences .getBoolean(UIPreferences.ALWAYS_USE_STAGING_VIEW); if (useStagingView) { if (uiPreferences.getBoolean(UIPreferences.AUTO_STAGE_ON_COMMIT)) { boolean includeUntracked = uiPreferences.getBoolean( UIPreferences.COMMIT_DIALOG_INCLUDE_UNTRACKED); autoStage(repository, includeUntracked, getResourcesInScope(event)); } PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { try { StagingView view = (StagingView) PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getActivePage() .showView(StagingView.VIEW_ID); if (view.getCurrentRepository() != repository) { view.reload(repository); } view.setFocus(); } catch (PartInitException e) { Activator.logError(e.getMessage(), e); } } }); } else { final Shell shell = getShell(event); IResource[] resourcesInScope = getResourcesInScope(event); if (resourcesInScope != null) { CommitUI commitUi = new CommitUI(shell, repository, resourcesInScope, false); commitUi.commit(); } } return null; } private IResource[] getResourcesInScope(ExecutionEvent event) throws ExecutionException { try { IResource[] selectedResources = getSelectedResources(event); if (selectedResources.length > 0) { IWorkbenchPart part = getPart(event); return GitScopeUtil.getRelatedChanges(part, selectedResources); } else { return new IResource[0]; } } catch (InterruptedException e) { // ignore, we will not show the commit dialog in case the user // cancels the scope operation return null; } } private IndexDiffData getIndexDiffData(final @NonNull Repository repository, final @NonNull Collection<IProject> projects) { IndexDiffCacheEntry diffCacheEntry = org.eclipse.egit.core.Activator .getDefault().getIndexDiffCache() .getIndexDiffCacheEntry(repository); IndexDiffData diff = null; if (diffCacheEntry != null) { diff = diffCacheEntry.getIndexDiff(); } if (diff != null) { return diff; } final IndexDiffData[] result = { null }; try { PlatformUI.getWorkbench().getProgressService() .busyCursorWhile(new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { result[0] = new IndexDiffData( CommitUI.getIndexDiff(repository, projects.toArray( new IProject[projects .size()]), monitor)); } catch (IOException e) { throw new InvocationTargetException(e); } } }); } catch (InvocationTargetException e) { Activator.handleError(UIText.CommitAction_errorComputingDiffs, e.getCause(), true); return null; } catch (InterruptedException e) { return null; } return result[0]; } private void autoStage(final @NonNull Repository repository, boolean includeUntracked, IResource[] resourcesInScope) { if (resourcesInScope == null || resourcesInScope.length == 0) { return; } final Set<IProject> projects = new HashSet<>(); for (IResource rsc : resourcesInScope) { projects.add(rsc.getProject()); } IndexDiffData diff = getIndexDiffData(repository, projects); if (diff == null) { return; } Set<String> mayBeCommitted = new HashSet<>(); mayBeCommitted.addAll(diff.getAdded()); mayBeCommitted.addAll(diff.getChanged()); mayBeCommitted.addAll(diff.getRemoved()); mayBeCommitted.addAll(diff.getModified()); mayBeCommitted.addAll(diff.getMissing()); if (!includeUntracked) { mayBeCommitted.removeAll(diff.getUntracked()); } else { mayBeCommitted.addAll(diff.getUntracked()); } mayBeCommitted.removeAll(diff.getAssumeUnchanged()); final Set<String> toBeStaged = CommitUI.getSelectedFiles(repository, mayBeCommitted, resourcesInScope); if (toBeStaged.isEmpty()) { return; } Job job = new Job(UIText.AddToIndexAction_addingFiles) { @Override protected IStatus run(IProgressMonitor monitor) { SubMonitor progress = SubMonitor.convert(monitor, toBeStaged.size() + 1); try (Git git = new Git(repository)) { AddCommand add = git.add(); for (String toStage : toBeStaged) { add.addFilepattern(toStage); if (progress.isCanceled()) { return Status.CANCEL_STATUS; } progress.worked(1); } add.call(); progress.worked(1); } catch (GitAPIException e) { return Activator.createErrorStatus( CoreText.AddToIndexOperation_failed, e); } finally { monitor.done(); } return Status.OK_STATUS; } @Override public boolean belongsTo(Object family) { return JobFamilies.ADD_TO_INDEX.equals(family) || super.belongsTo(family); } }; job.setUser(true); job.setRule(RuleUtil.getRule(repository)); job.schedule(); } @Override public boolean isEnabled() { return selectionMapsToSingleRepository(); } }