blob: a7b290b402deede4cd14a2cdb51e62fe95ebedfc [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2011, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2010, Jens Baumgart <jens.baumgart@sap.com>
*
* 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
*******************************************************************************/
package org.eclipse.egit.core.test;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.egit.core.op.BranchOperation;
import org.eclipse.egit.core.op.ConnectProviderOperation;
import org.eclipse.egit.core.op.DisconnectProviderOperation;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.api.errors.NoMessageException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepository;
import org.eclipse.jgit.treewalk.TreeWalk;
/**
* Helper class for creating and filling a test repository
*
*/
public class TestRepository {
Repository repository;
String workdirPrefix;
/**
* Creates a new test repository
*
* @param gitDir
* @throws IOException
*/
public TestRepository(File gitDir) throws IOException {
repository = new FileRepository(gitDir);
repository.create();
try {
workdirPrefix = repository.getWorkTree().getCanonicalPath();
} catch (IOException err) {
workdirPrefix = repository.getWorkTree().getAbsolutePath();
}
workdirPrefix = workdirPrefix.replace('\\', '/');
if (!workdirPrefix.endsWith("/")) //$NON-NLS-1$
workdirPrefix += "/"; //$NON-NLS-1$
}
/**
* Creates a test repository from an existing Repository
*
* @param repository
* @throws IOException
*/
public TestRepository(Repository repository) throws IOException {
this.repository = repository;
try {
workdirPrefix = repository.getWorkTree().getCanonicalPath();
} catch (IOException err) {
workdirPrefix = repository.getWorkTree().getAbsolutePath();
}
workdirPrefix = workdirPrefix.replace('\\', '/');
if (!workdirPrefix.endsWith("/")) //$NON-NLS-1$
workdirPrefix += "/"; //$NON-NLS-1$
}
/**
* @return the wrapped repository
*/
public Repository getRepository() {
return repository;
}
/**
* create an initial commit containing a file "dummy" in the
*
* @param message
* commit message
* @return commit object
* @throws IOException
* @throws NoHeadException
* @throws NoMessageException
* @throws ConcurrentRefUpdateException
* @throws JGitInternalException
* @throws WrongRepositoryStateException
*/
public RevCommit createInitialCommit(String message) throws IOException,
NoHeadException, NoMessageException, ConcurrentRefUpdateException,
JGitInternalException, WrongRepositoryStateException {
String repoPath = repository.getWorkTree().getAbsolutePath();
File file = new File(repoPath, "dummy");
file.createNewFile();
track(file);
return commit(message);
}
/**
* Create new file
*
* @param project
* instance of project inside with file will be created
* @param name
* name of file
* @return nearly created file
* @throws IOException
*/
public File createFile(IProject project, String name) throws IOException {
String path = project.getLocation().append(name).toOSString();
int lastSeparator = path.lastIndexOf(File.separator);
new File(path.substring(0, lastSeparator)).mkdirs();
File file = new File(path);
file.createNewFile();
return file;
}
/**
* Track, add to index and finally commit given file
*
* @param project
* @param file
* @param commitMessage
* @return commit object
* @throws Exception
*/
public RevCommit addAndCommit(IProject project, File file, String commitMessage)
throws Exception {
track(file);
addToIndex(project, file);
return commit(commitMessage);
}
/**
* Appends file content to given file, then track, add to index and finally
* commit it.
*
* @param project
* @param file
* @param content
* @param commitMessage
* @return commit object
* @throws Exception
*/
public RevCommit appendContentAndCommit(IProject project, File file,
byte[] content, String commitMessage) throws Exception {
return appendContentAndCommit(project, file, new String(content),
commitMessage);
}
/**
* Appends file content to given file, then track, add to index and finally
* commit it.
*
* @param project
* @param file
* @param content
* @param commitMessage
* @return commit object
* @throws Exception
*/
public RevCommit appendContentAndCommit(IProject project, File file,
String content, String commitMessage) throws Exception {
appendFileContent(file, content);
track(file);
addToIndex(project, file);
return commit(commitMessage);
}
/**
* Commits the current index
*
* @param message
* commit message
* @return commit object
*
* @throws NoHeadException
* @throws NoMessageException
* @throws UnmergedPathException
* @throws ConcurrentRefUpdateException
* @throws JGitInternalException
* @throws WrongRepositoryStateException
*/
public RevCommit commit(String message) throws NoHeadException,
NoMessageException, UnmergedPathException,
ConcurrentRefUpdateException, JGitInternalException,
WrongRepositoryStateException {
Git git = new Git(repository);
CommitCommand commitCommand = git.commit();
commitCommand.setAuthor("J. Git", "j.git@egit.org");
commitCommand.setCommitter(commitCommand.getAuthor());
commitCommand.setMessage(message);
return commitCommand.call();
}
/**
* Adds file to version control
*
* @param file
* @throws IOException
*/
public void track(File file) throws IOException {
String repoPath = getRepoRelativePath(new Path(file.getPath())
.toString());
try {
new Git(repository).add().addFilepattern(repoPath).call();
} catch (NoFilepatternException e) {
throw new IOException(e.getMessage());
}
}
/**
* Creates a new branch and immediately checkout it.
*
* @param refName
* starting point for the new branch
* @param newRefName
* @throws Exception
*/
public void createAndCheckoutBranch(String refName, String newRefName) throws Exception {
createBranch(refName, newRefName);
checkoutBranch(newRefName);
}
/**
* Creates a new branch
*
* @param refName
* starting point for the new branch
* @param newRefName
* @throws IOException
*/
public void createBranch(String refName, String newRefName)
throws IOException {
RefUpdate updateRef;
updateRef = repository.updateRef(newRefName);
Ref startRef = repository.getRef(refName);
ObjectId startAt = repository.resolve(refName);
String startBranch;
if (startRef != null)
startBranch = refName;
else
startBranch = startAt.name();
startBranch = Repository.shortenRefName(startBranch);
updateRef.setNewObjectId(startAt);
updateRef
.setRefLogMessage("branch: Created from " + startBranch, false); //$NON-NLS-1$
updateRef.update();
}
/**
* Checkouts branch
*
* @param refName
* full name of branch
* @throws CoreException
*/
public void checkoutBranch(String refName) throws CoreException {
new BranchOperation(repository, refName).execute(null);
}
/**
* Adds the given file to the index
*
* @param project
* @param file
* @throws Exception
*/
public void addToIndex(IProject project, File file) throws Exception {
IFile iFile = getIFile(project, file);
addToIndex(iFile);
}
/**
* Adds the given file to the index
*
* @param file
* @throws CoreException
* @throws IOException
*/
public void addToIndex(IFile file) throws CoreException, IOException {
String repoPath = getRepoRelativePath(file.getLocation().toOSString());
try {
new Git(repository).add().addFilepattern(repoPath).call();
} catch (NoFilepatternException e) {
throw new IOException(e.getMessage());
}
}
/**
* Appends content to end of given file.
*
* @param file
* @param content
* @throws IOException
*/
public void appendFileContent(File file, byte[] content) throws IOException {
appendFileContent(file, new String(content), true);
}
/**
* Appends content to end of given file.
*
* @param file
* @param content
* @throws IOException
*/
public void appendFileContent(File file, String content) throws IOException {
appendFileContent(file, content, true);
}
/**
* Appends content to given file.
*
* @param file
* @param content
* @param append
* if true, then bytes will be written to the end of the file
* rather than the beginning
* @throws IOException
*/
public void appendFileContent(File file, byte[] content, boolean append)
throws IOException {
appendFileContent(file, new String(content), append);
}
/**
* Appends content to given file.
*
* @param file
* @param content
* @param append
* if true, then bytes will be written to the end of the file
* rather than the beginning
* @throws IOException
*/
public void appendFileContent(File file, String content, boolean append)
throws IOException {
FileWriter fw = null;
try {
fw = new FileWriter(file, append);
fw.append(content);
} finally {
if (fw != null)
fw.close();
}
}
/**
* Checks if a file with the given path exists in the HEAD tree
*
* @param path
* @return true if the file exists
* @throws IOException
*/
public boolean inHead(String path) throws IOException {
ObjectId headId = repository.resolve(Constants.HEAD);
RevWalk rw = new RevWalk(repository);
TreeWalk tw = null;
try {
tw = TreeWalk.forPath(repository, path, rw.parseTree(headId));
return tw != null;
} finally {
rw.release();
rw.dispose();
if (tw != null)
tw.release();
}
}
public boolean inIndex(String path) throws IOException {
String repoPath = getRepoRelativePath(path);
DirCache dc = DirCache.read(repository.getIndexFile(), repository.getFS());
return dc.getEntry(repoPath) != null;
}
public long lastModifiedInIndex(String path) throws IOException {
String repoPath = getRepoRelativePath(path);
DirCache dc = DirCache.read(repository.getIndexFile(), repository.getFS());
return dc.getEntry(repoPath).getLastModified();
}
public int getDirCacheEntryLength(String path) throws IOException {
String repoPath = getRepoRelativePath(path);
DirCache dc = DirCache.read(repository.getIndexFile(), repository.getFS());
return dc.getEntry(repoPath).getLength();
}
public String getRepoRelativePath(String path) {
final int pfxLen = workdirPrefix.length();
final int pLen = path.length();
if (pLen > pfxLen)
return path.substring(pfxLen);
else if (path.length() == pfxLen - 1)
return ""; //$NON-NLS-1$
return null;
}
public IFile getIFile(IProject project, File file) throws CoreException {
String relativePath = getRepoRelativePath(file.getAbsolutePath());
String quotedProjectName = Pattern.quote(project.getName());
relativePath = relativePath.replaceFirst(quotedProjectName, "");
IFile iFile = project.getFile(relativePath);
iFile.refreshLocal(0, null);
return iFile;
}
public void dispose() {
repository.close();
repository = null;
}
/**
* Connect a project to this repository
*
* @param project
* @throws CoreException
*/
public void connect(IProject project) throws CoreException {
ConnectProviderOperation op = new ConnectProviderOperation(project,
this.getRepository().getDirectory());
op.execute(null);
}
/**
* Disconnects provider from project
*
* @param project
* @throws CoreException
*/
public void disconnect(IProject project) throws CoreException {
Collection<IProject> projects = Collections.singleton(project
.getProject());
DisconnectProviderOperation disconnect = new DisconnectProviderOperation(
projects);
disconnect.execute(null);
}
}