/******************************************************************************* * Copyright (c) 2012, 2015 Tasktop Technologies 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: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.gerrit.ui; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.eclipse.compare.CompareConfiguration; import org.eclipse.mylyn.commons.workbench.EditorHandle; import org.eclipse.mylyn.commons.workbench.browser.AbstractUrlHandler; import org.eclipse.mylyn.internal.gerrit.core.GerritConnector; import org.eclipse.mylyn.internal.gerrit.ui.editor.GerritTaskEditorPage; import org.eclipse.mylyn.reviews.core.model.IFileItem; import org.eclipse.mylyn.reviews.core.model.IReview; import org.eclipse.mylyn.reviews.core.model.IReviewItemSet; import org.eclipse.mylyn.reviews.ui.spi.editor.ReviewSetSection; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.ui.TasksUi; import org.eclipse.mylyn.tasks.ui.TasksUiUtil; import org.eclipse.mylyn.tasks.ui.editors.TaskEditor; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.forms.editor.IFormPage; import com.google.common.base.Joiner; /** * @author Steffen Pingel * @author Miles Parker */ public class GerritUrlHandler extends AbstractUrlHandler { // http://git.eclipse.org/r/123 or https://git.eclipse.org/r/#/c/123/ private static final Pattern URL_PATTERN = Pattern.compile("/?(#/c)?/(\\d+)"); //$NON-NLS-1$ public GerritUrlHandler() { // ignore } @Override public EditorHandle openUrl(IWorkbenchPage page, String url, int customFlags) { for (TaskRepository repository : TasksUi.getRepositoryManager().getRepositories(GerritConnector.CONNECTOR_KIND)) { String taskId = getTaskId(repository, url); if (taskId != null) { int patchSetNumber = getPatchSetNumber(repository, url, taskId); EditorHandle editorHandle = TasksUiUtil.openTaskWithResult(repository, taskId); if (patchSetNumber > 0) { GerritTaskEditorPage gerritPage = revealPatchSet(editorHandle, patchSetNumber); if (gerritPage != null) { IFileItem file = getFileItem(gerritPage.getReview(), patchSetNumber, getFilePath(repository, url, taskId, patchSetNumber)); openCompareEditor(file); } } return editorHandle; } } return null; } public void openCompareEditor(IFileItem file) { if (file != null) { GerritCompareUi.openFileComparisonEditor(new CompareConfiguration(), file, new GerritReviewBehavior(null)); } } protected GerritTaskEditorPage revealPatchSet(EditorHandle editorHandle, Integer patchSetNumber) { IWorkbenchPart part = editorHandle.getPart(); if (part instanceof TaskEditor) { TaskEditor taskEditor = (TaskEditor) part; IFormPage activePage = taskEditor.setActivePage(GerritTaskEditorPage.class.getName()); if (activePage instanceof GerritTaskEditorPage) { GerritTaskEditorPage gerritPage = (GerritTaskEditorPage) activePage; ReviewSetSection section = (ReviewSetSection) gerritPage.getPart(ReviewSetSection.class.getName()); if (section != null && !section.getControl().isDisposed()) { section.revealPatchSet(patchSetNumber); } return gerritPage; } } return null; } public String getTaskId(TaskRepository repository, String url) { if (url.startsWith(repository.getRepositoryUrl())) { String path = "/" + url.substring(repository.getRepositoryUrl().length()); //$NON-NLS-1$ Matcher matcher = URL_PATTERN.matcher(path); if (matcher.find()) { return matcher.group(2); } } return null; } /** * Returns the patch set number as encoded in a Gerrit URL. For example, * "http://review.mylyn.org/#/c/4698/5/foo/bar", "4698" -> 5. Returns -1 if the patch set number isn't specified or * is not an integer. */ int getPatchSetNumber(TaskRepository repository, String url, String taskId) { String[] fragments = StringUtils.split(extractUrlQualifiers(repository, url, taskId), "/"); //$NON-NLS-1$ if (fragments.length > 0) { String patchSetFragment = fragments[0]; try { return Integer.valueOf(patchSetFragment); } catch (NumberFormatException e) { //ignore, the patch fragment simply can't be parsed } } return -1; } public String getFilePath(TaskRepository repository, String url, String taskId, int patchSetNumber) { if (patchSetNumber > 0) { String[] fragments = StringUtils.split(extractUrlQualifiers(repository, url, taskId), "/"); //$NON-NLS-1$ if (fragments.length > 1) { return Joiner.on("/").join(Arrays.copyOfRange(fragments, 1, fragments.length)); //$NON-NLS-1$ } } return null; } private String extractUrlQualifiers(TaskRepository repository, String url, String taskId) { String taskUrl = TasksUi.getRepositoryConnector(GerritConnector.CONNECTOR_KIND).getTaskUrl(repository.getUrl(), taskId); return StringUtils.remove(url, taskUrl); } public IFileItem getFileItem(IReview review, final int patchSetNumber, final String path) { if (review != null) { for (IReviewItemSet set : review.getSets()) { if (set.getId().equals(Integer.toString(patchSetNumber))) { for (final IFileItem item : set.getItems()) { if (path.equals(item.getName())) { return item; } } } } } return null; } @Override public int getPriority() { return 200; } }