@@ -7,9 +7,26 @@ namespace SourceGit.Models
77{
88 public class Watcher : IDisposable
99 {
10+ public class LockContext : IDisposable
11+ {
12+ public LockContext ( Watcher target )
13+ {
14+ _target = target ;
15+ Interlocked . Increment ( ref _target . _lockCount ) ;
16+ }
17+
18+ public void Dispose ( )
19+ {
20+ Interlocked . Decrement ( ref _target . _lockCount ) ;
21+ }
22+
23+ private Watcher _target ;
24+ }
25+
1026 public Watcher ( IRepository repo , string fullpath , string gitDir )
1127 {
1228 _repo = repo ;
29+ _root = new DirectoryInfo ( fullpath ) . FullName ;
1330
1431 var testGitDir = new DirectoryInfo ( Path . Combine ( fullpath , ".git" ) ) . FullName ;
1532 var desiredDir = new DirectoryInfo ( gitDir ) . FullName ;
@@ -59,42 +76,29 @@ public Watcher(IRepository repo, string fullpath, string gitDir)
5976 _timer = new Timer ( Tick , null , 100 , 100 ) ;
6077 }
6178
62- public void SetEnabled ( bool enabled )
63- {
64- if ( enabled )
65- {
66- if ( _lockCount > 0 )
67- _lockCount -- ;
68- }
69- else
70- {
71- _lockCount ++ ;
72- }
73- }
74-
75- public void SetSubmodules ( List < Submodule > submodules )
79+ public IDisposable Lock ( )
7680 {
77- lock ( _lockSubmodule )
78- {
79- _submodules . Clear ( ) ;
80- foreach ( var submodule in submodules )
81- _submodules . Add ( submodule . Path ) ;
82- }
81+ return new LockContext ( this ) ;
8382 }
8483
8584 public void MarkBranchUpdated ( )
8685 {
87- _updateBranch = 0 ;
86+ Interlocked . Exchange ( ref _updateBranch , 0 ) ;
8887 }
8988
9089 public void MarkTagUpdated ( )
9190 {
92- _updateTags = 0 ;
91+ Interlocked . Exchange ( ref _updateTags , 0 ) ;
9392 }
9493
9594 public void MarkWorkingCopyUpdated ( )
9695 {
97- _updateWC = 0 ;
96+ Interlocked . Exchange ( ref _updateWC , 0 ) ;
97+ }
98+
99+ public void MarkStashUpdated ( )
100+ {
101+ Interlocked . Exchange ( ref _updateStashes , 0 ) ;
98102 }
99103
100104 public void Dispose ( )
@@ -112,57 +116,81 @@ public void Dispose()
112116
113117 private void Tick ( object sender )
114118 {
115- if ( _lockCount > 0 )
119+ if ( Interlocked . Read ( ref _lockCount ) > 0 )
116120 return ;
117121
118122 var now = DateTime . Now . ToFileTime ( ) ;
119- if ( _updateBranch > 0 && now > _updateBranch )
120- {
121- _updateBranch = 0 ;
122- _updateWC = 0 ;
123+ var refreshCommits = false ;
124+ var refreshSubmodules = false ;
123125
124- if ( _updateTags > 0 )
126+ var oldUpdateBranch = Interlocked . Exchange ( ref _updateBranch , - 1 ) ;
127+ if ( oldUpdateBranch > 0 )
128+ {
129+ if ( now > oldUpdateBranch )
125130 {
126- _updateTags = 0 ;
127- _repo . RefreshTags ( ) ;
128- }
131+ refreshCommits = true ;
132+ refreshSubmodules = _repo . MayHaveSubmodules ( ) ;
129133
130- if ( _updateSubmodules > 0 || _repo . MayHaveSubmodules ( ) )
134+ _repo . RefreshBranches ( ) ;
135+ _repo . RefreshWorktrees ( ) ;
136+ }
137+ else
131138 {
132- _updateSubmodules = 0 ;
133- _repo . RefreshSubmodules ( ) ;
139+ Interlocked . CompareExchange ( ref _updateBranch , oldUpdateBranch , - 1 ) ;
134140 }
135-
136- _repo . RefreshBranches ( ) ;
137- _repo . RefreshCommits ( ) ;
138- _repo . RefreshWorkingCopyChanges ( ) ;
139- _repo . RefreshWorktrees ( ) ;
140141 }
141142
142- if ( _updateWC > 0 && now > _updateWC )
143+ var oldUpdateWC = Interlocked . Exchange ( ref _updateWC , - 1 ) ;
144+ if ( oldUpdateWC > 0 )
143145 {
144- _updateWC = 0 ;
145- _repo . RefreshWorkingCopyChanges ( ) ;
146+ if ( now > oldUpdateWC )
147+ _repo . RefreshWorkingCopyChanges ( ) ;
148+ else
149+ Interlocked . CompareExchange ( ref _updateWC , oldUpdateWC , - 1 ) ;
146150 }
147151
148- if ( _updateSubmodules > 0 && now > _updateSubmodules )
152+ if ( refreshSubmodules )
149153 {
150- _updateSubmodules = 0 ;
154+ Interlocked . Exchange ( ref _updateSubmodules , - 1 ) ;
151155 _repo . RefreshSubmodules ( ) ;
152156 }
157+ else
158+ {
159+ var oldUpdateSubmodule = Interlocked . Exchange ( ref _updateSubmodules , - 1 ) ;
160+ if ( oldUpdateSubmodule > 0 )
161+ {
162+ if ( now > oldUpdateSubmodule )
163+ _repo . RefreshSubmodules ( ) ;
164+ else
165+ Interlocked . CompareExchange ( ref _updateSubmodules , oldUpdateSubmodule , - 1 ) ;
166+ }
167+ }
153168
154- if ( _updateStashes > 0 && now > _updateStashes )
169+ var oldUpdateStashes = Interlocked . Exchange ( ref _updateStashes , - 1 ) ;
170+ if ( oldUpdateStashes > 0 )
155171 {
156- _updateStashes = 0 ;
157- _repo . RefreshStashes ( ) ;
172+ if ( now > oldUpdateStashes )
173+ _repo . RefreshStashes ( ) ;
174+ else
175+ Interlocked . CompareExchange ( ref _updateStashes , oldUpdateStashes , - 1 ) ;
158176 }
159177
160- if ( _updateTags > 0 && now > _updateTags )
178+ var oldUpdateTags = Interlocked . Exchange ( ref _updateTags , - 1 ) ;
179+ if ( oldUpdateTags > 0 )
161180 {
162- _updateTags = 0 ;
163- _repo . RefreshTags ( ) ;
164- _repo . RefreshCommits ( ) ;
181+ if ( now > oldUpdateTags )
182+ {
183+ refreshCommits = true ;
184+ _repo . RefreshTags ( ) ;
185+ }
186+ else
187+ {
188+ Interlocked . CompareExchange ( ref _updateTags , oldUpdateTags , - 1 ) ;
189+ }
165190 }
191+
192+ if ( refreshCommits )
193+ _repo . RefreshCommits ( ) ;
166194 }
167195
168196 private void OnRepositoryChanged ( object o , FileSystemEventArgs e )
@@ -177,7 +205,7 @@ private void OnRepositoryChanged(object o, FileSystemEventArgs e)
177205 if ( name . StartsWith ( ".git/" , StringComparison . Ordinal ) )
178206 HandleGitDirFileChanged ( name . Substring ( 5 ) ) ;
179207 else
180- HandleWorkingCopyFileChanged ( name ) ;
208+ HandleWorkingCopyFileChanged ( name , e . FullPath ) ;
181209 }
182210
183211 private void OnGitDirChanged ( object o , FileSystemEventArgs e )
@@ -200,7 +228,7 @@ private void OnWorkingCopyChanged(object o, FileSystemEventArgs e)
200228 name . EndsWith ( "/.git" , StringComparison . Ordinal ) )
201229 return ;
202230
203- HandleWorkingCopyFileChanged ( name ) ;
231+ HandleWorkingCopyFileChanged ( name , e . FullPath ) ;
204232 }
205233
206234 private void HandleGitDirFileChanged ( string name )
@@ -215,76 +243,84 @@ private void HandleGitDirFileChanged(string name)
215243 if ( name . EndsWith ( "/HEAD" , StringComparison . Ordinal ) ||
216244 name . EndsWith ( "/ORIG_HEAD" , StringComparison . Ordinal ) )
217245 {
218- _updateSubmodules = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
219- _updateWC = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
246+ var desired = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
247+ Interlocked . Exchange ( ref _updateSubmodules , desired ) ;
248+ Interlocked . Exchange ( ref _updateWC , desired ) ;
220249 }
221250 }
222251 else if ( name . Equals ( "MERGE_HEAD" , StringComparison . Ordinal ) ||
223252 name . Equals ( "AUTO_MERGE" , StringComparison . Ordinal ) )
224253 {
225254 if ( _repo . MayHaveSubmodules ( ) )
226- _updateSubmodules = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
255+ Interlocked . Exchange ( ref _updateSubmodules , DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ) ;
227256 }
228257 else if ( name . StartsWith ( "refs/tags" , StringComparison . Ordinal ) )
229258 {
230- _updateTags = DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ;
259+ Interlocked . Exchange ( ref _updateTags , DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ) ;
231260 }
232261 else if ( name . StartsWith ( "refs/stash" , StringComparison . Ordinal ) )
233262 {
234- _updateStashes = DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ;
263+ Interlocked . Exchange ( ref _updateStashes , DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ) ;
235264 }
236265 else if ( name . Equals ( "HEAD" , StringComparison . Ordinal ) ||
237266 name . Equals ( "BISECT_START" , StringComparison . Ordinal ) ||
238267 name . StartsWith ( "refs/heads/" , StringComparison . Ordinal ) ||
239268 name . StartsWith ( "refs/remotes/" , StringComparison . Ordinal ) ||
240269 ( name . StartsWith ( "worktrees/" , StringComparison . Ordinal ) && name . EndsWith ( "/HEAD" , StringComparison . Ordinal ) ) )
241270 {
242- _updateBranch = DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ;
271+ Interlocked . Exchange ( ref _updateBranch , DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ) ;
243272 }
244273 else if ( name . StartsWith ( "objects/" , StringComparison . Ordinal ) || name . Equals ( "index" , StringComparison . Ordinal ) )
245274 {
246- _updateWC = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
275+ Interlocked . Exchange ( ref _updateWC , DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ) ;
247276 }
248277 }
249278
250- private void HandleWorkingCopyFileChanged ( string name )
279+ private void HandleWorkingCopyFileChanged ( string name , string fullpath )
251280 {
252281 if ( name . StartsWith ( ".vs/" , StringComparison . Ordinal ) )
253282 return ;
254283
255284 if ( name . Equals ( ".gitmodules" , StringComparison . Ordinal ) )
256285 {
257- _updateSubmodules = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
258- _updateWC = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
286+ var desired = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
287+ Interlocked . Exchange ( ref _updateSubmodules , desired ) ;
288+ Interlocked . Exchange ( ref _updateWC , desired ) ;
259289 return ;
260290 }
261291
262- lock ( _lockSubmodule )
292+ var dir = Directory . Exists ( fullpath ) ? fullpath : Path . GetDirectoryName ( fullpath ) ;
293+ if ( IsInSubmodule ( dir ) )
263294 {
264- foreach ( var submodule in _submodules )
265- {
266- if ( name . StartsWith ( submodule , StringComparison . Ordinal ) )
267- {
268- _updateSubmodules = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
269- return ;
270- }
271- }
295+ Interlocked . Exchange ( ref _updateSubmodules , DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ) ;
296+ return ;
272297 }
273298
274- _updateWC = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
299+ Interlocked . Exchange ( ref _updateWC , DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ) ;
300+ }
301+
302+ private bool IsInSubmodule ( string folder )
303+ {
304+ if ( File . Exists ( $ "{ folder } /.git") )
305+ return true ;
306+
307+ var parent = Path . GetDirectoryName ( folder ) ;
308+ if ( parent == null || parent . Equals ( _root , StringComparison . Ordinal ) )
309+ return false ;
310+
311+ return IsInSubmodule ( parent ) ;
275312 }
276313
277314 private readonly IRepository _repo = null ;
315+ private readonly string _root = null ;
278316 private List < FileSystemWatcher > _watchers = [ ] ;
279317 private Timer _timer = null ;
280- private int _lockCount = 0 ;
318+
319+ private long _lockCount = 0 ;
281320 private long _updateWC = 0 ;
282321 private long _updateBranch = 0 ;
283322 private long _updateSubmodules = 0 ;
284323 private long _updateStashes = 0 ;
285324 private long _updateTags = 0 ;
286-
287- private readonly Lock _lockSubmodule = new ( ) ;
288- private List < string > _submodules = new List < string > ( ) ;
289325 }
290326}
0 commit comments