Пример #1
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);
        }
Пример #2
0
 internal RemoteCallbacks(FetchOptions fetchOptions)
 {
     Ensure.ArgumentNotNull(fetchOptions, "fetchOptions");
     Progress = fetchOptions.OnProgress;
     DownloadTransferProgress = fetchOptions.OnTransferProgress;
     UpdateTips = fetchOptions.OnUpdateTips;
     Credentials = fetchOptions.Credentials;
 }
Пример #3
0
 internal RemoteCallbacks(
     ProgressHandler onProgress = null,
     TransferProgressHandler onDownloadProgress = null,
     UpdateTipsHandler onUpdateTips = null,
     CredentialsHandler credentialsProvider = null)
 {
     Progress = onProgress;
     DownloadTransferProgress = onDownloadProgress;
     UpdateTips = onUpdateTips;
     CredentialsProvider = credentialsProvider;
 }
Пример #4
0
 internal RemoteCallbacks(
     ProgressHandler onProgress = null,
     TransferProgressHandler onDownloadProgress = null,
     UpdateTipsHandler onUpdateTips             = null,
     Credentials credentials = null)
 {
     Progress = onProgress;
     DownloadTransferProgress = onDownloadProgress;
     UpdateTips  = onUpdateTips;
     Credentials = credentials;
 }
Пример #5
0
 internal RemoteCallbacks(
     ProgressHandler onProgress = null,
     TransferProgressHandler onDownloadProgress = null,
     UpdateTipsHandler onUpdateTips             = null,
     ICredentialsProvider credentialsProvider   = null)
 {
     Progress = onProgress;
     DownloadTransferProgress = onDownloadProgress;
     UpdateTips          = onUpdateTips;
     CredentialsProvider = credentialsProvider.GetCredentialsHandler();
 }
Пример #6
0
        /// <summary>
        /// Handler for libgit2 update_tips callback. Converts values
        /// received from libgit2 callback to more suitable types
        /// and calls delegate provided by LibGit2Sharp consumer.
        /// </summary>
        /// <param name="str">IntPtr to string</param>
        /// <param name="oldId">Old reference ID</param>
        /// <param name="newId">New referene ID</param>
        /// <param name="data">IntPtr to optional payload passed back to the callback.</param>
        /// <returns>0 on success; a negative value to abort the process.</returns>
        private int GitUpdateTipsHandler(IntPtr str, ref GitOid oldId, ref GitOid newId, IntPtr data)
        {
            UpdateTipsHandler onUpdateTips = UpdateTips;
            bool shouldContinue            = true;

            if (onUpdateTips != null)
            {
                string refName = LaxUtf8Marshaler.FromNative(str);
                shouldContinue = onUpdateTips(refName, oldId, newId);
            }

            return(Proxy.ConvertResultToCancelFlag(shouldContinue));
        }
Пример #7
0
        /// <summary>
        ///   Handler for libgit2 update_tips callback. Converts values
        ///   received from libgit2 callback to more suitable types
        ///   and calls delegate provided by LibGit2Sharp consumer.
        /// </summary>
        /// <param name="str">IntPtr to string</param>
        /// <param name="oldId">Old reference ID</param>
        /// <param name="newId">New referene ID</param>
        /// <param name="data"></param>
        /// <returns></returns>
        private int GitUpdateTipsHandler(IntPtr str, ref GitOid oldId, ref GitOid newId, IntPtr data)
        {
            UpdateTipsHandler onUpdateTips = UpdateTips;
            int result = 0;

            if (onUpdateTips != null)
            {
                string refName = Utf8Marshaler.FromNative(str);
                result = onUpdateTips(refName, oldId, newId);
            }

            return(result);
        }
Пример #8
0
        /// <summary>
        /// Fetch from the specified remote.
        /// </summary>
        /// <param name="repository">The <see cref="Repository"/> being worked with.</param>
        /// <param name="remoteName">The name of the <see cref="Remote"/> to fetch from.</param>
        /// <param name="tagFetchMode">Optional parameter indicating what tags to download.</param>
        /// <param name="onProgress">Progress callback. Corresponds to libgit2 progress callback.</param>
        /// <param name="onCompletion">Completion callback. Corresponds to libgit2 completion callback.</param>
        /// <param name="onUpdateTips">UpdateTips callback. Corresponds to libgit2 update_tips callback.</param>
        /// <param name="onTransferProgress">Callback method that transfer progress will be reported through.
        /// Reports the client's state regarding the received and processed (bytes, objects) from the server.</param>
        /// <param name="credentials">Credentials to use for username/password authentication.</param>
        public static void Fetch(this IRepository repository, string remoteName,
                                 TagFetchMode tagFetchMode                  = TagFetchMode.Auto,
                                 ProgressHandler onProgress                 = null,
                                 CompletionHandler onCompletion             = null,
                                 UpdateTipsHandler onUpdateTips             = null,
                                 TransferProgressHandler onTransferProgress = null,
                                 Credentials credentials = null)
        {
            Ensure.ArgumentNotNull(repository, "repository");
            Ensure.ArgumentNotNullOrEmptyString(remoteName, "remoteName");

            Remote remote = repository.Network.Remotes.RemoteForName(remoteName, true);

            repository.Network.Fetch(remote, tagFetchMode, onProgress, onCompletion, onUpdateTips,
                                     onTransferProgress, credentials);
        }
Пример #9
0
 public virtual void Fetch(
     Remote remote,
     TagFetchMode? tagFetchMode = null,
     ProgressHandler onProgress = null,
     UpdateTipsHandler onUpdateTips = null,
     TransferProgressHandler onTransferProgress = null,
     Credentials credentials = null)
 {
     Fetch(remote, new FetchOptions
     {
         TagFetchMode = tagFetchMode,
         OnProgress = onProgress,
         OnUpdateTips = onUpdateTips,
         OnTransferProgress = onTransferProgress,
         Credentials = credentials
     });
 }
Пример #10
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);
                }
            }
        }
Пример #11
0
        internal RemoteCallbacks(FetchOptionsBase fetchOptions)
        {
            if (fetchOptions == null)
            {
                return;
            }

            Progress = fetchOptions.OnProgress;
            DownloadTransferProgress = fetchOptions.OnTransferProgress;
            UpdateTips = fetchOptions.OnUpdateTips;
            CredentialsProvider = fetchOptions.CredentialsProvider;
            CertificateCheck = fetchOptions.CertificateCheck;
        }
Пример #12
0
        public void CanRecursivelyCloneSubmodules()
        {
            var    uri = new Uri($"file://{Path.GetFullPath(SandboxSubmoduleSmallTestRepo())}");
            var    scd = BuildSelfCleaningDirectory();
            string relativeSubmodulePath = "submodule_target_wd";

            // Construct the expected URL the submodule will clone from.
            string expectedSubmoduleUrl = Path.Combine(Path.GetDirectoryName(uri.AbsolutePath), relativeSubmodulePath);

            expectedSubmoduleUrl = expectedSubmoduleUrl.Replace('\\', '/');

            Dictionary <string, CloneCallbackInfo> callbacks = new Dictionary <string, CloneCallbackInfo>();

            CloneCallbackInfo currentEntry  = null;
            bool unexpectedOrderOfCallbacks = false;

            CheckoutProgressHandler checkoutProgressHandler = (x, y, z) =>
            {
                if (currentEntry != null)
                {
                    currentEntry.CheckoutProgressCalled = true;
                }
                else
                {
                    // Should not be called if there is not a current
                    // callbackInfo entry.
                    unexpectedOrderOfCallbacks = true;
                }
            };

            UpdateTipsHandler remoteRefUpdated = (x, y, z) =>
            {
                if (currentEntry != null)
                {
                    currentEntry.RemoteRefUpdateCalled = true;
                }
                else
                {
                    // Should not be called if there is not a current
                    // callbackInfo entry.
                    unexpectedOrderOfCallbacks = true;
                }

                return(true);
            };

            RepositoryOperationStarting repositoryOperationStarting = (x) =>
            {
                if (currentEntry != null)
                {
                    // Should not be called if there is a current
                    // callbackInfo entry.
                    unexpectedOrderOfCallbacks = true;
                }

                currentEntry = new CloneCallbackInfo();
                currentEntry.StartingWorkInRepositoryCalled = true;
                currentEntry.RecursionDepth = x.RecursionDepth;
                currentEntry.RemoteUrl      = x.RemoteUrl;
                callbacks.Add(x.RepositoryPath, currentEntry);

                return(true);
            };

            RepositoryOperationCompleted repositoryOperationCompleted = (x) =>
            {
                if (currentEntry != null)
                {
                    currentEntry.FinishedWorkInRepositoryCalled = true;
                    currentEntry = null;
                }
                else
                {
                    // Should not be called if there is not a current
                    // callbackInfo entry.
                    unexpectedOrderOfCallbacks = true;
                }
            };

            CloneOptions options = new CloneOptions()
            {
                RecurseSubmodules            = true,
                OnCheckoutProgress           = checkoutProgressHandler,
                OnUpdateTips                 = remoteRefUpdated,
                RepositoryOperationStarting  = repositoryOperationStarting,
                RepositoryOperationCompleted = repositoryOperationCompleted,
            };

            string clonedRepoPath = Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options);
            string workDirPath;

            using (Repository repo = new Repository(clonedRepoPath))
            {
                workDirPath = repo.Info.WorkingDirectory.TrimEnd(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar });
            }

            // Verification:
            // Verify that no callbacks were called in an unexpected order.
            Assert.False(unexpectedOrderOfCallbacks);

            Dictionary <string, CloneCallbackInfo> expectedCallbackInfo = new Dictionary <string, CloneCallbackInfo>();

            expectedCallbackInfo.Add(workDirPath, new CloneCallbackInfo()
            {
                RecursionDepth = 0,
                RemoteUrl      = uri.AbsolutePath,
                StartingWorkInRepositoryCalled = true,
                FinishedWorkInRepositoryCalled = true,
                CheckoutProgressCalled         = true,
                RemoteRefUpdateCalled          = true,
            });

            expectedCallbackInfo.Add(Path.Combine(workDirPath, relativeSubmodulePath), new CloneCallbackInfo()
            {
                RecursionDepth = 1,
                RemoteUrl      = expectedSubmoduleUrl,
                StartingWorkInRepositoryCalled = true,
                FinishedWorkInRepositoryCalled = true,
                CheckoutProgressCalled         = true,
                RemoteRefUpdateCalled          = true,
            });

            // Callbacks for each expected repository that is cloned
            foreach (KeyValuePair <string, CloneCallbackInfo> kvp in expectedCallbackInfo)
            {
                CloneCallbackInfo entry = null;
                Assert.True(callbacks.TryGetValue(kvp.Key, out entry), string.Format("{0} was not found in callbacks.", kvp.Key));

                Assert.Equal(kvp.Value.RemoteUrl, entry.RemoteUrl);
                Assert.Equal(kvp.Value.RecursionDepth, entry.RecursionDepth);
                Assert.Equal(kvp.Value.StartingWorkInRepositoryCalled, entry.StartingWorkInRepositoryCalled);
                Assert.Equal(kvp.Value.FinishedWorkInRepositoryCalled, entry.FinishedWorkInRepositoryCalled);
                Assert.Equal(kvp.Value.CheckoutProgressCalled, entry.CheckoutProgressCalled);
                Assert.Equal(kvp.Value.RemoteRefUpdateCalled, entry.RemoteRefUpdateCalled);
            }

            // Verify the state of the submodule
            using (Repository repo = new Repository(clonedRepoPath))
            {
                var sm = repo.Submodules[relativeSubmodulePath];
                Assert.True(sm.RetrieveStatus().HasFlag(SubmoduleStatus.InWorkDir |
                                                        SubmoduleStatus.InConfig |
                                                        SubmoduleStatus.InIndex |
                                                        SubmoduleStatus.InHead));

                Assert.NotNull(sm.HeadCommitId);
                Assert.Equal("480095882d281ed676fe5b863569520e54a7d5c0", sm.HeadCommitId.Sha);

                Assert.False(repo.RetrieveStatus().IsDirty);
            }
        }
Пример #13
0
 internal RemoteCallbacks(ProgressHandler onProgress = null, CompletionHandler onCompletion = null, UpdateTipsHandler onUpdateTips = null)
 {
     Progress   = onProgress;
     Completion = onCompletion;
     UpdateTips = onUpdateTips;
 }
Пример #14
0
 internal RemoteCallbacks(ProgressHandler onProgress = null, CompletionHandler onCompletion = null, UpdateTipsHandler onUpdateTips = null)
 {
     Progress = onProgress;
     Completion = onCompletion;
     UpdateTips = onUpdateTips;
 }
Пример #15
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);
        }