mirror of
https://fastgit.cc/github.com/sourcegit-scm/sourcegit
synced 2026-04-21 05:10:25 +08:00
329 lines
10 KiB
C#
329 lines
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
|
|
namespace SourceGit.Native
|
|
{
|
|
public static partial class OS
|
|
{
|
|
public interface IBackend
|
|
{
|
|
void SetupApp(AppBuilder builder);
|
|
void SetupWindow(Window window);
|
|
|
|
string GetDataDir();
|
|
string FindGitExecutable();
|
|
string FindTerminal(Models.ShellOrTerminal shell);
|
|
List<Models.ExternalTool> FindExternalTools();
|
|
|
|
void OpenTerminal(string workdir, string args);
|
|
void OpenInFileManager(string path);
|
|
void OpenBrowser(string url);
|
|
void OpenWithDefaultEditor(string file);
|
|
}
|
|
|
|
public static string DataDir
|
|
{
|
|
get;
|
|
private set;
|
|
} = string.Empty;
|
|
|
|
public static string GitExecutable
|
|
{
|
|
get => _gitExecutable;
|
|
set
|
|
{
|
|
if (_gitExecutable != value)
|
|
{
|
|
_gitExecutable = value;
|
|
UpdateGitVersion();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string GitVersionString
|
|
{
|
|
get;
|
|
private set;
|
|
} = string.Empty;
|
|
|
|
public static Version GitVersion
|
|
{
|
|
get;
|
|
private set;
|
|
} = new Version(0, 0, 0);
|
|
|
|
public static string CredentialHelper
|
|
{
|
|
get;
|
|
set;
|
|
} = "manager";
|
|
|
|
public static string ShellOrTerminal
|
|
{
|
|
get;
|
|
set;
|
|
} = string.Empty;
|
|
|
|
public static string ShellOrTerminalArgs
|
|
{
|
|
get;
|
|
set;
|
|
} = string.Empty;
|
|
|
|
public static List<Models.ExternalTool> ExternalTools
|
|
{
|
|
get;
|
|
set;
|
|
} = [];
|
|
|
|
public static int ExternalMergerType
|
|
{
|
|
get;
|
|
set;
|
|
} = 0;
|
|
|
|
public static string ExternalMergerExecFile
|
|
{
|
|
get;
|
|
set;
|
|
} = string.Empty;
|
|
|
|
public static string ExternalMergeArgs
|
|
{
|
|
get;
|
|
set;
|
|
} = string.Empty;
|
|
|
|
public static string ExternalDiffArgs
|
|
{
|
|
get;
|
|
set;
|
|
} = string.Empty;
|
|
|
|
public static bool UseSystemWindowFrame
|
|
{
|
|
get => OperatingSystem.IsLinux() && _enableSystemWindowFrame;
|
|
set => _enableSystemWindowFrame = value;
|
|
}
|
|
|
|
static OS()
|
|
{
|
|
if (OperatingSystem.IsWindows())
|
|
_backend = new Windows();
|
|
else if (OperatingSystem.IsMacOS())
|
|
_backend = new MacOS();
|
|
else if (OperatingSystem.IsLinux())
|
|
_backend = new Linux();
|
|
else
|
|
throw new PlatformNotSupportedException();
|
|
}
|
|
|
|
public static void SetupDataDir()
|
|
{
|
|
DataDir = _backend.GetDataDir();
|
|
if (!Directory.Exists(DataDir))
|
|
Directory.CreateDirectory(DataDir);
|
|
}
|
|
|
|
public static void SetupApp(AppBuilder builder)
|
|
{
|
|
_backend.SetupApp(builder);
|
|
}
|
|
|
|
public static void SetupExternalTools()
|
|
{
|
|
ExternalTools = _backend.FindExternalTools();
|
|
}
|
|
|
|
public static void SetupForWindow(Window window)
|
|
{
|
|
_backend.SetupWindow(window);
|
|
}
|
|
|
|
public static void LogException(Exception ex)
|
|
{
|
|
if (ex == null)
|
|
return;
|
|
|
|
var crashDir = Path.Combine(DataDir, "crashes");
|
|
if (!Directory.Exists(crashDir))
|
|
Directory.CreateDirectory(crashDir);
|
|
|
|
var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
|
var file = Path.Combine(crashDir, $"{time}.log");
|
|
using var writer = new StreamWriter(file);
|
|
writer.WriteLine($"Crash::: {ex.GetType().FullName}: {ex.Message}");
|
|
writer.WriteLine();
|
|
writer.WriteLine("----------------------------");
|
|
writer.WriteLine($"Version: {Assembly.GetExecutingAssembly().GetName().Version}");
|
|
writer.WriteLine($"OS: {Environment.OSVersion}");
|
|
writer.WriteLine($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}");
|
|
writer.WriteLine($"Source: {ex.Source}");
|
|
writer.WriteLine($"Thread Name: {Thread.CurrentThread.Name ?? "Unnamed"}");
|
|
writer.WriteLine($"App Start Time: {Process.GetCurrentProcess().StartTime}");
|
|
writer.WriteLine($"Exception Time: {DateTime.Now}");
|
|
writer.WriteLine($"Memory Usage: {Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024} MB");
|
|
writer.WriteLine("----------------------------");
|
|
writer.WriteLine();
|
|
writer.WriteLine(ex);
|
|
writer.Flush();
|
|
}
|
|
|
|
public static string FindGitExecutable()
|
|
{
|
|
return _backend.FindGitExecutable();
|
|
}
|
|
|
|
public static bool TestShellOrTerminal(Models.ShellOrTerminal shell)
|
|
{
|
|
return !string.IsNullOrEmpty(_backend.FindTerminal(shell));
|
|
}
|
|
|
|
public static void SetShellOrTerminal(Models.ShellOrTerminal shell)
|
|
{
|
|
ShellOrTerminal = shell != null ? _backend.FindTerminal(shell) : string.Empty;
|
|
ShellOrTerminalArgs = shell.Args;
|
|
}
|
|
|
|
public static Models.DiffMergeTool GetDiffMergeTool(bool onlyDiff)
|
|
{
|
|
if (ExternalMergerType < 0 || ExternalMergerType >= Models.ExternalMerger.Supported.Count)
|
|
return null;
|
|
|
|
if (ExternalMergerType != 0 && (string.IsNullOrEmpty(ExternalMergerExecFile) || !File.Exists(ExternalMergerExecFile)))
|
|
return null;
|
|
|
|
return new Models.DiffMergeTool(ExternalMergerExecFile, onlyDiff ? ExternalDiffArgs : ExternalMergeArgs);
|
|
}
|
|
|
|
public static void AutoSelectExternalMergeToolExecFile()
|
|
{
|
|
if (ExternalMergerType >= 0 && ExternalMergerType < Models.ExternalMerger.Supported.Count)
|
|
{
|
|
var merger = Models.ExternalMerger.Supported[ExternalMergerType];
|
|
var externalTool = ExternalTools.Find(x => x.Name.Equals(merger.Name, StringComparison.Ordinal));
|
|
if (externalTool != null)
|
|
ExternalMergerExecFile = externalTool.ExecFile;
|
|
else if (!OperatingSystem.IsWindows() && File.Exists(merger.Finder))
|
|
ExternalMergerExecFile = merger.Finder;
|
|
else
|
|
ExternalMergerExecFile = string.Empty;
|
|
|
|
ExternalDiffArgs = merger.DiffCmd;
|
|
ExternalMergeArgs = merger.MergeCmd;
|
|
}
|
|
else
|
|
{
|
|
ExternalMergerExecFile = string.Empty;
|
|
ExternalDiffArgs = string.Empty;
|
|
ExternalMergeArgs = string.Empty;
|
|
}
|
|
}
|
|
|
|
public static void OpenInFileManager(string path)
|
|
{
|
|
_backend.OpenInFileManager(path);
|
|
}
|
|
|
|
public static void OpenBrowser(string url)
|
|
{
|
|
_backend.OpenBrowser(url);
|
|
}
|
|
|
|
public static void OpenTerminal(string workdir)
|
|
{
|
|
if (string.IsNullOrEmpty(ShellOrTerminal))
|
|
Models.Notification.Send(workdir, "Terminal is not specified! Please confirm that the correct shell/terminal has been configured.", true);
|
|
else
|
|
_backend.OpenTerminal(workdir, ShellOrTerminalArgs);
|
|
}
|
|
|
|
public static void OpenWithDefaultEditor(string file)
|
|
{
|
|
_backend.OpenWithDefaultEditor(file);
|
|
}
|
|
|
|
public static string GetAbsPath(string root, string sub)
|
|
{
|
|
var fullpath = Path.Combine(root, sub);
|
|
if (OperatingSystem.IsWindows())
|
|
return fullpath.Replace('/', '\\');
|
|
|
|
return fullpath;
|
|
}
|
|
|
|
public static string GetRelativePathToHome(string path)
|
|
{
|
|
if (OperatingSystem.IsWindows())
|
|
return path;
|
|
|
|
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
|
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
|
|
if (path.StartsWith(home, StringComparison.Ordinal))
|
|
return $"~{path.AsSpan(prefixLen)}";
|
|
|
|
return path;
|
|
}
|
|
|
|
private static void UpdateGitVersion()
|
|
{
|
|
if (string.IsNullOrEmpty(_gitExecutable) || !File.Exists(_gitExecutable))
|
|
{
|
|
GitVersionString = string.Empty;
|
|
GitVersion = new Version(0, 0, 0);
|
|
return;
|
|
}
|
|
|
|
var start = new ProcessStartInfo();
|
|
start.FileName = _gitExecutable;
|
|
start.Arguments = "--version";
|
|
start.UseShellExecute = false;
|
|
start.CreateNoWindow = true;
|
|
start.RedirectStandardOutput = true;
|
|
start.RedirectStandardError = true;
|
|
start.StandardOutputEncoding = Encoding.UTF8;
|
|
start.StandardErrorEncoding = Encoding.UTF8;
|
|
|
|
try
|
|
{
|
|
using var proc = Process.Start(start)!;
|
|
var rs = proc.StandardOutput.ReadToEnd();
|
|
proc.WaitForExit();
|
|
if (proc.ExitCode == 0 && !string.IsNullOrWhiteSpace(rs))
|
|
{
|
|
GitVersionString = rs.Trim();
|
|
|
|
var match = REG_GIT_VERSION().Match(GitVersionString);
|
|
if (match.Success)
|
|
{
|
|
var major = int.Parse(match.Groups[1].Value);
|
|
var minor = int.Parse(match.Groups[2].Value);
|
|
var build = int.Parse(match.Groups[3].Value);
|
|
GitVersion = new Version(major, minor, build);
|
|
GitVersionString = GitVersionString.Substring(11).Trim();
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Ignore errors
|
|
}
|
|
}
|
|
|
|
[GeneratedRegex(@"^git version[\s\w]*(\d+)\.(\d+)[\.\-](\d+).*$")]
|
|
private static partial Regex REG_GIT_VERSION();
|
|
|
|
private static IBackend _backend = null;
|
|
private static string _gitExecutable = string.Empty;
|
|
private static bool _enableSystemWindowFrame = false;
|
|
}
|
|
}
|