2024-02-05 23:08:37 -08:00
|
|
|
|
using System;
|
2024-08-08 06:11:10 -07:00
|
|
|
|
using System.Collections.Generic;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Threading;
|
2024-02-05 23:08:37 -08:00
|
|
|
|
using System.Threading.Tasks;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
namespace SourceGit.Models
|
|
|
|
|
{
|
|
|
|
|
public interface IRepository
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
string FullPath { get; set; }
|
|
|
|
|
string GitDir { get; set; }
|
|
|
|
|
|
|
|
|
|
void RefreshBranches();
|
2024-06-27 03:25:16 -07:00
|
|
|
|
void RefreshWorktrees();
|
2024-02-05 23:08:37 -08:00
|
|
|
|
void RefreshTags();
|
|
|
|
|
void RefreshCommits();
|
|
|
|
|
void RefreshSubmodules();
|
|
|
|
|
void RefreshWorkingCopyChanges();
|
|
|
|
|
void RefreshStashes();
|
|
|
|
|
}
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public class Watcher : IDisposable
|
|
|
|
|
{
|
|
|
|
|
public Watcher(IRepository repo)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_repo = repo;
|
|
|
|
|
|
|
|
|
|
_wcWatcher = new FileSystemWatcher();
|
|
|
|
|
_wcWatcher.Path = _repo.FullPath;
|
|
|
|
|
_wcWatcher.Filter = "*";
|
|
|
|
|
_wcWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.CreationTime;
|
|
|
|
|
_wcWatcher.IncludeSubdirectories = true;
|
|
|
|
|
_wcWatcher.Created += OnWorkingCopyChanged;
|
|
|
|
|
_wcWatcher.Renamed += OnWorkingCopyChanged;
|
|
|
|
|
_wcWatcher.Changed += OnWorkingCopyChanged;
|
|
|
|
|
_wcWatcher.Deleted += OnWorkingCopyChanged;
|
|
|
|
|
_wcWatcher.EnableRaisingEvents = true;
|
|
|
|
|
|
2024-05-03 05:47:22 -07:00
|
|
|
|
// If this repository is a worktree repository, just watch the main repository's gitdir.
|
|
|
|
|
var gitDirNormalized = _repo.GitDir.Replace("\\", "/");
|
2024-07-14 09:30:31 -07:00
|
|
|
|
var worktreeIdx = gitDirNormalized.IndexOf(".git/worktrees/", StringComparison.Ordinal);
|
2024-05-03 05:47:22 -07:00
|
|
|
|
var repoWatchDir = _repo.GitDir;
|
|
|
|
|
if (worktreeIdx > 0)
|
|
|
|
|
repoWatchDir = _repo.GitDir.Substring(0, worktreeIdx + 4);
|
|
|
|
|
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_repoWatcher = new FileSystemWatcher();
|
2024-05-03 05:47:22 -07:00
|
|
|
|
_repoWatcher.Path = repoWatchDir;
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_repoWatcher.Filter = "*";
|
|
|
|
|
_repoWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName;
|
|
|
|
|
_repoWatcher.IncludeSubdirectories = true;
|
|
|
|
|
_repoWatcher.Created += OnRepositoryChanged;
|
|
|
|
|
_repoWatcher.Renamed += OnRepositoryChanged;
|
|
|
|
|
_repoWatcher.Changed += OnRepositoryChanged;
|
|
|
|
|
_repoWatcher.Deleted += OnRepositoryChanged;
|
|
|
|
|
_repoWatcher.EnableRaisingEvents = true;
|
|
|
|
|
|
|
|
|
|
_timer = new Timer(Tick, null, 100, 100);
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public void SetEnabled(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
if (enabled)
|
|
|
|
|
{
|
2024-03-31 01:54:29 -07:00
|
|
|
|
if (_lockCount > 0)
|
|
|
|
|
_lockCount--;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_lockCount++;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-08 20:33:37 -07:00
|
|
|
|
public void SetSubmodules(List<Submodule> submodules)
|
2024-08-08 06:11:10 -07:00
|
|
|
|
{
|
|
|
|
|
lock (_lockSubmodule)
|
|
|
|
|
{
|
|
|
|
|
_submodules.Clear();
|
|
|
|
|
foreach (var submodule in submodules)
|
|
|
|
|
_submodules.Add(submodule.Path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public void MarkBranchDirtyManually()
|
|
|
|
|
{
|
2024-03-07 17:57:29 -08:00
|
|
|
|
_updateBranch = DateTime.Now.ToFileTime() - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public void MarkWorkingCopyDirtyManually()
|
|
|
|
|
{
|
2024-03-07 17:57:29 -08:00
|
|
|
|
_updateWC = DateTime.Now.ToFileTime() - 1;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_repoWatcher.EnableRaisingEvents = false;
|
|
|
|
|
_repoWatcher.Created -= OnRepositoryChanged;
|
|
|
|
|
_repoWatcher.Renamed -= OnRepositoryChanged;
|
|
|
|
|
_repoWatcher.Changed -= OnRepositoryChanged;
|
|
|
|
|
_repoWatcher.Deleted -= OnRepositoryChanged;
|
|
|
|
|
_repoWatcher.Dispose();
|
|
|
|
|
_repoWatcher = null;
|
|
|
|
|
|
|
|
|
|
_wcWatcher.EnableRaisingEvents = false;
|
|
|
|
|
_wcWatcher.Created -= OnWorkingCopyChanged;
|
|
|
|
|
_wcWatcher.Renamed -= OnWorkingCopyChanged;
|
|
|
|
|
_wcWatcher.Changed -= OnWorkingCopyChanged;
|
|
|
|
|
_wcWatcher.Deleted -= OnWorkingCopyChanged;
|
|
|
|
|
_wcWatcher.Dispose();
|
|
|
|
|
_wcWatcher = null;
|
|
|
|
|
|
|
|
|
|
_timer.Dispose();
|
|
|
|
|
_timer = null;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private void Tick(object sender)
|
|
|
|
|
{
|
2024-03-31 01:54:29 -07:00
|
|
|
|
if (_lockCount > 0)
|
|
|
|
|
return;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-02-05 23:08:37 -08:00
|
|
|
|
var now = DateTime.Now.ToFileTime();
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (_updateBranch > 0 && now > _updateBranch)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateBranch = 0;
|
|
|
|
|
_updateWC = 0;
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (_updateTags > 0)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateTags = 0;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_repo.RefreshTags();
|
|
|
|
|
_repo.RefreshBranches();
|
|
|
|
|
_repo.RefreshCommits();
|
|
|
|
|
});
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_repo.RefreshBranches();
|
|
|
|
|
_repo.RefreshCommits();
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-02-05 23:08:37 -08:00
|
|
|
|
Task.Run(_repo.RefreshWorkingCopyChanges);
|
2024-06-27 03:25:16 -07:00
|
|
|
|
Task.Run(_repo.RefreshWorktrees);
|
2024-02-05 23:08:37 -08:00
|
|
|
|
}
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (_updateWC > 0 && now > _updateWC)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateWC = 0;
|
|
|
|
|
Task.Run(_repo.RefreshWorkingCopyChanges);
|
|
|
|
|
}
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (_updateSubmodules > 0 && now > _updateSubmodules)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateSubmodules = 0;
|
|
|
|
|
_repo.RefreshSubmodules();
|
|
|
|
|
}
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (_updateStashes > 0 && now > _updateStashes)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateStashes = 0;
|
|
|
|
|
_repo.RefreshStashes();
|
|
|
|
|
}
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (_updateTags > 0 && now > _updateTags)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateTags = 0;
|
|
|
|
|
_repo.RefreshTags();
|
|
|
|
|
_repo.RefreshCommits();
|
|
|
|
|
}
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private void OnRepositoryChanged(object o, FileSystemEventArgs e)
|
|
|
|
|
{
|
2024-07-16 02:00:08 -07:00
|
|
|
|
if (string.IsNullOrEmpty(e.Name) || e.Name.EndsWith(".lock", StringComparison.Ordinal))
|
2024-03-31 01:54:29 -07:00
|
|
|
|
return;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-02-05 23:08:37 -08:00
|
|
|
|
var name = e.Name.Replace("\\", "/");
|
2024-08-08 06:11:10 -07:00
|
|
|
|
if (name.StartsWith("modules", StringComparison.Ordinal) && name.EndsWith("HEAD", StringComparison.Ordinal))
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
|
2024-08-08 23:34:19 -07:00
|
|
|
|
_updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (name.StartsWith("refs/tags", StringComparison.Ordinal))
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateTags = DateTime.Now.AddSeconds(.5).ToFileTime();
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (name.StartsWith("refs/stash", StringComparison.Ordinal))
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateStashes = DateTime.Now.AddSeconds(.5).ToFileTime();
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (name.Equals("HEAD", StringComparison.Ordinal) ||
|
2024-02-05 23:08:37 -08:00
|
|
|
|
name.StartsWith("refs/heads/", StringComparison.Ordinal) ||
|
2024-05-06 19:29:24 -07:00
|
|
|
|
name.StartsWith("refs/remotes/", StringComparison.Ordinal) ||
|
|
|
|
|
(name.StartsWith("worktrees/", StringComparison.Ordinal) && name.EndsWith("/HEAD", StringComparison.Ordinal)))
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_updateBranch = DateTime.Now.AddSeconds(.5).ToFileTime();
|
2024-08-11 03:12:58 -07:00
|
|
|
|
|
2024-08-10 19:13:01 -07:00
|
|
|
|
lock (_submodules)
|
|
|
|
|
{
|
|
|
|
|
if (_submodules.Count > 0)
|
|
|
|
|
_updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
|
|
|
|
|
}
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (name.StartsWith("objects/", StringComparison.Ordinal) || name.Equals("index", StringComparison.Ordinal))
|
|
|
|
|
{
|
2024-03-12 00:50:00 -07:00
|
|
|
|
_updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private void OnWorkingCopyChanged(object o, FileSystemEventArgs e)
|
|
|
|
|
{
|
2024-03-31 01:54:29 -07:00
|
|
|
|
if (string.IsNullOrEmpty(e.Name))
|
|
|
|
|
return;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-02-05 23:08:37 -08:00
|
|
|
|
var name = e.Name.Replace("\\", "/");
|
2024-03-31 01:54:29 -07:00
|
|
|
|
if (name == ".git" || name.StartsWith(".git/", StringComparison.Ordinal))
|
|
|
|
|
return;
|
2024-08-08 06:11:10 -07:00
|
|
|
|
|
|
|
|
|
lock (_submodules)
|
|
|
|
|
{
|
|
|
|
|
foreach (var submodule in _submodules)
|
|
|
|
|
{
|
|
|
|
|
if (name.StartsWith(submodule, StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
_updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
|
2024-08-08 23:34:19 -07:00
|
|
|
|
return;
|
2024-08-08 06:11:10 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-08 20:33:37 -07:00
|
|
|
|
}
|
2024-08-08 06:11:10 -07:00
|
|
|
|
|
2024-03-12 00:50:00 -07:00
|
|
|
|
_updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private readonly IRepository _repo = null;
|
2024-02-05 23:08:37 -08:00
|
|
|
|
private FileSystemWatcher _repoWatcher = null;
|
|
|
|
|
private FileSystemWatcher _wcWatcher = null;
|
|
|
|
|
private Timer _timer = null;
|
|
|
|
|
private int _lockCount = 0;
|
|
|
|
|
private long _updateWC = 0;
|
|
|
|
|
private long _updateBranch = 0;
|
|
|
|
|
private long _updateSubmodules = 0;
|
|
|
|
|
private long _updateStashes = 0;
|
|
|
|
|
private long _updateTags = 0;
|
2024-08-08 06:11:10 -07:00
|
|
|
|
|
|
|
|
|
private object _lockSubmodule = new object();
|
|
|
|
|
private List<string> _submodules = new List<string>();
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
2024-03-31 01:54:29 -07:00
|
|
|
|
}
|