Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2sharp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornulltoken <emeric.fermas@gmail.com>2012-04-13 19:07:35 +0400
committernulltoken <emeric.fermas@gmail.com>2012-05-16 01:57:34 +0400
commit84c16528d57db4c8fc24e60262a1c89ed5e634dc (patch)
treea5ee7adf685261e4ee097eed61f6a9ea504b5fcf
parent5c5b9c7e8937b9bcf80927dedd95f35abae2b903 (diff)
Add RepositoryOptions to provide the Repository with overridden working directory and/or index
This also allows to work against a bare repository as if it was a standard one. Partially fixes #127.
-rw-r--r--LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj1
-rw-r--r--LibGit2Sharp.Tests/RepositoryOptionsFixture.cs154
-rw-r--r--LibGit2Sharp/Core/NativeMethods.cs15
-rw-r--r--LibGit2Sharp/Index.cs14
-rw-r--r--LibGit2Sharp/LibGit2Sharp.csproj1
-rw-r--r--LibGit2Sharp/Repository.cs51
-rw-r--r--LibGit2Sharp/RepositoryOptions.cs29
7 files changed, 253 insertions, 12 deletions
diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
index 08d35190..02341209 100644
--- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
+++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
@@ -49,6 +49,7 @@
<Compile Include="AttributesFixture.cs" />
<Compile Include="ObjectDatabaseFixture.cs" />
<Compile Include="DiffFixture.cs" />
+ <Compile Include="RepositoryOptionsFixture.cs" />
<Compile Include="ResetFixture.cs" />
<Compile Include="LazyFixture.cs" />
<Compile Include="RemoteFixture.cs" />
diff --git a/LibGit2Sharp.Tests/RepositoryOptionsFixture.cs b/LibGit2Sharp.Tests/RepositoryOptionsFixture.cs
new file mode 100644
index 00000000..c7938475
--- /dev/null
+++ b/LibGit2Sharp.Tests/RepositoryOptionsFixture.cs
@@ -0,0 +1,154 @@
+using System;
+using System.IO;
+using LibGit2Sharp.Tests.TestHelpers;
+using Xunit;
+
+namespace LibGit2Sharp.Tests
+{
+ public class RepositoryOptionsFixture : BaseFixture
+ {
+ private readonly string newWorkdir;
+ private readonly string newIndex;
+
+ //TODO: Add facts ensuring the correct opening of a workdir/index through relative and absolute paths
+
+ public RepositoryOptionsFixture()
+ {
+ SelfCleaningDirectory scd = BuildSelfCleaningDirectory();
+
+ newWorkdir = Path.Combine(scd.DirectoryPath, "wd");
+ Directory.CreateDirectory(newWorkdir);
+
+ newIndex = Path.Combine(scd.DirectoryPath, "my-index");
+ }
+
+ [Fact]
+ public void CanOpenABareRepoAsIfItWasAStandardOne()
+ {
+ File.Copy(Path.Combine(StandardTestRepoPath, "index"), newIndex);
+
+ var options = new RepositoryOptions { WorkingDirectoryPath = newWorkdir, IndexPath = newIndex };
+
+ using (var repo = new Repository(BareTestRepoPath, options))
+ {
+ var st = repo.Index.RetrieveStatus("1/branch_file.txt");
+ Assert.Equal(FileStatus.Missing, st);
+ }
+ }
+
+ [Fact]
+ public void CanOpenABareRepoAsIfItWasAStandardOneWithANonExisitingIndexFile()
+ {
+ var options = new RepositoryOptions { WorkingDirectoryPath = newWorkdir, IndexPath = newIndex };
+
+ using (var repo = new Repository(BareTestRepoPath, options))
+ {
+ var st = repo.Index.RetrieveStatus("1/branch_file.txt");
+ Assert.Equal(FileStatus.Removed, st);
+ }
+ }
+
+ [Fact]
+ public void CanProvideADifferentWorkDirToAStandardRepo()
+ {
+ var scd = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath);
+
+ using (var repo = new Repository(scd.DirectoryPath))
+ {
+ Assert.Equal(FileStatus.Unaltered, repo.Index.RetrieveStatus("1/branch_file.txt"));
+ }
+
+ var options = new RepositoryOptions { WorkingDirectoryPath = newWorkdir };
+
+ scd = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath);
+ using (var repo = new Repository(scd.DirectoryPath, options))
+ {
+ Assert.Equal(FileStatus.Missing, repo.Index.RetrieveStatus("1/branch_file.txt"));
+ }
+ }
+
+ [Fact]
+ public void CanProvideADifferentIndexToAStandardRepo()
+ {
+ var scd = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath);
+
+ using (var repo = new Repository(scd.DirectoryPath))
+ {
+ Assert.Equal(FileStatus.Untracked, repo.Index.RetrieveStatus("new_untracked_file.txt"));
+
+ repo.Index.Stage("new_untracked_file.txt");
+
+ Assert.Equal(FileStatus.Added, repo.Index.RetrieveStatus("new_untracked_file.txt"));
+
+ File.Copy(Path.Combine(repo.Info.Path, "index"), newIndex);
+ }
+
+ var options = new RepositoryOptions { IndexPath = newIndex };
+
+ scd = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath);
+ using (var repo = new Repository(scd.DirectoryPath, options))
+ {
+ Assert.Equal(FileStatus.Added, repo.Index.RetrieveStatus("new_untracked_file.txt"));
+ }
+ }
+
+ [Fact]
+ public void OpeningABareRepoWithoutProvidingBothWorkDirAndIndexThrows()
+ {
+ Repository repo;
+
+ Assert.Throws<ArgumentException>(() => repo = new Repository(BareTestRepoPath, new RepositoryOptions { IndexPath = newIndex }));
+ Assert.Throws<ArgumentException>(() => repo = new Repository(BareTestRepoPath, new RepositoryOptions { WorkingDirectoryPath = newWorkdir }));
+ }
+
+ [Fact]
+ public void OpeningARepoWithAnEmptyRepositoryOptionsThrows()
+ {
+ var options = new RepositoryOptions();
+ Repository repo;
+
+ Assert.Throws<ArgumentException>(() => repo = new Repository(BareTestRepoPath, options));
+ Assert.Throws<ArgumentException>(() => repo = new Repository(StandardTestRepoPath, options));
+ }
+
+ [Fact]
+ public void CanSneakAdditionalCommitsIntoAStandardRepoWithoutAlteringTheWorkdirOrTheIndex()
+ {
+ var scd = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath);
+
+ using (var repo = new Repository(scd.DirectoryPath))
+ {
+ Branch head = repo.Head;
+
+ Assert.Equal(FileStatus.Nonexistent, repo.Index.RetrieveStatus("zomg.txt"));
+
+ string commitSha = MeanwhileInAnotherDimensionAnEvilMastermindIsAtWork(scd.DirectoryPath);
+
+ Branch newHead = repo.Head;
+
+ Assert.NotEqual(head.Tip.Sha, newHead.Tip.Sha);
+ Assert.Equal(commitSha, newHead.Tip.Sha);
+
+ Assert.Equal(FileStatus.Removed, repo.Index.RetrieveStatus("zomg.txt"));
+ }
+ }
+
+ private string MeanwhileInAnotherDimensionAnEvilMastermindIsAtWork(string workingDirectoryPath)
+ {
+ var options = new RepositoryOptions { WorkingDirectoryPath = newWorkdir, IndexPath = newIndex };
+
+ using (var sneakyRepo = new Repository(workingDirectoryPath, options))
+ {
+ Assert.Equal(Path.GetFullPath(newWorkdir) + Path.DirectorySeparatorChar, Path.GetFullPath(sneakyRepo.Info.WorkingDirectory));
+
+ sneakyRepo.Reset(ResetOptions.Mixed, sneakyRepo.Head.Tip.Sha);
+
+ var filepath = Path.Combine(sneakyRepo.Info.WorkingDirectory, "zomg.txt");
+ File.WriteAllText(filepath, "I'm being sneaked in!\n");
+
+ sneakyRepo.Index.Stage(filepath);
+ return sneakyRepo.Commit("Tadaaaa!", DummySignature, DummySignature).Sha;
+ }
+ }
+ }
+}
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index 24cebf42..3f9b0660 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -307,6 +307,11 @@ namespace LibGit2Sharp.Core
public static extern IndexEntrySafeHandle git_index_get(IndexSafeHandle index, uint n);
[DllImport(libgit2)]
+ public static extern int git_index_open(
+ out IndexSafeHandle index,
+ [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))] FilePath indexpath);
+
+ [DllImport(libgit2)]
public static extern int git_index_read_tree(IndexSafeHandle index, GitObjectSafeHandle tree);
[DllImport(libgit2)]
@@ -473,6 +478,16 @@ namespace LibGit2Sharp.Core
public static extern FilePath git_repository_path(RepositorySafeHandle repository);
[DllImport(libgit2)]
+ public static extern void git_repository_set_index(
+ RepositorySafeHandle repository,
+ IndexSafeHandle index);
+
+ [DllImport(libgit2)]
+ public static extern int git_repository_set_workdir(
+ RepositorySafeHandle repository,
+ [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))] FilePath workdir);
+
+ [DllImport(libgit2)]
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))]
public static extern FilePath git_repository_workdir(RepositorySafeHandle repository);
diff --git a/LibGit2Sharp/Index.cs b/LibGit2Sharp/Index.cs
index 470ebca1..69d9fa16 100644
--- a/LibGit2Sharp/Index.cs
+++ b/LibGit2Sharp/Index.cs
@@ -23,8 +23,18 @@ namespace LibGit2Sharp
internal Index(Repository repo)
{
this.repo = repo;
- int res = NativeMethods.git_repository_index(out handle, repo.Handle);
- Ensure.Success(res);
+
+ Ensure.Success(NativeMethods.git_repository_index(out handle, repo.Handle));
+
+ repo.RegisterForCleanup(handle);
+ }
+
+ internal Index(Repository repo, string indexPath)
+ {
+ this.repo = repo;
+
+ Ensure.Success(NativeMethods.git_index_open(out handle, indexPath));
+ NativeMethods.git_repository_set_index(repo.Handle, handle);
repo.RegisterForCleanup(handle);
}
diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj
index 3372f8e6..e20b4162 100644
--- a/LibGit2Sharp/LibGit2Sharp.csproj
+++ b/LibGit2Sharp/LibGit2Sharp.csproj
@@ -133,6 +133,7 @@
<Compile Include="RepositoryInformation.cs" />
<Compile Include="RepositoryExtensions.cs" />
<Compile Include="Core\Handles\RepositorySafeHandle.cs" />
+ <Compile Include="RepositoryOptions.cs" />
<Compile Include="RepositoryStatus.cs" />
<Compile Include="ResetOptions.cs" />
<Compile Include="Signature.cs" />
diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs
index bcee8867..2bd09b94 100644
--- a/LibGit2Sharp/Repository.cs
+++ b/LibGit2Sharp/Repository.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Reflection;
using LibGit2Sharp.Core;
@@ -23,33 +24,63 @@ namespace LibGit2Sharp
private readonly TagCollection tags;
private readonly Lazy<RepositoryInformation> info;
private readonly Diff diff;
- private readonly bool isBare;
private readonly Lazy<ObjectDatabase> odb;
private readonly Stack<SafeHandleBase> handlesToCleanup = new Stack<SafeHandleBase>();
private static readonly Lazy<string> versionRetriever = new Lazy<string>(RetrieveVersion);
/// <summary>
- /// Initializes a new instance of the <see cref = "Repository" /> class.
+ /// Initializes a new instance of the <see cref = "Repository" /> class, providing ooptional behavioral overrides through <paramref name="options"/> parameter.
/// <para>For a standard repository, <paramref name = "path" /> should either point to the ".git" folder or to the working directory. For a bare repository, <paramref name = "path" /> should directly point to the repository folder.</para>
/// </summary>
/// <param name = "path">
- /// The path to the git repository to open, can be either the path to the git directory (for non-bare repositories this
+ /// The path to the git repository to open, can be either the path to the git directory (for non-bare repositories this
/// would be the ".git" folder inside the working directory) or the path to the working directory.
/// </param>
- public Repository(string path)
+ /// <param name="options">
+ /// Overrides to the way a repository is opened.
+ /// </param>
+ public Repository(string path, RepositoryOptions options = null)
{
Ensure.ArgumentNotNullOrEmptyString(path, "path");
- int res = NativeMethods.git_repository_open(out handle, path);
- Ensure.Success(res);
-
+ Ensure.Success(NativeMethods.git_repository_open(out handle, path));
RegisterForCleanup(handle);
- isBare = NativeMethods.RepositoryStateChecker(handle, NativeMethods.git_repository_is_bare);
+ bool isBare = NativeMethods.RepositoryStateChecker(handle, NativeMethods.git_repository_is_bare);
+
+ Func<Index> indexBuilder = () => new Index(this);
+
+ if (options != null)
+ {
+ bool isWorkDirNull = string.IsNullOrEmpty(options.WorkingDirectoryPath);
+ bool isIndexNull = string.IsNullOrEmpty(options.IndexPath);
+
+ if (isWorkDirNull && isIndexNull)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "At least one member of the {0} instance has to be provided.", typeof(RepositoryOptions).Name));
+ }
+
+ if (isBare && (isWorkDirNull ^ isIndexNull))
+ {
+ throw new ArgumentException("When overriding the opening of a bare repository, both RepositoryOptions.WorkingDirectoryPath an RepositoryOptions.IndexPath have to be provided.");
+ }
+
+ isBare = false;
+
+ if (!isIndexNull)
+ {
+ indexBuilder = () => new Index(this, options.IndexPath);
+ }
+
+ if (!isWorkDirNull)
+ {
+ Ensure.Success(NativeMethods.git_repository_set_workdir(handle, options.WorkingDirectoryPath));
+ }
+ }
if (!isBare)
{
- index = new Index(this);
+ index = indexBuilder();
}
commits = new CommitCollection(this);
@@ -462,7 +493,7 @@ namespace LibGit2Sharp
Assembly assembly = typeof(Repository).Assembly;
Version version = assembly.GetName().Version;
-
+
string libgit2Hash = ReadContentFromResource(assembly, "libgit2_hash.txt");
string libgit2sharpHash = ReadContentFromResource(assembly, "libgit2sharp_hash.txt");
diff --git a/LibGit2Sharp/RepositoryOptions.cs b/LibGit2Sharp/RepositoryOptions.cs
new file mode 100644
index 00000000..507288d6
--- /dev/null
+++ b/LibGit2Sharp/RepositoryOptions.cs
@@ -0,0 +1,29 @@
+namespace LibGit2Sharp
+{
+ /// <summary>
+ /// Provides optional additional information to the Repository to be opened.
+ /// </summary>
+ public class RepositoryOptions
+ {
+ /// <summary>
+ /// Overrides the probed location of the working directory of a standard repository,
+ /// or, combined with <see cref = "IndexPath" />, would
+ /// allow to work against a bare repository as it was a standard one.
+ /// <para>
+ /// The path has to lead to an existing directory.
+ /// </para>
+ /// </summary>
+ public string WorkingDirectoryPath { get; set; }
+
+ /// <summary>
+ /// Overrides the probed location of the Index file of a standard repository,
+ /// or, combined with <see cref = "WorkingDirectoryPath" />, would
+ /// allow to work against a bare repository as it was a standard one.
+ /// <para>
+ /// The path has either to lead to an existing valid Index file,
+ /// or to a non existent Index file which will be eventually created.
+ /// </para>
+ /// </summary>
+ public string IndexPath { get; set; }
+ }
+}