/*******************************************************************************
* Copyright (c) 2013, 2016 Robin Stocker <robin@nibor.org> 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:
* Thomas Wolf <thomas.wolf@paranor.ch> - Bug 493352
*******************************************************************************/
package org.eclipse.egit.core.internal.gerrit;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.egit.core.Activator;
import org.eclipse.egit.core.internal.CoreText;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
/**
* Gerrit utilities
*/
public class GerritUtil {
/**
* The Gerrit magic push prefix {@value} .
*/
public static final String REFS_FOR = "refs/for/"; //$NON-NLS-1$
/**
* The Gerrit magic push prefix {@value}
*/
public static final String REFS_PUBLISH = "refs/publish/"; //$NON-NLS-1$
/**
* The Gerrit magic push prefix {@value}
*/
public static final String REFS_DRAFTS = "refs/drafts/"; //$NON-NLS-1$
/**
* @param config
* @return true if there if "create change ID" is configured
*/
public static boolean getCreateChangeId(Config config) {
return config.getBoolean(ConfigConstants.CONFIG_GERRIT_SECTION,
ConfigConstants.CONFIG_KEY_CREATECHANGEID, false);
}
/**
* Set the "create change ID" configuration
*
* @param config
*/
public static void setCreateChangeId(Config config) {
config.setBoolean(ConfigConstants.CONFIG_GERRIT_SECTION, null,
ConfigConstants.CONFIG_KEY_CREATECHANGEID, true);
}
/**
* Find the remote config for the given remote name
*
* @param config
* the configuration containing the remote config
* @param remoteName
* the name of the remote to find
* @return the found remoteConfig or {@code null}
* @throws URISyntaxException
* if the configuration contains an illegal URI
*/
public static RemoteConfig findRemoteConfig(Config config, String remoteName)
throws URISyntaxException {
RemoteConfig remoteConfig = null;
List<RemoteConfig> allRemoteConfigs = RemoteConfig
.getAllRemoteConfigs(config);
for (RemoteConfig rc : allRemoteConfigs) {
if (rc.getName().equals(remoteName)) {
remoteConfig = rc;
break;
}
}
return remoteConfig;
}
/**
* Configure the pushURI for Gerrit
*
* @param remoteConfig
* the remote configuration to add this to
* @param pushURI
* the pushURI to configure
*/
public static void configurePushURI(RemoteConfig remoteConfig,
URIish pushURI) {
List<URIish> pushURIs = new ArrayList<URIish>(
remoteConfig.getPushURIs());
for (URIish urIish : pushURIs) {
remoteConfig.removePushURI(urIish);
}
remoteConfig.addPushURI(pushURI);
}
/**
* Configure the gerrit push refspec HEAD:refs/for/<gerritBranch>
*
* @param remoteConfig
* the remote configuration to configure this in
* @param gerritBranch
* the branch to push to review for
*/
public static void configurePushRefSpec(RemoteConfig remoteConfig,
String gerritBranch) {
List<RefSpec> pushRefSpecs = new ArrayList<RefSpec>(
remoteConfig.getPushRefSpecs());
for (RefSpec refSpec : pushRefSpecs) {
remoteConfig.removePushRefSpec(refSpec);
}
remoteConfig.addPushRefSpec(new RefSpec(
"HEAD:" + GerritUtil.REFS_FOR + gerritBranch)); //$NON-NLS-1$
}
/**
* Configure fetching review summary notes
*
* @param remoteConfig
* the remote configuration to configure this in
* @return {@code true} if the {@code remoteConfig} was changed,
* {@code false} otherwise.
*/
public static boolean configureFetchNotes(RemoteConfig remoteConfig) {
String notesRef = Constants.R_NOTES + "*"; //$NON-NLS-1$
List<RefSpec> fetchRefSpecs = remoteConfig.getFetchRefSpecs();
for (RefSpec refSpec : fetchRefSpecs) {
if (refSpec.matchSource(notesRef)) {
return false;
}
}
remoteConfig.addFetchRefSpec(new RefSpec(notesRef + ':' + notesRef));
return true;
}
/**
* @param rc
* the remote configuration
* @return {@code true} if the remote configuration is configured for
* pushing to Gerrit
*/
public static boolean isGerritPush(RemoteConfig rc) {
for (RefSpec pushSpec : rc.getPushRefSpecs()) {
String destination = pushSpec.getDestination();
if (destination == null) {
continue;
}
if (destination.startsWith(GerritUtil.REFS_FOR)
|| destination.startsWith(GerritUtil.REFS_PUBLISH)
|| destination.startsWith(GerritUtil.REFS_DRAFTS)) {
return true;
}
}
return false;
}
/**
* @param rc
* the remote configuration
* @return {@code true} if the remote configuration is configured for
* fetching from Gerrit
*/
public static boolean isGerritFetch(RemoteConfig rc) {
for (RefSpec fetchSpec : rc.getFetchRefSpecs()) {
String source = fetchSpec.getSource();
String destination = fetchSpec.getDestination();
if (source == null || destination == null) {
continue;
}
if (source.startsWith(Constants.R_NOTES)
&& destination.startsWith(Constants.R_NOTES)) {
return true;
}
}
return false;
}
/**
* If the repository is not bare and looks like it might be a Gerrit
* repository, try to configure it such that EGit's Gerrit support is
* enabled.
*
* @param repository
* to try to configure
*/
public static void tryToAutoConfigureForGerrit(
@NonNull Repository repository) {
if (repository.isBare()) {
return;
}
StoredConfig config = repository.getConfig();
boolean isGerrit = false;
boolean changed = false;
try {
for (RemoteConfig remote : RemoteConfig
.getAllRemoteConfigs(config)) {
if (isGerritPush(remote)) {
isGerrit = true;
if (configureFetchNotes(remote)) {
changed = true;
remote.update(config);
}
}
}
} catch (URISyntaxException ignored) {
// Ignore it here -- we're just trying to set up Gerrit support.
}
if (isGerrit) {
if (config.getString(ConfigConstants.CONFIG_GERRIT_SECTION, null,
ConfigConstants.CONFIG_KEY_CREATECHANGEID) != null) {
// Already configured.
} else {
setCreateChangeId(config);
changed = true;
}
if (changed) {
try {
config.save();
} catch (IOException e) {
Activator.logError(
MessageFormat.format(
CoreText.GerritUtil_ConfigSaveError,
repository.getDirectory()),
e);
}
}
}
}
/**
* If the repository is not bare and looks like it might be a Gerrit
* repository, try to configure it such that EGit's Gerrit support is
* enabled. Does nothing if the {@code repositoryDir} is {@code null} or the
* repository cannot be configured.
*
* @param repositoryDir
* .git Directory of the repository to try to configure
*/
public static void tryToAutoConfigureForGerrit(
@Nullable File repositoryDir) {
if (repositoryDir != null) {
try {
Repository repository = Activator.getDefault()
.getRepositoryCache().lookupRepository(repositoryDir);
if (repository != null) {
tryToAutoConfigureForGerrit(repository);
}
} catch (IOException ignored) {
// Ignore it here -- this is just a best-effort. If the repo
// cannot be read, other places will report the problem.
}
}
}
}