Skip to content

Code quality: Move Git operations to a different thread #13608

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
57ac822
Use a task to fetch branches
ferrariofilippo Oct 27, 2023
ad6f72a
Delay repository head sorting
ferrariofilippo Oct 27, 2023
94d50b6
Move some git operations to a different thread
ferrariofilippo Oct 29, 2023
6ce6cba
Move more git operations to a different thread
ferrariofilippo Oct 30, 2023
c58b6ca
Merge branch 'main' into Git_Tests
ferrariofilippo Oct 30, 2023
5ad0970
GitHub: Preview deploy action (#13615)
yaira2 Oct 30, 2023
013ea59
Merge branch 'main' into Git_Tests
yaira2 Oct 30, 2023
eea0fb2
GitHub: Preview deploy action
yaira2 Oct 30, 2023
6330b43
Dispose the thread when not in use
ferrariofilippo Oct 31, 2023
3963d0c
Merge branch 'main' into Git_Tests
ferrariofilippo Oct 31, 2023
2119e12
Use Interlocked
ferrariofilippo Oct 31, 2023
bfc2cb2
Update GitHelpers.cs
ferrariofilippo Oct 31, 2023
eac354c
Update src/Files.App/Utils/Git/GitHelpers.cs
ferrariofilippo Oct 31, 2023
0d890bc
Update src/Files.App/Utils/Git/GitHelpers.cs
ferrariofilippo Oct 31, 2023
6190177
Update src/Files.App/Utils/Git/GitHelpers.cs
ferrariofilippo Oct 31, 2023
d95cd7a
Update src/Files.App/Utils/Git/GitHelpers.cs
ferrariofilippo Oct 31, 2023
4cef968
Update src/Files.App/Utils/Git/GitHelpers.cs
ferrariofilippo Oct 31, 2023
1494fc9
Update src/Files.App/Utils/Git/GitHelpers.cs
ferrariofilippo Oct 31, 2023
f89d8fe
Update src/Files.App/Utils/Git/GitHelpers.cs
ferrariofilippo Oct 31, 2023
e3993cf
Use methods
ferrariofilippo Oct 31, 2023
22ba1b1
Fix errors
ferrariofilippo Oct 31, 2023
5c32a0d
Use async suffix
ferrariofilippo Oct 31, 2023
9365d41
Manage exceptions
ferrariofilippo Nov 4, 2023
e0497dc
Merge branch 'main' into Git_Tests
ferrariofilippo Nov 4, 2023
8228dca
Merge branch 'main' into Git_Tests
ferrariofilippo Nov 5, 2023
42ac22e
Git columns are not loaded
ferrariofilippo Nov 5, 2023
8694b2d
Catch git exceptions
ferrariofilippo Nov 8, 2023
a4affb6
Merge branch 'main' into Git_Tests
ferrariofilippo Nov 21, 2023
1bd2cde
Fix a bug where branches flyout might automatically switch back to lo…
ferrariofilippo Nov 21, 2023
575efb8
Delay git info fetching
ferrariofilippo Nov 23, 2023
66f37c4
Delay branch load
ferrariofilippo Nov 23, 2023
5043b3c
Squashed commit of the following:
yaira2 Nov 23, 2023
4105051
Merge branch 'main' into Git_Tests
ferrariofilippo Nov 23, 2023
fbc9380
Hide Git status column by default
ferrariofilippo Nov 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Files.App/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ await SafetyExtensions.IgnoreExceptions(async () =>
},
Logger);

// Dispose git operations' thread
GitHelpers.TryDispose();

// Destroy cached properties windows
FilePropertiesHelpers.DestroyCachedWindows();
AppModel.IsMainWindowClosed = true;
Expand Down
18 changes: 3 additions & 15 deletions src/Files.App/Data/Models/CurrentInstanceViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,27 +165,15 @@ public string? GitRepositoryPath
set
{
if (SetProperty(ref gitRepositoryPath, value))
{
OnPropertyChanged(nameof(IsGitRepository));
OnPropertyChanged(nameof(GitBranchName));
}
}
}

private string gitBranchName = string.Empty;
public string GitBranchName
{
get
{
if (IsGitRepository)
return GitHelpers.GetRepositoryHeadName(gitRepositoryPath);

return string.Empty;
}
}

public void UpdateCurrentBranchName()
{
OnPropertyChanged(nameof(GitBranchName));
get => gitBranchName;
set => SetProperty(ref gitBranchName, value);
}
}
}
48 changes: 29 additions & 19 deletions src/Files.App/Data/Models/DirectoryPropertiesViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public class DirectoryPropertiesViewModel : ObservableObject

private readonly ObservableCollection<string> _remoteBranches = new();

public bool IsBranchesFlyoutExpaned { get; set; } = false;

private string? _DirectoryItemCount;
public string? DirectoryItemCount
{
Expand Down Expand Up @@ -92,38 +94,46 @@ public DirectoryPropertiesViewModel()
=> GitHelpers.CreateNewBranchAsync(_gitRepositoryPath!, _localBranches[ACTIVE_BRANCH_INDEX]));
}

public void UpdateGitInfo(bool isGitRepository, string? repositoryPath, BranchItem[] branches)
public void UpdateGitInfo(bool isGitRepository, string? repositoryPath, BranchItem? head)
{
GitBranchDisplayName = isGitRepository &&
branches.Any() &&
!(ContentPageContext.ShellPage!.InstanceViewModel.IsPageTypeSearchResults)
? branches[ACTIVE_BRANCH_INDEX].Name
head is not null &&
!ContentPageContext.ShellPage!.InstanceViewModel.IsPageTypeSearchResults
? head.Name
: null;

_gitRepositoryPath = repositoryPath;
ShowLocals = true;

// Change ShowLocals value only if branches flyout is closed
if (!IsBranchesFlyoutExpaned)
ShowLocals = true;

var behind = branches.Any() ? branches[0].BehindBy ?? 0 : 0;
var ahead = branches.Any() ? branches[0].AheadBy ?? 0 : 0;
var behind = head is not null ? head.BehindBy ?? 0 : 0;
var ahead = head is not null ? head.AheadBy ?? 0 : 0;

ExtendedStatusInfo = string.Format("GitSyncStatusExtendedInfo".GetLocalizedResource(), ahead, behind);
StatusInfo = $"{ahead} / {behind}";
}

if (isGitRepository)
{
_localBranches.Clear();
_remoteBranches.Clear();
public async Task LoadBranches()
{
if (string.IsNullOrEmpty(_gitRepositoryPath))
return;

foreach (var branch in branches)
{
if (branch.IsRemote)
_remoteBranches.Add(branch.Name);
else
_localBranches.Add(branch.Name);
}
var branches = await GitHelpers.GetBranchesNames(_gitRepositoryPath);

_localBranches.Clear();
_remoteBranches.Clear();

SelectedBranchIndex = ACTIVE_BRANCH_INDEX;
foreach (var branch in branches)
{
if (branch.IsRemote)
_remoteBranches.Add(branch.Name);
else
_localBranches.Add(branch.Name);
}

SelectedBranchIndex = ShowLocals ? ACTIVE_BRANCH_INDEX : -1;
}
}
}
106 changes: 55 additions & 51 deletions src/Files.App/Data/Models/ItemViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,13 @@ public GitProperties EnabledGitProperties
{
if (SetProperty(ref _EnabledGitProperties, value) && value is not GitProperties.None)
{
filesAndFolders.ToList().ForEach(async item => {
filesAndFolders.ToList().ForEach(async item =>
{
if (item is GitItem gitItem &&
(!gitItem.StatusPropertiesInitialized && value is GitProperties.All or GitProperties.Status
|| !gitItem.CommitPropertiesInitialized && value is GitProperties.All or GitProperties.Commit))
{
try
{
await Task.Run(async () => await LoadGitPropertiesAsync(gitItem, loadPropsCTS));
}
catch (OperationCanceledException)
{
// Ignored
}
await LoadGitPropertiesAsync(gitItem);
}
});
}
Expand Down Expand Up @@ -169,7 +163,7 @@ public async Task SetWorkingDirectoryAsync(string? value)
}

GitDirectory = GitHelpers.GetGitRepositoryPath(WorkingDirectory, pathRoot);
IsValidGitDirectory = !string.IsNullOrEmpty(GitHelpers.GetRepositoryHeadName(GitDirectory));
IsValidGitDirectory = !string.IsNullOrEmpty((await GitHelpers.GetRepositoryHead(GitDirectory))?.Name);

OnPropertyChanged(nameof(WorkingDirectory));
}
Expand Down Expand Up @@ -1229,9 +1223,6 @@ await SafetyExtensions.IgnoreExceptions(() =>
gp.InitializeExtendedGroupHeaderInfoAsync();
}));
}

if (EnabledGitProperties != GitProperties.None && item is GitItem gitItem)
await LoadGitPropertiesAsync(gitItem, cts);
}
}, cts.Token);
}
Expand All @@ -1245,57 +1236,70 @@ await SafetyExtensions.IgnoreExceptions(() =>
}
}

private async Task LoadGitPropertiesAsync(GitItem gitItem, CancellationTokenSource cts)
public async Task LoadGitPropertiesAsync(GitItem gitItem)
{
var getStatus = EnabledGitProperties is GitProperties.All or GitProperties.Status && !gitItem.StatusPropertiesInitialized;
var getCommit = EnabledGitProperties is GitProperties.All or GitProperties.Commit && !gitItem.CommitPropertiesInitialized;

if (!getStatus && !getCommit)
return;

if (GitHelpers.IsRepositoryEx(gitItem.ItemPath, out var repoPath) &&
!string.IsNullOrEmpty(repoPath))
{
cts.Token.ThrowIfCancellationRequested();

if (getStatus)
gitItem.StatusPropertiesInitialized = true;

if (getCommit)
gitItem.CommitPropertiesInitialized = true;
var cts = loadPropsCTS;

await SafetyExtensions.IgnoreExceptions(() =>
try
{
await Task.Run(async () =>
{
return dispatcherQueue.EnqueueOrInvokeAsync(() =>

if (GitHelpers.IsRepositoryEx(gitItem.ItemPath, out var repoPath) &&
!string.IsNullOrEmpty(repoPath))
{
var repo = new Repository(repoPath);
GitItemModel gitItemModel = GitHelpers.GetGitInformationForItem(repo, gitItem.ItemPath, getStatus, getCommit);
cts.Token.ThrowIfCancellationRequested();

if (getStatus)
{
gitItem.UnmergedGitStatusIcon = gitItemModel.Status switch
{
ChangeKind.Added => (Microsoft.UI.Xaml.Style)Microsoft.UI.Xaml.Application.Current.Resources["ColorIconGitAdded"],
ChangeKind.Deleted => (Microsoft.UI.Xaml.Style)Microsoft.UI.Xaml.Application.Current.Resources["ColorIconGitDeleted"],
ChangeKind.Modified => (Microsoft.UI.Xaml.Style)Microsoft.UI.Xaml.Application.Current.Resources["ColorIconGitModified"],
ChangeKind.Untracked => (Microsoft.UI.Xaml.Style)Microsoft.UI.Xaml.Application.Current.Resources["ColorIconGitUntracked"],
_ => null,
};
gitItem.UnmergedGitStatusName = gitItemModel.StatusHumanized;
}
gitItem.StatusPropertiesInitialized = true;

if (getCommit)
gitItem.CommitPropertiesInitialized = true;

await SafetyExtensions.IgnoreExceptions(() =>
{
gitItem.GitLastCommitDate = gitItemModel.LastCommit?.Author.When;
gitItem.GitLastCommitMessage = gitItemModel.LastCommit?.MessageShort;
gitItem.GitLastCommitAuthor = gitItemModel.LastCommit?.Author.Name;
gitItem.GitLastCommitSha = gitItemModel.LastCommit?.Sha.Substring(0, 7);
gitItem.GitLastCommitFullSha = gitItemModel.LastCommit?.Sha;
}
return dispatcherQueue.EnqueueOrInvokeAsync(() =>
{
var repo = new Repository(repoPath);
GitItemModel gitItemModel = GitHelpers.GetGitInformationForItem(repo, gitItem.ItemPath, getStatus, getCommit);

repo.Dispose();
},
Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
});
if (getStatus)
{
gitItem.UnmergedGitStatusIcon = gitItemModel.Status switch
{
ChangeKind.Added => (Microsoft.UI.Xaml.Style)Microsoft.UI.Xaml.Application.Current.Resources["ColorIconGitAdded"],
ChangeKind.Deleted => (Microsoft.UI.Xaml.Style)Microsoft.UI.Xaml.Application.Current.Resources["ColorIconGitDeleted"],
ChangeKind.Modified => (Microsoft.UI.Xaml.Style)Microsoft.UI.Xaml.Application.Current.Resources["ColorIconGitModified"],
ChangeKind.Untracked => (Microsoft.UI.Xaml.Style)Microsoft.UI.Xaml.Application.Current.Resources["ColorIconGitUntracked"],
_ => null,
};
gitItem.UnmergedGitStatusName = gitItemModel.StatusHumanized;
}
if (getCommit)
{
gitItem.GitLastCommitDate = gitItemModel.LastCommit?.Author.When;
gitItem.GitLastCommitMessage = gitItemModel.LastCommit?.MessageShort;
gitItem.GitLastCommitAuthor = gitItemModel.LastCommit?.Author.Name;
gitItem.GitLastCommitSha = gitItemModel.LastCommit?.Sha.Substring(0, 7);
gitItem.GitLastCommitFullSha = gitItemModel.LastCommit?.Sha;
}

repo.Dispose();
},
Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
});
}
}, cts.Token);
}
catch (OperationCanceledException)
{
// Ignored
}
}

Expand Down Expand Up @@ -1439,7 +1443,7 @@ private async Task RapidAddItemsToCollectionAsync(string? path, LibraryItem? lib
IsTypeCloudDrive = syncStatus != CloudDriveSyncStatus.NotSynced && syncStatus != CloudDriveSyncStatus.Unknown,
IsTypeGitRepository = IsValidGitDirectory
});

if (!HasNoWatcher)
WatchForDirectoryChanges(path, syncStatus);
if (IsValidGitDirectory)
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Services/Settings/FoldersSettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public bool ShowSizeColumn

public bool ShowGitStatusColumn
{
get => Get(true);
get => Get(false);
set => Set(value);
}

Expand Down
5 changes: 4 additions & 1 deletion src/Files.App/UserControls/StatusBarControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,10 @@
</Button.Content>

<Button.Flyout>
<Flyout x:Name="BranchesFlyout" Opening="BranchesFlyout_Opening">
<Flyout
x:Name="BranchesFlyout"
Closing="BranchesFlyout_Closing"
Opening="BranchesFlyout_Opening">
<Grid
Width="300"
Height="340"
Expand Down
12 changes: 11 additions & 1 deletion src/Files.App/UserControls/StatusBarControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,28 @@ public StatusBarControl()
InitializeComponent();
}

private void BranchesFlyout_Opening(object sender, object e)
private async void BranchesFlyout_Opening(object _, object e)
{
if (DirectoryPropertiesViewModel is null)
return;

DirectoryPropertiesViewModel.IsBranchesFlyoutExpaned = true;
DirectoryPropertiesViewModel.ShowLocals = true;
await DirectoryPropertiesViewModel.LoadBranches();
DirectoryPropertiesViewModel.SelectedBranchIndex = DirectoryPropertiesViewModel.ACTIVE_BRANCH_INDEX;
}

private void BranchesList_ItemClick(object sender, ItemClickEventArgs e)
{
BranchesFlyout.Hide();
}

private void BranchesFlyout_Closing(object _, object e)
{
if (DirectoryPropertiesViewModel is null)
return;

DirectoryPropertiesViewModel.IsBranchesFlyoutExpaned = false;
}
}
}
Loading