using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Handles;
namespace LibGit2Sharp
{
///
/// Provides methods to directly work against the Git object database
/// without involving the index nor the working directory.
///
public class ObjectDatabase
{
private readonly Repository repo;
private readonly ObjectDatabaseSafeHandle handle;
///
/// Needed for mocking purposes.
///
protected ObjectDatabase()
{ }
internal ObjectDatabase(Repository repo)
{
this.repo = repo;
handle = Proxy.git_repository_odb(repo.Handle);
repo.RegisterForCleanup(handle);
}
///
/// Determines if the given object can be found in the object database.
///
/// Identifier of the object being searched for.
/// True if the object has been found; false otherwise.
public virtual bool Contains(ObjectId objectId)
{
Ensure.ArgumentNotNull(objectId, "objectId");
return Proxy.git_odb_exists(handle, objectId);
}
///
/// Inserts a into the object database, created from the content of a file.
///
/// Path to the file to create the blob from. A relative path is allowed to
/// be passed if the is a standard, non-bare, repository. The path
/// will then be considered as a path relative to the root of the working directory.
/// The created .
public virtual Blob CreateBlob(string path)
{
Ensure.ArgumentNotNullOrEmptyString(path, "path");
if (repo.Info.IsBare && !Path.IsPathRooted(path))
{
throw new InvalidOperationException(
string.Format(CultureInfo.InvariantCulture,
"Cannot create a blob in a bare repository from a relative path ('{0}').", path));
}
ObjectId id = Path.IsPathRooted(path)
? Proxy.git_blob_create_fromdisk(repo.Handle, path)
: Proxy.git_blob_create_fromfile(repo.Handle, path);
return repo.Lookup(id);
}
///
/// Adds the provided backend to the object database with the specified priority.
///
/// The backend to add
/// The priority at which libgit2 should consult this backend (higher values are consulted first)
public virtual void AddBackend(OdbBackend backend, int priority)
{
Ensure.ArgumentNotNull(backend, "backend");
Ensure.ArgumentConformsTo(priority, s => s > 0, "priority");
Proxy.git_odb_add_backend(this.handle, backend.GitOdbBackendPointer, priority);
}
private class Processor
{
private readonly BinaryReader _reader;
public Processor(BinaryReader reader)
{
_reader = reader;
}
public int Provider(IntPtr content, int max_length, IntPtr data)
{
var local = new byte[max_length];
int numberOfReadBytes = _reader.Read(local, 0, max_length);
Marshal.Copy(local, 0, content, numberOfReadBytes);
return numberOfReadBytes;
}
}
///
/// Inserts a into the object database, created from the content of a data provider.
///
/// The reader that will provide the content of the blob to be created.
/// The hintpath is used to determine what git filters should be applied to the object before it can be placed to the object database.
/// The created .
public virtual Blob CreateBlob(BinaryReader reader, string hintpath = null)
{
Ensure.ArgumentNotNull(reader, "reader");
var proc = new Processor(reader);
ObjectId id = Proxy.git_blob_create_fromchunks(repo.Handle, hintpath, proc.Provider);
return repo.Lookup(id);
}
///
/// Inserts a into the object database, created from a .
///
/// The .
/// The created .
public virtual Tree CreateTree(TreeDefinition treeDefinition)
{
Ensure.ArgumentNotNull(treeDefinition, "treeDefinition");
return treeDefinition.Build(repo);
}
///
/// Inserts a into the object database, referencing an existing .
///
/// The description of why a change was made to the repository.
/// The of who made the change.
/// The of who added the change to the repository.
/// The of the to be created.
/// The parents of the to be created.
/// The created .
public virtual Commit CreateCommit(string message, Signature author, Signature committer, Tree tree, IEnumerable parents)
{
return CreateCommit(message, author, committer, tree, parents, null);
}
internal Commit CreateCommit(string message, Signature author, Signature committer, Tree tree, IEnumerable parents, string referenceName)
{
Ensure.ArgumentNotNull(message, "message");
Ensure.ArgumentNotNull(author, "author");
Ensure.ArgumentNotNull(committer, "committer");
Ensure.ArgumentNotNull(tree, "tree");
Ensure.ArgumentNotNull(parents, "parents");
string prettifiedMessage = Proxy.git_message_prettify(message);
IEnumerable parentIds = parents.Select(p => p.Id);
ObjectId commitId = Proxy.git_commit_create(repo.Handle, referenceName, author, committer, prettifiedMessage, tree, parentIds);
return repo.Lookup(commitId);
}
}
}