/// <summary> /// Creates a <see cref="Remote"/> with the specified name and for the repository at the specified location. /// </summary> /// <param name="name">The name of the remote to create.</param> /// <param name="url">The location of the repository.</param> /// <param name="fetchRefSpec">The refSpec to be used when fetching from this remote.</param> /// <returns>A new <see cref="Remote"/>.</returns> public virtual Remote Add(string name, string url, string fetchRefSpec) { Ensure.ArgumentNotNull(name, "name"); Ensure.ArgumentNotNull(url, "url"); Ensure.ArgumentNotNull(fetchRefSpec, "fetchRefSpec"); using (RemoteSafeHandle handle = Proxy.git_remote_create(repository.Handle, name, url)) { Proxy.git_remote_add_fetch(handle, fetchRefSpec); Proxy.git_remote_save(handle); return(Remote.BuildFromPtr(handle, this.repository)); } }
/// <summary> /// Fetch from the <see cref="Remote"/>, using custom refspecs. /// </summary> /// <param name="remote">The remote to fetch</param> /// <param name="refspecs">Refspecs to use, replacing the remote's fetch refspecs</param> /// <param name="options"><see cref="FetchOptions"/> controlling fetch 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 Fetch(Remote remote, IEnumerable <string> refspecs, FetchOptions options = null, Signature signature = null, string logMessage = null) { Ensure.ArgumentNotNull(remote, "remote"); Ensure.ArgumentNotNull(refspecs, "refspecs"); using (RemoteSafeHandle remoteHandle = Proxy.git_remote_load(repository.Handle, remote.Name, true)) { Proxy.git_remote_set_fetch_refspecs(remoteHandle, refspecs); DoFetch(remoteHandle, options, signature.OrDefault(repository.Config), logMessage); } }
/// <summary> /// Fetch from a url with a set of fetch refspecs /// </summary> /// <param name="url">The url to fetch from</param> /// <param name="refspecs">The list of resfpecs to use</param> /// <param name="options"><see cref="FetchOptions"/> controlling fetch behavior</param> public virtual void Fetch( string url, IEnumerable <string> refspecs, FetchOptions options = null) { Ensure.ArgumentNotNull(url, "url"); Ensure.ArgumentNotNull(refspecs, "refspecs"); using (RemoteSafeHandle remoteHandle = Proxy.git_remote_create_inmemory(repository.Handle, null, url)) { Proxy.git_remote_set_fetch_refspecs(remoteHandle, refspecs); DoFetch(remoteHandle, options); } }
static IList <RefSpec> RetrieveRefSpecs(RemoteSafeHandle remoteHandle) { int count = Proxy.git_remote_refspec_count(remoteHandle); List <RefSpec> refSpecs = new List <RefSpec>(); for (int i = 0; i < count; i++) { using (GitRefSpecHandle handle = Proxy.git_remote_get_refspec(remoteHandle, i)) { refSpecs.Add(RefSpec.BuildFromPtr(handle)); } } return(refSpecs); }
/// <summary> /// Fetch from a url with a set of fetch refspecs /// </summary> /// <param name="url">The url to fetch from</param> /// <param name="refspecs">The list of resfpecs to use</param> /// <param name="options"><see cref="FetchOptions"/> controlling fetch 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 Fetch( string url, IEnumerable <string> refspecs, FetchOptions options = null, Signature signature = null, string logMessage = null) { Ensure.ArgumentNotNull(url, "url"); Ensure.ArgumentNotNull(refspecs, "refspecs"); using (RemoteSafeHandle remoteHandle = Proxy.git_remote_create_anonymous(repository.Handle, url, null)) { Proxy.git_remote_set_fetch_refspecs(remoteHandle, refspecs); DoFetch(remoteHandle, options, signature.OrDefault(repository.Config), 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)); } }
internal static Remote CreateFromPtr(RemoteSafeHandle handle) { if (handle == null) { return(null); } string name = NativeMethods.git_remote_name(handle); string url = NativeMethods.git_remote_url(handle); var remote = new Remote { Name = name, Url = url, }; return(remote); }
/// <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); } } }
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; } if (options.Prune.HasValue) { fetchOptions.Prune = options.Prune.Value ? FetchPruneStrategy.Prune : FetchPruneStrategy.NoPrune; } else { fetchOptions.Prune = FetchPruneStrategy.FromConfigurationOrDefault; } Proxy.git_remote_fetch(remoteHandle, refspecs, fetchOptions, logMessage); }
static void DoFetch(RemoteSafeHandle remoteHandle, FetchOptions options) { 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); 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 RefSpecCollection(RemoteSafeHandle handle) { Ensure.ArgumentNotNull(handle, "handle"); refspecs = RetrieveRefSpecs(handle); }
internal static extern int git_remote_get_push_refspecs(out git_strarray array, RemoteSafeHandle remote);
internal static Remote BuildFromPtr(RemoteSafeHandle handle, Repository repo) { var remote = new Remote(handle, repo); return(remote); }
/// <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); }
/// <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 = null, 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(); if (tagFetchMode.HasValue) { Proxy.git_remote_set_autotag(remoteHandle, tagFetchMode.Value); } 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); }
/// <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="onPushStatusError">Handler for reporting failed push updates.</param> /// <param name="credentials">Credentials to use for user/pass authentication</param> public virtual void Push( Remote remote, IEnumerable <string> pushRefSpecs, PushStatusErrorHandler onPushStatusError, Credentials credentials = null) { Ensure.ArgumentNotNull(remote, "remote"); Ensure.ArgumentNotNull(pushRefSpecs, "pushRefSpecs"); // 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; // Return early if there is nothing to push. if (!pushRefSpecs.Any()) { return; } PushCallbacks pushStatusUpdates = new PushCallbacks(onPushStatusError); // Load the remote. using (RemoteSafeHandle remoteHandle = Proxy.git_remote_load(repository.Handle, remote.Name, true)) { 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); } try { Proxy.git_remote_connect(remoteHandle, GitDirection.Push); // Perform the actual push. using (PushSafeHandle pushHandle = Proxy.git_push_new(remoteHandle)) { // 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); } } finally { Proxy.git_remote_disconnect(remoteHandle); } } // To be safe, make sure the credential callback is kept // alive until at least this point. GC.KeepAlive(credentialCallback); }
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); }