blob: 1929d8e2ad33ca305935ea243bbe3396fb65c15d [file] [log] [blame]
/*
* Copyright (c) 2013, 2014 Eike Stepper (Berlin, Germany) 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:
* Eike Stepper - initial API and implementation
* Ericsson AB (Julian Enoch) - Bug 429520 - Support additional push URL
*/
package org.eclipse.emf.cdo.releng.setup.impl;
import org.eclipse.emf.cdo.releng.setup.CompoundSetupTask;
import org.eclipse.emf.cdo.releng.setup.GitCloneTask;
import org.eclipse.emf.cdo.releng.setup.SetupFactory;
import org.eclipse.emf.cdo.releng.setup.SetupPackage;
import org.eclipse.emf.cdo.releng.setup.SetupTask.Sniffer.SourcePathProvider;
import org.eclipse.emf.cdo.releng.setup.SetupTaskContainer;
import org.eclipse.emf.cdo.releng.setup.SetupTaskContext;
import org.eclipse.emf.cdo.releng.setup.Trigger;
import org.eclipse.emf.cdo.releng.setup.log.ProgressLogMonitor;
import org.eclipse.emf.cdo.releng.setup.util.FileUtil;
import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.io.IOUtil;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.egit.core.RepositoryUtil;
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.CreateBranchCommand;
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.StatusCommand;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.lib.ProgressMonitor;
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;
import org.osgi.framework.Bundle;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Git Clone Task</b></em>'.
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* <ul>
* <li>{@link org.eclipse.emf.cdo.releng.setup.impl.GitCloneTaskImpl#getLocation <em>Location</em>}</li>
* <li>{@link org.eclipse.emf.cdo.releng.setup.impl.GitCloneTaskImpl#getRemoteName <em>Remote Name</em>}</li>
* <li>{@link org.eclipse.emf.cdo.releng.setup.impl.GitCloneTaskImpl#getRemoteURI <em>Remote URI</em>}</li>
* <li>{@link org.eclipse.emf.cdo.releng.setup.impl.GitCloneTaskImpl#getPushURI <em>Push URI</em>}</li>
* <li>{@link org.eclipse.emf.cdo.releng.setup.impl.GitCloneTaskImpl#getUserID <em>User ID</em>}</li>
* <li>{@link org.eclipse.emf.cdo.releng.setup.impl.GitCloneTaskImpl#getCheckoutBranch <em>Checkout Branch</em>}</li>
* </ul>
* </p>
*
* @generated
*/
public class GitCloneTaskImpl extends SetupTaskImpl implements GitCloneTask
{
/**
* The default value of the '{@link #getLocation() <em>Location</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getLocation()
* @generated
* @ordered
*/
protected static final String LOCATION_EDEFAULT = null;
/**
* The cached value of the '{@link #getLocation() <em>Location</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getLocation()
* @generated
* @ordered
*/
protected String location = LOCATION_EDEFAULT;
/**
* The default value of the '{@link #getRemoteName() <em>Remote Name</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getRemoteName()
* @generated
* @ordered
*/
protected static final String REMOTE_NAME_EDEFAULT = "origin";
/**
* The cached value of the '{@link #getRemoteName() <em>Remote Name</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getRemoteName()
* @generated
* @ordered
*/
protected String remoteName = REMOTE_NAME_EDEFAULT;
/**
* The default value of the '{@link #getRemoteURI() <em>Remote URI</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getRemoteURI()
* @generated
* @ordered
*/
protected static final String REMOTE_URI_EDEFAULT = null;
/**
* The cached value of the '{@link #getRemoteURI() <em>Remote URI</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getRemoteURI()
* @generated
* @ordered
*/
protected String remoteURI = REMOTE_URI_EDEFAULT;
/**
* The default value of the '{@link #getPushURI() <em>Push URI</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getPushURI()
* @generated
* @ordered
*/
protected static final String PUSH_URI_EDEFAULT = null;
/**
* The cached value of the '{@link #getPushURI() <em>Push URI</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getPushURI()
* @generated
* @ordered
*/
protected String pushURI = PUSH_URI_EDEFAULT;
/**
* The default value of the '{@link #getUserID() <em>User ID</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getUserID()
* @generated
* @ordered
*/
protected static final String USER_ID_EDEFAULT = "${git.user.id}";
/**
* The cached value of the '{@link #getUserID() <em>User ID</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getUserID()
* @generated
* @ordered
*/
protected String userID = USER_ID_EDEFAULT;
/**
* The default value of the '{@link #getCheckoutBranch() <em>Checkout Branch</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getCheckoutBranch()
* @generated
* @ordered
*/
protected static final String CHECKOUT_BRANCH_EDEFAULT = null;
/**
* The cached value of the '{@link #getCheckoutBranch() <em>Checkout Branch</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getCheckoutBranch()
* @generated
* @ordered
*/
protected String checkoutBranch = CHECKOUT_BRANCH_EDEFAULT;
private transient GitDelegate gitDelegate;
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected GitCloneTaskImpl()
{
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass()
{
return SetupPackage.Literals.GIT_CLONE_TASK;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public String getLocation()
{
return location;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setLocation(String newLocation)
{
String oldLocation = location;
location = newLocation;
if (eNotificationRequired())
{
eNotify(new ENotificationImpl(this, Notification.SET, SetupPackage.GIT_CLONE_TASK__LOCATION, oldLocation,
location));
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public String getRemoteName()
{
return remoteName;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setRemoteName(String newRemoteName)
{
String oldRemoteName = remoteName;
remoteName = newRemoteName;
if (eNotificationRequired())
{
eNotify(new ENotificationImpl(this, Notification.SET, SetupPackage.GIT_CLONE_TASK__REMOTE_NAME, oldRemoteName,
remoteName));
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public String getRemoteURI()
{
return remoteURI;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setRemoteURI(String newRemoteURI)
{
String oldRemoteURI = remoteURI;
remoteURI = newRemoteURI;
if (eNotificationRequired())
{
eNotify(new ENotificationImpl(this, Notification.SET, SetupPackage.GIT_CLONE_TASK__REMOTE_URI, oldRemoteURI,
remoteURI));
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public String getCheckoutBranch()
{
return checkoutBranch;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setCheckoutBranch(String newCheckoutBranch)
{
String oldCheckoutBranch = checkoutBranch;
checkoutBranch = newCheckoutBranch;
if (eNotificationRequired())
{
eNotify(new ENotificationImpl(this, Notification.SET, SetupPackage.GIT_CLONE_TASK__CHECKOUT_BRANCH,
oldCheckoutBranch, checkoutBranch));
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public String getPushURI()
{
return pushURI;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setPushURI(String newPushURI)
{
String oldPushURI = pushURI;
pushURI = newPushURI;
if (eNotificationRequired())
{
eNotify(new ENotificationImpl(this, Notification.SET, SetupPackage.GIT_CLONE_TASK__PUSH_URI, oldPushURI, pushURI));
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public String getUserID()
{
return userID;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setUserID(String newUserID)
{
String oldUserID = userID;
userID = newUserID;
if (eNotificationRequired())
{
eNotify(new ENotificationImpl(this, Notification.SET, SetupPackage.GIT_CLONE_TASK__USER_ID, oldUserID, userID));
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType)
{
switch (featureID)
{
case SetupPackage.GIT_CLONE_TASK__LOCATION:
return getLocation();
case SetupPackage.GIT_CLONE_TASK__REMOTE_NAME:
return getRemoteName();
case SetupPackage.GIT_CLONE_TASK__REMOTE_URI:
return getRemoteURI();
case SetupPackage.GIT_CLONE_TASK__PUSH_URI:
return getPushURI();
case SetupPackage.GIT_CLONE_TASK__USER_ID:
return getUserID();
case SetupPackage.GIT_CLONE_TASK__CHECKOUT_BRANCH:
return getCheckoutBranch();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eSet(int featureID, Object newValue)
{
switch (featureID)
{
case SetupPackage.GIT_CLONE_TASK__LOCATION:
setLocation((String)newValue);
return;
case SetupPackage.GIT_CLONE_TASK__REMOTE_NAME:
setRemoteName((String)newValue);
return;
case SetupPackage.GIT_CLONE_TASK__REMOTE_URI:
setRemoteURI((String)newValue);
return;
case SetupPackage.GIT_CLONE_TASK__PUSH_URI:
setPushURI((String)newValue);
return;
case SetupPackage.GIT_CLONE_TASK__USER_ID:
setUserID((String)newValue);
return;
case SetupPackage.GIT_CLONE_TASK__CHECKOUT_BRANCH:
setCheckoutBranch((String)newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eUnset(int featureID)
{
switch (featureID)
{
case SetupPackage.GIT_CLONE_TASK__LOCATION:
setLocation(LOCATION_EDEFAULT);
return;
case SetupPackage.GIT_CLONE_TASK__REMOTE_NAME:
setRemoteName(REMOTE_NAME_EDEFAULT);
return;
case SetupPackage.GIT_CLONE_TASK__REMOTE_URI:
setRemoteURI(REMOTE_URI_EDEFAULT);
return;
case SetupPackage.GIT_CLONE_TASK__PUSH_URI:
setPushURI(PUSH_URI_EDEFAULT);
return;
case SetupPackage.GIT_CLONE_TASK__USER_ID:
setUserID(USER_ID_EDEFAULT);
return;
case SetupPackage.GIT_CLONE_TASK__CHECKOUT_BRANCH:
setCheckoutBranch(CHECKOUT_BRANCH_EDEFAULT);
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean eIsSet(int featureID)
{
switch (featureID)
{
case SetupPackage.GIT_CLONE_TASK__LOCATION:
return LOCATION_EDEFAULT == null ? location != null : !LOCATION_EDEFAULT.equals(location);
case SetupPackage.GIT_CLONE_TASK__REMOTE_NAME:
return REMOTE_NAME_EDEFAULT == null ? remoteName != null : !REMOTE_NAME_EDEFAULT.equals(remoteName);
case SetupPackage.GIT_CLONE_TASK__REMOTE_URI:
return REMOTE_URI_EDEFAULT == null ? remoteURI != null : !REMOTE_URI_EDEFAULT.equals(remoteURI);
case SetupPackage.GIT_CLONE_TASK__PUSH_URI:
return PUSH_URI_EDEFAULT == null ? pushURI != null : !PUSH_URI_EDEFAULT.equals(pushURI);
case SetupPackage.GIT_CLONE_TASK__USER_ID:
return USER_ID_EDEFAULT == null ? userID != null : !USER_ID_EDEFAULT.equals(userID);
case SetupPackage.GIT_CLONE_TASK__CHECKOUT_BRANCH:
return CHECKOUT_BRANCH_EDEFAULT == null ? checkoutBranch != null : !CHECKOUT_BRANCH_EDEFAULT
.equals(checkoutBranch);
}
return super.eIsSet(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public String toString()
{
if (eIsProxy())
{
return super.toString();
}
StringBuffer result = new StringBuffer(super.toString());
result.append(" (location: ");
result.append(location);
result.append(", remoteName: ");
result.append(remoteName);
result.append(", remoteURI: ");
result.append(remoteURI);
result.append(", pushURI: ");
result.append(pushURI);
result.append(", userID: ");
result.append(userID);
result.append(", checkoutBranch: ");
result.append(checkoutBranch);
result.append(')');
return result.toString();
}
@Override
public Set<Trigger> getValidTriggers()
{
return Trigger.IDE_TRIGGERS;
}
public boolean isNeeded(SetupTaskContext context) throws Exception
{
gitDelegate = GitUtil.create();
return gitDelegate.isNeeded(context, this);
}
public void perform(SetupTaskContext context) throws Exception
{
if (gitDelegate != null)
{
gitDelegate.perform(context, this);
}
}
@Override
public void dispose()
{
if (gitDelegate != null)
{
gitDelegate.dispose();
gitDelegate = null;
}
}
@Override
public MirrorRunnable mirror(final MirrorContext context, File mirrorsDir, boolean includingLocals) throws Exception
{
String sourceURL = context.redirect(getRemoteURI());
final File local = new File(mirrorsDir, FileUtil.encodeFileName(sourceURL));
String localURL = URI.createFileURI(local.getAbsolutePath()).toString();
context.addRedirection(sourceURL, localURL);
if (local.exists())
{
return null;
}
return new MirrorRunnable()
{
public void run(IProgressMonitor monitor) throws Exception
{
File repo = new File(getLocation(), ".git");
File localRepo = new File(local, ".git");
IOUtil.copyTree(repo, localRepo);
}
};
}
@Override
public void collectSniffers(List<Sniffer> sniffers)
{
sniffers.add(new CloneSniffer(true));
sniffers.add(new CloneSniffer(false));
}
/**
* @author Ed Merks
*/
private interface GitDelegate
{
public boolean isNeeded(SetupTaskContext context, GitCloneTaskImpl impl) throws Exception;
public void perform(SetupTaskContext context, GitCloneTaskImpl impl) throws Exception;
public void dispose();
}
/**
* @author Ed Merks
*/
private static class GitUtil implements GitDelegate
{
private boolean workDirExisted;
private File workDir;
private boolean hasCheckout;
private Git cachedGit;
private Repository cachedRepository;
private static GitDelegate create()
{
return new GitUtil();
}
public boolean isNeeded(SetupTaskContext context, GitCloneTaskImpl impl) throws Exception
{
String location = impl.getLocation();
workDir = new File(location);
if (!workDir.isDirectory())
{
return true;
}
workDirExisted = true;
if (workDir.list().length > 1)
{
return false;
}
context.log("Opening Git clone " + workDir);
try
{
Git git = Git.open(workDir);
if (!GitUtil.hasWorkTree(git))
{
FileUtil.rename(workDir);
return true;
}
Repository repository = git.getRepository();
String checkoutBranch = impl.getCheckoutBranch();
String remoteName = impl.getRemoteName();
String pushURI = context.redirect(impl.getPushURI());
String userID = impl.getUserID();
GitUtil.configureRepository(context, repository, checkoutBranch, remoteName, pushURI, userID);
hasCheckout = repository.getAllRefs().containsKey("refs/heads/" + checkoutBranch);
if (!hasCheckout)
{
cachedGit = git;
cachedRepository = repository;
return true;
}
return false;
}
catch (Throwable ex)
{
if (!workDirExisted)
{
FileUtil.delete(workDir, new ProgressLogMonitor(context));
}
throw new Exception(ex);
}
}
public void perform(SetupTaskContext context, GitCloneTaskImpl impl) throws Exception
{
try
{
// Force start egit to make sure we get the association
Bundle egitCore = Platform.getBundle("org.eclipse.egit.core");
if (egitCore != null)
{
egitCore.start();
}
String checkoutBranch = impl.getCheckoutBranch();
String remoteName = impl.getRemoteName();
String remoteURI = context.redirect(impl.getRemoteURI());
String userID = impl.getUserID();
if (cachedGit == null)
{
cachedGit = GitUtil.cloneRepository(context, workDir, checkoutBranch, remoteName, remoteURI, userID);
cachedRepository = cachedGit.getRepository();
if (!URI.createURI(remoteURI).isFile())
{
String pushURI = context.redirect(impl.getPushURI());
GitUtil.configureRepository(context, cachedRepository, checkoutBranch, remoteName, pushURI, userID);
}
}
if (!hasCheckout)
{
GitUtil.createBranch(context, cachedGit, checkoutBranch, remoteName);
GitUtil.checkout(context, cachedGit, checkoutBranch);
GitUtil.resetHard(context, cachedGit);
}
}
catch (Throwable ex)
{
if (!workDirExisted)
{
FileUtil.delete(workDir, new ProgressLogMonitor(context));
}
throw new Exception(ex);
}
}
public void dispose()
{
if (cachedRepository != null)
{
cachedRepository.close();
}
}
private static boolean hasWorkTree(Git git) throws Exception
{
try
{
StatusCommand statusCommand = git.status();
statusCommand.call();
return true;
}
catch (NoWorkTreeException ex)
{
return false;
}
}
private static Git cloneRepository(SetupTaskContext context, File workDir, String checkoutBranch,
String remoteName, String remoteURI, String userID) throws Exception
{
String remote;
URI baseURI = URI.createURI(remoteURI);
if (baseURI.isFile())
{
remote = baseURI.toString();
}
else
{
String scheme = baseURI.scheme();
String[] segments = baseURI.segments();
if (ANONYMOUS.equals(userID))
{
if (baseURI.port() != null)
{
scheme = "git";
String[] newSegments = new String[1 + segments.length];
newSegments[0] = "gitroot";
System.arraycopy(segments, 0, newSegments, 1, segments.length);
segments = newSegments;
}
remote = URI.createHierarchicalURI(scheme, baseURI.host(), baseURI.device(), segments, baseURI.query(),
baseURI.fragment()).toString();
}
else
{
remote = URI.createHierarchicalURI(scheme, userID + "@" + baseURI.authority(), baseURI.device(), segments,
baseURI.query(), baseURI.fragment()).toString();
}
}
context.log("Cloning Git repo " + remote + " to " + workDir);
CloneCommand command = Git.cloneRepository();
command.setNoCheckout(true);
command.setURI(remote);
command.setRemote(remoteName);
command.setBranchesToClone(Collections.singleton(checkoutBranch));
command.setDirectory(workDir);
command.setTimeout(60);
command.setProgressMonitor(new ProgressLogWrapper(context));
return command.call();
}
private static void configureRepository(SetupTaskContext context, Repository repository, String checkoutBranch,
String remoteName, String pushURI, String userID) throws Exception, IOException
{
StoredConfig config = repository.getConfig();
boolean changed = false;
changed |= configureLineEndingConversion(context, config);
changed |= addPushRefSpec(context, config, checkoutBranch, remoteName);
changed |= addPushURI(context, config, remoteName, pushURI, userID);
if (changed)
{
config.save();
}
}
private static boolean configureLineEndingConversion(SetupTaskContext context, StoredConfig config)
throws Exception
{
if (context.getOS().isLineEndingConversionNeeded())
{
if (context.isPerforming())
{
context.log("Setting " + ConfigConstants.CONFIG_KEY_AUTOCRLF + " = true");
}
config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_AUTOCRLF, AutoCRLF.TRUE);
return true;
}
return false;
}
private static boolean addPushRefSpec(SetupTaskContext context, StoredConfig config, String checkoutBranch,
String remoteName) throws Exception
{
String gerritQueue = "refs/for/" + checkoutBranch;
for (RemoteConfig remoteConfig : RemoteConfig.getAllRemoteConfigs(config))
{
if (remoteName.equals(remoteConfig.getName()))
{
List<RefSpec> pushRefSpecs = remoteConfig.getPushRefSpecs();
if (hasGerritPushRefSpec(pushRefSpecs, gerritQueue))
{
return false;
}
RefSpec refSpec = new RefSpec("HEAD:" + gerritQueue);
if (context.isPerforming())
{
context.log("Adding push ref spec: " + refSpec);
}
remoteConfig.addPushRefSpec(refSpec);
remoteConfig.update(config);
return true;
}
}
return false;
}
private static boolean addPushURI(SetupTaskContext context, StoredConfig config, String remoteName, String pushURI,
String userID) throws Exception
{
boolean uriAdded = false;
if (!StringUtil.isEmpty(pushURI))
{
String remote;
URI baseURI = URI.createURI(pushURI);
if (baseURI.isFile())
{
remote = baseURI.toString();
}
else
{
remote = URI.createHierarchicalURI(baseURI.scheme(), userID + "@" + baseURI.authority(), baseURI.device(),
baseURI.segments(), baseURI.query(), baseURI.fragment()).toString();
}
URIish uri = new URIish(remote);
for (RemoteConfig remoteConfig : RemoteConfig.getAllRemoteConfigs(config))
{
if (remoteName.equals(remoteConfig.getName()))
{
if (context.isPerforming())
{
context.log("Adding push URI: " + remote);
}
uriAdded = remoteConfig.addPushURI(uri);
if (uriAdded)
{
remoteConfig.update(config);
}
break;
}
}
}
return uriAdded;
}
private static boolean hasGerritPushRefSpec(List<RefSpec> pushRefSpecs, String gerritQueue)
{
for (RefSpec refSpec : pushRefSpecs)
{
if (refSpec.getDestination().equals(gerritQueue))
{
return true;
}
}
return false;
}
private static void createBranch(SetupTaskContext context, Git git, String checkoutBranch, String remoteName)
throws Exception
{
context.log("Creating local branch " + checkoutBranch);
CreateBranchCommand command = git.branchCreate();
command.setUpstreamMode(SetupUpstreamMode.SET_UPSTREAM);
command.setName(checkoutBranch);
command.setStartPoint("refs/remotes/" + remoteName + "/" + checkoutBranch);
command.call();
StoredConfig config = git.getRepository().getConfig();
config.setBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, checkoutBranch, ConfigConstants.CONFIG_KEY_REBASE, true);
config.save();
}
private static void checkout(SetupTaskContext context, Git git, String checkoutBranch) throws Exception
{
context.log("Checking out local branch " + checkoutBranch);
CheckoutCommand command = git.checkout();
command.setName(checkoutBranch);
command.call();
}
private static void resetHard(SetupTaskContext context, Git git) throws Exception
{
context.log("Resetting hard");
ResetCommand command = git.reset();
command.setMode(ResetType.HARD);
command.call();
}
/**
* @author Eike Stepper
*/
private static final class ProgressLogWrapper implements ProgressMonitor
{
private SetupTaskContext context;
private String title;
private int work;
private int totalWork;
public ProgressLogWrapper(SetupTaskContext context)
{
this.context = context;
}
public void update(int completed)
{
work += completed;
if (totalWork != 0 && title != null)
{
context.log(title + " (" + Math.round(100f / totalWork * work) + "%)");
}
}
public void start(int totalTasks)
{
}
public boolean isCancelled()
{
return context.isCanceled();
}
public void endTask()
{
if (title != null)
{
context.log(title + " (100%)");
}
title = null;
totalWork = 0;
work = 0;
}
public void beginTask(String title, int totalWork)
{
if (title != null)
{
if (title.startsWith("remote: "))
{
title = title.substring(8);
}
context.log(title + " (0%)");
}
this.title = title;
this.totalWork = totalWork;
work = 0;
}
}
}
/**
* @author Eike Stepper
*/
private class CloneSniffer extends BasicSniffer implements SourcePathProvider
{
private final Map<File, IPath> sourcePaths = new HashMap<File, IPath>();
private boolean used;
public CloneSniffer(boolean used)
{
super(GitCloneTaskImpl.this);
setLabel((used ? "Used" : "Unused") + " Git clones");
setDescription("Creates tasks for the " + StringUtil.uncap(getLabel()) + ".");
this.used = used;
}
public Map<File, IPath> getSourcePaths()
{
return sourcePaths;
}
@SuppressWarnings("restriction")
public void sniff(SetupTaskContainer container, List<Sniffer> dependencies, IProgressMonitor monitor)
throws Exception
{
try
{
List<Repository> repositories = new ArrayList<Repository>();
RepositoryUtil repositoryUtil = org.eclipse.egit.ui.Activator.getDefault().getRepositoryUtil();
for (String path : repositoryUtil.getConfiguredRepositories())
{
if (used == isUsed(new Path(path).removeLastSegments(1)))
{
Git git = Git.open(new File(path));
Repository repository = git.getRepository();
repositories.add(repository);
}
}
if (!repositories.isEmpty())
{
monitor.beginTask("", repositories.size());
for (Repository repository : repositories)
{
addTaskForRepository(container, repository);
monitor.worked(1);
}
}
}
finally
{
monitor.done();
}
}
private boolean isUsed(IPath path)
{
for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects())
{
if (contains(path, project.getLocation()))
{
return true;
}
}
return false;
}
private boolean contains(IPath container, IPath contained)
{
String[] containerSegments = container.segments();
String[] containedSegments = contained.segments();
if (containedSegments.length < containerSegments.length)
{
return false;
}
for (int i = 0; i < containerSegments.length; i++)
{
if (!containerSegments[i].equals(containedSegments[i]))
{
return false;
}
}
return true;
}
private void addTaskForRepository(SetupTaskContainer container, Repository repository) throws Exception
{
StoredConfig config = repository.getConfig();
RemoteConfig remoteConfig = getRemoteConfig(config);
if (remoteConfig == null)
{
return;
}
File workTree = repository.getWorkTree();
IPath relativePath = new Path("git").append(workTree.getName());
String location = "${setup.branch.dir/" + relativePath + "}";
sourcePaths.put(workTree, relativePath);
String remoteURI = getRemoteURI(remoteConfig);
String userID = ANONYMOUS;
URI uri = URI.createURI(remoteURI);
if (uri.userInfo() != null)
{
String authority = uri.authority();
int pos = authority.indexOf('@');
userID = authority.substring(0, pos);
authority = authority.substring(pos + 1);
remoteURI = URI.createHierarchicalURI(uri.scheme(), authority, uri.device(), uri.segments(), uri.query(),
uri.fragment()).toString();
}
GitCloneTask task = SetupFactory.eINSTANCE.createGitCloneTask();
task.setCheckoutBranch(repository.getBranch());
task.setLocation(location);
task.setRemoteName(remoteConfig.getName());
task.setRemoteURI(remoteURI);
task.setUserID(userID);
CompoundSetupTask compound = getCompound(container, getLabel());
compound.getSetupTasks().add(task);
}
private RemoteConfig getRemoteConfig(StoredConfig config) throws URISyntaxException
{
RemoteConfig firstConfig = null;
for (RemoteConfig remoteConfig : RemoteConfig.getAllRemoteConfigs(config))
{
if ("origin".equals(remoteConfig.getName()))
{
return remoteConfig;
}
if (firstConfig == null)
{
firstConfig = remoteConfig;
}
}
return firstConfig;
}
private String getRemoteURI(RemoteConfig remoteConfig)
{
String remoteURI = getRemoteURI(remoteConfig.getPushURIs());
if (StringUtil.isEmpty(remoteURI))
{
remoteURI = getRemoteURI(remoteConfig.getURIs());
}
return remoteURI;
}
private String getRemoteURI(List<URIish> uris)
{
if (uris == null || uris.isEmpty())
{
return "";
}
return uris.get(0).toString();
}
}
} // GitCloneTaskImpl