/******************************************************************************
* Copyright (c) 2014, Tobias Melcher <tobias.melcher@sap.com>,
* Felix Otto <felix.otto@sap.com>
*
* 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.history.command;
import java.io.File;
import java.util.HashSet;
import java.util.List;
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.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
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.egit.ui.Activator;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.commit.RepositoryCommit;
import org.eclipse.egit.ui.internal.history.FileDiff;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
/**
* Imports the projects changed by (a) given commit(s).
*
* Loops over all changed files of a revision to find the enclosing projects and
* imports them.
*/
@SuppressWarnings("restriction")
public class ImportChangedProjectsCommand
extends AbstractHistoryCommandHandler {
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
Repository repository = getRepository(event);
Set<File> changedFiles = new HashSet<>();
List<RevCommit> commits = getSelectedCommits(event);
for (RevCommit commit : commits) {
RepositoryCommit repoCommit = new RepositoryCommit(repository,
commit);
changedFiles.addAll(determineChangedFilesOfCommit(repoCommit));
}
Set<File> dotProjectFiles = findDotProjectFiles(changedFiles,
repository);
importProjects(dotProjectFiles);
return null;
}
private Set<File> determineChangedFilesOfCommit(
RepositoryCommit repoCommit) {
Set<File> changedFilesOfCommit = new HashSet<>();
File rootOfWorkingDirectory = repoCommit.getRepository().getWorkTree();
FileDiff[] fileDiffs = repoCommit.getDiffs();
for (FileDiff fileDiff : fileDiffs) {
// in case of brand new files there is no old path
addIfNotDevNull(changedFilesOfCommit, rootOfWorkingDirectory,
fileDiff.getNewPath());
// in case of deletions there is no new path
addIfNotDevNull(changedFilesOfCommit, rootOfWorkingDirectory,
fileDiff.getOldPath());
}
return changedFilesOfCommit;
}
private void addIfNotDevNull(Set<File> changedFilesOfCommit,
File rootOfWorkingDirectory, String relativePathOfChangedFile) {
if (!relativePathOfChangedFile.contains("/dev/null")) { //$NON-NLS-1$
changedFilesOfCommit.add(new File(rootOfWorkingDirectory,
relativePathOfChangedFile));
}
}
private Set<File> findDotProjectFiles(Set<File> changedFiles,
Repository repository) {
Set<File> result = new HashSet<>();
String workingTreeRootPath = repository.getWorkTree().toString();
for (File changedFile : changedFiles) {
File projectFile = searchEnclosingProjectInWorkDir(
changedFile.getParentFile().getAbsoluteFile(),
workingTreeRootPath);
if (projectFile != null)
result.add(projectFile);
}
return result;
}
private File searchEnclosingProjectInWorkDir(File startFolder,
String workingTreeRootPath) {
File projectFile = null;
File currentPath = startFolder;
while (currentPath.toString().startsWith(workingTreeRootPath)) {
projectFile = new File(
currentPath.toString() + File.separator + ".project"); //$NON-NLS-1$
if (projectFile.isFile())
break;
projectFile = null;
currentPath = currentPath.getParentFile();
}
return projectFile;
}
private void importProjects(final Set<File> dotProjectFiles) {
WorkspaceJob job = new WorkspaceJob(
UIText.ImportChangedProjectsCommand_ImportingChangedProjects) {
@Override
public IStatus runInWorkspace(IProgressMonitor monitor)
throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor,
dotProjectFiles.size());
for (File f : dotProjectFiles) {
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
}
String ap = f.getAbsolutePath();
importProject(ap, progress.newChild(1));
}
return Status.OK_STATUS;
}
};
job.schedule();
}
private void importProject(String path, IProgressMonitor monitor) {
try {
IProjectDescription description = IDEWorkbenchPlugin
.getPluginWorkspace().loadProjectDescription(
new org.eclipse.core.runtime.Path(path));
if (description != null) {
String projectName = description.getName();
IProject project = ResourcesPlugin.getWorkspace().getRoot()
.getProject(projectName);
if (project.exists()) {
if (!project.isOpen()) {
project.open(IResource.BACKGROUND_REFRESH, monitor);
}
} else {
SubMonitor progress = SubMonitor.convert(monitor, 2);
project.create(description, progress.newChild(1));
project.open(IResource.BACKGROUND_REFRESH,
progress.newChild(1));
}
}
} catch (CoreException e) {
Activator.error(e.getMessage(), e);
}
}
}