Class to translate libgit2 callbacks into delegates exposed by LibGit2Sharp. Handles generating libgit2 git_remote_callbacks datastructure given a set of LibGit2Sharp delegates and handles propagating libgit2 callbacks into corresponding LibGit2Sharp exposed delegates.
Пример #1
0
        /// <summary>
        /// Update specified submodule.
        /// <para>
        ///   This will:
        ///   1) Optionally initialize the if it not already initialzed,
        ///   2) clone the sub repository if it has not already been cloned, and
        ///   3) checkout the commit ID for the submodule in the sub repository.
        /// </para>
        /// </summary>
        /// <param name="name">The name of the submodule to update.</param>
        /// <param name="options">Options controlling submodule udpate behavior and callbacks.</param>
        public virtual void Update(string name, SubmoduleUpdateOptions options)
        {
            options = options ?? new SubmoduleUpdateOptions();

            using (var handle = Proxy.git_submodule_lookup(repo.Handle, name))
            {
                if (handle == null)
                {
                    throw new NotFoundException("Submodule lookup failed for '{0}'.",
                                                name);
                }

                using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options))
                {
                    var gitCheckoutOptions = checkoutOptionsWrapper.Options;

                    var remoteCallbacks    = new RemoteCallbacks(options);
                    var gitRemoteCallbacks = remoteCallbacks.GenerateCallbacks();

                    var gitSubmoduleUpdateOpts = new GitSubmoduleOptions
                    {
                        Version         = 1,
                        CheckoutOptions = gitCheckoutOptions,
                        FetchOptions    = new GitFetchOptions {
                            RemoteCallbacks = gitRemoteCallbacks
                        },
                        CloneCheckoutStrategy = CheckoutStrategy.GIT_CHECKOUT_SAFE
                    };

                    Proxy.git_submodule_update(handle, options.Init, ref gitSubmoduleUpdateOpts);
                }
            }
        }
Пример #2
0
        /// <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),
                });
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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);
                }
        }
Пример #7
0
        /// <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));
            }
        }
Пример #8
0
        /// <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_load(repository.Handle, remote.Name, true))
            {
                if (credentialsProvider != null)
                {
                    var callbacks = new RemoteCallbacks(null, null, null, 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);
            }
        }
Пример #9
0
        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));
            }
        }
Пример #10
0
        /// <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);
                }
            }
        }
Пример #11
0
        /// <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))
            {

                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;
                }

                fetchOptions.ProxyOptions = new GitProxyOptions { Version = 1 };

                Proxy.git_remote_fetch(remoteHandle, refspecs, fetchOptions, logMessage);
            }
        }
Пример #12
0
        /// <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);
        }
Пример #13
0
        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);
        }
Пример #14
0
        /// <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);
        }
Пример #15
0
        private IEnumerable<Reference> ListReferencesInternal(string url, CredentialsHandler credentialsProvider)
        {
            using (RemoteHandle remoteHandle = BuildRemoteHandle(repository.Handle, url))
            {
                GitRemoteCallbacks gitCallbacks = new GitRemoteCallbacks { version = 1 };
                GitProxyOptions proxyOptions = new GitProxyOptions { Version = 1 };

                if (credentialsProvider != null)
                {
                    var callbacks = new RemoteCallbacks(credentialsProvider);
                    gitCallbacks = callbacks.GenerateCallbacks();
                }

                Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions);
                return Proxy.git_remote_ls(repository, remoteHandle);
            }
        }
Пример #16
0
        /// <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);
                }
            }
        }
Пример #17
0
        /// <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);
                }
            }
        }
Пример #18
0
        /// <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);
        }
Пример #19
0
        /// <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 = 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();
            }

            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 pushTransferCallbacks = new PushTransferCallbacks(pushOptions.OnPushTransferProgress);
                        PackbuilderCallbacks packBuilderCallbacks = new PackbuilderCallbacks(pushOptions.OnPackBuilderProgress);

                        NativeMethods.git_push_transfer_progress pushProgress = pushTransferCallbacks.GenerateCallback();
                        NativeMethods.git_packbuilder_progress 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);
                    }
                }
                finally
                {
                    Proxy.git_remote_disconnect(remoteHandle);
                }
            }
        }
Пример #20
0
        /// <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 },
                                      });
            }
        }
Пример #21
0
        /// <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);
        }