diff --git a/src/App.axaml.cs b/src/App.axaml.cs index a5f90e02..682ec5fc 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -534,7 +534,6 @@ namespace SourceGit { Native.OS.SetupEnternalTools(); Models.AvatarManager.Instance.Start(); - Models.AutoFetchManager.Instance.Start(); string startupRepo = null; if (desktop.Args != null && desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0])) diff --git a/src/Commands/Fetch.cs b/src/Commands/Fetch.cs index 07622821..94b7fde9 100644 --- a/src/Commands/Fetch.cs +++ b/src/Commands/Fetch.cs @@ -22,8 +22,6 @@ namespace SourceGit.Commands Args += "--force "; Args += remote; - - Models.AutoFetchManager.Instance.MarkFetched(repo); } public Fetch(string repo, string remote, string localBranch, string remoteBranch, Action outputHandler) diff --git a/src/Models/AutoFetchManager.cs b/src/Models/AutoFetchManager.cs deleted file mode 100644 index 313f5f64..00000000 --- a/src/Models/AutoFetchManager.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace SourceGit.Models -{ - public class AutoFetchManager - { - public static AutoFetchManager Instance - { - get - { - if (_instance == null) - _instance = new AutoFetchManager(); - - return _instance; - } - } - - public class Job - { - public string IndexLockFile = string.Empty; - public Commands.Fetch Cmd = null; - public DateTime NextRunTimepoint = DateTime.MinValue; - } - - public bool IsEnabled - { - get; - set; - } = false; - - public int Interval - { - get => _interval; - set - { - _interval = Math.Max(1, value); - - lock (_lock) - { - foreach (var job in _jobs) - job.Value.NextRunTimepoint = DateTime.Now.AddMinutes(_interval * 1.0); - } - } - } - - private static AutoFetchManager _instance = null; - private Dictionary _jobs = new Dictionary(); - private object _lock = new object(); - private int _interval = 10; - - public void Start() - { - Task.Run(() => - { - while (true) - { - if (!IsEnabled) - { - Thread.Sleep(10000); - continue; - } - - var now = DateTime.Now; - var uptodate = new List(); - lock (_lock) - { - foreach (var job in _jobs) - { - if (job.Value.NextRunTimepoint.Subtract(now).TotalSeconds <= 0) - uptodate.Add(job.Value); - } - } - - foreach (var job in uptodate) - { - if (!File.Exists(job.IndexLockFile)) - { - job.Cmd.Exec(); - job.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)); - } - } - - Thread.Sleep(2000); - } - - // ReSharper disable once FunctionNeverReturns - }); - } - - public void AddRepository(string repo, string gitDir) - { - var job = new Job - { - IndexLockFile = Path.Combine(gitDir, "index.lock"), - Cmd = new Commands.Fetch(repo, "--all", true, false, null) { RaiseError = false }, - NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)), - }; - - lock (_lock) - { - _jobs[repo] = job; - } - } - - public void RemoveRepository(string repo) - { - lock (_lock) - { - _jobs.Remove(repo); - } - } - - public void MarkFetched(string repo) - { - lock (_lock) - { - if (_jobs.TryGetValue(repo, out var value)) - value.NextRunTimepoint = DateTime.Now.AddMinutes(Interval * 1.0); - } - } - } -} diff --git a/src/Models/IRepository.cs b/src/Models/IRepository.cs new file mode 100644 index 00000000..12b1adba --- /dev/null +++ b/src/Models/IRepository.cs @@ -0,0 +1,16 @@ +namespace SourceGit.Models +{ + public interface IRepository + { + string FullPath { get; set; } + string GitDir { get; set; } + + void RefreshBranches(); + void RefreshWorktrees(); + void RefreshTags(); + void RefreshCommits(); + void RefreshSubmodules(); + void RefreshWorkingCopyChanges(); + void RefreshStashes(); + } +} diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs index 06e60a87..244fc673 100644 --- a/src/Models/RepositorySettings.cs +++ b/src/Models/RepositorySettings.cs @@ -94,6 +94,18 @@ namespace SourceGit.Models set; } = new AvaloniaList(); + public bool EnableAutoFetch + { + get; + set; + } = false; + + public int AutoFetchInterval + { + get; + set; + } = 10; + public void PushCommitMessage(string message) { var existIdx = CommitMessages.IndexOf(message); diff --git a/src/Models/Watcher.cs b/src/Models/Watcher.cs index 6cd77a15..6665250c 100644 --- a/src/Models/Watcher.cs +++ b/src/Models/Watcher.cs @@ -6,20 +6,6 @@ using System.Threading.Tasks; namespace SourceGit.Models { - public interface IRepository - { - string FullPath { get; set; } - string GitDir { get; set; } - - void RefreshBranches(); - void RefreshWorktrees(); - void RefreshTags(); - void RefreshCommits(); - void RefreshSubmodules(); - void RefreshWorkingCopyChanges(); - void RefreshStashes(); - } - public class Watcher : IDisposable { public Watcher(IRepository repo) diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index 90445ec9..80c16372 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -137,6 +137,8 @@ Email Adresse Email Adresse GIT + Remotes automatisch fetchen + Minute(n) TICKETSYSTEM Beispiel für Github-Regel hinzufügen Beispiel für Jira-Regel hinzufügen @@ -410,9 +412,6 @@ Commit-Historie Längenvorgabe für Commit-Nachrichten GIT - Remotes automatisch fetchen - Auto-Fetch Intervall - Minute(n) Aktiviere Auto-CRLF Clone Standardordner Benutzer Email diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index cebbe194..0ce2ec05 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -136,6 +136,8 @@ Email Address Email address GIT + Fetch remotes automatically + Minute(s) ISSUE TRACKER Add Sample Github Rule Add Sample Jira Rule @@ -409,9 +411,6 @@ History Commits Subject Guide Length GIT - Fetch remotes automatically - Auto Fetch Interval - Minute(s) Enable Auto CRLF Default Clone Dir User Email @@ -489,6 +488,7 @@ Unique name for this branch Branch: ABORT + Auto fetching changes from remotes... Cleanup(GC & Prune) Run `git gc` command for this repository. Clear all diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index 0db805ca..5464596c 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -133,6 +133,8 @@ Addresse e-mail Addresse e-mail GIT + Fetch les dépôts distants automatiquement + minute(s) ISSUE TRACKER Add Sample Github Rule Add Sample Jira Rule @@ -397,9 +399,6 @@ Historique de commits Guide de longueur du sujet GIT - Fetch les dépôts distants automatiquement - Intervalle de fetch auto - minute(s) Activer auto CRLF Répertoire de clônage par défaut E-mail utilsateur diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index 6ff8e06c..0eaf252f 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -132,6 +132,8 @@ Endereço de Email Endereço de email GIT + Buscar remotos automaticamente + Minuto(s) RASTREADOR DE PROBLEMAS Adicionar Regra de Exemplo do Github Adicionar Regra de Exemplo do Jira @@ -391,9 +393,6 @@ Commits do Histórico Comprimento do Guia de Assunto GIT - Buscar remotos automaticamente - Intervalo de Busca Automática - Minuto(s) Habilitar Auto CRLF Diretório Padrão de Clone E-mail do Usuário diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index 5f4aa785..18e64224 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -136,6 +136,8 @@ Адрес электронной почты Адрес электронной почты GIT + Автоматическое извлечение внешних хранилищ + Минут(а/ы) ОТСЛЕЖИВАНИЕ ПРОБЛЕМ Добавить пример правила для Git Добавить пример правила Jira @@ -409,9 +411,6 @@ История фиксаций Длина темы фиксации GIT - Автоматическое извлечение внешних хранилищ - Интервал автоматического извлечения - Минут(а/ы) Включить автозавершение CRLF Каталог клонирования по-умолчанию Электроная почта пользователя @@ -573,7 +572,7 @@ НЕДЕЛЯ ФИКСАЦИИ: АВТОРЫ: - ОБЗОР + ОБЗОР ПОДМОДУЛИ Добавить подмодули Копировать относительный путь diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 9989c30d..82190529 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -139,6 +139,8 @@ 电子邮箱 邮箱地址 GIT配置 + 启用定时自动拉取远程更新 + 分钟 ISSUE追踪 新增匹配Github Issue规则 新增匹配Jira规则 @@ -408,9 +410,6 @@ 最大历史提交数 SUBJECT字数检测 GIT配置 - 启用定时自动拉取远程更新 - 自动拉取间隔 - 分钟 自动换行转换 默认克隆路径 邮箱 @@ -487,6 +486,7 @@ 新的分支名不能与现有分支名相同 分支 : 终止合并 + 自动拉取远端变更中... 清理本仓库(GC) 本操作将执行`git gc`命令。 清空过滤规则 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 7ed253dc..efbb555e 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -139,6 +139,8 @@ 電子郵件 電子郵件地址 Git 設定 + 啟用定時自動提取 (fetch) 遠端更新 + 分鐘 Issue 追蹤 新增符合 GitHub Issue 規則 新增符合 Jira 規則 @@ -412,9 +414,6 @@ 最大歷史提交數 提交標題字數偵測 Git 設定 - 啟用定時自動提取 (fetch) 遠端更新 - 自動提取間隔 - 分鐘 自動換行轉換 預設複製 (clone) 路徑 電子郵件 @@ -492,6 +491,7 @@ 新的分支名稱不能與現有分支名稱相同 分支: 中止 + 自動提取遠端變更中... 清理本存放庫 (GC) 本操作將執行 `git gc` 命令。 清空篩選規則 diff --git a/src/ViewModels/AddRemote.cs b/src/ViewModels/AddRemote.cs index 104a4ed6..f2e71f4c 100644 --- a/src/ViewModels/AddRemote.cs +++ b/src/ViewModels/AddRemote.cs @@ -104,6 +104,7 @@ namespace SourceGit.ViewModels } CallUIThread(() => { + _repo.MarkFetched(); _repo.MarkBranchesDirtyManually(); _repo.SetWatcherEnabled(true); }); diff --git a/src/ViewModels/Fetch.cs b/src/ViewModels/Fetch.cs index fa1986b3..bf208193 100644 --- a/src/ViewModels/Fetch.cs +++ b/src/ViewModels/Fetch.cs @@ -62,7 +62,12 @@ namespace SourceGit.ViewModels new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, Prune, NoTags, SetProgressDescription).Exec(); } - CallUIThread(() => _repo.SetWatcherEnabled(true)); + CallUIThread(() => + { + _repo.MarkFetched(); + _repo.SetWatcherEnabled(true); + }); + return true; }); } diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 17234cec..5abf50e8 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -179,7 +179,6 @@ namespace SourceGit.ViewModels ActiveWorkspace.Repositories.Clear(); ActiveWorkspace.ActiveIdx = 0; - Models.AutoFetchManager.Instance.RemoveRepository(repo.FullPath); repo.Close(); Welcome.Instance.ClearSearchFilter(); @@ -293,7 +292,6 @@ namespace SourceGit.ViewModels }; repo.Open(); - Models.AutoFetchManager.Instance.AddRepository(repo.FullPath, repo.GitDir); if (page == null) { @@ -522,7 +520,6 @@ namespace SourceGit.ViewModels if (removeFromWorkspace) ActiveWorkspace.Repositories.Remove(repo.FullPath); - Models.AutoFetchManager.Instance.RemoveRepository(repo.FullPath); repo.Close(); } diff --git a/src/ViewModels/LauncherPage.cs b/src/ViewModels/LauncherPage.cs index 71d4a634..92114f5e 100644 --- a/src/ViewModels/LauncherPage.cs +++ b/src/ViewModels/LauncherPage.cs @@ -44,6 +44,14 @@ namespace SourceGit.ViewModels return _node.Id; } + public override bool IsInProgress() + { + if (_data is Repository { IsAutoFetching: true }) + return true; + + return base.IsInProgress(); + } + public void CopyPath() { if (_node.IsRepository) diff --git a/src/ViewModels/PopupHost.cs b/src/ViewModels/PopupHost.cs index 1a4c8bb2..01d1158c 100644 --- a/src/ViewModels/PopupHost.cs +++ b/src/ViewModels/PopupHost.cs @@ -18,7 +18,7 @@ namespace SourceGit.ViewModels public static bool CanCreatePopup() { - return Active != null && (Active._popup == null || !Active._popup.InProgress); + return Active?.IsInProgress() != true; } public static void ShowPopup(Popup popup) @@ -40,6 +40,11 @@ namespace SourceGit.ViewModels return string.Empty; } + public virtual bool IsInProgress() + { + return _popup is { InProgress: true }; + } + public async void ProcessPopup() { if (_popup != null) diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index be1137ac..68966f5d 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -216,35 +216,6 @@ namespace SourceGit.ViewModels set => SetProperty(ref _gitDefaultCloneDir, value); } - public bool GitAutoFetch - { - get => Models.AutoFetchManager.Instance.IsEnabled; - set - { - if (Models.AutoFetchManager.Instance.IsEnabled != value) - { - Models.AutoFetchManager.Instance.IsEnabled = value; - OnPropertyChanged(); - } - } - } - - public int? GitAutoFetchInterval - { - get => Models.AutoFetchManager.Instance.Interval; - set - { - if (value is null || value < 1) - return; - - if (Models.AutoFetchManager.Instance.Interval != value) - { - Models.AutoFetchManager.Instance.Interval = (int)value; - OnPropertyChanged(); - } - } - } - public int ShellOrTerminal { get => _shellOrTerminal; diff --git a/src/ViewModels/Pull.cs b/src/ViewModels/Pull.cs index 75c0f47a..49c3cb19 100644 --- a/src/ViewModels/Pull.cs +++ b/src/ViewModels/Pull.cs @@ -140,6 +140,8 @@ namespace SourceGit.ViewModels if (!rs) return false; + _repo.MarkFetched(); + // Use merge/rebase instead of pull as fetch is done manually. if (UseRebase) { diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index e2dbef65..eed1bd3a 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using Avalonia.Collections; @@ -323,6 +324,12 @@ namespace SourceGit.ViewModels } } + public bool IsAutoFetching + { + get; + private set; + } + public void Open() { var settingsFile = Path.Combine(_gitDir, "sourcegit.settings"); @@ -359,6 +366,7 @@ namespace SourceGit.ViewModels _inProgressContext = null; _hasUnsolvedConflicts = false; + _autoFetchTimer = new Timer(AutoFetchImpl, null, 5000, 5000); RefreshAll(); } @@ -377,6 +385,9 @@ namespace SourceGit.ViewModels } _settings = null; + _autoFetchTimer.Dispose(); + _autoFetchTimer = null; + _watcher?.Dispose(); _histories.Cleanup(); _workingCopy.Cleanup(); @@ -628,6 +639,11 @@ namespace SourceGit.ViewModels _watcher.MarkWorkingCopyDirtyManually(); } + public void MarkFetched() + { + _lastFetchTime = DateTime.Now; + } + public void NavigateToCommit(string sha) { if (_histories != null) @@ -1991,6 +2007,28 @@ namespace SourceGit.ViewModels } } + private void AutoFetchImpl(object sender) + { + if (!_settings.EnableAutoFetch || IsAutoFetching) + return; + + var lockFile = Path.Combine(_gitDir, "index.lock"); + if (File.Exists(lockFile)) + return; + + var now = DateTime.Now; + var desire = _lastFetchTime.AddMinutes(_settings.AutoFetchInterval); + if (desire > now) + return; + + IsAutoFetching = true; + Dispatcher.UIThread.Invoke(() => OnPropertyChanged(nameof(IsAutoFetching))); + new Commands.Fetch(_fullpath, "--all", true, false, null) { RaiseError = false }.Exec(); + _lastFetchTime = DateTime.Now; + IsAutoFetching = false; + Dispatcher.UIThread.Invoke(() => OnPropertyChanged(nameof(IsAutoFetching))); + } + private string _fullpath = string.Empty; private string _gitDir = string.Empty; private Models.RepositorySettings _settings = null; @@ -2036,5 +2074,8 @@ namespace SourceGit.ViewModels private InProgressContext _inProgressContext = null; private bool _hasUnsolvedConflicts = false; private Models.Commit _searchResultSelectedCommit = null; + + private Timer _autoFetchTimer = null; + private DateTime _lastFetchTime = DateTime.MinValue; } } diff --git a/src/ViewModels/RepositoryConfigure.cs b/src/ViewModels/RepositoryConfigure.cs index 8ddf84a5..fe5b1a2f 100644 --- a/src/ViewModels/RepositoryConfigure.cs +++ b/src/ViewModels/RepositoryConfigure.cs @@ -42,6 +42,26 @@ namespace SourceGit.ViewModels set => SetProperty(ref _httpProxy, value); } + public bool EnableAutoFetch + { + get => _repo.Settings.EnableAutoFetch; + set => _repo.Settings.EnableAutoFetch = value; + } + + public int? AutoFetchInterval + { + get => _repo.Settings.AutoFetchInterval; + set + { + if (value is null || value < 1) + return; + + var interval = (int)value; + if (_repo.Settings.AutoFetchInterval != interval) + _repo.Settings.AutoFetchInterval = interval; + } + } + public AvaloniaList CommitTemplates { get => _repo.Settings.CommitTemplates; diff --git a/src/Views/Preference.axaml b/src/Views/Preference.axaml index 18cf64a8..cbc785b5 100644 --- a/src/Views/Preference.axaml +++ b/src/Views/Preference.axaml @@ -52,7 +52,7 @@ - + - - - - - - - - - diff --git a/src/Views/Repository.axaml b/src/Views/Repository.axaml index 6200bd69..e8a0f424 100644 --- a/src/Views/Repository.axaml +++ b/src/Views/Repository.axaml @@ -631,5 +631,19 @@ + + + + + + + + + + diff --git a/src/Views/RepositoryConfigure.axaml b/src/Views/RepositoryConfigure.axaml index 346639e2..e871759e 100644 --- a/src/Views/RepositoryConfigure.axaml +++ b/src/Views/RepositoryConfigure.axaml @@ -51,7 +51,7 @@ - + + + + + + + + +