| /******************************************************************************* |
| * 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); |
| } |
| |
| } |