/*******************************************************************************
* Copyright (c) 2011 Benjamin Muskalla 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:
* Benjamin Muskalla <bmuskalla@tasktop.com> - initial API and implementation
* Ilya Ivanov <ilya.ivanov@intland.com> - task repository url resolving
*******************************************************************************/
package org.eclipse.egit.internal.mylyn.ui.commit;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.List;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.egit.core.Activator;
import org.eclipse.egit.internal.mylyn.ui.EGitMylynUI;
import org.eclipse.egit.ui.internal.synchronize.model.GitModelCommit;
import org.eclipse.egit.ui.internal.synchronize.model.GitModelRepository;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
import org.eclipse.mylyn.internal.team.ui.LinkedTaskInfo;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.team.ui.AbstractTaskReference;
/**
* Adapter factory to bridge between Mylyn and EGit domain models.
*/
@SuppressWarnings("restriction")
public class TaskReferenceFactory implements IAdapterFactory {
private static final Class<?>[] ADAPTER_TYPES = new Class[] { AbstractTaskReference.class };
private static final String BUGTRACK_SECTION = "bugtracker"; //$NON-NLS-1$
private static final String BUGTRACK_URL = "url"; //$NON-NLS-1$
@Override
@SuppressWarnings({ "rawtypes" })
public Class[] getAdapterList() {
final Class[] c = new Class[ADAPTER_TYPES.length];
System.arraycopy(ADAPTER_TYPES, 0, c, 0, c.length);
return c;
}
@Override
@SuppressWarnings("rawtypes")
public Object getAdapter(Object adaptableObject, Class adapterType) {
if (!AbstractTaskReference.class.equals(adapterType))
return null;
return adaptFromObject(adaptableObject);
}
private AbstractTaskReference adaptFromObject(Object element) {
RevCommit commit = getCommitForElement(element);
if (commit != null)
return adaptFromRevCommit(commit);
return null;
}
/**
* Finds {@link TaskRepository} for provided {@link RevCommit} object and returns new {@link LinkedTaskInfo} object
* or <code>null</code> if nothing found.
* @param commit a {@link RevCommit} object to look for
* @return {@link LinkedTaskInfo} object, or <code>null</code> if repository not found
*/
private AbstractTaskReference adaptFromRevCommit(RevCommit commit) {
Repository[] repositories = Activator.getDefault().getRepositoryCache().getAllRepositories();
for (Repository r : repositories) {
String repoUrl = null;
String message = null;
long timestamp = 0;
// try to get repository url and commit message
try (RevWalk revWalk = new RevWalk(r)) {
RevCommit revCommit = revWalk.parseCommit(commit);
if (revCommit != null) {
repoUrl = getRepoUrl(r);
message = revCommit.getFullMessage();
timestamp = (long)revCommit.getCommitTime() * 1000;
}
} catch (IOException e) {
continue;
} catch (RuntimeException e) {
continue;
}
if (message == null || message.trim().length() == 0)
continue;
String taskRepositoryUrl = null;
if (repoUrl != null) {
TaskRepository repository = getTaskRepositoryByGitRepoURL(repoUrl);
if (repository != null)
taskRepositoryUrl = repository.getRepositoryUrl();
}
return new LinkedTaskInfo(taskRepositoryUrl, null, null, message, timestamp);
}
return null;
}
private static RevCommit getCommitForElement(Object element) {
RevCommit commit = null;
if (element instanceof RevCommit)
commit = (RevCommit) element;
else if (element instanceof GitModelCommit) {
GitModelCommit modelCommit = (GitModelCommit) element;
if (!(modelCommit.getParent() instanceof GitModelRepository))
return null; // should never happen
GitModelRepository parent = (GitModelRepository) modelCommit.getParent();
Repository repo = parent.getRepository();
AbbreviatedObjectId id = modelCommit.getCachedCommitObj().getId();
try (RevWalk rw = new RevWalk(repo)) {
commit = rw.lookupCommit(id.toObjectId());
}
}
return commit;
}
/**
* Finds {@link TaskRepository} by provided Git repository Url
* @param repoUrl Git repository url
* @return {@link TaskRepository} associated with this Git repo or <code>null</code> if nothing found
*/
private TaskRepository getTaskRepositoryByGitRepoURL(final String repoUrl) {
if (repoUrl == null)
return null;
try {
return getTaskRepositoryByHost(new URIish(repoUrl).getHost());
} catch (Exception ex) {
EGitMylynUI.getDefault().getLog().log(
new Status(IStatus.ERROR, EGitMylynUI.PLUGIN_ID, "failed to get repo url", ex)); //$NON-NLS-1$
}
return null;
}
private static String getRepoUrl(Repository repo) {
String configuredUrl = repo.getConfig().getString(BUGTRACK_SECTION, null, BUGTRACK_URL);
String originUrl = repo.getConfig().getString(ConfigConstants.CONFIG_REMOTE_SECTION,
Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL);
return configuredUrl != null ? configuredUrl : originUrl;
}
private TaskRepository getTaskRepositoryByHost(String host) {
List<TaskRepository> repositories = TasksUiPlugin.getRepositoryManager().getAllRepositories();
if (repositories == null || repositories.isEmpty())
return null;
if (repositories.size() == 1)
return repositories.iterator().next();
for (TaskRepository repository : repositories) {
if (!repository.isOffline()) {
try {
URL url = new URL(repository.getRepositoryUrl());
if (isSameHosts(host, url.getHost()))
return repository;
} catch (MalformedURLException e) {
// We cannot do anything.
}
}
}
return null;
}
private boolean isSameHosts(final String name1, final String name2) {
String hostname1 = name1 == null ? "" : name1.trim(); //$NON-NLS-1$
String hostname2 = name2 == null ? "" : name2.trim(); //$NON-NLS-1$
if (hostname1.equals(hostname2))
return true;
String localHost = "localhost"; //$NON-NLS-1$
String resolvedHostName;
try {
resolvedHostName = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException ex) {
resolvedHostName = localHost;
}
if (hostname1.length() == 0)
hostname1 = resolvedHostName;
if (hostname2.length() == 0)
hostname2 = resolvedHostName;
if (hostname1.equals(hostname2))
return true;
if ((hostname1.equals(localHost) && hostname2.equals(resolvedHostName))
|| (hostname1.equals(resolvedHostName) && hostname2.equals(localHost)))
return true;
return false;
}
}