public void CanCancelRecursiveClone() { var uri = new Uri($"file://{Path.GetFullPath(SandboxSubmoduleSmallTestRepo())}"); var scd = BuildSelfCleaningDirectory(); string relativeSubmodulePath = "submodule_target_wd"; int cancelDepth = 0; RepositoryOperationStarting repositoryOperationStarting = (x) => { return(!(x.RecursionDepth >= cancelDepth)); }; CloneOptions options = new CloneOptions() { RecurseSubmodules = true, RepositoryOperationStarting = repositoryOperationStarting, }; Assert.Throws <UserCancelledException>(() => Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options)); // Cancel after super repository is cloned, but before submodule is cloned. cancelDepth = 1; string clonedRepoPath = null; try { Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options); } catch (RecurseSubmodulesException ex) { Assert.NotNull(ex.InnerException); Assert.Equal(typeof(UserCancelledException), ex.InnerException.GetType()); clonedRepoPath = ex.InitialRepositoryPath; } // Verify that the submodule was not initialized. using (Repository repo = new Repository(clonedRepoPath)) { var submoduleStatus = repo.Submodules[relativeSubmodulePath].RetrieveStatus(); Assert.Equal(SubmoduleStatus.InConfig | SubmoduleStatus.InHead | SubmoduleStatus.InIndex | SubmoduleStatus.WorkDirUninitialized, submoduleStatus); } }
public void CanRecursivelyCloneSubmodules() { var uri = new Uri($"file://{Path.GetFullPath(SandboxSubmoduleSmallTestRepo())}"); var scd = BuildSelfCleaningDirectory(); string relativeSubmodulePath = "submodule_target_wd"; // Construct the expected URL the submodule will clone from. string expectedSubmoduleUrl = Path.Combine(Path.GetDirectoryName(uri.AbsolutePath), relativeSubmodulePath); expectedSubmoduleUrl = expectedSubmoduleUrl.Replace('\\', '/'); Dictionary <string, CloneCallbackInfo> callbacks = new Dictionary <string, CloneCallbackInfo>(); CloneCallbackInfo currentEntry = null; bool unexpectedOrderOfCallbacks = false; CheckoutProgressHandler checkoutProgressHandler = (x, y, z) => { if (currentEntry != null) { currentEntry.CheckoutProgressCalled = true; } else { // Should not be called if there is not a current // callbackInfo entry. unexpectedOrderOfCallbacks = true; } }; UpdateTipsHandler remoteRefUpdated = (x, y, z) => { if (currentEntry != null) { currentEntry.RemoteRefUpdateCalled = true; } else { // Should not be called if there is not a current // callbackInfo entry. unexpectedOrderOfCallbacks = true; } return(true); }; RepositoryOperationStarting repositoryOperationStarting = (x) => { if (currentEntry != null) { // Should not be called if there is a current // callbackInfo entry. unexpectedOrderOfCallbacks = true; } currentEntry = new CloneCallbackInfo(); currentEntry.StartingWorkInRepositoryCalled = true; currentEntry.RecursionDepth = x.RecursionDepth; currentEntry.RemoteUrl = x.RemoteUrl; callbacks.Add(x.RepositoryPath, currentEntry); return(true); }; RepositoryOperationCompleted repositoryOperationCompleted = (x) => { if (currentEntry != null) { currentEntry.FinishedWorkInRepositoryCalled = true; currentEntry = null; } else { // Should not be called if there is not a current // callbackInfo entry. unexpectedOrderOfCallbacks = true; } }; CloneOptions options = new CloneOptions() { RecurseSubmodules = true, OnCheckoutProgress = checkoutProgressHandler, OnUpdateTips = remoteRefUpdated, RepositoryOperationStarting = repositoryOperationStarting, RepositoryOperationCompleted = repositoryOperationCompleted, }; string clonedRepoPath = Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options); string workDirPath; using (Repository repo = new Repository(clonedRepoPath)) { workDirPath = repo.Info.WorkingDirectory.TrimEnd(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); } // Verification: // Verify that no callbacks were called in an unexpected order. Assert.False(unexpectedOrderOfCallbacks); Dictionary <string, CloneCallbackInfo> expectedCallbackInfo = new Dictionary <string, CloneCallbackInfo>(); expectedCallbackInfo.Add(workDirPath, new CloneCallbackInfo() { RecursionDepth = 0, RemoteUrl = uri.AbsolutePath, StartingWorkInRepositoryCalled = true, FinishedWorkInRepositoryCalled = true, CheckoutProgressCalled = true, RemoteRefUpdateCalled = true, }); expectedCallbackInfo.Add(Path.Combine(workDirPath, relativeSubmodulePath), new CloneCallbackInfo() { RecursionDepth = 1, RemoteUrl = expectedSubmoduleUrl, StartingWorkInRepositoryCalled = true, FinishedWorkInRepositoryCalled = true, CheckoutProgressCalled = true, RemoteRefUpdateCalled = true, }); // Callbacks for each expected repository that is cloned foreach (KeyValuePair <string, CloneCallbackInfo> kvp in expectedCallbackInfo) { CloneCallbackInfo entry = null; Assert.True(callbacks.TryGetValue(kvp.Key, out entry), string.Format("{0} was not found in callbacks.", kvp.Key)); Assert.Equal(kvp.Value.RemoteUrl, entry.RemoteUrl); Assert.Equal(kvp.Value.RecursionDepth, entry.RecursionDepth); Assert.Equal(kvp.Value.StartingWorkInRepositoryCalled, entry.StartingWorkInRepositoryCalled); Assert.Equal(kvp.Value.FinishedWorkInRepositoryCalled, entry.FinishedWorkInRepositoryCalled); Assert.Equal(kvp.Value.CheckoutProgressCalled, entry.CheckoutProgressCalled); Assert.Equal(kvp.Value.RemoteRefUpdateCalled, entry.RemoteRefUpdateCalled); } // Verify the state of the submodule using (Repository repo = new Repository(clonedRepoPath)) { var sm = repo.Submodules[relativeSubmodulePath]; Assert.True(sm.RetrieveStatus().HasFlag(SubmoduleStatus.InWorkDir | SubmoduleStatus.InConfig | SubmoduleStatus.InIndex | SubmoduleStatus.InHead)); Assert.NotNull(sm.HeadCommitId); Assert.Equal("480095882d281ed676fe5b863569520e54a7d5c0", sm.HeadCommitId.Sha); Assert.False(repo.RetrieveStatus().IsDirty); } }