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

Commit 146a781

Browse files
authored
Merge pull request #610 from github-for-unity/1.0rc/master
1.0RC preparation branch
2 parents 6dc4d73 + 06805c4 commit 146a781

File tree

126 files changed

+4242
-3103
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+4242
-3103
lines changed

src/GitHub.Api/Application/ApplicationManagerBase.cs

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,17 @@ abstract class ApplicationManagerBase : IApplicationManager
1212
protected static ILogging Logger { get; } = LogHelper.GetLogger<IApplicationManager>();
1313

1414
private RepositoryManager repositoryManager;
15+
private Progress progressReporter;
16+
protected bool isBusy;
17+
public event Action<IProgress> OnProgress
18+
{
19+
add { progressReporter.OnProgress += value; }
20+
remove { progressReporter.OnProgress -= value; }
21+
}
1522

1623
public ApplicationManagerBase(SynchronizationContext synchronizationContext)
1724
{
25+
progressReporter = new Progress();
1826
SynchronizationContext = synchronizationContext;
1927
SynchronizationContext.SetSynchronizationContext(SynchronizationContext);
2028
ThreadingHelper.SetUIThread();
@@ -46,6 +54,8 @@ public void Run(bool firstRun)
4654
{
4755
Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory);
4856

57+
isBusy = true;
58+
4959
var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath();
5060
if (gitExecutablePath.HasValue && gitExecutablePath.Value.FileExists()) // we have a git path
5161
{
@@ -56,32 +66,41 @@ public void Run(bool firstRun)
5666
{
5767
Logger.Trace("No git path found in settings");
5868

59-
var initEnvironmentTask = new ActionTask<NPath>(CancellationToken, (_, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI };
69+
var initEnvironmentTask = new ActionTask<NPath>(CancellationToken,
70+
(b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI };
6071
var findExecTask = new FindExecTask("git", CancellationToken)
61-
.FinallyInUI((b, ex, path) => {
72+
.FinallyInUI((b, ex, path) =>
73+
{
6274
if (b && path.IsInitialized)
6375
{
64-
Logger.Trace("FindExecTask Success: {0}", path);
76+
//Logger.Trace("FindExecTask Success: {0}", path);
6577
InitializeEnvironment(path);
6678
}
6779
else
6880
{
69-
Logger.Warning("FindExecTask Failure");
81+
//Logger.Warning("FindExecTask Failure");
7082
Logger.Error("Git not found");
7183
}
7284
});
7385

74-
var installDetails = new GitInstallDetails(Environment.UserCachePath, true);
75-
var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails);
86+
var gitInstaller = new GitInstaller(Environment, CancellationToken);
7687

7788
// if successful, continue with environment initialization, otherwise try to find an existing git installation
78-
gitInstaller.SetupGitIfNeeded(initEnvironmentTask, findExecTask);
89+
var setupTask = gitInstaller.SetupGitIfNeeded();
90+
setupTask.Progress(progressReporter.UpdateProgress);
91+
setupTask.OnEnd += (thisTask, result, success, exception) =>
92+
{
93+
if (success && result.IsInitialized)
94+
thisTask.Then(initEnvironmentTask);
95+
else
96+
thisTask.Then(findExecTask);
97+
};
7998
}
8099
}
81100

82101
public ITask InitializeRepository()
83102
{
84-
Logger.Trace("Running Repository Initialize");
103+
//Logger.Trace("Running Repository Initialize");
85104

86105
var targetPath = NPath.CurrentDirectory;
87106

@@ -124,17 +143,18 @@ public void RestartRepository()
124143
{
125144
if (Environment.RepositoryPath.IsInitialized)
126145
{
127-
repositoryManager = Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, Environment.FileSystem, Environment.RepositoryPath);
146+
repositoryManager = Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, Environment.FileSystem, Environment.RepositoryPath);
128147
repositoryManager.Initialize();
129-
Environment.Repository.Initialize(repositoryManager);
148+
Environment.Repository.Initialize(repositoryManager, TaskManager);
130149
repositoryManager.Start();
131-
Logger.Trace($"Got a repository? {Environment.Repository}");
150+
Environment.Repository.Start();
151+
Logger.Trace($"Got a repository? {(Environment.Repository != null ? Environment.Repository.LocalPath : "null")}");
132152
}
133153
}
134154

135155
protected void SetupMetrics(string unityVersion, bool firstRun)
136156
{
137-
Logger.Trace("Setup metrics");
157+
//Logger.Trace("Setup metrics");
138158

139159
var usagePath = Environment.UserCachePath.Combine(Constants.UsageFile);
140160

@@ -175,40 +195,35 @@ protected void SetupMetrics(string unityVersion, bool firstRun)
175195
/// <param name="octorunScriptPath"></param>
176196
private void InitializeEnvironment(NPath gitExecutablePath)
177197
{
198+
Environment.GitExecutablePath = gitExecutablePath;
199+
Environment.User.Initialize(GitClient);
200+
178201
var afterGitSetup = new ActionTask(CancellationToken, RestartRepository)
179202
.ThenInUI(InitializeUI);
180203

181-
Environment.GitExecutablePath = gitExecutablePath;
182-
Environment.User.Initialize(GitClient);
183204
SetupMetrics();
184-
205+
ITask task = afterGitSetup;
185206
if (Environment.IsWindows)
186207
{
187-
GitClient
188-
.GetConfig("credential.helper", GitConfigSource.Global)
189-
.Then((b, credentialHelper) => {
190-
if (!string.IsNullOrEmpty(credentialHelper))
191-
{
192-
Logger.Trace("Windows CredentialHelper: {0}", credentialHelper);
193-
afterGitSetup.Start();
194-
}
195-
else
208+
var credHelperTask = GitClient.GetConfig("credential.helper", GitConfigSource.Global);
209+
credHelperTask.OnEnd += (thisTask, credentialHelper, success, exception) =>
210+
{
211+
if (!success || string.IsNullOrEmpty(credentialHelper))
196212
{
197213
Logger.Warning("No Windows CredentialHelper found: Setting to wincred");
198-
199-
GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global)
200-
.Then(afterGitSetup)
201-
.Start();
214+
thisTask
215+
.Then(GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global))
216+
.Then(afterGitSetup);
202217
}
203-
})
204-
.Start();
205-
}
206-
else
207-
{
208-
afterGitSetup.Start();
218+
else
219+
thisTask.Then(afterGitSetup);
220+
};
221+
task = credHelperTask;
209222
}
223+
task.Start();
210224
}
211225

226+
212227
private bool disposed = false;
213228
protected virtual void Dispose(bool disposing)
214229
{
@@ -238,6 +253,7 @@ public void Dispose()
238253
public ISettings SystemSettings { get; protected set; }
239254
public ISettings UserSettings { get; protected set; }
240255
public IUsageTracker UsageTracker { get; protected set; }
256+
public bool IsBusy { get { return isBusy; } }
241257
protected TaskScheduler UIScheduler { get; private set; }
242258
protected SynchronizationContext SynchronizationContext { get; private set; }
243259
protected IRepositoryManager RepositoryManager { get { return repositoryManager; } }

src/GitHub.Api/Application/IApplicationManager.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ public interface IApplicationManager : IDisposable
1717
ITaskManager TaskManager { get; }
1818
IGitClient GitClient { get; }
1919
IUsageTracker UsageTracker { get; }
20-
20+
bool IsBusy { get; }
2121
void Run(bool firstRun);
2222
void RestartRepository();
2323
ITask InitializeRepository();
24+
event Action<IProgress> OnProgress;
2425
}
2526
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using GitHub.Logging;
5+
6+
namespace GitHub.Unity
7+
{
8+
public class CacheContainer : ICacheContainer
9+
{
10+
private static ILogging Logger = LogHelper.GetLogger<CacheContainer>();
11+
12+
private Dictionary<CacheType, Lazy<IManagedCache>> caches = new Dictionary<CacheType, Lazy<IManagedCache>>();
13+
14+
public event Action<CacheType> CacheInvalidated;
15+
public event Action<CacheType, DateTimeOffset> CacheUpdated;
16+
17+
public void SetCacheInitializer(CacheType cacheType, Func<IManagedCache> initializer)
18+
{
19+
caches.Add(cacheType, new Lazy<IManagedCache>(() => SetupCache(initializer())));
20+
}
21+
22+
public void ValidateAll()
23+
{
24+
// this can trigger invalidation requests fyi
25+
foreach (var cache in caches.Values)
26+
cache.Value.ValidateData();
27+
}
28+
29+
public void InvalidateAll()
30+
{
31+
foreach (var cache in caches.Values)
32+
{
33+
// force an invalidation if the cache is valid, otherwise it will do it on its own
34+
if (cache.Value.ValidateData())
35+
cache.Value.InvalidateData();
36+
}
37+
}
38+
39+
private IManagedCache SetupCache(IManagedCache cache)
40+
{
41+
cache.CacheInvalidated += OnCacheInvalidated;
42+
cache.CacheUpdated += OnCacheUpdated;
43+
return cache;
44+
}
45+
46+
public IManagedCache GetCache(CacheType cacheType)
47+
{
48+
return caches[cacheType].Value;
49+
}
50+
51+
public void CheckAndRaiseEventsIfCacheNewer(CacheType cacheType, CacheUpdateEvent cacheUpdateEvent)
52+
{
53+
var cache = GetCache(cacheType);
54+
var needsInvalidation = cache.ValidateData();
55+
if (!cacheUpdateEvent.IsInitialized || !needsInvalidation || cache.LastUpdatedAt != cacheUpdateEvent.UpdatedTime)
56+
{
57+
OnCacheUpdated(cache.CacheType, cache.LastUpdatedAt);
58+
}
59+
}
60+
61+
private void OnCacheUpdated(CacheType cacheType, DateTimeOffset datetime)
62+
{
63+
Logger.Trace("OnCacheUpdated cacheType:{0} datetime:{1}", cacheType, datetime);
64+
CacheUpdated.SafeInvoke(cacheType, datetime);
65+
}
66+
67+
private void OnCacheInvalidated(CacheType cacheType)
68+
{
69+
Logger.Trace("OnCacheInvalidated cacheType:{0}", cacheType);
70+
CacheInvalidated.SafeInvoke(cacheType);
71+
}
72+
73+
private bool disposed;
74+
private void Dispose(bool disposing)
75+
{
76+
if (disposed) return;
77+
disposed = true;
78+
79+
if (disposing)
80+
{
81+
foreach (var cache in caches.Values)
82+
{
83+
cache.Value.CacheInvalidated -= OnCacheInvalidated;
84+
cache.Value.CacheUpdated -= OnCacheUpdated;
85+
}
86+
}
87+
}
88+
89+
public void Dispose()
90+
{
91+
Dispose(true);
92+
GC.SuppressFinalize(this);
93+
}
94+
95+
public IBranchCache BranchCache { get { return (IBranchCache)caches[CacheType.Branches].Value; } }
96+
public IGitLogCache GitLogCache { get { return (IGitLogCache)caches[CacheType.GitLog].Value; } }
97+
public IGitAheadBehindCache GitTrackingStatusCache { get { return (IGitAheadBehindCache)caches[CacheType.GitAheadBehind].Value; } }
98+
public IGitStatusCache GitStatusEntriesCache { get { return (IGitStatusCache)caches[CacheType.GitStatus].Value; } }
99+
public IGitLocksCache GitLocksCache { get { return (IGitLocksCache)caches[CacheType.GitLocks].Value; } }
100+
public IGitUserCache GitUserCache { get { return (IGitUserCache)caches[CacheType.GitUser].Value; } }
101+
public IRepositoryInfoCache RepositoryInfoCache { get { return (IRepositoryInfoCache)caches[CacheType.RepositoryInfo].Value; } }
102+
}
103+
104+
[Serializable]
105+
public struct CacheUpdateEvent
106+
{
107+
[NonSerialized] private DateTimeOffset? updatedTimeValue;
108+
public string updatedTimeString;
109+
public CacheType cacheType;
110+
111+
public CacheUpdateEvent(CacheType type, DateTimeOffset when)
112+
{
113+
if (type == CacheType.None) throw new ArgumentOutOfRangeException(nameof(type));
114+
115+
cacheType = type;
116+
updatedTimeValue = when;
117+
updatedTimeString = when.ToString(Constants.Iso8601Format);
118+
}
119+
120+
public override int GetHashCode()
121+
{
122+
int hash = 17;
123+
hash = hash * 23 + cacheType.GetHashCode();
124+
hash = hash * 23 + (updatedTimeString?.GetHashCode() ?? 0);
125+
return hash;
126+
}
127+
128+
public override bool Equals(object other)
129+
{
130+
if (other is CacheUpdateEvent)
131+
return Equals((CacheUpdateEvent)other);
132+
return false;
133+
}
134+
135+
public bool Equals(CacheUpdateEvent other)
136+
{
137+
return
138+
cacheType == other.cacheType &&
139+
String.Equals(updatedTimeString, other.updatedTimeString)
140+
;
141+
}
142+
143+
public static bool operator ==(CacheUpdateEvent lhs, CacheUpdateEvent rhs)
144+
{
145+
// If both are null, or both are same instance, return true.
146+
if (ReferenceEquals(lhs, rhs))
147+
return true;
148+
149+
// If one is null, but not both, return false.
150+
if (((object)lhs == null) || ((object)rhs == null))
151+
return false;
152+
153+
// Return true if the fields match:
154+
return lhs.Equals(rhs);
155+
}
156+
157+
public static bool operator !=(CacheUpdateEvent lhs, CacheUpdateEvent rhs)
158+
{
159+
return !(lhs == rhs);
160+
}
161+
162+
public DateTimeOffset UpdatedTime
163+
{
164+
get
165+
{
166+
if (!updatedTimeValue.HasValue)
167+
{
168+
DateTimeOffset result;
169+
if (DateTimeOffset.TryParseExact(updatedTimeString, Constants.Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.None, out result))
170+
{
171+
updatedTimeValue = result;
172+
}
173+
else
174+
{
175+
updatedTimeValue = DateTimeOffset.MinValue;
176+
updatedTimeString = updatedTimeValue.Value.ToString(Constants.Iso8601Format);
177+
}
178+
}
179+
180+
return updatedTimeValue.Value;
181+
}
182+
}
183+
184+
public bool IsInitialized => cacheType != CacheType.None;
185+
186+
public string UpdatedTimeString => updatedTimeString;
187+
}
188+
}

0 commit comments

Comments
 (0)