Пример #1
0
        /// <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));
            }
        }
Пример #2
0
        /// <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);
            }
        }
Пример #3
0
        /// <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);
        }
Пример #5
0
        /// <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);
            }
        }
Пример #6
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));
            }
        }
Пример #7
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));
            }
        }
Пример #8
0
        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);
        }
Пример #9
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);
                }
            }
        }
Пример #10
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;
            }

            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);
        }
Пример #11
0
        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);
        }
Пример #13
0
 internal static extern int git_remote_get_push_refspecs(out git_strarray array, RemoteSafeHandle remote);
Пример #14
0
        internal static Remote BuildFromPtr(RemoteSafeHandle handle, Repository repo)
        {
            var remote = new Remote(handle, repo);

            return(remote);
        }
Пример #15
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);
        }
Пример #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="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);
        }
Пример #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="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);
        }
Пример #18
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);
        }