using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Threading.Tasks; using Avalonia.Collections; namespace SourceGit.Models { public class RepositorySettings { public string DefaultRemote { get; set; } = string.Empty; public int PreferredMergeMode { get; set; } = 0; public string ConventionalTypesOverride { get; set; } = string.Empty; public bool EnableRecursiveWhenAutoUpdatingSubmodules { get; set; } = true; public bool AskBeforeAutoUpdatingSubmodules { get; set; } = false; public string PreferredOpenAIService { get; set; } = "---"; public AvaloniaList CommitTemplates { get; set; } = []; public AvaloniaList CustomActions { get; set; } = []; public static RepositorySettings Get(string gitCommonDir) { var fileInfo = new FileInfo(Path.Combine(gitCommonDir, "sourcegit.settings")); var fullpath = fileInfo.FullName; if (_cache.TryGetValue(fullpath, out var setting)) return setting; if (!File.Exists(fullpath)) { setting = new(); } else { try { using var stream = File.OpenRead(fullpath); setting = JsonSerializer.Deserialize(stream, JsonCodeGen.Default.RepositorySettings); } catch { setting = new(); } } // Serialize setting again to make sure there are no unnecessary whitespaces. Task.Run(() => { var formatted = JsonSerializer.Serialize(setting, JsonCodeGen.Default.RepositorySettings); setting._orgHash = HashContent(formatted); }); setting._file = fullpath; _cache.Add(fullpath, setting); return setting; } public void Save() { try { var content = JsonSerializer.Serialize(this, JsonCodeGen.Default.RepositorySettings); var hash = HashContent(content); if (!hash.Equals(_orgHash, StringComparison.Ordinal)) { var tmpfile = $"{_file}.tmp"; File.WriteAllText(tmpfile, content); File.Move(tmpfile, _file, true); _orgHash = hash; } } catch { // Ignore save errors } } public CustomAction AddNewCustomAction() { var act = new CustomAction() { Name = "Unnamed Action" }; CustomActions.Add(act); return act; } public void RemoveCustomAction(CustomAction act) { if (act != null) CustomActions.Remove(act); } public void MoveCustomActionUp(CustomAction act) { var idx = CustomActions.IndexOf(act); if (idx > 0) CustomActions.Move(idx - 1, idx); } public void MoveCustomActionDown(CustomAction act) { var idx = CustomActions.IndexOf(act); if (idx < CustomActions.Count - 1) CustomActions.Move(idx + 1, idx); } private static string HashContent(string source) { var hash = MD5.HashData(Encoding.Default.GetBytes(source)); return Convert.ToHexStringLower(hash); } private static Dictionary _cache = new(); private string _file = string.Empty; private string _orgHash = string.Empty; } }