Skip to content

Commit

Permalink
Inline usages of static AsyncLoader.DoAsync
Browse files Browse the repository at this point in the history
Now that this method just uses JTF it's clearer and more idiomatic to inline
these calls so that calling code is clearer.

This highlighted some further work, identified by TODO comments.
  • Loading branch information
drewnoakes committed Aug 24, 2018
1 parent 47f884e commit ab4fa7c
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 125 deletions.
47 changes: 0 additions & 47 deletions GitCommands/AsyncLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,53 +9,6 @@ namespace GitCommands
{
public sealed class AsyncLoader : IDisposable
{
/// <summary>
/// Invokes <paramref name="loadContent"/> on the thread pool, then executes <paramref name="continueWith"/> on the main thread.
/// </summary>
/// <remarks>
/// Note this method does not perform any cancellation of prior loads, nor does it support cancellation upon disposal.
/// If you require those features, use an instance of <see cref="AsyncLoader"/> instead.
/// </remarks>
/// <typeparam name="T">Type of data returned by <paramref name="loadContent"/> and accepted by <paramref name="continueWith"/>.</typeparam>
/// <param name="loadContent">A function to invoke on the thread pool that returns a value to be passed to <paramref name="continueWith"/>.</param>
/// <param name="continueWith">An action to invoke on the main thread with the return value from <paramref name="loadContent"/>.</param>
/// <param name="onError">
/// A callback for notification of exceptions from <paramref name="loadContent"/>.
/// Invoked on the original synchronisation context.
/// Invoked once per exception, so may be called multiple times.
/// Handlers must set <see cref="AsyncErrorEventArgs.Handled"/> to <c>true</c> to prevent any exceptions being re-thrown and faulting the async operation.
/// </param>
public static Task<T> DoAsync<T>(Func<T> loadContent, Action<T> continueWith, [CanBeNull] Action<AsyncErrorEventArgs> onError)
{
return ThreadHelper.JoinableTaskFactory.RunAsync(
async () =>
{
try
{
await TaskScheduler.Default;

var content = loadContent();

await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

continueWith(content);

return content;
}
catch (Exception e)
{
var args = new AsyncErrorEventArgs(e);
onError?.Invoke(args);
if (!args.Handled)
{
throw;
}

return default;
}
}).Task;
}

public event EventHandler<AsyncErrorEventArgs> LoadingError;

private readonly CancellationTokenSequence _cancellationSequence = new CancellationTokenSequence();
Expand Down
33 changes: 26 additions & 7 deletions GitUI/CommandsDialogs/BrowseDialog/GitStatusMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using GitCommands;
using GitUIPluginInterfaces;
using Microsoft.VisualStudio.Threading;

namespace GitUI.CommandsDialogs.BrowseDialog
{
Expand Down Expand Up @@ -391,7 +393,30 @@ private void Update()
_commandIsRunning = true;
_statusIsUpToDate = true;
_previousUpdateTime = Environment.TickCount;
AsyncLoader.DoAsync(RunStatusCommand, UpdatedStatusReceived, OnUpdateStatusError);

ThreadHelper.JoinableTaskFactory.RunAsync(
async () =>
{
try
{
await TaskScheduler.Default;

// TODO parse response output on thread pool, not UI thread
var content = RunStatusCommand();

await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

UpdatedStatusReceived(content);
}
catch
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

_commandIsRunning = false;
CurrentStatus = GitStatusMonitorState.Stopped;
}
})
.FileAndForget();

// Schedule update every 5 min, even if we don't know that anything changed
CalculateNextUpdateTime(MaxUpdatePeriod);
Expand Down Expand Up @@ -436,12 +461,6 @@ void UpdatedStatusReceived(string updatedStatus)
CalculateNextUpdateTime(UpdateDelay);
}
}

void OnUpdateStatusError(AsyncErrorEventArgs e)
{
_commandIsRunning = false;
CurrentStatus = GitStatusMonitorState.Stopped;
}
}

private void CalculateNextUpdateTime(int delay)
Expand Down
38 changes: 26 additions & 12 deletions GitUI/CommandsDialogs/RepoHosting/CreatePullRequestForm.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using GitCommands;
using GitUIPluginInterfaces.RepositoryHosts;
using JetBrains.Annotations;
using Microsoft.VisualStudio.Threading;
using ResourceManager;

namespace GitUI.CommandsDialogs.RepoHosting
Expand Down Expand Up @@ -104,11 +106,17 @@ private void _pullReqTargetsCB_SelectedIndexChanged(object sender, EventArgs e)
_remoteBranchesCB.Items.Clear();
_remoteBranchesCB.Text = _strLoading.Text;

AsyncLoader.DoAsync(
() => _currentHostedRemote.GetHostedRepository().Branches,
branches =>
// TODO merge with nearly identical code below
ThreadHelper.JoinableTaskFactory.RunAsync(
async () =>
{
branches.Sort((a, b) => string.Compare(a.Name, b.Name, true));
await TaskScheduler.Default;

var branches = _currentHostedRemote.GetHostedRepository().Branches;
branches.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));

await this.SwitchToMainThreadAsync();

int selectItem = 0;
_remoteBranchesCB.Items.Clear();
for (int i = 0; i < branches.Count; i++)
Expand All @@ -126,8 +134,8 @@ private void _pullReqTargetsCB_SelectedIndexChanged(object sender, EventArgs e)
{
_remoteBranchesCB.SelectedIndex = selectItem;
}
},
ex => { ex.Handled = false; });
})
.FileAndForget();
}

[CanBeNull]
Expand All @@ -142,11 +150,17 @@ private void LoadMyBranches()
return;
}

AsyncLoader.DoAsync(
() => MyRemote.GetHostedRepository().Branches,
branches =>
// TODO merge with nearly identical code above
ThreadHelper.JoinableTaskFactory.RunAsync(
async () =>
{
branches.Sort((a, b) => string.Compare(a.Name, b.Name, true));
await TaskScheduler.Default;

var branches = MyRemote.GetHostedRepository().Branches;
branches.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));

await this.SwitchToMainThreadAsync();

int selectItem = 0;
for (int i = 0; i < branches.Count; i++)
{
Expand All @@ -163,8 +177,8 @@ private void LoadMyBranches()
{
_yourBranchesCB.SelectedIndex = selectItem;
}
},
ex => { ex.Handled = false; });
})
.FileAndForget();
}

private void _yourBranchCB_SelectedIndexChanged(object sender, EventArgs e)
Expand Down
115 changes: 78 additions & 37 deletions GitUI/CommandsDialogs/RepoHosting/ForkAndCloneForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using GitCommands;
using GitCommands.UserRepositoryHistory;
using GitUIPluginInterfaces.RepositoryHosts;
using JetBrains.Annotations;
using Microsoft.VisualStudio.Threading;
using ResourceManager;

namespace GitUI.CommandsDialogs.RepoHosting
Expand Down Expand Up @@ -84,29 +86,41 @@ private void UpdateMyRepos()
_myReposLV.Items.Clear();
_myReposLV.Items.Add(new ListViewItem { Text = _strLoading.Text });

AsyncLoader.DoAsync(
() => _gitHoster.GetMyRepos(),
repos =>
ThreadHelper.JoinableTaskFactory.RunAsync(
async () =>
{
_myReposLV.Items.Clear();
foreach (var repo in repos)
try
{
var lvi = new ListViewItem { Tag = repo, Text = repo.Name };
lvi.SubItems.Add(repo.IsAFork ? _strYes.Text : _strNo.Text);
lvi.SubItems.Add(repo.Forks.ToString());
lvi.SubItems.Add(repo.IsPrivate ? _strYes.Text : _strNo.Text);
_myReposLV.Items.Add(lvi);
await TaskScheduler.Default;

var repos = _gitHoster.GetMyRepos();

await this.SwitchToMainThreadAsync();

_myReposLV.Items.Clear();
foreach (var repo in repos)
{
var lvi = new ListViewItem { Tag = repo, Text = repo.Name };
lvi.SubItems.Add(repo.IsAFork ? _strYes.Text : _strNo.Text);
lvi.SubItems.Add(repo.Forks.ToString());
lvi.SubItems.Add(repo.IsPrivate ? _strYes.Text : _strNo.Text);
_myReposLV.Items.Add(lvi);
}
}
},
ex =>
{
_myReposLV.Items.Clear();
_helpTextLbl.Text = string.Format(_strFailedToGetRepos.Text, _gitHoster.Description) +
"\r\n\r\nException: " + ex.Exception.Message + "\r\n\r\n" + _helpTextLbl.Text;
});
catch (Exception ex) when (!(ex is OperationCanceledException))
{
await this.SwitchToMainThreadAsync();

_myReposLV.Items.Clear();
_helpTextLbl.Text = string.Format(_strFailedToGetRepos.Text, _gitHoster.Description) +
"\r\n\r\nException: " + ex.Message + "\r\n\r\n" + _helpTextLbl.Text;
}
})
.FileAndForget();
}

#region GUI Handlers

private void _searchBtn_Click(object sender, EventArgs e)
{
var search = _searchTB.Text;
Expand All @@ -117,15 +131,28 @@ private void _searchBtn_Click(object sender, EventArgs e)

PrepareSearch(sender, e);

AsyncLoader.DoAsync(
() => _gitHoster.SearchForRepository(search),
HandleSearchResult,
ex =>
ThreadHelper.JoinableTaskFactory.RunAsync(
async () =>
{
MessageBox.Show(this, _strSearchFailed.Text + Environment.NewLine + ex.Exception.Message,
_strError.Text);
_searchBtn.Enabled = true;
});
try
{
await TaskScheduler.Default;

var repositories = _gitHoster.SearchForRepository(search);

await this.SwitchToMainThreadAsync();

HandleSearchResult(repositories);
}
catch (Exception ex) when (!(ex is OperationCanceledException))
{
await this.SwitchToMainThreadAsync();

MessageBox.Show(this, _strSearchFailed.Text + Environment.NewLine + ex.Message, _strError.Text);
_searchBtn.Enabled = true;
}
})
.FileAndForget();
}

private void _getFromUserBtn_Click(object sender, EventArgs e)
Expand All @@ -138,23 +165,37 @@ private void _getFromUserBtn_Click(object sender, EventArgs e)

PrepareSearch(sender, e);

AsyncLoader.DoAsync(
() => _gitHoster.GetRepositoriesOfUser(search.Trim()),
HandleSearchResult,
ex =>
ThreadHelper.JoinableTaskFactory.RunAsync(
async () =>
{
if (ex.Exception.Message.Contains("404"))
try
{
MessageBox.Show(this, _strUserNotFound.Text, _strError.Text);
await TaskScheduler.Default;

var repositories = _gitHoster.GetRepositoriesOfUser(search.Trim());

await this.SwitchToMainThreadAsync();

HandleSearchResult(repositories);
}
else
catch (Exception ex) when (!(ex is OperationCanceledException))
{
MessageBox.Show(this, _strCouldNotFetchReposOfUser.Text + Environment.NewLine +
ex.Exception.Message, _strError.Text);
await this.SwitchToMainThreadAsync();

if (ex.Message.Contains("404"))
{
MessageBox.Show(this, _strUserNotFound.Text, _strError.Text);
}
else
{
MessageBox.Show(this, _strCouldNotFetchReposOfUser.Text + Environment.NewLine +
ex.Message, _strError.Text);
}

_searchBtn.Enabled = true;
}

_searchBtn.Enabled = true;
});
})
.FileAndForget();
}

private void PrepareSearch(object sender, EventArgs e)
Expand Down
Loading

0 comments on commit ab4fa7c

Please sign in to comment.