10000 Refactor bulk implementation of Index methods · Folcon/libgit2sharp@008ccac · GitHub
[go: up one dir, main page]

Skip to content

Commit 008ccac

Browse files
committed
Refactor bulk implementation of Index methods
1 parent 1032a14 commit 008ccac

File tree

3 files changed

+99
-122
lines changed

3 files changed

+99
-122
lines changed

LibGit2Sharp.Tests/IndexFixture.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public void CanStageTheRemovalOfAStagedFile()
167167
[Test]
168168
public void StagingANewVersionOfAFileThenUnstagingItRevertsTheBlobToTheVersionOfHead()
169169
{
170-
var path = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath);
170+
TemporaryCloneOfTestRepo path = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath);
171171
using (var repo = new Repository(path.RepositoryPath))
172172
{
173173
int count = repo.Index.Count;
@@ -284,7 +284,9 @@ public void StageFileWithBadParamsThrows()
284284
using (var repo = new Repository(StandardTestRepoPath))
285285
{
286286
Assert.Throws<ArgumentException>(() => repo.Index.Stage(string.Empty));
287-
Assert.Throws<ArgumentNullException>(() => repo.Index.Stage(null));
287+
Assert.Throws<ArgumentNullException>(() => repo.Index.Stage((string)null));
288+
Assert.Throws<ArgumentNullException>(() => repo.Index.Stage(new string[] { }));
289+
Assert.Throws<ArgumentNullException>(() => repo.Index.Stage(new string[] { null }));
288290
}
289291
}
290292

@@ -339,7 +341,9 @@ public void UnstagingFileWithBadParamsThrows()
339341
using (var repo = new Repository(StandardTestRepoPath))
340342
{
341343
Assert.Throws<ArgumentException>(() => repo.Index.Unstage(string.Empty));
342-
Assert.Throws<ArgumentNullException>(() => repo.Index.Unstage(null));
344+
Assert.Throws<ArgumentNullException>(() => repo.Index.Unstage((string)null));
345+
Assert.Throws<ArgumentNullException>(() => repo.Index.Unstage(new string[] { }));
346+
Assert.Throws<ArgumentNullException>(() => repo.Index.Unstage(new string[] { null }));
343347
}
344348
}
345349

@@ -417,12 +421,14 @@ public void CanRemoveAFile()
417421
}
418422
}
419423

420-
[Test]
421-
public void RemovingANonStagedFileThrows()
424+
[TestCase("deleted_staged_file.txt")]
425+
[TestCase("deleted_unstaged_file.txt")]
426+
[TestCase("shadowcopy_of_an_unseen_ghost.txt")]
427+
public void RemovingAInvalidFileThrows(string filepath)
422428
{
423429
using (var repo = new Repository(StandardTestRepoPath))
424430
{
425-
Assert.Throws<LibGit2Exception>(() => repo.Index.Remove("shadowcopy_of_an_unseen_ghost.txt"));
431+
Assert.Throws<LibGit2Exception>(() => repo.Index.Remove(filepath));
426432
}
427433
}
428434

@@ -472,7 +478,7 @@ public void CanRetrieveTheStatusOfTheWholeWorkingDirectory()
472478
status2.IsDirty.ShouldBeTrue();
473479

474480
status2.Untracked.Single().ShouldEqual("new_untracked_file.txt");
475-
CollectionAssert.AreEqual(new[] {file, "modified_unstaged_file.txt"}, status2.Modified);
481+
CollectionAssert.AreEqual(new[] { file, "modified_unstaged_file.txt" }, status2.Modified);
476482
status2.Missing.Single().ShouldEqual("deleted_unstaged_file.txt");
477483
status2.Added.Single().ShouldEqual("new_tracked_file.txt");
478484
status2.Staged.Single().ShouldEqual(file);

LibGit2Sharp/Core/EnumExtensions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
24

35
namespace LibGit2Sharp.Core
46
{
@@ -8,5 +10,10 @@ public static bool Has<T>(this Enum enumInstance, T entry)
810
{
911
return ((int)(object)enumInstance & (int)(object)entry) == (int)(object)(entry);
1012
}
13+
14+
public static bool HasAny<T>(this Enum enumInstance, IEnumerable<T> entries)
15+
{
16+
return entries.Any(enumInstance.Has);
17+
}
1118
}
1219
}

LibGit2Sharp/Index.cs

Lines changed: 79 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Globalization;
55
using System.IO;
66
using LibGit2Sharp.Core;
7+
using LibGit2Sharp.Core.Compat;
78

89
namespace LibGit2Sharp
910
{
@@ -118,36 +119,16 @@ IEnumerator IEnumerable.GetEnumerator()
118119
/// <summary>
119120
/// Promotes to the staging area the latest modifications of a file in the working directory (addition, updation or removal).
120121
/// </summary>
121-
/// <param name="path">The relative path within the working directory to the file.</param>
122+
/// <param name = "path">The path of the file within the working directory.</param>
122123
public void Stage(string path)
123124
{
124-
Ensure.ArgumentNotNullOrEmptyString(path, "path");
125-
126-
string relativePath = BuildRelativePathFrom(repo, path);
127-
128-
FileStatus fileStatus = RetrieveStatus(relativePath);
129-
130-
if (fileStatus.Has(FileStatus.Nonexistent))
131-
{
132-
throw new LibGit2Exception("Can not stage '{0}'. The file does not exist.");
133-
}
134-
135-
if (fileStatus.Has(FileStatus.Missing))
136-
{
137-
RemoveFromIndex(relativePath);
138-
}
139-
else
140-
{
141-
AddToIndex(relativePath);
142-
}
143-
144-
UpdatePhysicalIndex();
125+
Stage(new[] { path });
145126
}
146127

147128
/// <summary>
148129
/// Promotes to the staging area the latest modifications of a collection of files in the working directory (addition, updation or removal).
149130
/// </summary>
150-
/// <param name="paths">The collection of paths within the working directory to the files.</param>
131+
/// <param name = "paths">The collection of paths of the files within the working directory.</param>
151132
public void Stage(IEnumerable<string> paths)
152133
{
153134
Ensure.ArgumentNotNull(paths, "paths");
@@ -190,36 +171,16 @@ public void Stage(IEnumerable<string> paths)
190171
/// <summary>
191172
/// Removes from the staging area all the modifications of a file since the latest commit (addition, updation or removal).
192173
/// </summary>
193-
/// <param name="path">The relative path within the working directory to the file.</param>
174+
/// <param name = "path">The path of the file within the working directory.</param>
194175
public void Unstage(string path)
195176
{
196-
Ensure.ArgumentNotNullOrEmptyString(path, "path");
197-
198-
string relativePath = BuildRelativePathFrom(repo, path);
199-
200-
FileStatus fileStatus = RetrieveStatus(relativePath);
201-
202-
bool doesExistInindex =
203-
!(fileStatus.Has(FileStatus.Nonexistent) || fileStatus.Has(FileStatus.Removed) ||
204-
fileStatus.Has(FileStatus.Untracked));
205-
206-
if (doesExistInindex)
207-
{
208-
RemoveFromIndex(relativePath);
209-
}
210-
211-
bool doesExistInWorkingDirectory =
212-
!(fileStatus.Has(FileStatus.Removed) || fileStatus.Has(FileStatus.Nonexistent) ||
213-
fileStatus.Has(FileStatus.Missing));
214-
RestorePotentialPreviousVersionOfHeadIntoIndex(relativePath, doesExistInWorkingDirectory);
215-
216-
UpdatePhysicalIndex();
177+
Unstage(new[] { path });
217178
}
218179

219180
/// <summary>
220181
/// Removes from the staging area all the modifications of a collection of file since the latest commit (addition, updation or removal).
221182
/// </summary>
222-
/// <param name="paths">The collection of paths within the working directory to the files.</param>
183+
/// <param name = "paths">The collection of paths of the files within the working directory.</param>
223184
public void Unstage(IEnumerable<string> paths)
224185
{
225186
Ensure.ArgumentNotNull(paths, "paths");
@@ -254,75 +215,54 @@ public void Unstage(IEnumerable<string> paths)
254215
/// <summary>
255216
/// Moves and/or renames a file in the working directory and promotes the change to the staging area.
256217
/// </summary>
257-
/// <param name="sourcePath">The relative path within the working directory to the file which has to be moved/renamed.</param>
258-
/// <param name="destinationPath">The target relative path within the working directory of the file.</param>
218+
/// <param name = "sourcePath">The path of the file within the working directory which has to be moved/renamed.</param>
219+
/// <param name = "destinationPath">The target path of the file within the working directory.</param>
259220
public void Move(string sourcePath, string destinationPath)
260221
{
261-
Ensure.ArgumentNotNullOrEmptyString(sourcePath, "sourcepath");
262-
Ensure.ArgumentNotNullOrEmptyString(destinationPath, "destinationpath");
263-
264-
string relativeSourcePath = BuildRelativePathFrom(repo, sourcePath);
265-
string relativeDestinationPath = BuildRelativePathFrom(repo, destinationPath);
266-
267-
string wd = repo.Info.WorkingDirectory;
268-
if (Directory.Exists(Path.Combine(wd, relativeSourcePath)))
269-
{
270-
throw new NotImplementedException();
271-
}
272-
273-
RemoveFromIndex(relativeSourcePath);
274-
275-
File.Move(Path.Combine(wd, relativeSourcePath), Path.Combine(wd, relativeDestinationPath));
276-
277-
AddToIndex(relativeDestinationPath);
278-
279-
UpdatePhysicalIndex();
222+
Move(new[] { sourcePath }, new[] { destinationPath });
280223
}
281224

282225
/// <summary>
283-
/// Moves and/or renames a file in the working directory and promotes the change to the staging area.
226+
/// Moves and/or renames a collection of files in the working directory and promotes the changes to the staging area.
284227
/// </summary>
285-
/// <param name="sourcePaths">The relative paths within the working directory to the files which has to be moved/renamed.</param>
286-
/// <param name="destinationPaths">The target relative paths within the working directory of the files.</param>
228+
/// <param name = "sourcePaths">The paths of the files within the working directory which have to be moved/renamed.</param>
229+
/// <param name = "destinationPaths">The target paths of the files within the working directory.</param>
287230
public void Move(IEnumerable<string> sourcePaths, IEnumerable<string> destinationPaths)
288231
{
289232
Ensure.ArgumentNotNull(sourcePaths, "sourcePaths");
290233
Ensure.ArgumentNotNull(destinationPaths, "destinationPaths");
291234

292-
List<string> sourcePathsList = new List<string>();
293-
List<string> destinationPathsList = new List<string>();
235+
IDictionary<Tuple<string, FileStatus>, Tuple<string, FileStatus>> batch = PrepareBatch(sourcePaths, destinationPaths);
294236

295-
foreach (string sourcePath in sourcePaths)
296-
{
297-
sourcePathsList.Add(BuildRelativePathFrom(repo, sourcePath));
298-
}
299-
foreach (string destinationPath in destinationPaths)
237+
if (batch.Count == 0)
300238
{
301-
destinationPathsList.Add(BuildRelativePathFrom(repo, destinationPath));
239+
throw new ArgumentNullException("sourcePaths");
302240
}
303241

304-
if (sourcePathsList.Count != destinationPathsList.Count)
242+
foreach (KeyValuePair<Tuple<string, FileStatus>, Tuple<string, FileStatus>> keyValuePair in batch)
305243
{
306-
throw new ArgumentException("The collection of paths are of different lengths");
307-
}
308-
309-
string wd = repo.Info.WorkingDirectory;
244+
if (keyValuePair.Key.Item2.HasAny(new[] { FileStatus.Nonexistent, FileStatus.Removed, FileStatus.Untracked, FileStatus.Missing }))
245+
{
246+
throw new LibGit2Exception(string.Format("Unable to move file '{0}'. Its current status is '{1}'.", keyValuePair.Key.Item1, Enum.GetName(typeof(FileStatus), keyValuePair.Key.Item2)));
247+
}
310248

311-
foreach (string relativeSourcePath in sourcePathsList)
312-
{
313-
if (Directory.Exists(Path.Combine(wd, relativeSourcePath)))
249+
if (keyValuePair.Value.Item2.Has(FileStatus.Nonexistent))
314250
{
315-
throw new NotImplementedException();
251+
continue;
316252
}
253+
254+
throw new LibGit2Exception(string.Format("Unable to overwrite file '{0}'. Its current status is '{1}'.", keyValuePair.Value.Item1, Enum.GetName(typeof(FileStatus), keyValuePair.Value.Item2)));
317255
}
318256

319-
for (int i = 0; i < sourcePathsList.Count; i++)
257+
string wd = repo.Info.WorkingDirectory;
258+
foreach (KeyValuePair<Tuple<string, FileStatus>, Tuple<string, FileStatus>> keyValuePair in batch)
320259
{
321-
RemoveFromIndex(sourcePathsList[i]);
260+
string from = keyValuePair.Key.Item1;
261+
string to = keyValuePair.Value.Item1;
322262

323-
File.Move(Path.Combine(wd, sourcePathsList[i]), Path.Combine(wd, destinationPathsList[i]));
324-
325-
AddToIndex(destinationPathsList[i]);
263+
RemoveFromIndex(from);
264+
File.Move(Path.Combine(wd, from), Path.Combine(wd, to));
265+
AddToIndex(to);
326266
}
327267

328268
UpdatePhysicalIndex();
@@ -331,30 +271,16 @@ public void Move(IEnumerable<string> sourcePaths, IEnumerable<string> destinatio
331271
/// <summary>
332272
/// Removes a file from the working directory and promotes the removal to the staging area.
333273
/// </summary>
334-
/// <param name="path">The relative path within the working directory to the file.</param>
274+
/// <param name = "path">The path of the file within the working directory.</param>
335275
public void Remove(string path)
336276
{
337-
Ensure.ArgumentNotNullOrEmptyString(path, "path");
338-
339-
string relativePath = BuildRelativePathFrom(repo, path);
340-
341-
string wd = repo.Info.WorkingDirectory;
342-
if (Directory.Exists(Path.Combine(wd, relativePath)))
343-
{
344-
throw new NotImplementedException();
345-
}
346-
347-
RemoveFromIndex(relativePath);
348-
349-
File.Delete(Path.Combine(wd, relativePath));
350-
351-
UpdatePhysicalIndex();
277+
Remove(new[] { path });
352278
}
353279

354280
/// <summary>
355281
/// Removes a collection of files from the working directory and promotes the removal to the staging area.
356282
/// </summary>
357-
/// <param name="paths">The relative paths within the working directory to the files.</param>
283+
/// <param name = "paths">The collection of paths of the files within the working directory.</param>
358284
public void Remove(IEnumerable<string> paths)
359285
{
360286
Ensure.ArgumentNotNull(paths, "paths");
@@ -366,15 +292,17 @@ public void Remove(IEnumerable<string> paths)
366292
throw new ArgumentNullException("paths");
367293
}
368294

369-
string wd = repo.Info.WorkingDirectory;
370295
foreach (KeyValuePair<string, FileStatus> keyValuePair in batch)
371296
{
372-
if (Directory.Exists(Path.Combine(wd, keyValuePair.Key)))
297+
if (!keyValuePair.Value.HasAny(new[] { FileStatus.Missing, FileStatus.Nonexistent, FileStatus.Removed, FileStatus.Untracked }))
373298
{
374-
throw new NotImplementedException();
299+
continue;
375300
}
301+
302+
throw new LibGit2Exception(string.Format("Unable to remove file '{0}'. Its current status is '{1}'.", keyValuePair.Key, Enum.GetName(typeof(FileStatus), keyValuePair.Value)));
376303
}
377304

305+
string wd = repo.Info.WorkingDirectory;
378306
foreach (KeyValuePair<string, FileStatus> keyValuePair in batch)
379307
{
380308
RemoveFromIndex(keyValuePair.Key);
@@ -399,6 +327,42 @@ private IDictionary<string, FileStatus> PrepareBatch(IEnumerable<string> paths)
399327
return dic;
400328
}
401329

330+
private IDictionary<Tuple<string, FileStatus>, Tuple<string, FileStatus>> PrepareBatch(IEnumerable<string> leftPaths, IEnumerable<string> rightPaths)
331+
{
332+
IDictionary<Tuple<string, FileStatus>, Tuple<string, FileStatus>> dic = new Dictionary<Tuple<string, FileStatus>, Tuple<string, FileStatus>>();
333+
334+
IEnumerator<string> leftEnum = leftPaths.GetEnumerator();
335+
IEnumerator<string> rightEnum = rightPaths.GetEnumerator();
336+
337+
while (Enumerate(leftEnum, rightEnum))
338+
{
339+
Tuple<string, FileStatus> from = BuildFrom(leftEnum.Current);
340+
Tuple<string, FileStatus> to = BuildFrom(rightEnum.Current);
341+
dic.Add(from, to);
342+
}
343+
344+
return dic;
345+
}
346+
347+
private Tuple<string, FileStatus> BuildFrom(string path)
348+
{
349+
string relativePath = BuildRelativePathFrom(repo, path);
350+
return new Tuple<string, FileStatus>(relativePath, RetrieveStatus(relativePath));
351+
}
352+
353+
private bool Enumerate(IEnumerator<string> leftEnum, IEnumerator<string> rightEnum)
354+
{
355+
bool isLeftEoF = leftEnum.MoveNext();
356+
bool isRightEoF = rightEnum.MoveNext();
357+
358+
if (isLeftEoF == isRightEoF)
359+
{
360+
return isLeftEoF;
361+
}
362+
363+
throw new ArgumentException("The collection of paths are of different lengths.");
364+
}
365+
402366
private void AddToIndex(string relativePath)
403367
{
404368
relativePath = PosixPathHelper.ToPosix(relativePath);
@@ -477,8 +441,8 @@ private static string BuildRelativePathFrom(Repository repo, string path)
477441
/// <summary>
478442
/// Retrieves the state of a file in the working directory, comparing it against the staging area and the latest commmit.
479443
/// </summary>
480-
/// <param name="filePath">The relative path within the working directory to the file.</param>
481-
/// <returns>A <see cref="FileStatus" /> representing the state of the <paramref name="filePath"/> parameter.</returns>
444+
/// <param name = "filePath">The relative path within the working directory to the file.</param>
445+
/// <returns>A <see cref = "FileStatus" /> representing the state of the <paramref name = "filePath" /> parameter.</returns>
482446
public FileStatus RetrieveStatus(string filePath)
483447
{
484448
Ensure.ArgumentNotNullOrEmptyString(filePath, "filePath");
@@ -501,7 +465,7 @@ public FileStatus RetrieveStatus(string filePath)
501465
/// <summary>
502466
/// Retrieves the state of all files in the working directory, comparing them against the staging area and the latest commmit.
503467
/// </summary>
504-
/// <returns>A <see cref="RepositoryStatus" /> holding the state of all the files.</returns>
468+
/// <returns>A <see cref = "RepositoryStatus" /> holding the state of all the files.</returns>
505469
public RepositoryStatus RetrieveStatus()
506470
{
507471
return new RepositoryStatus(repo);

0 commit comments

Comments
 (0)
0