/// <summary> /// Fetch from the <see cref = "Remote" />. /// </summary> /// <param name="remote">The remote to fetch</param> /// <param name="tagFetchMode">Optional parameter indicating what tags to download.</param> /// <param name="onProgress">Progress callback. Corresponds to libgit2 progress callback.</param> /// <param name="onCompletion">Completion callback. Corresponds to libgit2 completion callback.</param> /// <param name="onUpdateTips">UpdateTips callback. Corresponds to libgit2 update_tips callback.</param> /// <param name="onTransferProgress">Callback method that transfer progress will be reported through. /// Reports the client's state regarding the received and processed (bytes, objects) from the server.</param> /// <param name="credentials">Credentials to use for username/password authentication.</param> public virtual void Fetch( Remote remote, TagFetchMode tagFetchMode = TagFetchMode.Auto, ProgressHandler onProgress = null, CompletionHandler onCompletion = null, UpdateTipsHandler onUpdateTips = null, TransferProgressHandler onTransferProgress = null, Credentials credentials = null) { Ensure.ArgumentNotNull(remote, "remote"); // We need to keep a reference to the git_cred_acquire_cb callback around // so it will not be garbage collected before we are done with it. // Note that we also have a GC.KeepAlive call at the end of the method. NativeMethods.git_cred_acquire_cb credentialCallback = null; using (RemoteSafeHandle remoteHandle = Proxy.git_remote_load(repository.Handle, remote.Name, true)) { var callbacks = new RemoteCallbacks(onProgress, onCompletion, onUpdateTips); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); Proxy.git_remote_set_autotag(remoteHandle, tagFetchMode); if (credentials != null) { credentialCallback = (out IntPtr cred, IntPtr url, IntPtr username_from_url, uint types, IntPtr payload) => NativeMethods.git_cred_userpass_plaintext_new(out cred, credentials.Username, credentials.Password); Proxy.git_remote_set_cred_acquire_cb( remoteHandle, credentialCallback, IntPtr.Zero); } // It is OK to pass the reference to the GitCallbacks directly here because libgit2 makes a copy of // the data in the git_remote_callbacks structure. If, in the future, libgit2 changes its implementation // to store a reference to the git_remote_callbacks structure this would introduce a subtle bug // where the managed layer could move the git_remote_callbacks to a different location in memory, // but libgit2 would still reference the old address. // // Also, if GitRemoteCallbacks were a class instead of a struct, we would need to guard against // GC occuring in between setting the remote callbacks and actual usage in one of the functions afterwords. Proxy.git_remote_set_callbacks(remoteHandle, ref gitCallbacks); try { Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch); Proxy.git_remote_download(remoteHandle, onTransferProgress); Proxy.git_remote_update_tips(remoteHandle); } finally { Proxy.git_remote_disconnect(remoteHandle); } } // To be safe, make sure the credential callback is kept until // alive until at least this point. GC.KeepAlive(credentialCallback); }
internal RemoteCallbacks(FetchOptions fetchOptions) { Ensure.ArgumentNotNull(fetchOptions, "fetchOptions"); Progress = fetchOptions.OnProgress; DownloadTransferProgress = fetchOptions.OnTransferProgress; UpdateTips = fetchOptions.OnUpdateTips; Credentials = fetchOptions.Credentials; }
internal RemoteCallbacks( ProgressHandler onProgress = null, TransferProgressHandler onDownloadProgress = null, UpdateTipsHandler onUpdateTips = null, CredentialsHandler credentialsProvider = null) { Progress = onProgress; DownloadTransferProgress = onDownloadProgress; UpdateTips = onUpdateTips; CredentialsProvider = credentialsProvider; }
internal RemoteCallbacks( ProgressHandler onProgress = null, TransferProgressHandler onDownloadProgress = null, UpdateTipsHandler onUpdateTips = null, Credentials credentials = null) { Progress = onProgress; DownloadTransferProgress = onDownloadProgress; UpdateTips = onUpdateTips; Credentials = credentials; }
internal RemoteCallbacks( ProgressHandler onProgress = null, TransferProgressHandler onDownloadProgress = null, UpdateTipsHandler onUpdateTips = null, ICredentialsProvider credentialsProvider = null) { Progress = onProgress; DownloadTransferProgress = onDownloadProgress; UpdateTips = onUpdateTips; CredentialsProvider = credentialsProvider.GetCredentialsHandler(); }
/// <summary> /// Handler for libgit2 update_tips callback. Converts values /// received from libgit2 callback to more suitable types /// and calls delegate provided by LibGit2Sharp consumer. /// </summary> /// <param name="str">IntPtr to string</param> /// <param name="oldId">Old reference ID</param> /// <param name="newId">New referene ID</param> /// <param name="data">IntPtr to optional payload passed back to the callback.</param> /// <returns>0 on success; a negative value to abort the process.</returns> private int GitUpdateTipsHandler(IntPtr str, ref GitOid oldId, ref GitOid newId, IntPtr data) { UpdateTipsHandler onUpdateTips = UpdateTips; bool shouldContinue = true; if (onUpdateTips != null) { string refName = LaxUtf8Marshaler.FromNative(str); shouldContinue = onUpdateTips(refName, oldId, newId); } return(Proxy.ConvertResultToCancelFlag(shouldContinue)); }
/// <summary> /// Handler for libgit2 update_tips callback. Converts values /// received from libgit2 callback to more suitable types /// and calls delegate provided by LibGit2Sharp consumer. /// </summary> /// <param name="str">IntPtr to string</param> /// <param name="oldId">Old reference ID</param> /// <param name="newId">New referene ID</param> /// <param name="data"></param> /// <returns></returns> private int GitUpdateTipsHandler(IntPtr str, ref GitOid oldId, ref GitOid newId, IntPtr data) { UpdateTipsHandler onUpdateTips = UpdateTips; int result = 0; if (onUpdateTips != null) { string refName = Utf8Marshaler.FromNative(str); result = onUpdateTips(refName, oldId, newId); } return(result); }
/// <summary> /// Fetch from the specified remote. /// </summary> /// <param name="repository">The <see cref="Repository"/> being worked with.</param> /// <param name="remoteName">The name of the <see cref="Remote"/> to fetch from.</param> /// <param name="tagFetchMode">Optional parameter indicating what tags to download.</param> /// <param name="onProgress">Progress callback. Corresponds to libgit2 progress callback.</param> /// <param name="onCompletion">Completion callback. Corresponds to libgit2 completion callback.</param> /// <param name="onUpdateTips">UpdateTips callback. Corresponds to libgit2 update_tips callback.</param> /// <param name="onTransferProgress">Callback method that transfer progress will be reported through. /// Reports the client's state regarding the received and processed (bytes, objects) from the server.</param> /// <param name="credentials">Credentials to use for username/password authentication.</param> public static void Fetch(this IRepository repository, string remoteName, TagFetchMode tagFetchMode = TagFetchMode.Auto, ProgressHandler onProgress = null, CompletionHandler onCompletion = null, UpdateTipsHandler onUpdateTips = null, TransferProgressHandler onTransferProgress = null, Credentials credentials = null) { Ensure.ArgumentNotNull(repository, "repository"); Ensure.ArgumentNotNullOrEmptyString(remoteName, "remoteName"); Remote remote = repository.Network.Remotes.RemoteForName(remoteName, true); repository.Network.Fetch(remote, tagFetchMode, onProgress, onCompletion, onUpdateTips, onTransferProgress, credentials); }
public virtual void Fetch( Remote remote, TagFetchMode? tagFetchMode = null, ProgressHandler onProgress = null, UpdateTipsHandler onUpdateTips = null, TransferProgressHandler onTransferProgress = null, Credentials credentials = null) { Fetch(remote, new FetchOptions { TagFetchMode = tagFetchMode, OnProgress = onProgress, OnUpdateTips = onUpdateTips, OnTransferProgress = onTransferProgress, Credentials = credentials }); }
/// <summary> /// Fetch from the <see cref="Remote"/>. /// </summary> /// <param name="remote">The remote to fetch</param> /// <param name="tagFetchMode">Optional parameter indicating what tags to download.</param> /// <param name="onProgress">Progress callback. Corresponds to libgit2 progress callback.</param> /// <param name="onUpdateTips">UpdateTips callback. Corresponds to libgit2 update_tips callback.</param> /// <param name="onTransferProgress">Callback method that transfer progress will be reported through. /// Reports the client's state regarding the received and processed (bytes, objects) from the server.</param> /// <param name="credentials">Credentials to use for username/password authentication.</param> public virtual void Fetch( Remote remote, TagFetchMode? tagFetchMode = null, ProgressHandler onProgress = null, UpdateTipsHandler onUpdateTips = null, TransferProgressHandler onTransferProgress = null, Credentials credentials = null) { Ensure.ArgumentNotNull(remote, "remote"); using (RemoteSafeHandle remoteHandle = Proxy.git_remote_load(repository.Handle, remote.Name, true)) { var callbacks = new RemoteCallbacks(onProgress, onTransferProgress, onUpdateTips, credentials); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); if (tagFetchMode.HasValue) { Proxy.git_remote_set_autotag(remoteHandle, tagFetchMode.Value); } // It is OK to pass the reference to the GitCallbacks directly here because libgit2 makes a copy of // the data in the git_remote_callbacks structure. If, in the future, libgit2 changes its implementation // to store a reference to the git_remote_callbacks structure this would introduce a subtle bug // where the managed layer could move the git_remote_callbacks to a different location in memory, // but libgit2 would still reference the old address. // // Also, if GitRemoteCallbacks were a class instead of a struct, we would need to guard against // GC occuring in between setting the remote callbacks and actual usage in one of the functions afterwords. Proxy.git_remote_set_callbacks(remoteHandle, ref gitCallbacks); try { Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch); Proxy.git_remote_download(remoteHandle); Proxy.git_remote_update_tips(remoteHandle); } finally { Proxy.git_remote_disconnect(remoteHandle); } } }
internal RemoteCallbacks(FetchOptionsBase fetchOptions) { if (fetchOptions == null) { return; } Progress = fetchOptions.OnProgress; DownloadTransferProgress = fetchOptions.OnTransferProgress; UpdateTips = fetchOptions.OnUpdateTips; CredentialsProvider = fetchOptions.CredentialsProvider; CertificateCheck = fetchOptions.CertificateCheck; }
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); } }
internal RemoteCallbacks(ProgressHandler onProgress = null, CompletionHandler onCompletion = null, UpdateTipsHandler onUpdateTips = null) { Progress = onProgress; Completion = onCompletion; UpdateTips = onUpdateTips; }
internal RemoteCallbacks(ProgressHandler onProgress = null, CompletionHandler onCompletion = null, UpdateTipsHandler onUpdateTips = null) { Progress = onProgress; Completion = onCompletion; UpdateTips = onUpdateTips; }
/// <summary> /// Fetch from the <see cref = "Remote" />. /// </summary> /// <param name="remote">The remote to fetch</param> /// <param name="tagFetchMode">Optional parameter indicating what tags to download.</param> /// <param name="onProgress">Progress callback. Corresponds to libgit2 progress callback.</param> /// <param name="onCompletion">Completion callback. Corresponds to libgit2 completion callback.</param> /// <param name="onUpdateTips">UpdateTips callback. Corresponds to libgit2 update_tips callback.</param> /// <param name="onTransferProgress">Callback method that transfer progress will be reported through. /// Reports the client's state regarding the received and processed (bytes, objects) from the server.</param> /// <param name="credentials">Credentials to use for username/password authentication.</param> public virtual void Fetch( Remote remote, TagFetchMode tagFetchMode = TagFetchMode.Auto, ProgressHandler onProgress = null, CompletionHandler onCompletion = null, UpdateTipsHandler onUpdateTips = null, TransferProgressHandler onTransferProgress = null, Credentials credentials = null) { Ensure.ArgumentNotNull(remote, "remote"); // We need to keep a reference to the git_cred_acquire_cb callback around // so it will not be garbage collected before we are done with it. // Note that we also have a GC.KeepAlive call at the end of the method. NativeMethods.git_cred_acquire_cb credentialCallback = null; using (RemoteSafeHandle remoteHandle = Proxy.git_remote_load(repository.Handle, remote.Name, true)) { var callbacks = new RemoteCallbacks(onProgress, onCompletion, onUpdateTips); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); Proxy.git_remote_set_autotag(remoteHandle, tagFetchMode); if (credentials != null) { credentialCallback = (out IntPtr cred, IntPtr url, IntPtr username_from_url, uint types, IntPtr payload) => NativeMethods.git_cred_userpass_plaintext_new(out cred, credentials.Username, credentials.Password); Proxy.git_remote_set_cred_acquire_cb( remoteHandle, credentialCallback, IntPtr.Zero); } // It is OK to pass the reference to the GitCallbacks directly here because libgit2 makes a copy of // the data in the git_remote_callbacks structure. If, in the future, libgit2 changes its implementation // to store a reference to the git_remote_callbacks structure this would introduce a subtle bug // where the managed layer could move the git_remote_callbacks to a different location in memory, // but libgit2 would still reference the old address. // // Also, if GitRemoteCallbacks were a class instead of a struct, we would need to guard against // GC occuring in between setting the remote callbacks and actual usage in one of the functions afterwords. Proxy.git_remote_set_callbacks(remoteHandle, ref gitCallbacks); try { Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch); Proxy.git_remote_download(remoteHandle, onTransferProgress); Proxy.git_remote_update_tips(remoteHandle); } finally { Proxy.git_remote_disconnect(remoteHandle); } } // To be safe, make sure the credential callback is kept until // alive until at least this point. GC.KeepAlive(credentialCallback); }