/// <summary> /// Push specified references to the <see cref="Remote"/>. /// </summary> /// <param name="remote">The <see cref="Remote"/> to push to.</param> /// <param name="pushRefSpecs">The pushRefSpecs to push.</param> /// <param name="pushOptions"><see cref="PushOptions"/> controlling push behavior</param> public virtual void Push(Remote remote, IEnumerable <string> pushRefSpecs, PushOptions pushOptions) { Ensure.ArgumentNotNull(remote, "remote"); Ensure.ArgumentNotNull(pushRefSpecs, "pushRefSpecs"); // Return early if there is nothing to push. if (!pushRefSpecs.Any()) { return; } if (pushOptions == null) { pushOptions = new PushOptions(); } // Load the remote. using (RemoteHandle remoteHandle = Proxy.git_remote_lookup(repository.Handle, remote.Name, true)) { var callbacks = new RemoteCallbacks(pushOptions); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); Proxy.git_remote_push(remoteHandle, pushRefSpecs, new GitPushOptions() { PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism, RemoteCallbacks = gitCallbacks, ProxyOptions = new GitProxyOptions { Version = 1 }, CustomHeaders = GitStrArrayManaged.BuildFrom(pushOptions.CustomHeaders), }); } }
internal GitRemoteCallbacks GenerateCallbacks() { var callbacks = new GitRemoteCallbacks { version = 1 }; if (Progress != null) { callbacks.progress = GitProgressHandler; } if (UpdateTips != null) { callbacks.update_tips = GitUpdateTipsHandler; } if (Credentials != null) { callbacks.acquire_credentials = Credentials.GitCredentialHandler; } if (DownloadTransferProgress != null) { callbacks.download_progress = GitDownloadTransferProgressHandler; } return(callbacks); }
static void DoFetch(RemoteSafeHandle remoteHandle, FetchOptions options, Signature signature, string logMessage) { if (options == null) { options = new FetchOptions(); } if (options.TagFetchMode.HasValue) { Proxy.git_remote_set_autotag(remoteHandle, options.TagFetchMode.Value); } var callbacks = new RemoteCallbacks(options); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); // 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); Proxy.git_remote_fetch(remoteHandle, signature, logMessage); }
private static void DoFetch(FetchOptions options, RemoteSafeHandle remoteHandle, string logMessage, IEnumerable <string> refspecs) { Debug.Assert(remoteHandle != null && !remoteHandle.IsClosed && !remoteHandle.IsInvalid); options = options ?? new FetchOptions(); var callbacks = new RemoteCallbacks(options); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); // 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. var fetchOptions = new GitFetchOptions { RemoteCallbacks = gitCallbacks, download_tags = Proxy.git_remote_autotag(remoteHandle), }; if (options.TagFetchMode.HasValue) { fetchOptions.download_tags = options.TagFetchMode.Value; } Proxy.git_remote_fetch(remoteHandle, refspecs, fetchOptions, logMessage); }
/// <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 unsafe GitRemoteCallbacks GenerateCallbacks() { var callbacks = new GitRemoteCallbacks { version = 1 }; if (Progress != null) { callbacks.progress = GitProgressHandler; } if (UpdateTips != null) { callbacks.update_tips = GitUpdateTipsHandler; } if (PushStatusError != null) { callbacks.push_update_reference = GitPushUpdateReference; } if (CredentialsProvider != null) { callbacks.acquire_credentials = GitCredentialHandler; } if (CertificateCheck != null) { callbacks.certificate_check = GitCertificateCheck; } if (DownloadTransferProgress != null) { callbacks.download_progress = GitDownloadTransferProgressHandler; } if (PushTransferProgress != null) { callbacks.push_transfer_progress = GitPushTransferProgressHandler; } if (PackBuilderProgress != null) { callbacks.pack_progress = GitPackbuilderProgressHandler; } if (PrePushCallback != null) { callbacks.push_negotiation = GitPushNegotiationHandler; } return(callbacks); }
/// <summary> /// Perform a fetch /// </summary> /// <param name="repository">The repository in which to fetch.</param> /// <param name="remote">The remote to fetch from. Either as a remote name or a URL</param> /// <param name="options">Fetch options.</param> /// <param name="logMessage">Log message for any ref updates.</param> /// <param name="refspecs">List of refspecs to apply as active.</param> public static void Fetch(Repository repository, string remote, IEnumerable <string> refspecs, FetchOptions options, string logMessage) { Ensure.ArgumentNotNull(remote, "remote"); options = options ?? new FetchOptions(); using (var remoteHandle = RemoteFromNameOrUrl(repository.Handle, remote)) using (var fetchOptionsWrapper = new GitFetchOptionsWrapper()) { var callbacks = new RemoteCallbacks(options); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); // 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. var fetchOptions = fetchOptionsWrapper.Options; fetchOptions.RemoteCallbacks = gitCallbacks; fetchOptions.download_tags = Proxy.git_remote_autotag(remoteHandle); if (options.TagFetchMode.HasValue) { fetchOptions.download_tags = options.TagFetchMode.Value; } if (options.Prune.HasValue) { fetchOptions.Prune = options.Prune.Value ? FetchPruneStrategy.Prune : FetchPruneStrategy.NoPrune; } else { fetchOptions.Prune = FetchPruneStrategy.FromConfigurationOrDefault; } if (options.CustomHeaders != null && options.CustomHeaders.Length > 0) { fetchOptions.CustomHeaders = GitStrArrayManaged.BuildFrom(options.CustomHeaders); } fetchOptions.ProxyOptions = new GitProxyOptions { Version = 1 }; Proxy.git_remote_fetch(remoteHandle, refspecs, fetchOptions, logMessage); } }
/// <summary> /// List references in a <see cref="Remote"/> repository. /// <para> /// When the remote tips are ahead of the local ones, the retrieved /// <see cref="DirectReference"/>s may point to non existing /// <see cref="GitObject"/>s in the local repository. In that /// case, <see cref="DirectReference.Target"/> will return <c>null</c>. /// </para> /// </summary> /// <param name="remote">The <see cref="Remote"/> to list from.</param> /// <param name="credentialsProvider">The optional <see cref="Func{Credentials}"/> used to connect to remote repository.</param> /// <returns>The references in the <see cref="Remote"/> repository.</returns> public virtual IEnumerable <DirectReference> ListReferences(Remote remote, CredentialsHandler credentialsProvider = null) { Ensure.ArgumentNotNull(remote, "remote"); using (RemoteSafeHandle remoteHandle = Proxy.git_remote_lookup(repository.Handle, remote.Name, true)) { if (credentialsProvider != null) { var callbacks = new RemoteCallbacks(credentialsProvider); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); Proxy.git_remote_set_callbacks(remoteHandle, ref gitCallbacks); } Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch); return(Proxy.git_remote_ls(repository, remoteHandle)); } }
private IEnumerable <Reference> ListReferencesInternal(string url, CredentialsHandler credentialsProvider) { using (RemoteSafeHandle remoteHandle = BuildRemoteSafeHandle(repository.Handle, url)) { GitRemoteCallbacks gitCallbacks = new GitRemoteCallbacks { version = 1 }; if (credentialsProvider != null) { var callbacks = new RemoteCallbacks(credentialsProvider); gitCallbacks = callbacks.GenerateCallbacks(); } Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks); return(Proxy.git_remote_ls(repository, remoteHandle)); } }
/// <summary> /// Push specified references to the <see cref="Remote"/>. /// </summary> /// <param name="remote">The <see cref="Remote"/> to push to.</param> /// <param name="pushRefSpecs">The pushRefSpecs to push.</param> /// <param name="pushOptions"><see cref="PushOptions"/> controlling push behavior</param> /// <param name="signature">Identity for use when updating the reflog.</param> /// <param name="logMessage">Message to use when updating the reflog.</param> public virtual void Push( Remote remote, IEnumerable <string> pushRefSpecs, PushOptions pushOptions = null, Signature signature = null, string logMessage = null) { Ensure.ArgumentNotNull(remote, "remote"); Ensure.ArgumentNotNull(pushRefSpecs, "pushRefSpecs"); // Return early if there is nothing to push. if (!pushRefSpecs.Any()) { return; } if (pushOptions == null) { pushOptions = new PushOptions(); } // Load the remote. using (RemoteSafeHandle remoteHandle = Proxy.git_remote_lookup(repository.Handle, remote.Name, true)) { var callbacks = new RemoteCallbacks(pushOptions); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); Proxy.git_remote_set_callbacks(remoteHandle, ref gitCallbacks); try { Proxy.git_remote_connect(remoteHandle, GitDirection.Push); Proxy.git_remote_push(remoteHandle, pushRefSpecs, new GitPushOptions() { PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism }, signature.OrDefault(repository.Config), logMessage); } finally { Proxy.git_remote_disconnect(remoteHandle); } } }
internal GitRemoteCallbacks GenerateCallbacks() { GitRemoteCallbacks callbacks = new GitRemoteCallbacks { version = 1 }; if (Progress != null) { callbacks.progress = GitProgressHandler; } if (UpdateTips != null) { callbacks.update_tips = GitUpdateTipsHandler; } if (Completion != null) { callbacks.completion = GitCompletionHandler; } return(callbacks); }
/// <summary> /// Clone with specified options. /// </summary> /// <param name="sourceUrl">URI for the remote repository</param> /// <param name="workdirPath">Local path to clone into</param> /// <param name="bare">True will result in a bare clone, false a full clone.</param> /// <param name="checkout">If true, the origin's HEAD will be checked out. This only applies /// to non-bare repositories.</param> /// <param name="onTransferProgress">Handler for network transfer and indexing progress information</param> /// <param name="onCheckoutProgress">Handler for checkout progress information</param> /// <param name="credentials">Credentials to use for user/pass authentication</param> /// <returns>The path to the created repository.</returns> public static string Clone(string sourceUrl, string workdirPath, bool bare = false, bool checkout = true, TransferProgressHandler onTransferProgress = null, CheckoutProgressHandler onCheckoutProgress = null, Credentials credentials = null) { CheckoutCallbacks checkoutCallbacks = CheckoutCallbacks.GenerateCheckoutCallbacks(onCheckoutProgress, null); var callbacks = new RemoteCallbacks(null, onTransferProgress, null, credentials); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); var cloneOpts = new GitCloneOptions { Bare = bare ? 1 : 0, CheckoutOpts = { version = 1, progress_cb = checkoutCallbacks.CheckoutProgressCallback, checkout_strategy = checkout ? CheckoutStrategy.GIT_CHECKOUT_SAFE_CREATE : CheckoutStrategy.GIT_CHECKOUT_NONE }, RemoteCallbacks = gitCallbacks, }; FilePath repoPath; using (RepositorySafeHandle repo = Proxy.git_clone(sourceUrl, workdirPath, cloneOpts)) { repoPath = Proxy.git_repository_path(repo); } return(repoPath.Native); }
/// <summary> /// Push specified references to the <see cref="Remote"/>. /// </summary> /// <param name="remote">The <see cref="Remote"/> to push to.</param> /// <param name="pushRefSpecs">The pushRefSpecs to push.</param> /// <param name="pushOptions"><see cref="PushOptions"/> controlling push behavior</param> /// <param name="signature">Identity for use when updating the reflog.</param> /// <param name="logMessage">Message to use when updating the reflog.</param> public virtual void Push( Remote remote, IEnumerable <string> pushRefSpecs, PushOptions pushOptions = null, Signature signature = null, string logMessage = null) { Ensure.ArgumentNotNull(remote, "remote"); Ensure.ArgumentNotNull(pushRefSpecs, "pushRefSpecs"); // The following local variables are protected from garbage collection // by a GC.KeepAlive call at the end of the method. Otherwise, // random crashes during push progress reporting could occur. PushTransferCallbacks pushTransferCallbacks; PackbuilderCallbacks packBuilderCallbacks; NativeMethods.git_push_transfer_progress pushProgress; NativeMethods.git_packbuilder_progress packBuilderProgress; // Return early if there is nothing to push. if (!pushRefSpecs.Any()) { return; } if (pushOptions == null) { pushOptions = new PushOptions(); } PushCallbacks pushStatusUpdates = new PushCallbacks(pushOptions.OnPushStatusError); // Load the remote. using (RemoteSafeHandle remoteHandle = Proxy.git_remote_load(repository.Handle, remote.Name, true)) { var callbacks = new RemoteCallbacks(null, null, null, pushOptions.Credentials); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); Proxy.git_remote_set_callbacks(remoteHandle, ref gitCallbacks); try { Proxy.git_remote_connect(remoteHandle, GitDirection.Push); // Perform the actual push. using (PushSafeHandle pushHandle = Proxy.git_push_new(remoteHandle)) { pushTransferCallbacks = new PushTransferCallbacks(pushOptions.OnPushTransferProgress); packBuilderCallbacks = new PackbuilderCallbacks(pushOptions.OnPackBuilderProgress); pushProgress = pushTransferCallbacks.GenerateCallback(); packBuilderProgress = packBuilderCallbacks.GenerateCallback(); Proxy.git_push_set_callbacks(pushHandle, pushProgress, packBuilderProgress); // Set push options. Proxy.git_push_set_options(pushHandle, new GitPushOptions() { PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism }); // Add refspecs. foreach (string pushRefSpec in pushRefSpecs) { Proxy.git_push_add_refspec(pushHandle, pushRefSpec); } Proxy.git_push_finish(pushHandle); if (!Proxy.git_push_unpack_ok(pushHandle)) { throw new LibGit2SharpException("Push failed - remote did not successfully unpack."); } Proxy.git_push_status_foreach(pushHandle, pushStatusUpdates.Callback); Proxy.git_push_update_tips(pushHandle, signature.OrDefault(repository.Config), logMessage); } } finally { Proxy.git_remote_disconnect(remoteHandle); } } GC.KeepAlive(pushProgress); GC.KeepAlive(packBuilderProgress); GC.KeepAlive(pushTransferCallbacks); GC.KeepAlive(packBuilderCallbacks); }