Skip to content
This repository was archived by the owner on Dec 5, 2024. It is now read-only.

Task/Cache Jenga 2: Fixing initialization and git installation and other fixes #604

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2270f0e
Loading spinner and progress reporting
shana Feb 19, 2018
abeb39e
Fidget that spinner
shana Feb 19, 2018
ff27758
Dedupe code
shana Mar 5, 2018
fbff071
Fix typo
shana Mar 5, 2018
24be3ee
DataTimeout should never be infinite, otherwise invalid data will nev…
shana Mar 5, 2018
f2ee4ef
Fix initialization sequence and cache invalidation on startup
shana Mar 5, 2018
883ed16
GitInstallDetails is better off under GitInstaller
shana Mar 5, 2018
4bc9602
Merge enhancements/loading
shana Mar 5, 2018
95f1cb7
Fix a bunch of bugs in the git installation sequence and update progress
shana Mar 5, 2018
4c1d33c
This might be accessed before things have a chance to initialize
shana Mar 5, 2018
a850584
Remove debug output
shana Mar 5, 2018
447fd9c
Replay any cache invalidation requests that happen before RepositoryM…
shana Mar 5, 2018
6d17c4b
Fix setting busy flag when tasks are done
shana Mar 5, 2018
95449aa
Fix the error and end pattern of process task
shana Mar 5, 2018
b814a24
Merge shana/kill-dead-code into shana/fix-initialization
shana Mar 6, 2018
c9436c2
Make sure the threaded and non-threaded API is easily distinguishable
shana Mar 7, 2018
711190b
Fix continuing when something fails
shana Mar 7, 2018
af2b677
Fix test, it was checking the wrong md5
shana Mar 7, 2018
fa188d3
Fix calling finally handlers and add regression test for it
shana Mar 7, 2018
0cd1013
Clarify why we need to do this manually
shana Mar 7, 2018
d763fe6
This needs to be a Then, nobody should be doing Finally except for Ho…
shana Mar 7, 2018
c5e9d8a
I want to see if this is fixed now in appveyor
shana Mar 7, 2018
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
67 changes: 44 additions & 23 deletions src/GitHub.Api/Application/ApplicationManagerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@ abstract class ApplicationManagerBase : IApplicationManager
protected static ILogging Logger { get; } = LogHelper.GetLogger<IApplicationManager>();

private RepositoryManager repositoryManager;
private Progress progressReporter;
protected bool isBusy;
public event Action<IProgress> OnProgress
{
add { progressReporter.OnProgress += value; }
remove { progressReporter.OnProgress -= value; }
}

public ApplicationManagerBase(SynchronizationContext synchronizationContext)
{
progressReporter = new Progress();
SynchronizationContext = synchronizationContext;
SynchronizationContext.SetSynchronizationContext(SynchronizationContext);
ThreadingHelper.SetUIThread();
Expand Down Expand Up @@ -47,7 +55,7 @@ public void Run(bool firstRun)
{
Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory);

var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath();
var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath();
if (gitExecutablePath != null && gitExecutablePath.FileExists()) // we have a git path
{
Logger.Trace("Using git install path from settings: {0}", gitExecutablePath);
Expand All @@ -57,9 +65,12 @@ public void Run(bool firstRun)
{
Logger.Trace("No git path found in settings");

var initEnvironmentTask = new ActionTask<NPath>(CancellationToken, (b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI };
isBusy = true;
var initEnvironmentTask = new ActionTask<NPath>(CancellationToken,
(b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI };
var findExecTask = new FindExecTask("git", CancellationToken)
.FinallyInUI((b, ex, path) => {
.FinallyInUI((b, ex, path) =>
{
if (b && path != null)
{
Logger.Trace("FindExecTask Success: {0}", path);
Expand All @@ -70,13 +81,21 @@ public void Run(bool firstRun)
Logger.Warning("FindExecTask Failure");
Logger.Error("Git not found");
}
isBusy = false;
});

var installDetails = new GitInstallDetails(Environment.UserCachePath, true);
var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails);
var gitInstaller = new GitInstaller(Environment, CancellationToken);

// if successful, continue with environment initialization, otherwise try to find an existing git installation
gitInstaller.SetupGitIfNeeded(initEnvironmentTask, findExecTask);
var setupTask = gitInstaller.SetupGitIfNeeded();
setupTask.Progress(progressReporter.UpdateProgress);
setupTask.OnEnd += (thisTask, result, success, exception) =>
{
if (success && result != null)
thisTask.Then(initEnvironmentTask);
else
thisTask.Then(findExecTask);
};
}
}

Expand Down Expand Up @@ -131,6 +150,7 @@ public void RestartRepository()
repositoryManager.Initialize();
Environment.Repository.Initialize(repositoryManager);
repositoryManager.Start();
Environment.Repository.Start();
Logger.Trace($"Got a repository? {Environment.Repository}");
}
}
Expand Down Expand Up @@ -171,34 +191,34 @@ protected void SetupMetrics(string unityVersion, bool firstRun)
/// <param name="gitExecutablePath"></param>
private void InitializeEnvironment(NPath gitExecutablePath)
{
var afterGitSetup = new ActionTask(CancellationToken, RestartRepository)
.ThenInUI(InitializeUI);

Environment.GitExecutablePath = gitExecutablePath;
Environment.User.Initialize(GitClient);

var afterGitSetup = new ActionTask(CancellationToken, RestartRepository)
.ThenInUI(InitializeUI);

ITask task = afterGitSetup;
if (Environment.IsWindows)
{
var task = GitClient
.GetConfig("credential.helper", GitConfigSource.Global)
.Then((b, credentialHelper) => {
if (string.IsNullOrEmpty(credentialHelper))
var credHelperTask = GitClient.GetConfig("credential.helper", GitConfigSource.Global);
credHelperTask.OnEnd += (thisTask, credentialHelper, success, exception) =>
{
if (!success || string.IsNullOrEmpty(credentialHelper))
{
Logger.Warning("No Windows CredentialHelper found: Setting to wincred");
throw new ArgumentNullException(nameof(credentialHelper));
thisTask
.Then(GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global))
.Then(afterGitSetup);
}
});
// if there's no credential helper, set it before restarting the repository
task.Then(GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global), TaskRunOptions.OnFailure)
.Then(afterGitSetup, taskIsTopOfChain: true);

// if there's a credential helper, we're good, restart the repository
task.Then(afterGitSetup, TaskRunOptions.OnSuccess, taskIsTopOfChain: true);
else
thisTask.Then(afterGitSetup);
};
task = credHelperTask;
}

afterGitSetup.Start();
task.Start();
}


private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
Expand Down Expand Up @@ -228,6 +248,7 @@ public void Dispose()
public ISettings SystemSettings { get; protected set; }
public ISettings UserSettings { get; protected set; }
public IUsageTracker UsageTracker { get; protected set; }
public bool IsBusy { get { return isBusy || (RepositoryManager?.IsBusy ?? false); } }
protected TaskScheduler UIScheduler { get; private set; }
protected SynchronizationContext SynchronizationContext { get; private set; }
protected IRepositoryManager RepositoryManager { get { return repositoryManager; } }
Expand Down
3 changes: 2 additions & 1 deletion src/GitHub.Api/Application/IApplicationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ public interface IApplicationManager : IDisposable
ITaskManager TaskManager { get; }
IGitClient GitClient { get; }
IUsageTracker UsageTracker { get; }

bool IsBusy { get; }
void Run(bool firstRun);
void RestartRepository();
ITask InitializeRepository();
event Action<IProgress> OnProgress;
}
}
4 changes: 2 additions & 2 deletions src/GitHub.Api/Cache/CacheInterfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public interface IConfigRemoteDictionary : IDictionary<string, ConfigRemote>
public interface IBranchCache : IManagedCache
{
ConfigRemote? CurrentConfigRemote { get; set; }
ConfigBranch? CurentConfigBranch { get; set; }
ConfigBranch? CurrentConfigBranch { get; set; }

GitBranch[] LocalBranches { get; set; }
GitBranch[] RemoteBranches { get; set; }
Expand All @@ -105,7 +105,7 @@ public interface IBranchCache : IManagedCache
public interface IRepositoryInfoCache : IManagedCache
{
GitRemote? CurrentGitRemote { get; set; }
GitBranch? CurentGitBranch { get; set; }
GitBranch? CurrentGitBranch { get; set; }
}

public interface IGitLogCache : IManagedCache
Expand Down
1 change: 1 addition & 0 deletions src/GitHub.Api/Git/IRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,6 @@ public interface IRepository : IEquatable<IRepository>
event Action<CacheUpdateEvent> LocksChanged;
event Action<CacheUpdateEvent> RemoteBranchListChanged;
event Action<CacheUpdateEvent> LocalAndRemoteBranchListChanged;
void Start();
}
}
30 changes: 24 additions & 6 deletions src/GitHub.Api/Git/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Repository : IEquatable<Repository>, IRepository
private ICacheContainer cacheContainer;
private UriString cloneUrl;
private string name;
private HashSet<CacheType> cacheInvalidationRequests = new HashSet<CacheType>();

public event Action<CacheUpdateEvent> LogChanged;
public event Action<CacheUpdateEvent> TrackingStatusChanged;
Expand All @@ -39,7 +40,7 @@ public Repository(NPath localPath, ICacheContainer container)
LocalPath = localPath;

cacheContainer = container;
cacheContainer.CacheInvalidated += CacheContainer_OnCacheInvalidated;
cacheContainer.CacheInvalidated += InvalidateCache;
cacheContainer.CacheUpdated += CacheContainer_OnCacheUpdated;
}

Expand All @@ -58,6 +59,14 @@ public void Initialize(IRepositoryManager initRepositoryManager)
repositoryManager.RemoteBranchesUpdated += RepositoryManagerOnRemoteBranchesUpdated;
}

public void Start()
{
foreach (var req in cacheInvalidationRequests)
{
InvalidateCache(req);
}
}

public ITask SetupRemote(string remote, string remoteUrl)
{
Guard.ArgumentNotNullOrWhiteSpace(remote, "remote");
Expand Down Expand Up @@ -275,8 +284,16 @@ private void CheckBranchCacheEvent(CacheUpdateEvent cacheUpdateEvent)
}
}

private void CacheContainer_OnCacheInvalidated(CacheType cacheType)
private void InvalidateCache(CacheType cacheType)
{
if (repositoryManager == null)
{
if (!cacheInvalidationRequests.Contains(cacheType))
cacheInvalidationRequests.Add(cacheType);
return;
}


switch (cacheType)
{
case CacheType.BranchCache:
Expand All @@ -298,6 +315,7 @@ private void CacheContainer_OnCacheInvalidated(CacheType cacheType)
break;

case CacheType.RepositoryInfoCache:
repositoryManager?.UpdateRepositoryInfo();
break;

case CacheType.GitStatusEntriesCache:
Expand Down Expand Up @@ -523,8 +541,8 @@ public GitBranch[] RemoteBranches

private ConfigBranch? CurrentConfigBranch
{
get { return this.cacheContainer.BranchCache.CurentConfigBranch; }
set { cacheContainer.BranchCache.CurentConfigBranch = value; }
get { return this.cacheContainer.BranchCache.CurrentConfigBranch; }
set { cacheContainer.BranchCache.CurrentConfigBranch = value; }
}

private ConfigRemote? CurrentConfigRemote
Expand Down Expand Up @@ -553,8 +571,8 @@ public List<GitStatusEntry> CurrentChanges

public GitBranch? CurrentBranch
{
get { return cacheContainer.RepositoryInfoCache.CurentGitBranch; }
private set { cacheContainer.RepositoryInfoCache.CurentGitBranch = value; }
get { return cacheContainer.RepositoryInfoCache.CurrentGitBranch; }
private set { cacheContainer.RepositoryInfoCache.CurrentGitBranch = value; }
}

public string CurrentBranchName => CurrentConfigBranch?.Name;
Expand Down
16 changes: 8 additions & 8 deletions src/GitHub.Api/Git/RepositoryManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public interface IRepositoryManager : IDisposable
void UpdateGitAheadBehindStatus();
void UpdateLocks();
int WaitForEvents();
void UpdateRepositoryInfo();

IGitConfig Config { get; }
IGitClient GitClient { get; }
Expand Down Expand Up @@ -331,10 +332,9 @@ public ITask DiscardChanges(GitStatusEntry[] gitStatusEntries)
if (itemsToRevert.Any())
{
gitDiscardTask = GitClient.Discard(itemsToRevert);
task
.Then(gitDiscardTask)
// we're appending a new continuation, we need to reset the finally handler
// so it runs after the discard task
task.Then(gitDiscardTask)
// we're appending a new continuation after HookupHandlers has run,
// we need to set the finally handler manually so it runs at the end of everything
.Finally(s =>
{
watcher.Start();
Expand Down Expand Up @@ -379,7 +379,7 @@ public void UpdateGitAheadBehindStatus()
public void UpdateLocks()
{
GitClient.ListLocks(false)
.Finally((success, locks) =>
.Then((success, locks) =>
{
if (success)
{
Expand All @@ -399,7 +399,7 @@ private ITask HookupHandlers(ITask task, bool filesystemChangesExpected)
var isExclusive = task.IsChainExclusive();
task.GetTopOfChain().OnStart += t =>
{
if (t.Affinity == TaskAffinity.Exclusive)
if (isExclusive)
{
Logger.Trace("Starting Operation - Setting Busy Flag");
IsBusy = true;
Expand Down Expand Up @@ -443,7 +443,7 @@ private void SetupWatcher()
private void UpdateHead()
{
Logger.Trace("UpdateHead");
UpdateCurrentBranchAndRemote();
UpdateRepositoryInfo();
UpdateGitLog();
}

Expand All @@ -452,7 +452,7 @@ private string GetCurrentHead()
return repositoryPaths.DotGitHead.ReadAllLines().FirstOrDefault();
}

private void UpdateCurrentBranchAndRemote()
public void UpdateRepositoryInfo()
{
ConfigBranch? branch;
ConfigRemote? remote;
Expand Down
21 changes: 19 additions & 2 deletions src/GitHub.Api/Helpers/Progress.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using GitHub.Logging;
using System;

namespace GitHub.Unity
Expand All @@ -11,25 +12,41 @@ public interface IProgress
float Percentage { get; }
long Value { get; }
long Total { get; }
string Message { get; }
event Action<IProgress> OnProgress;
}

public class Progress : IProgress
{
private static ILogging Logger = LogHelper.GetLogger<Progress>();
public ITask Task { get; internal set; }
public float Percentage { get { return Total > 0 ? (float)(double)Value / Total : 0f; } }
public long Value { get; internal set; }
public long Total { get; internal set; }
public string Message { get; internal set; }

private long previousValue;
private float averageSpeed = -1f;
private float lastSpeed = 0f;
private float smoothing = 0.005f;
public event Action<IProgress> OnProgress;

public void UpdateProgress(long value, long total)
public void UpdateProgress(IProgress progress)
{
Task = progress.Task;
UpdateProgress(progress.Value, progress.Total, progress.Message);
}

public void UpdateProgress(long value, long total, string message = null)
{
previousValue = Value;
Total = total;
Value = value;
Message = message ?? Message;
if (Total == 0 || ((float)(double)Value / Total) - ((float)(double)previousValue / Total) > 1f / 100f)
{ // signal progress in 1% increments or if we don't know what the total is
previousValue = Value;
OnProgress?.Invoke(this);
}
}
}
}
2 changes: 0 additions & 2 deletions src/GitHub.Api/IO/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public static bool Copy(Stream source, Stream destination,
Func<long, long, bool> progress = null,
int progressUpdateRate = 100)
{
var logger = LogHelper.GetLogger("Copy");
byte[] buffer = new byte[chunkSize];
int bytesRead = 0;
long totalRead = 0;
Expand Down Expand Up @@ -62,7 +61,6 @@ public static bool Copy(Stream source, Stream destination,
timeToFinish = Math.Max(1L,
(long)((totalSize - totalRead) / (averageSpeed / progressUpdateRate)));

logger.Trace($"totalRead: {totalRead} of {totalSize}");
success = progress(totalRead, timeToFinish);
if (!success)
break;
Expand Down
Loading