blob: 96ccfcf502d55f7b5ef0b839b00975618e2ebc8f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 The University of Tennessee 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:
* John Eblen - initial implementation
*******************************************************************************/
package org.eclipse.ptp.internal.rdt.sync.git.core;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.MergeCommand;
import org.eclipse.jgit.api.MergeResult;
import org.eclipse.jgit.api.RmCommand;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.StatusCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.RemoteSession;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.TransportGitSsh;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.util.FS;
import org.eclipse.ptp.internal.rdt.sync.git.core.GitSyncFileFilter.DiffFiles;
import org.eclipse.ptp.internal.rdt.sync.git.core.messages.Messages;
import org.eclipse.ptp.rdt.sync.core.AbstractSyncFileFilter;
import org.eclipse.ptp.rdt.sync.core.RecursiveSubMonitor;
import org.eclipse.ptp.rdt.sync.core.RemoteLocation;
import org.eclipse.ptp.rdt.sync.core.SyncManager;
import org.eclipse.ptp.rdt.sync.core.exceptions.MissingConnectionException;
import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteProcessService;
import org.eclipse.remote.core.exception.RemoteConnectionException;
/**
* Class for a local Git repository managed by JGit
*/
public class JGitRepo {
public static final String remoteBranchName = "eclipse_auto"; //$NON-NLS-1$
public static final String EMPTY_FILE_NAME = ".ptp-sync-folder"; //$NON-NLS-1$
private final IPath localDirectory;
private Git git;
private GitSyncFileFilter fileFilter = null;
private boolean mergeMapInitialized = false; // If false, call "readMergeConflictFiles" to populate the map.
private final Map<IPath, String[]> fileToMergePartsMap = new HashMap<IPath, String[]>();
private final Map<RemoteLocation, TransportGitSsh> remoteToTransportMap = new HashMap<RemoteLocation, TransportGitSsh>();
/**
* Create a JGit repository instance for the given local directory, creating resources, such as Git-specific files, if
* necessary.
*
* @param localDir
* @param monitor
*
* @throws GitAPIException
* on JGit-specific problems - instance should be considered invalid
* @throws IOException
* on file system problems - instance should be considered invalid
*/
public JGitRepo(IPath localDir, IProgressMonitor monitor) throws GitAPIException, IOException {
localDirectory = localDir;
try {
buildRepo(localDirectory.toOSString(), monitor);
} finally {
if (monitor != null) {
monitor.done();
}
}
}
private boolean anyDiffInIndex() throws IOException {
final Repository repo = getRepository();
final TreeWalk treeWalk = new TreeWalk(repo);
treeWalk.setRecursive(true); // recursive is required because a hash for a (sub)tree might not be available
final ObjectId rev = repo.resolve("HEAD"); //$NON-NLS-1$
if (rev != null) { // HEAD doesn't exist for a new repo, then we want to compare against empty tree
treeWalk.addTree(new RevWalk(repo).parseTree(rev));
}
treeWalk.addTree(new DirCacheIterator(repo.readDirCache()));
treeWalk.setFilter(TreeFilter.ANY_DIFF);
return treeWalk.next();
}
/**
* Build the JGit repository - creating resources, such as Git-specific files, if necessary.
*
* @param localDirectory
* Repository location
* @param monitor
* @return
* @throws GitAPIException
* on JGit-specific problems
* @throws IOException
* on file system problems
*/
private Git buildRepo(String localDirectory, IProgressMonitor monitor) throws GitAPIException, IOException {
final RecursiveSubMonitor subMon = RecursiveSubMonitor.convert(monitor, 10);
try {
// Get local Git repository, creating it if necessary.
File localDir = new File(localDirectory);
FileRepositoryBuilder repoBuilder = new FileRepositoryBuilder();
File gitDirFile = new File(localDirectory + File.separator + GitSyncService.gitDir);
Repository repository = repoBuilder.setWorkTree(localDir).setGitDir(gitDirFile).build();
boolean repoExists = gitDirFile.exists();
if (!repoExists) {
repository.create(false);
}
git = new Git(repository);
if (!repoExists) {
fileFilter = new GitSyncFileFilter(this, SyncManager.getDefaultFileFilter());
fileFilter.saveFilter();
} else {
fileFilter = new GitSyncFileFilter(this);
fileFilter.loadFilter();
}
subMon.worked(5);
// An initial commit to create the master branch.
subMon.subTask(Messages.JGitRepo_0);
if (!repoExists) {
commit(subMon.newChild(4));
} else {
subMon.worked(4);
}
return git;
} finally {
if (monitor != null) {
monitor.done();
}
}
}
/**
* Builds the remote configuration for the connection, setting up fetch and
* push operations between local and remote master branches.
*
* @param config
* configuration for the local repository
* @return the remote configuration
* @throws RuntimeException
* if the URI in the passed configuration is not properly
* formatted.
*/
private RemoteConfig buildRemoteConfig(StoredConfig config) {
RemoteConfig rconfig = null;
try {
rconfig = new RemoteConfig(config, remoteBranchName);
} catch (final URISyntaxException e) {
throw new RuntimeException(e);
}
final RefSpec refSpecFetch = new RefSpec("+refs/heads/master:refs/remotes/" + //$NON-NLS-1$
remoteBranchName + "/master"); //$NON-NLS-1$
final RefSpec refSpecPush = new RefSpec("+master:" + GitSyncService.remotePushBranch); //$NON-NLS-1$
rconfig.addFetchRefSpec(refSpecFetch);
rconfig.addPushRefSpec(refSpecPush);
return rconfig;
}
/**
* Replace given files with the most recent versions in the repository
*
* @param paths
* Array of paths to checkout
* @throws GitAPIException
* on JGit-specific problems
*/
public void checkout(IPath[] paths) throws GitAPIException {
CheckoutCommand checkoutCommand = git.checkout();
for (IPath p : paths) {
checkoutCommand.addPath(p.toString());
}
checkoutCommand.setStartPoint("HEAD"); //$NON-NLS-1$
checkoutCommand.call();
}
/**
* Replace given files with the most recent local copies from the remote (not necessarily the same as the current remote since
* no transferring of files is done)
*
* @param paths
* Array of paths to replace
* @throws GitAPIException
*/
public void checkoutRemoteCopy(IPath[] paths) throws GitAPIException {
CheckoutCommand checkoutCommand = git.checkout();
for (IPath p : paths) {
checkoutCommand.addPath(p.toString());
}
checkoutCommand.setStartPoint("refs/remotes/" + remoteBranchName + "/master"); //$NON-NLS-1$ //$NON-NLS-2$
checkoutCommand.call();
}
/**
* Commit files in working directory.
*
* assumes that no files are in conflict (do not call during merge)
*
* @param monitor
*
* @return whether any changes were committed
* @throws GitAPIException
* on JGit-specific problems
* @throws IOException
* on file system problems
*/
public boolean commit(IProgressMonitor monitor) throws GitAPIException, IOException {
RecursiveSubMonitor subMon = RecursiveSubMonitor.convert(monitor, 10);
assert (!inUnresolvedMergeState());
try {
DiffFiles diffFiles = fileFilter.getDiffFiles();
// Create and add an empty file to all synchronized directories to force sync'ing of empty directories
for (String dirName : diffFiles.dirSet) {
IPath emptyFilePath = new Path(this.getRepository().getWorkTree().getAbsolutePath());
emptyFilePath = emptyFilePath.append(dirName);
// Bug 439609 - directory may have been deleted
File emptyFileDir = new File(emptyFilePath.toOSString());
if (!emptyFileDir.exists()) {
continue;
}
emptyFilePath = emptyFilePath.append(EMPTY_FILE_NAME);
File emptyFile = new File(emptyFilePath.toOSString());
boolean fileWasCreated = emptyFile.createNewFile();
if (fileWasCreated) {
diffFiles.added.add(emptyFilePath.toString());
}
}
subMon.subTask(Messages.JGitRepo_2);
if (!diffFiles.added.isEmpty()) {
final AddCommand addCommand = git.add();
// Bug 401161 doesn't matter here because files are already filtered anyhow. It would be OK
// if the tree iterator would always return false in isEntryIgnored
addCommand.setWorkingTreeIterator(new SyncFileTreeIterator(git.getRepository(), fileFilter));
for (String fileName : diffFiles.added) {
addCommand.addFilepattern(fileName);
}
addCommand.call();
}
subMon.worked(3);
subMon.subTask(Messages.JGitRepo_3);
if (!diffFiles.removed.isEmpty()) {
final RmCommand rmCommand = new RmCommand(git.getRepository());
rmCommand.setCached(true);
for (String fileName : diffFiles.removed) {
rmCommand.addFilepattern(fileName);
}
rmCommand.call();
}
subMon.worked(3);
// Check if a commit is required.
subMon.subTask(Messages.JGitRepo_4);
if (anyDiffInIndex() || inMergeState()) {
final CommitCommand commitCommand = git.commit();
commitCommand.setMessage(GitSyncService.commitMessage);
commitCommand.call();
return true;
} else {
return false;
}
} finally {
if (monitor != null) {
monitor.done();
}
}
}
/**
* Check if the given commit exists.
*
* @return whether the commit exists
* @throws IOException
* on problems accessing the file system
* @throws IncorrectObjectTypeException
* @throws AmbiguousObjectException
* @throws RevisionSyntaxException
* exceptions that most likely indicate JGit had problems handling the passed id
*/
boolean commitExists(String commitId) throws RevisionSyntaxException, AmbiguousObjectException, IncorrectObjectTypeException,
IOException {
ObjectId commitObjectId = this.getRepository().resolve(commitId);
return this.getRepository().hasObject(commitObjectId);
}
/**
* Fetch files from the given remote. This only transmits the files. It does not update the local repository.
*
* @param remoteRepo
* remote Git repository
* @param monitor
*
* @throws TransportException
* on problem transferring files
*/
public void fetch(GitRepo remoteRepo, IProgressMonitor monitor) throws TransportException {
RemoteLocation remoteLoc = remoteRepo.getRemoteLocation();
int work = 10;
RecursiveSubMonitor subMon = RecursiveSubMonitor.convert(monitor, work);
TransportGitSsh transport = remoteToTransportMap.get(remoteLoc);
if (transport == null) {
work /= 2;
subMon.subTask(Messages.JGitRepo_5);
transport = this.buildTransport(remoteLoc, subMon.newChild(work));
remoteToTransportMap.put(remoteLoc, transport);
}
try {
subMon.subTask(Messages.JGitRepo_6);
String uploadCommand = remoteRepo.gitBinary() + " upload-pack"; //$NON-NLS-1$
transport.setOptionUploadPack(uploadCommand);
transport.fetch(new EclipseGitProgressTransformer(subMon.newChild(work)), null);
} catch (NotSupportedException e) {
throw new RuntimeException(e);
}
}
/**
* Push local repository changes to remote. (Only committed changes are pushed). Does not update the remote repository.
*
* @param remoteRepo
* remote Git repository
* @param monitor
*
* @throws TransportException
* on problem transferring files
*/
public void push(GitRepo remoteRepo, IProgressMonitor monitor) throws TransportException {
RemoteLocation remoteLoc = remoteRepo.getRemoteLocation();
int work = 10;
RecursiveSubMonitor subMon = RecursiveSubMonitor.convert(monitor, work);
TransportGitSsh transport = remoteToTransportMap.get(remoteLoc);
if (transport == null) {
work /= 2;
subMon.subTask(Messages.JGitRepo_5);
transport = this.buildTransport(remoteLoc, subMon.newChild(work));
remoteToTransportMap.put(remoteLoc, transport);
}
try {
subMon.subTask(Messages.JGitRepo_8);
String receiveCommand = remoteRepo.gitBinary() + " receive-pack"; //$NON-NLS-1$
transport.setOptionReceivePack(receiveCommand);
transport.push(new EclipseGitProgressTransformer(subMon.newChild(work)), null);
} catch (NotSupportedException e) {
throw new RuntimeException(e);
}
}
/**
* Is repository currently in a merge state, either resolved or unresolved?
*
* @return whether repository is in a merge state
* @throws IOException
*/
public boolean inMergeState() throws IOException {
try {
if (git.getRepository().resolve("MERGE_HEAD") == null) { //$NON-NLS-1$
return false;
} else {
return true;
}
} catch (AmbiguousObjectException e) {
// Should never happen...
Activator.log(e);
return true;
}
}
/**
* Is repository currently in an unresolved merge state?
*
* @return whether repository is in an unresolved merge state
* @throws IOException
*/
public boolean inUnresolvedMergeState() throws IOException {
if (inMergeState() && !(git.getRepository().getRepositoryState().equals(RepositoryState.MERGING_RESOLVED))) {
return true;
} else {
return false;
}
}
/**
* Find and parse each merge-conflicted file, storing local, remote, and ancestor versions of each file in a cache.
*
* @param monitor
*
* @return whether any merge conflicts were found
* @throws GitAPIException
* on JGit-specific problems
* @throws IOException
* on file system problems
*/
public boolean readMergeConflictFiles(IProgressMonitor monitor) throws GitAPIException, IOException {
RecursiveSubMonitor subMon = RecursiveSubMonitor.convert(monitor, 100);
String repoPath = git.getRepository().getWorkTree().getAbsolutePath();
if (!repoPath.endsWith(java.io.File.separator)) { // The documentation does not say if the separator is added...
repoPath += java.io.File.separator;
}
fileToMergePartsMap.clear();
mergeMapInitialized = true;
RevWalk walk = null;
try {
if (!git.getRepository().getRepositoryState().equals(RepositoryState.MERGING)) {
return false;
}
subMon.subTask(Messages.JGitRepo_9);
StatusCommand statusCommand = git.status();
Status status = statusCommand.call();
if (status.getConflicting().isEmpty()) {
return false;
}
subMon.worked(30);
subMon.subTask(Messages.JGitRepo_10);
walk = new RevWalk(git.getRepository());
// Get the head, merge head, and merge base commits
walk.setRevFilter(RevFilter.MERGE_BASE);
ObjectId headSHA = git.getRepository().resolve("HEAD"); //$NON-NLS-1$
ObjectId mergeHeadSHA = git.getRepository().resolve("MERGE_HEAD"); //$NON-NLS-1$
RevCommit head = walk.parseCommit(headSHA);
RevCommit mergeHead = walk.parseCommit(mergeHeadSHA);
walk.markStart(head);
walk.markStart(mergeHead);
RevCommit mergeBase = walk.next();
subMon.worked(30);
// For each merge-conflicted file, pull out and store its contents for each of the three commits
// Would be much faster to use a treewalk and check whether entry is conflicting instead of using
// status (which uses a treewalk) and then searching for those status found.
subMon.subTask(Messages.JGitRepo_11);
for (String s : status.getConflicting()) {
String localContents = ""; //$NON-NLS-1$
TreeWalk localTreeWalk = TreeWalk.forPath(git.getRepository(), s, head.getTree());
if (localTreeWalk != null) {
ObjectId localId = localTreeWalk.getObjectId(0);
localContents = new String(git.getRepository().open(localId).getBytes());
}
String remoteContents = ""; //$NON-NLS-1$
TreeWalk remoteTreeWalk = TreeWalk.forPath(git.getRepository(), s, mergeHead.getTree());
if (remoteTreeWalk != null) {
ObjectId remoteId = remoteTreeWalk.getObjectId(0);
remoteContents = new String(git.getRepository().open(remoteId).getBytes());
}
String ancestorContents = ""; //$NON-NLS-1$
if (mergeBase != null) {
TreeWalk ancestorTreeWalk = TreeWalk.forPath(git.getRepository(), s, mergeBase.getTree());
if (ancestorTreeWalk != null) {
ObjectId ancestorId = ancestorTreeWalk.getObjectId(0);
ancestorContents = new String(git.getRepository().open(ancestorId).getBytes());
}
}
String[] mergeParts = { localContents, remoteContents, ancestorContents };
fileToMergePartsMap.put(new Path(s), mergeParts);
}
subMon.worked(40);
} finally {
if (walk != null) {
walk.dispose();
}
if (monitor != null) {
monitor.done();
}
}
return fileToMergePartsMap.isEmpty();
}
/**
* Get the local directory for this repository (an absolute path)
*
* @return directory
*/
public IPath getDirectory() {
return localDirectory;
}
/**
* Get the file filter for this repository
*
* @return filter
*/
public GitSyncFileFilter getFilter() {
return fileFilter;
}
/**
* Get the Git instance for this repository
*
* @return Git instance
*/
public Git getGit() {
return git;
}
/**
* Get the real JGit repository
*
* @return repository
*/
public Repository getRepository() {
return git.getRepository();
}
/**
* Get the set of merge-conflicted files
*
* @return set of relative (to localDirectory) paths of merge-conflicted files.
* @throws GitAPIException
* on JGit-specific problems
* @throws IOException
* on file system problems
*/
public Set<IPath> getMergeConflictFiles() throws GitAPIException, IOException {
if (!mergeMapInitialized) {
this.readMergeConflictFiles(null);
}
return fileToMergePartsMap.keySet();
}
/**
* Return three strings representing the three parts of the given merge-conflicted file (local, remote, and ancestor,
* respectively) or null if the given file is not in a merge conflict.
*
* @param localFile
* Must be a relative path to the file from the repository
* @return the three parts or null
* @throws GitAPIException
* on JGit-specific problems
* @throws IOException
* on file system problems
*/
public String[] getMergeConflictParts(IPath localFile) throws GitAPIException, IOException {
if (!mergeMapInitialized) {
this.readMergeConflictFiles(null);
}
return fileToMergePartsMap.get(localFile);
}
/**
* Merge changes previously fetched from a remote repository
*
* @param monitor
*
* @return merge results
* @throws GitAPIException
* on JGit-specific problems
* @throws IOException
* on file system problems
*/
public MergeResult merge(IProgressMonitor monitor) throws IOException, GitAPIException {
RecursiveSubMonitor subMon = RecursiveSubMonitor.convert(monitor, 10);
try {
Ref remoteMasterRef = git.getRepository().findRef("refs/remotes/" + remoteBranchName + "/master"); //$NON-NLS-1$ //$NON-NLS-2$
final MergeCommand mergeCommand = git.merge().include(remoteMasterRef);
subMon.subTask(Messages.JGitRepo_12);
// Bug 434783: Merge resolution only works once for each Eclipse session.
// Need to reset flag after each merge.
mergeMapInitialized = false;
return mergeCommand.call();
} finally {
if (monitor != null) {
monitor.done();
}
}
}
/**
* Set filter for this repository
*
* @param filter
*/
public void setFilter(AbstractSyncFileFilter filter) {
fileFilter = new GitSyncFileFilter(this);
fileFilter.initialize(filter);
try {
fileFilter.saveFilter();
} catch (IOException e) {
Activator.log(Messages.JGitRepo_13 + localDirectory, e);
}
}
/**
* Add the given path to the repository, resolving the merge conflict (if any)
*
* @param paths
* @throws GitAPIException
* on JGit-specific problems
*/
public void setMergeAsResolved(IPath[] paths) throws GitAPIException {
AddCommand addCommand = git.add();
for (IPath p : paths) {
addCommand.addFilepattern(p.toString());
}
addCommand.call();
// Make sure each file is no longer conflicted before marking as resolved.
// Sometimes JGit will silently fail to add.
StatusCommand statusCommand = git.status();
Status status = statusCommand.call();
for (IPath p : paths) {
if (!(status.getConflicting().contains(p.toString()))) {
fileToMergePartsMap.remove(p);
}
}
}
// Subclass JGit's generic RemoteSession to run commands using the remote location's process builder
private class PTPSession implements RemoteSession {
private final RemoteLocation remoteLoc;
private final URIish uri;
/**
* Build new session instance for the given remote location
*
* @param remoteLoc
*/
public PTPSession(RemoteLocation remoteLoc) {
this.remoteLoc = remoteLoc;
this.uri = buildURI(remoteLoc.getDirectory());
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jgit.transport.RemoteSession#exec(java.lang.String, int)
*/
@Override
public Process exec(String command, int timeout) throws TransportException {
// TODO: Use a library for command splitting.
List<String> commandList = new LinkedList<String>();
commandList.add("sh"); //$NON-NLS-1$
commandList.add("-c"); //$NON-NLS-1$
commandList.add(command);
try {
IRemoteConnection connection = remoteLoc.getConnection();
if (!connection.isOpen()) {
connection.open(null);
}
return (Process) connection.getService(IRemoteProcessService.class).getProcessBuilder(commandList).start();
} catch (IOException e) {
throw new TransportException(uri, e.getMessage(), e);
} catch (RemoteConnectionException e) {
throw new TransportException(uri, e.getMessage(), e);
} catch (MissingConnectionException e) {
throw new TransportException(uri, Messages.JGitRepo_14 + e.getConnectionName(), e);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jgit.transport.RemoteSession#disconnect()
*/
@Override
public void disconnect() {
// Nothing to do
}
}
/**
* Creates a new transport object for executing commands at the given remote location.
*
* @param remoteLocation
* the remote location
*
* @return new transport instance - never null.
* @throws TransportException
* on problem creating transport
* @throws RuntimeException
* if the requested transport is not supported by JGit.
*/
private TransportGitSsh buildTransport(final RemoteLocation remoteLoc, IProgressMonitor monitor) throws TransportException {
RecursiveSubMonitor subMon = RecursiveSubMonitor.convert(monitor, 10);
RemoteConfig remoteConfig = buildRemoteConfig(git.getRepository().getConfig());
final URIish uri = buildURI(remoteLoc.getDirectory());
TransportGitSsh transport;
try {
subMon.subTask(Messages.JGitRepo_15);
transport = (TransportGitSsh) Transport.open(git.getRepository(), uri);
} catch (NotSupportedException e) {
throw new RuntimeException(e);
} finally {
if (monitor != null) {
monitor.done();
}
}
// Set the transport to use our own means of executing remote commands.
transport.setSshSessionFactory(new SshSessionFactory() {
@Override
public RemoteSession getSession(URIish uri, CredentialsProvider credentialsProvider, FS fs, int tms)
throws TransportException {
return new PTPSession(remoteLoc);
}
@Override
public String getType() {
return "ptp"; //$NON-NLS-1$
}
});
transport.applyConfig(remoteConfig);
return transport;
}
/**
* Build the URI for the remote host as needed by the transport. Since the
* transport will use an external SSH session, we do not need to provide
* user, host, or password. However, the function for opening a transport
* throws an exception if the host is null or empty length. So we set it to
* a dummy string.
*
* @return URIish
*/
private URIish buildURI(String directory) {
return new URIish()
// .setUser(connection.getUsername())
.setHost("none") //$NON-NLS-1$
// .setPass("")
.setScheme("ssh") //$NON-NLS-1$
.setPath(directory + "/" + GitSyncService.gitDir); //$NON-NLS-1$ // Should use remote path seperator but first
// 315720 has to be fixed
}
/**
* Releases all resources allocated by this JGit repository instance, including closing all transport objects and closing the
* repository itself. Instance should not be used after calling this method.
*/
public void close() {
for (TransportGitSsh t : remoteToTransportMap.values()) {
t.close();
}
remoteToTransportMap.clear();
git.getRepository().close();
git = null;
fileFilter = null;
fileToMergePartsMap.clear();
}
}