Skip to content

Commit 7558ded

Browse files
committed
Bring over existing add work
Credit to libgit2#1501 / JasonGoemaat
1 parent 70d62d5 commit 7558ded

4 files changed

Lines changed: 135 additions & 0 deletions

File tree

LibGit2Sharp.Tests/SubmoduleFixture.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,70 @@ public void CanEnumerateRepositorySubmodules()
132132
}
133133
}
134134

135+
[Fact]
136+
public void CanAddSubmodule()
137+
{
138+
var path = SandboxStandardTestRepo();
139+
var pathSubRepoOrigin = SandboxStandardTestRepo();
140+
141+
string submoduleSubPath = "submodule_target_wd";
142+
string expectedSubmodulePath = Path.GetFullPath(Path.Combine(path, submoduleSubPath));
143+
string expectedSubmoduleUrl = pathSubRepoOrigin.Replace('\\', '/');
144+
ObjectId expectedCommitId = (ObjectId)"32eab9cb1f450b5fe7ab663462b77d7f4b703344";
145+
146+
using (var repo = new Repository(path))
147+
{
148+
// setup config with dummy user so we can commit
149+
CreateConfigurationWithDummyUser(repo, Constants.Identity);
150+
151+
// check on adding config entry
152+
var configEntryBeforeAdd = repo.Config.Get<string>(string.Format("submodule.{0}.url", submoduleSubPath));
153+
Assert.Null(configEntryBeforeAdd);
154+
155+
// first step is cloning the repository to where it goes
156+
Repository.Clone(pathSubRepoOrigin, expectedSubmodulePath);
157+
158+
// add submodule
159+
repo.Submodules.Add(pathSubRepoOrigin, submoduleSubPath, 1);
160+
Submodule submodule = repo.Submodules[submoduleSubPath];
161+
Assert.NotNull(submodule);
162+
163+
// check that the expected commit is checked out, but not set in parent repo until committed
164+
Assert.Equal(expectedCommitId, repo.Submodules[submoduleSubPath].WorkDirCommitId);
165+
Assert.Null(repo.Submodules[submoduleSubPath].HeadCommitId);
166+
167+
// check status
168+
var submoduleStatus = submodule.RetrieveStatus();
169+
Assert.True((submoduleStatus & SubmoduleStatus.InIndex) == SubmoduleStatus.InIndex);
170+
Assert.True((submoduleStatus & SubmoduleStatus.InConfig) == SubmoduleStatus.InConfig);
171+
Assert.True((submoduleStatus & SubmoduleStatus.InWorkDir) == SubmoduleStatus.InWorkDir);
172+
Assert.True((submoduleStatus & SubmoduleStatus.IndexAdded) == SubmoduleStatus.IndexAdded);
173+
174+
// check that config entry was added with the correct url
175+
var configEntryAfterAdd = repo.Config.Get<string>(string.Format("submodule.{0}.url", submoduleSubPath));
176+
Assert.NotNull(configEntryAfterAdd);
177+
Assert.Equal(expectedSubmoduleUrl, configEntryAfterAdd.Value);
178+
179+
// check on directory being added and repository directory
180+
Assert.True(Directory.Exists(expectedSubmodulePath));
181+
Assert.True(Directory.Exists(Path.Combine(expectedSubmodulePath, ".git")));
182+
183+
// manually check commit by opening submodule as a repository
184+
using (var repo2 = new Repository(expectedSubmodulePath))
185+
{
186+
Assert.False(repo2.Info.IsHeadDetached);
187+
Assert.False(repo2.Info.IsHeadUnborn);
188+
Commit headCommit = repo2.Head.Tip;
189+
Assert.Equal(headCommit.Id, expectedCommitId);
190+
}
191+
192+
// commit parent repository, then verify it reports the correct CommitId for the submodule
193+
Signature signature = repo.Config.BuildSignature(DateTimeOffset.Now);
194+
repo.Commit("Added submodule " + submoduleSubPath, signature, signature);
195+
Assert.Equal(expectedCommitId, repo.Submodules[submoduleSubPath].HeadCommitId);
196+
}
197+
}
198+
135199
[Theory]
136200
[InlineData("sm_changed_head")]
137201
[InlineData("sm_changed_head/")]
@@ -322,6 +386,8 @@ public void CanReadSubmoduleProperties()
322386

323387
using (var repo = new Repository(path))
324388
{
389+
CreateConfigurationWithDummyUser(repo, Constants.Identity);
390+
325391
var submodule = repo.Submodules[submoduleName];
326392

327393
Assert.Equal(SubmoduleUpdate.Checkout, submodule.UpdateRule);

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,6 +1790,31 @@ internal static extern unsafe void git_status_list_free(
17901790
internal static extern void git_strarray_free(
17911791
ref GitStrArray array);
17921792

1793+
/// <summary>
1794+
/// To fully emulate "git submodule add", call this function, then open
1795+
/// the submodule repo and perform the clone step as needed. Lastly, call
1796+
/// 'git_submodule_add_finalize()' to wrap up adding the new submodule and
1797+
/// .gitmodules to the index to be ready to commit.
1798+
///
1799+
/// In our case, go ahead and do the clone first. The setup can be done
1800+
/// with the directory contents already in place.
1801+
/// </summary>
1802+
[DllImport(libgit2)]
1803+
internal static extern unsafe int git_submodule_add_setup(
1804+
out git_submodule* reference,
1805+
git_repository* repo,
1806+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string url,
1807+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string path,
1808+
int use_gitlink);
1809+
1810+
[DllImport(libgit2)]
1811+
internal static extern unsafe int git_submodule_add_finalize(
1812+
git_submodule* submodule);
1813+
1814+
[DllImport(libgit2)]
1815+
internal static extern unsafe string git_submodule_name(
1816+
git_submodule* submodule);
1817+
17931818
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
17941819
internal static extern unsafe int git_submodule_lookup(
17951820
out git_submodule* reference,

LibGit2Sharp/Core/Proxy.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2964,6 +2964,34 @@ public static unsafe int git_status_list_entrycount(StatusListHandle list)
29642964

29652965
#region git_submodule_
29662966

2967+
/// <summary>
2968+
/// This does "git submodule add" up to the fetch and checkout of the
2969+
/// submodule contents. It preps a new submodule, creates an entry in
2970+
/// .gitmodules and creates an empty initialized repository either at the
2971+
/// given path in the working directory or in .git/modules with a gitlink
2972+
/// from the working directory to the new repo.
2973+
/// </summary>s
2974+
public static unsafe SubmoduleHandle git_submodule_add_setup(RepositoryHandle repo, string url, string path, int useGitLink)
2975+
{
2976+
git_submodule* submodule;
2977+
var res = NativeMethods.git_submodule_add_setup(out submodule, repo, url, path, useGitLink);
2978+
Ensure.ZeroResult(res);
2979+
return new SubmoduleHandle(submodule, true);
2980+
}
2981+
2982+
public static unsafe void git_submodule_add_finalize(SubmoduleHandle submodule)
2983+
{
2984+
var res = NativeMethods.git_submodule_add_finalize(submodule);
2985+
Ensure.ZeroResult(res);
2986+
}
2987+
2988+
public static unsafe string git_submodule_name(SubmoduleHandle submodule)
2989+
{
2990+
return NativeMethods.git_submodule_name(submodule);
2991+
}
2992+
2993+
2994+
29672995
/// <summary>
29682996
/// Returns a handle to the corresponding submodule,
29692997
/// or an invalid handle if a submodule is not found.

LibGit2Sharp/SubmoduleCollection.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,22 @@ public virtual Submodule this[string name]
4747
}
4848
}
4949

50+
/// <summary>
51+
/// Add a new submodule from the given url to the given path. The
52+
/// repository should have already been cloned into the destination
53+
/// path. After this call the submodule and updated .gitmodules
54+
/// file will be added to the index.
55+
/// </summary>
56+
/// <param name="url">Url to use for the submodule</param>
57+
/// <param name="path">Path of the submodule</param>
58+
/// <param name="useGitLink">Non-zero to use git link</param>
59+
public virtual void Add(string url, string path, int useGitLink)
60+
{
61+
var handle = Proxy.git_submodule_add_setup(repo.Handle, url, path, useGitLink);
62+
Proxy.git_submodule_add_finalize(handle);
63+
handle.Free();
64+
}
65+
5066
/// <summary>
5167
/// Initialize specified submodule.
5268
/// <para>

0 commit comments

Comments
 (0)