@@ -7,9 +7,26 @@ namespace SourceGit.Models
7
7
{
8
8
public class Watcher : IDisposable
9
9
{
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
+
10
26
public Watcher ( IRepository repo , string fullpath , string gitDir )
11
27
{
12
28
_repo = repo ;
29
+ _root = new DirectoryInfo ( fullpath ) . FullName ;
13
30
14
31
var testGitDir = new DirectoryInfo ( Path . Combine ( fullpath , ".git" ) ) . FullName ;
15
32
var desiredDir = new DirectoryInfo ( gitDir ) . FullName ;
@@ -59,42 +76,29 @@ public Watcher(IRepository repo, string fullpath, string gitDir)
59
76
_timer = new Timer ( Tick , null , 100 , 100 ) ;
60
77
}
61
78
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 ( )
76
80
{
77
- lock ( _lockSubmodule )
78
- {
79
- _submodules . Clear ( ) ;
80
- foreach ( var submodule in submodules )
81
- _submodules . Add ( submodule . Path ) ;
82
- }
81
+ return new LockContext ( this ) ;
83
82
}
84
83
85
84
public void MarkBranchUpdated ( )
86
85
{
87
- _updateBranch = 0 ;
86
+ Interlocked . Exchange ( ref _updateBranch , 0 ) ;
88
87
}
89
88
90
89
public void MarkTagUpdated ( )
91
90
{
92
- _updateTags = 0 ;
91
+ Interlocked . Exchange ( ref _updateTags , 0 ) ;
93
92
}
94
93
95
94
public void MarkWorkingCopyUpdated ( )
96
95
{
97
- _updateWC = 0 ;
96
+ Interlocked . Exchange ( ref _updateWC , 0 ) ;
97
+ }
98
+
99
+ public void MarkStashUpdated ( )
100
+ {
101
+ Interlocked . Exchange ( ref _updateStashes , 0 ) ;
98
102
}
99
103
100
104
public void Dispose ( )
@@ -112,57 +116,81 @@ public void Dispose()
112
116
113
117
private void Tick ( object sender )
114
118
{
115
- if ( _lockCount > 0 )
119
+ if ( Interlocked . Read ( ref _lockCount ) > 0 )
116
120
return ;
117
121
118
122
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 ;
123
125
124
- if ( _updateTags > 0 )
126
+ var oldUpdateBranch = Interlocked . Exchange ( ref _updateBranch , - 1 ) ;
127
+ if ( oldUpdateBranch > 0 )
128
+ {
129
+ if ( now > oldUpdateBranch )
125
130
{
126
- _updateTags = 0 ;
127
- _repo . RefreshTags ( ) ;
128
- }
131
+ refreshCommits = true ;
132
+ refreshSubmodules = _repo . MayHaveSubmodules ( ) ;
129
133
130
- if ( _updateSubmodules > 0 || _repo . MayHaveSubmodules ( ) )
134
+ _repo . RefreshBranches ( ) ;
135
+ _repo . RefreshWorktrees ( ) ;
136
+ }
137
+ else
131
138
{
132
- _updateSubmodules = 0 ;
133
- _repo . RefreshSubmodules ( ) ;
139
+ Interlocked . CompareExchange ( ref _updateBranch , oldUpdateBranch , - 1 ) ;
134
140
}
135
-
136
- _repo . RefreshBranches ( ) ;
137
- _repo . RefreshCommits ( ) ;
138
- _repo . RefreshWorkingCopyChanges ( ) ;
139
- _repo . RefreshWorktrees ( ) ;
140
141
}
141
142
142
- if ( _updateWC > 0 && now > _updateWC )
143
+ var oldUpdateWC = Interlocked . Exchange ( ref _updateWC , - 1 ) ;
144
+ if ( oldUpdateWC > 0 )
143
145
{
144
- _updateWC = 0 ;
145
- _repo . RefreshWorkingCopyChanges ( ) ;
146
+ if ( now > oldUpdateWC )
147
+ _repo . RefreshWorkingCopyChanges ( ) ;
148
+ else
149
+ Interlocked . CompareExchange ( ref _updateWC , oldUpdateWC , - 1 ) ;
146
150
}
147
151
148
- if ( _updateSubmodules > 0 && now > _updateSubmodules )
152
+ if ( refreshSubmodules )
149
153
{
150
- _updateSubmodules = 0 ;
154
+ Interlocked . Exchange ( ref _updateSubmodules , - 1 ) ;
151
155
_repo . RefreshSubmodules ( ) ;
152
156
}
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
+ }
153
168
154
- if ( _updateStashes > 0 && now > _updateStashes )
169
+ var oldUpdateStashes = Interlocked . Exchange ( ref _updateStashes , - 1 ) ;
170
+ if ( oldUpdateStashes > 0 )
155
171
{
156
- _updateStashes = 0 ;
157
- _repo . RefreshStashes ( ) ;
172
+ if ( now > oldUpdateStashes )
173
+ _repo . RefreshStashes ( ) ;
174
+ else
175
+ Interlocked . CompareExchange ( ref _updateStashes , oldUpdateStashes , - 1 ) ;
158
176
}
159
177
160
- if ( _updateTags > 0 && now > _updateTags )
178
+ var oldUpdateTags = Interlocked . Exchange ( ref _updateTags , - 1 ) ;
179
+ if ( oldUpdateTags > 0 )
161
180
{
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
+ }
165
190
}
191
+
192
+ if ( refreshCommits )
193
+ _repo . RefreshCommits ( ) ;
166
194
}
167
195
168
196
private void OnRepositoryChanged ( object o , FileSystemEventArgs e )
@@ -177,7 +205,7 @@ private void OnRepositoryChanged(object o, FileSystemEventArgs e)
177
205
if ( name . StartsWith ( ".git/" , StringComparison . Ordinal ) )
178
206
HandleGitDirFileChanged ( name . Substring ( 5 ) ) ;
179
207
else
180
- HandleWorkingCopyFileChanged ( name ) ;
208
+ HandleWorkingCopyFileChanged ( name , e . FullPath ) ;
181
209
}
182
210
183
211
private void OnGitDirChanged ( object o , FileSystemEventArgs e )
@@ -200,7 +228,7 @@ private void OnWorkingCopyChanged(object o, FileSystemEventArgs e)
200
228
name . EndsWith ( "/.git" , StringComparison . Ordinal ) )
201
229
return ;
202
230
203
- HandleWorkingCopyFileChanged ( name ) ;
231
+ HandleWorkingCopyFileChanged ( name , e . FullPath ) ;
204
232
}
205
233
206
234
private void HandleGitDirFileChanged ( string name )
@@ -215,76 +243,84 @@ private void HandleGitDirFileChanged(string name)
215
243
if ( name . EndsWith ( "/HEAD" , StringComparison . Ordinal ) ||
216
244
name . EndsWith ( "/ORIG_HEAD" , StringComparison . Ordinal ) )
217
245
{
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 ) ;
220
249
}
221
250
}
222
251
else if ( name . Equals ( "MERGE_HEAD" , StringComparison . Ordinal ) ||
223
252
name . Equals ( "AUTO_MERGE" , StringComparison . Ordinal ) )
224
253
{
225
254
if ( _repo . MayHaveSubmodules ( ) )
226
- _updateSubmodules = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
255
+ Interlocked . Exchange ( ref _updateSubmodules , DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ) ;
227
256
}
228
257
else if ( name . StartsWith ( "refs/tags" , StringComparison . Ordinal ) )
229
258
{
230
- _updateTags = DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ;
259
+ Interlocked . Exchange ( ref _updateTags , DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ) ;
231
260
}
232
261
else if ( name . StartsWith ( "refs/stash" , StringComparison . Ordinal ) )
233
262
{
234
- _updateStashes = DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ;
263
+ Interlocked . Exchange ( ref _updateStashes , DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ) ;
235
264
}
236
265
else if ( name . Equals ( "HEAD" , StringComparison . Ordinal ) ||
237
266
name . Equals ( "BISECT_START" , StringComparison . Ordinal ) ||
238
267
name . StartsWith ( "refs/heads/" , StringComparison . Ordinal ) ||
239
268
name . StartsWith ( "refs/remotes/" , StringComparison . Ordinal ) ||
240
269
( name . StartsWith ( "worktrees/" , StringComparison . Ordinal ) && name . EndsWith ( "/HEAD" , StringComparison . Ordinal ) ) )
241
270
{
242
- _updateBranch = DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ;
271
+ Interlocked . Exchange ( ref _updateBranch , DateTime . Now . AddSeconds ( .5 ) . ToFileTime ( ) ) ;
243
272
}
244
273
else if ( name . StartsWith ( "objects/" , StringComparison . Ordinal ) || name . Equals ( "index" , StringComparison . Ordinal ) )
245
274
{
246
- _updateWC = DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ;
275
+ Interlocked . Exchange ( ref _updateWC , DateTime . Now . AddSeconds ( 1 ) . ToFileTime ( ) ) ;
247
276
}
248
277
}
249
278
250
- private void HandleWorkingCopyFileChanged ( string name )
279
+ private void HandleWorkingCopyFileChanged ( string name , string fullpath )
251
280
{
252
281
if ( name . StartsWith ( ".vs/" , StringComparison . Ordinal ) )
253
282
return ;
254
283
255
284
if ( name . Equals ( ".gitmodules" , StringComparison . Ordinal ) )
256
285
{
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 ) ;
259
289
return ;
260
290
}
261
291
262
- lock ( _lockSubmodule )
292
+ var dir = Directory . Exists ( fullpath ) ? fullpath : Path . GetDirectoryName ( fullpath ) ;
293
+ if ( IsInSubmodule ( dir ) )
263
294
{
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 ;
272
297
}
273
298
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 ) ;
275
312
}
276
313
277
314
private readonly IRepository _repo = null ;
315
+ private readonly string _root = null ;
278
316
private List < FileSystemWatcher > _watchers = [ ] ;
279
317
private Timer _timer = null ;
280
- private int _lockCount = 0 ;
318
+
319
+ private long _lockCount = 0 ;
281
320
private long _updateWC = 0 ;
282
321
private long _updateBranch = 0 ;
283
322
private long _updateSubmodules = 0 ;
284
323
private long _updateStashes = 0 ;
285
324
private long _updateTags = 0 ;
286
-
287
- private readonly Lock _lockSubmodule = new ( ) ;
288
- private List < string > _submodules = new List < string > ( ) ;
289
325
}
290
326
}
0 commit comments