org.gitective.core.BlobUtils Maven / Gradle / Ivy
Show all versions of gitective-core Show documentation
/*
* Copyright (c) 2011 Kevin Sawicki
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
package org.gitective.core;
import static java.lang.Integer.MAX_VALUE;
import static org.eclipse.jgit.diff.RawText.EMPTY_TEXT;
import static org.eclipse.jgit.diff.RawTextComparator.DEFAULT;
import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.eclipse.jgit.lib.FileMode.TYPE_FILE;
import static org.eclipse.jgit.lib.FileMode.TYPE_MASK;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Collections;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.diff.HistogramDiff;
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.ObjectStream;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.TreeWalk;
/**
* Utilities for dealing with Git blobs.
*
* This class provides helpers for getting the content and the ids of blobs at
* different paths and commits.
*
* This class also provides helpers for computing the differences between the
* content of blobs.
*/
public abstract class BlobUtils {
/**
* Get the contents of the the blob with the given id as a byte array.
*
* @param repository
* @param id
* @return blob bytes
*/
protected static byte[] getBytes(final Repository repository,
final ObjectId id) {
try {
return repository.open(id, OBJ_BLOB).getCachedBytes(MAX_VALUE);
} catch (IOException e) {
throw new GitException(e, repository);
}
}
/**
* Get the contents of the the blob with the given id as a byte array.
*
* @param reader
* @param id
* @return blob bytes
*/
protected static byte[] getBytes(final ObjectReader reader,
final ObjectId id) {
try {
return reader.open(id, OBJ_BLOB).getCachedBytes(MAX_VALUE);
} catch (IOException e) {
throw new GitException(e, null);
}
}
/**
* Convert byte array to UTF-8 {@link String}
*
* @param repository
* @param raw
* @return UTF-8 string or null if bytes are null
*/
protected static String toString(final Repository repository,
final byte[] raw) {
if (raw == null)
return null;
try {
return new String(raw, CHARACTER_ENCODING);
} catch (UnsupportedEncodingException e) {
throw new GitException(e, repository);
}
}
/**
* Get the contents of the the blob with the given id as a UTF-8
* {@link String}.
*
* @param repository
* @param id
* @return content of blob as UTF-8 string
*/
public static String getContent(final Repository repository,
final ObjectId id) {
if (repository == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Repository"));
if (id == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Object id"));
return toString(repository, getBytes(repository, id));
}
/**
* Get the id of the blob at the path in the given commit.
*
* @param repository
* @param commit
* @param path
* @return blob id, null if not present
*/
protected static ObjectId lookupId(final Repository repository,
final RevCommit commit, final String path) {
final TreeWalk walk;
try {
walk = TreeWalk.forPath(repository, path, commit.getTree());
} catch (IOException e) {
throw new GitException(e, repository);
}
if (walk == null)
return null;
if ((walk.getRawMode(0) & TYPE_MASK) != TYPE_FILE)
return null;
return walk.getObjectId(0);
}
/**
* Get the contents of the the blob in the commit located at the given path
* as a byte array.
*
* @param repository
* @param commit
* @param path
* @return raw content
*/
protected static byte[] getBytes(final Repository repository,
final RevCommit commit, final String path) {
final ObjectId id = lookupId(repository, commit, path);
return id != null ? getBytes(repository, id) : null;
}
/**
* Get raw contents of the blob at the given path in the commit that the
* revision references.
*
* @param repository
* @param revision
* @param path
* @return raw content or null if no blob with path at given revision
*/
public static byte[] getRawContent(final Repository repository,
final String revision, final String path) {
if (repository == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Repository"));
if (revision == null)
throw new IllegalArgumentException(Assert.formatNotNull("Revision"));
if (revision.length() == 0)
throw new IllegalArgumentException(
Assert.formatNotEmpty("Revision"));
if (path == null)
throw new IllegalArgumentException(Assert.formatNotNull("Path"));
if (path.length() == 0)
throw new IllegalArgumentException(Assert.formatNotEmpty("Path"));
final RevCommit commit = CommitUtils.parse(repository,
CommitUtils.strictResolve(repository, revision));
return getBytes(repository, commit, path);
}
/**
* Get the raw contents of the blob in the commit located at the given path.
*
* @param repository
* @param commitId
* @param path
* @return raw content or null if no blob with path at given commit
*/
public static byte[] getRawContent(final Repository repository,
final ObjectId commitId, final String path) {
if (repository == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Repository"));
if (commitId == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Commit id"));
if (path == null)
throw new IllegalArgumentException(Assert.formatNotNull("Path"));
if (path.length() == 0)
throw new IllegalArgumentException(Assert.formatNotEmpty("Path"));
final RevCommit commit = CommitUtils.parse(repository, commitId);
return getBytes(repository, commit, path);
}
/**
* Get the contents of the blob in the commit located at the given path.
*
* @param repository
* @param commitId
* @param path
* @return contents or null if no blob with path at given commit
*/
public static String getContent(final Repository repository,
final ObjectId commitId, final String path) {
return toString(repository, getRawContent(repository, commitId, path));
}
/**
* Get the contents of the blob at the given path in the commit that the
* revision references.
*
* @param repository
* @param revision
* @param path
* @return contents or null if no blob with path at given revision
*/
public static String getContent(final Repository repository,
final String revision, final String path) {
return toString(repository, getRawContent(repository, revision, path));
}
/**
* Get the contents of the blob at the given path in the commit that HEAD
* references.
*
* @param repository
* @param path
* @return content or null if no blob with path at HEAD commit
*/
public static String getHeadContent(final Repository repository,
final String path) {
return getContent(repository, HEAD, path);
}
/**
* Get the raw contents of the blob at the given path in the commit that
* HEAD references.
*
* @param repository
* @param path
* @return content or null if no blob with path at HEAD commit
*/
public static byte[] getRawHeadContent(final Repository repository,
final String path) {
return getRawContent(repository, HEAD, path);
}
/**
* Get the id of the blob at the path in the commit that the given revision
* references.
*
* @param repository
* @param revision
* @param path
* @return blob id
*/
public static ObjectId getId(final Repository repository,
final String revision, final String path) {
if (repository == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Repository"));
if (revision == null)
throw new IllegalArgumentException(Assert.formatNotNull("Revision"));
if (revision.length() == 0)
throw new IllegalArgumentException(
Assert.formatNotEmpty("Revision"));
if (path == null)
throw new IllegalArgumentException(Assert.formatNotNull("Path"));
if (path.length() == 0)
throw new IllegalArgumentException(Assert.formatNotEmpty("Path"));
final RevCommit commit = CommitUtils.parse(repository,
CommitUtils.strictResolve(repository, revision));
return lookupId(repository, commit, path);
}
/**
* Get the id of the blob at the path in the commit that HEAD currently
* references.
*
* @param repository
* @param path
* @return blob id
*/
public static ObjectId getHeadId(final Repository repository,
final String path) {
return getId(repository, HEAD, path);
}
/**
* Get the id of the blob at the path in the commit that the given revision
* references.
*
* @param repository
* @param commitId
* @param path
* @return blob id
*/
public static ObjectId getId(final Repository repository,
final ObjectId commitId, final String path) {
if (repository == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Repository"));
if (commitId == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Commit id"));
if (path == null)
throw new IllegalArgumentException(Assert.formatNotNull("Path"));
if (path.length() == 0)
throw new IllegalArgumentException(Assert.formatNotEmpty("Path"));
final RevCommit commit = CommitUtils.parse(repository, commitId);
return lookupId(repository, commit, path);
}
/**
* Open a stream to the contents of the blob at the path in the given commit
*
* @param repository
* @param commitId
* @param path
* @return stream, null if no blob at given path
*/
public static ObjectStream getStream(final Repository repository,
final ObjectId commitId, final String path) {
if (repository == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Repository"));
if (commitId == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Commit id"));
if (path == null)
throw new IllegalArgumentException(Assert.formatNotNull("Path"));
if (path.length() == 0)
throw new IllegalArgumentException(Assert.formatNotEmpty("Path"));
final RevCommit commit = CommitUtils.parse(repository, commitId);
final ObjectId blobId = lookupId(repository, commit, path);
if (blobId == null)
return null;
try {
return repository.open(blobId, OBJ_BLOB).openStream();
} catch (IOException e) {
throw new GitException(e, repository);
}
}
/**
* Open a stream to the contents of the blob at the path in the commit that
* HEAD currently references.
*
* @param repository
* @param path
* @return stream
*/
public static ObjectStream getHeadStream(final Repository repository,
final String path) {
return getStream(repository, HEAD, path);
}
/**
* Open a stream to the contents of the blob at the path in the commit that
* the given revision references.
*
* @param repository
* @param revision
* @param path
* @return stream
*/
public static ObjectStream getStream(final Repository repository,
final String revision, final String path) {
if (repository == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Repository"));
if (revision == null)
throw new IllegalArgumentException(Assert.formatNotNull("Revision"));
if (revision.length() == 0)
throw new IllegalArgumentException(
Assert.formatNotEmpty("Revision"));
if (path == null)
throw new IllegalArgumentException(Assert.formatNotNull("Path"));
if (path.length() == 0)
throw new IllegalArgumentException(Assert.formatNotEmpty("Path"));
final RevCommit commit = CommitUtils.parse(repository,
CommitUtils.strictResolve(repository, revision));
final ObjectId blobId = lookupId(repository, commit, path);
if (blobId == null)
return null;
try {
return repository.open(blobId, OBJ_BLOB).openStream();
} catch (IOException e) {
throw new GitException(e, repository);
}
}
/**
* Diff the blobs at the given object ids using the
* {@link RawTextComparator#DEFAULT} comparator.
*
* @see #diff(Repository, ObjectId, ObjectId, RawTextComparator)
* @param repository
* @param blob1
* @param blob2
* @return list of edits
*/
public static Collection diff(final Repository repository,
final ObjectId blob1, final ObjectId blob2) {
return diff(repository, blob1, blob2, DEFAULT);
}
/**
* Diff the blobs at the given object ids.
*
* This method will return an empty list if the content of either blob is
* binary.
*
* @param repository
* @param blob1
* @param blob2
* @param comparator
* @return list of edits, never null
*/
public static Collection diff(final Repository repository,
final ObjectId blob1, final ObjectId blob2,
final RawTextComparator comparator) {
if (repository == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Repository"));
if (blob1 == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Blob id 1"));
if (blob2 == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Blob id 2"));
if (comparator == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Comparator"));
if (blob1.equals(blob2))
return Collections.emptyList();
final byte[] data1;
if (!blob1.equals(ObjectId.zeroId())) {
data1 = getBytes(repository, blob1);
if (RawText.isBinary(data1))
return Collections.emptyList();
} else
data1 = new byte[0];
final byte[] data2;
if (!blob2.equals(ObjectId.zeroId())) {
data2 = getBytes(repository, blob2);
if (RawText.isBinary(data2))
return Collections.emptyList();
} else
data2 = new byte[0];
return new HistogramDiff().diff(comparator, //
data1.length > 0 ? new RawText(data1) : EMPTY_TEXT, //
data2.length > 0 ? new RawText(data2) : EMPTY_TEXT);
}
/**
* Diff the blobs at the given object ids using the
* {@link RawTextComparator#DEFAULT} comparator.
*
* @see #diff(ObjectReader, ObjectId, ObjectId, RawTextComparator)
* @param reader
* @param blob1
* @param blob2
* @return list of edits
*/
public static Collection diff(final ObjectReader reader,
final ObjectId blob1, final ObjectId blob2) {
return diff(reader, blob1, blob2, DEFAULT);
}
/**
* Diff the blobs at the given object ids.
*
* This method will return an empty list if the content of either blob is
* binary.
*
* @param reader
* @param blob1
* @param blob2
* @param comparator
* @return list of edits, never null
*/
public static Collection diff(final ObjectReader reader,
final ObjectId blob1, final ObjectId blob2,
final RawTextComparator comparator) {
if (reader == null)
throw new IllegalArgumentException(Assert.formatNotNull("Reader"));
if (blob1 == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Blob id 1"));
if (blob2 == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Blob id 2"));
if (comparator == null)
throw new IllegalArgumentException(
Assert.formatNotNull("Comparator"));
if (blob1.equals(blob2))
return Collections.emptyList();
final byte[] data1;
if (!blob1.equals(ObjectId.zeroId())) {
data1 = getBytes(reader, blob1);
if (RawText.isBinary(data1))
return Collections.emptyList();
} else
data1 = new byte[0];
final byte[] data2;
if (!blob2.equals(ObjectId.zeroId())) {
data2 = getBytes(reader, blob2);
if (RawText.isBinary(data2))
return Collections.emptyList();
} else
data2 = new byte[0];
return new HistogramDiff().diff(comparator, //
data1.length > 0 ? new RawText(data1) : EMPTY_TEXT, //
data2.length > 0 ? new RawText(data2) : EMPTY_TEXT);
}
}