From cf537260422f4d68b8429357ee05abf6efd5754f Mon Sep 17 00:00:00 2001 From: Tyrie Vella Date: Wed, 8 Apr 2026 16:16:02 -0700 Subject: [PATCH] Remove GVFS.Service.UI (dead code) The Service.UI process displayed Windows toast notifications, but only the MountFailure notification was actively sent, and it provided no useful value. Removing eliminates XmlSerializer and WinRT COM interop dependencies that would block NativeAOT compilation. Removes: project, unit tests, installer integration, service launch logic, notification handler, diagnostics log collection, and the Microsoft.Windows.SDK.Contracts package. Assisted-by: Claude Opus 4.6 Signed-off-by: Tyrie Vella --- Directory.Packages.props | 1 - GVFS.sln | 6 - GVFS/GVFS.Common/GVFSConstants.cs | 2 - GVFS/GVFS.Installers/Setup.iss | 39 ---- GVFS/GVFS.Payload/GVFS.Payload.csproj | 2 - GVFS/GVFS.Payload/layout.bat | 1 - GVFS/GVFS.Service.UI/Data/ActionItem.cs | 17 -- GVFS/GVFS.Service.UI/Data/ActionsData.cs | 10 - GVFS/GVFS.Service.UI/Data/BindingData.cs | 13 -- GVFS/GVFS.Service.UI/Data/BindingItem.cs | 37 ---- GVFS/GVFS.Service.UI/Data/ToastData.cs | 20 -- GVFS/GVFS.Service.UI/Data/VisualData.cs | 10 - GVFS/GVFS.Service.UI/GVFS.Service.UI.csproj | 22 -- GVFS/GVFS.Service.UI/GVFSServiceUI.cs | 56 ----- .../GVFSToastRequestHandler.cs | 193 ------------------ GVFS/GVFS.Service.UI/IToastNotifier.cs | 10 - GVFS/GVFS.Service.UI/Program.cs | 46 ----- GVFS/GVFS.Service.UI/WinToastNotifier.cs | 103 ---------- GVFS/GVFS.Service.UI/XmlList.cs | 32 --- GVFS/GVFS.Service/Configuration.cs | 2 - GVFS/GVFS.Service/GVFS.Service.csproj | 1 - GVFS/GVFS.Service/GVFSService.Windows.cs | 52 ----- .../Handlers/NotificationHandler.cs | 33 +-- GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj | 1 - .../ServiceUI/GVFSToastRequestHandlerTests.cs | 111 ---------- GVFS/GVFS/CommandLine/DiagnoseVerb.cs | 7 - 26 files changed, 1 insertion(+), 826 deletions(-) delete mode 100644 GVFS/GVFS.Service.UI/Data/ActionItem.cs delete mode 100644 GVFS/GVFS.Service.UI/Data/ActionsData.cs delete mode 100644 GVFS/GVFS.Service.UI/Data/BindingData.cs delete mode 100644 GVFS/GVFS.Service.UI/Data/BindingItem.cs delete mode 100644 GVFS/GVFS.Service.UI/Data/ToastData.cs delete mode 100644 GVFS/GVFS.Service.UI/Data/VisualData.cs delete mode 100644 GVFS/GVFS.Service.UI/GVFS.Service.UI.csproj delete mode 100644 GVFS/GVFS.Service.UI/GVFSServiceUI.cs delete mode 100644 GVFS/GVFS.Service.UI/GVFSToastRequestHandler.cs delete mode 100644 GVFS/GVFS.Service.UI/IToastNotifier.cs delete mode 100644 GVFS/GVFS.Service.UI/Program.cs delete mode 100644 GVFS/GVFS.Service.UI/WinToastNotifier.cs delete mode 100644 GVFS/GVFS.Service.UI/XmlList.cs delete mode 100644 GVFS/GVFS.UnitTests/Windows/ServiceUI/GVFSToastRequestHandlerTests.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 2e1b042d8..5b65344c3 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -28,7 +28,6 @@ - diff --git a/GVFS.sln b/GVFS.sln index 80a2cbf0e..5cddccefb 100644 --- a/GVFS.sln +++ b/GVFS.sln @@ -33,8 +33,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GVFS.ReadObjectHook", "GVFS EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GVFS.Service", "GVFS\GVFS.Service\GVFS.Service.csproj", "{5E236AF3-31D7-4313-A129-F080FF058283}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GVFS.Service.UI", "GVFS\GVFS.Service.UI\GVFS.Service.UI.csproj", "{D8FB16E2-EAE0-4E05-A993-940062CD7CA7}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GVFS.Tests", "GVFS\GVFS.Tests\GVFS.Tests.csproj", "{FE70E0D6-B0A6-421D-AA12-F28F822F09A0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GVFS.UnitTests", "GVFS\GVFS.UnitTests\GVFS.UnitTests.csproj", "{1A46C414-7F39-4EF0-B216-A88033D18678}" @@ -115,10 +113,6 @@ Global {5E236AF3-31D7-4313-A129-F080FF058283}.Debug|x64.Build.0 = Debug|Any CPU {5E236AF3-31D7-4313-A129-F080FF058283}.Release|x64.ActiveCfg = Release|Any CPU {5E236AF3-31D7-4313-A129-F080FF058283}.Release|x64.Build.0 = Release|Any CPU - {D8FB16E2-EAE0-4E05-A993-940062CD7CA7}.Debug|x64.ActiveCfg = Debug|Any CPU - {D8FB16E2-EAE0-4E05-A993-940062CD7CA7}.Debug|x64.Build.0 = Debug|Any CPU - {D8FB16E2-EAE0-4E05-A993-940062CD7CA7}.Release|x64.ActiveCfg = Release|Any CPU - {D8FB16E2-EAE0-4E05-A993-940062CD7CA7}.Release|x64.Build.0 = Release|Any CPU {FE70E0D6-B0A6-421D-AA12-F28F822F09A0}.Debug|x64.ActiveCfg = Debug|Any CPU {FE70E0D6-B0A6-421D-AA12-F28F822F09A0}.Debug|x64.Build.0 = Debug|Any CPU {FE70E0D6-B0A6-421D-AA12-F28F822F09A0}.Release|x64.ActiveCfg = Release|Any CPU diff --git a/GVFS/GVFS.Common/GVFSConstants.cs b/GVFS/GVFS.Common/GVFSConstants.cs index 24374b26a..e81ecc635 100644 --- a/GVFS/GVFS.Common/GVFSConstants.cs +++ b/GVFS/GVFS.Common/GVFSConstants.cs @@ -68,7 +68,6 @@ public static class Service { public const string ServiceName = "GVFS.Service"; public const string LogDirectory = "Logs"; - public const string UIName = "GVFS.Service.UI"; } public static class MediaTypes @@ -108,7 +107,6 @@ public static class LogFileTypes public const string Prefetch = "prefetch"; public const string Repair = "repair"; public const string Service = "service"; - public const string ServiceUI = "service_ui"; public const string Sparse = "sparse"; public const string UpgradeVerb = UpgradePrefix + "_verb"; public const string UpgradeProcess = UpgradePrefix + "_process"; diff --git a/GVFS/GVFS.Installers/Setup.iss b/GVFS/GVFS.Installers/Setup.iss index 886da1042..f8a166d75 100644 --- a/GVFS/GVFS.Installers/Setup.iss +++ b/GVFS/GVFS.Installers/Setup.iss @@ -15,7 +15,6 @@ #define GVFSConfigFileName "gvfs.config" #define GVFSStatuscacheTokenFileName "EnableGitStatusCacheToken.dat" #define ServiceName "GVFS.Service" -#define ServiceUIName "VFS For Git" [Setup] AppId={{489CA581-F131-4C28-BE04-4FB178933E6D} @@ -66,9 +65,6 @@ DestDir: "{app}"; Flags: ignoreversion; Source:"{#LayoutDir}\GVFS.Service.exe"; [Dirs] Name: "{app}\ProgramData\{#ServiceName}"; Permissions: users-readexec -[Icons] -Name: "{commonstartmenu}\{#ServiceUIName}"; Filename: "{app}\GVFS.Service.UI.exe"; AppUserModelID: "GVFS" - [UninstallDelete] ; Deletes the entire installation directory, including files and subdirectories Type: filesandordirs; Name: "{app}"; @@ -249,38 +245,6 @@ begin end; end; -procedure StartGVFSServiceUI(); -var - ResultCode: integer; -begin - if GetEnv('GVFS_UNATTENDED') = '1' then - begin - Log('StartGVFSServiceUI: Skipping launching GVFS.Service.UI'); - end - else if ExecAsOriginalUser(ExpandConstant('{app}\GVFS.Service.UI.exe'), '', '', SW_HIDE, ewNoWait, ResultCode) then - begin - Log('StartGVFSServiceUI: Successfully launched GVFS.Service.UI'); - end - else - begin - Log('StartGVFSServiceUI: Failed to launch GVFS.Service.UI'); - end; -end; - -procedure StopGVFSServiceUI(); -var - ResultCode: integer; -begin - if Exec('powershell.exe', '-NoProfile "Stop-Process -Name GVFS.Service.UI"', '', SW_HIDE, ewNoWait, ResultCode) then - begin - Log('StopGVFSServiceUI: Successfully stopped GVFS.Service.UI'); - end - else - begin - RaiseException('Fatal: Could not stop process: GVFS.Service.UI'); - end; -end; - function DeleteFileIfItExists(FilePath: string) : Boolean; begin Result := False; @@ -688,7 +652,6 @@ begin ssPostInstall: begin MigrateConfigAndStatusCacheFiles(); - StartGVFSServiceUI(); if ExpandConstant('{param:REMOUNTREPOS|true}') = 'true' then begin MountRepos(); @@ -707,7 +670,6 @@ begin case CurStep of usUninstall: begin - StopGVFSServiceUI(); UninstallService('GVFS.Service', False); RemovePath(ExpandConstant('{app}')); end; @@ -731,7 +693,6 @@ begin Abort(); end; StopService('GVFS.Service'); - StopGVFSServiceUI(); UninstallGvFlt(); UninstallProjFSIfNecessary(); end; diff --git a/GVFS/GVFS.Payload/GVFS.Payload.csproj b/GVFS/GVFS.Payload/GVFS.Payload.csproj index e7bc79415..830581714 100644 --- a/GVFS/GVFS.Payload/GVFS.Payload.csproj +++ b/GVFS/GVFS.Payload/GVFS.Payload.csproj @@ -22,7 +22,6 @@ - @@ -48,7 +47,6 @@ $(OutputPath)\GVFS.PostIndexChangedHook.exe; $(OutputPath)\GVFS.ReadObjectHook.exe; $(OutputPath)\GVFS.Service.exe; - $(OutputPath)\GVFS.Service.UI.exe; $(OutputPath)\GVFS.VirtualFileSystemHook.exe; $(OutputPath)\GVFS.Virtualization.dll;"> Microsoft400 diff --git a/GVFS/GVFS.Payload/layout.bat b/GVFS/GVFS.Payload/layout.bat index ebdae19c2..70a8de57b 100644 --- a/GVFS/GVFS.Payload/layout.bat +++ b/GVFS/GVFS.Payload/layout.bat @@ -54,7 +54,6 @@ xcopy /Y /S %BUILD_OUT%\GVFS\%MANAGED_OUT_FRAGMENT%\* %OUTPUT% xcopy /Y /S %BUILD_OUT%\GVFS.Hooks\%MANAGED_OUT_FRAGMENT%\* %OUTPUT% xcopy /Y /S %BUILD_OUT%\GVFS.Mount\%MANAGED_OUT_FRAGMENT%\* %OUTPUT% xcopy /Y /S %BUILD_OUT%\GVFS.Service\%MANAGED_OUT_FRAGMENT%\* %OUTPUT% -xcopy /Y /S %BUILD_OUT%\GVFS.Service.UI\%MANAGED_OUT_FRAGMENT%\* %OUTPUT% xcopy /Y /S %BUILD_OUT%\GitHooksLoader\%NATIVE_OUT_FRAGMENT%\* %OUTPUT% xcopy /Y /S %BUILD_OUT%\GVFS.PostIndexChangedHook\%NATIVE_OUT_FRAGMENT%\* %OUTPUT% xcopy /Y /S %BUILD_OUT%\GVFS.ReadObjectHook\%NATIVE_OUT_FRAGMENT%\* %OUTPUT% diff --git a/GVFS/GVFS.Service.UI/Data/ActionItem.cs b/GVFS/GVFS.Service.UI/Data/ActionItem.cs deleted file mode 100644 index 1034ea0aa..000000000 --- a/GVFS/GVFS.Service.UI/Data/ActionItem.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Xml.Serialization; - -namespace GVFS.Service.UI.Data -{ - [XmlRoot("action")] - public class ActionItem - { - [XmlAttribute("content")] - public string Content { get; set; } - - [XmlAttribute("arguments")] - public string Arguments { get; set; } - - [XmlAttribute("activationtype")] - public string ActivationType { get; set; } - } -} \ No newline at end of file diff --git a/GVFS/GVFS.Service.UI/Data/ActionsData.cs b/GVFS/GVFS.Service.UI/Data/ActionsData.cs deleted file mode 100644 index 56b92af81..000000000 --- a/GVFS/GVFS.Service.UI/Data/ActionsData.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Xml.Serialization; - -namespace GVFS.Service.UI.Data -{ - public class ActionsData - { - [XmlAnyElement("actions")] - public XmlList Actions { get; set; } - } -} diff --git a/GVFS/GVFS.Service.UI/Data/BindingData.cs b/GVFS/GVFS.Service.UI/Data/BindingData.cs deleted file mode 100644 index b364abed5..000000000 --- a/GVFS/GVFS.Service.UI/Data/BindingData.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Xml.Serialization; - -namespace GVFS.Service.UI.Data -{ - public class BindingData - { - [XmlAttribute("template")] - public string Template { get; set; } - - [XmlAnyElement] - public XmlList Items { get; set; } - } -} diff --git a/GVFS/GVFS.Service.UI/Data/BindingItem.cs b/GVFS/GVFS.Service.UI/Data/BindingItem.cs deleted file mode 100644 index e116d1a16..000000000 --- a/GVFS/GVFS.Service.UI/Data/BindingItem.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Xml.Serialization; - -namespace GVFS.Service.UI.Data -{ - public abstract class BindingItem - { - [XmlRoot("text")] - public class TextData : BindingItem - { - public TextData() - { - // Required for serialization - } - - public TextData(string value) - { - this.Value = value; - } - - [XmlText] - public string Value { get; set; } - } - - [XmlRoot("image")] - public class ImageData : BindingItem - { - [XmlAttribute("placement")] - public string Placement { get; set; } - - [XmlAttribute("src")] - public string Source { get; set; } - - [XmlAttribute("hint-crop")] - public string HintCrop { get; set; } - } - } -} diff --git a/GVFS/GVFS.Service.UI/Data/ToastData.cs b/GVFS/GVFS.Service.UI/Data/ToastData.cs deleted file mode 100644 index 6750e4e78..000000000 --- a/GVFS/GVFS.Service.UI/Data/ToastData.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Xml.Serialization; - -namespace GVFS.Service.UI.Data -{ - [XmlRoot("toast")] - public class ToastData - { - [XmlAttribute("launch")] - public string Launch { get; set; } - - [XmlElement("visual")] - public VisualData Visual { get; set; } - - [XmlElement("actions")] - public ActionsData Actions { get; set; } - - [XmlElement("scenario")] - public string Scenario { get; set; } - } -} diff --git a/GVFS/GVFS.Service.UI/Data/VisualData.cs b/GVFS/GVFS.Service.UI/Data/VisualData.cs deleted file mode 100644 index 10fb75d49..000000000 --- a/GVFS/GVFS.Service.UI/Data/VisualData.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Xml.Serialization; - -namespace GVFS.Service.UI.Data -{ - public class VisualData - { - [XmlElement("binding")] - public BindingData Binding { get; set; } - } -} diff --git a/GVFS/GVFS.Service.UI/GVFS.Service.UI.csproj b/GVFS/GVFS.Service.UI/GVFS.Service.UI.csproj deleted file mode 100644 index 4f3c5ac83..000000000 --- a/GVFS/GVFS.Service.UI/GVFS.Service.UI.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - Exe - net471 - - - - - - - - - - - - - PreserveNewest - - - - diff --git a/GVFS/GVFS.Service.UI/GVFSServiceUI.cs b/GVFS/GVFS.Service.UI/GVFSServiceUI.cs deleted file mode 100644 index c81e80b7d..000000000 --- a/GVFS/GVFS.Service.UI/GVFSServiceUI.cs +++ /dev/null @@ -1,56 +0,0 @@ -using GVFS.Common; -using GVFS.Common.NamedPipes; -using GVFS.Common.Tracing; -using System; -using System.Threading; - -namespace GVFS.Service.UI -{ - public class GVFSServiceUI - { - private readonly ITracer tracer; - private readonly GVFSToastRequestHandler toastRequestHandler; - - public GVFSServiceUI(ITracer tracer, GVFSToastRequestHandler toastRequestHandler) - { - this.tracer = tracer; - this.toastRequestHandler = toastRequestHandler; - } - - public void Start(string[] args) - { - using (ITracer activity = this.tracer.StartActivity("Start", EventLevel.Informational)) - using (NamedPipeServer server = NamedPipeServer.StartNewServer(GVFSConstants.Service.UIName, this.tracer, this.HandleRequest)) - { - ManualResetEvent mre = new ManualResetEvent(false); - mre.WaitOne(); - } - } - - private void HandleRequest(ITracer tracer, string request, NamedPipeServer.Connection connection) - { - try - { - NamedPipeMessages.Message message = NamedPipeMessages.Message.FromString(request); - switch (message.Header) - { - case NamedPipeMessages.Notification.Request.Header: - NamedPipeMessages.Notification.Request toastRequest = NamedPipeMessages.Notification.Request.FromMessage(message); - if (toastRequest != null) - { - using (ITracer activity = this.tracer.StartActivity("SendToast", EventLevel.Informational)) - { - this.toastRequestHandler.HandleToastRequest(activity, toastRequest); - } - } - - break; - } - } - catch (Exception e) - { - this.tracer.RelatedError("Unhandled exception: {0}", e.ToString()); - } - } - } -} diff --git a/GVFS/GVFS.Service.UI/GVFSToastRequestHandler.cs b/GVFS/GVFS.Service.UI/GVFSToastRequestHandler.cs deleted file mode 100644 index f6c5872b8..000000000 --- a/GVFS/GVFS.Service.UI/GVFSToastRequestHandler.cs +++ /dev/null @@ -1,193 +0,0 @@ -using GVFS.Common.NamedPipes; -using GVFS.Common.Tracing; -using System; -using System.Diagnostics; -using System.IO; - -namespace GVFS.Service.UI -{ - public class GVFSToastRequestHandler - { - private const string VFSForGitAutomountStartTitle= "VFS For Git Automount"; - private const string VFSForGitAutomountStartMessageFormat = "Attempting to mount {0} VFS For Git {1}"; - private const string VFSForGitMultipleRepos = "repos"; - private const string VFSForGitSingleRepo = "repo"; - - private const string VFSForGitAutomountSuccessTitle = "VFS For Git Automount"; - private const string VFSForGitAutomountSuccessMessageFormat = "The following VFS For Git repo is now mounted: {0}{1}"; - - private const string VFSForGitAutomountErrorTitle = "VFS For Git Automount"; - private const string VFSForGitAutomountErrorMessageFormat = "The following VFS For Git repo failed to mount: {0}{1}"; - private const string VFSForGitAutomountButtonTitle = "Retry"; - - private const string VFSForGitUpgradeTitleFormat = "New version {0} is available"; - private const string VFSForGitUpgradeMessage = "Upgrade will unmount and remount VFS For Git repos, ensure you are at a stopping point. When ready, click Upgrade button to run upgrade."; - private const string VFSForGitUpgradeButtonTitle = "Upgrade"; - - private const string VFSForGitRemountActionPrefix = "gvfs mount"; - private const string VFSForGitUpgradeActionPrefix = "gvfs upgrade --confirm"; - - private readonly ITracer tracer; - private readonly IToastNotifier toastNotifier; - - public GVFSToastRequestHandler(IToastNotifier toastNotifier, ITracer tracer) - { - this.toastNotifier = toastNotifier; - this.toastNotifier.UserResponseCallback = this.UserResponseCallback; - this.tracer = tracer; - } - - public void HandleToastRequest(ITracer tracer, NamedPipeMessages.Notification.Request request) - { - string title = null; - string message = null; - string buttonTitle = null; - string args = null; - string path = null; - - switch (request.Id) - { - case NamedPipeMessages.Notification.Request.Identifier.AutomountStart: - string reposSuffix = request.EnlistmentCount <= 1 ? VFSForGitSingleRepo : VFSForGitMultipleRepos; - title = VFSForGitAutomountStartTitle; - message = string.Format(VFSForGitAutomountStartMessageFormat, request.EnlistmentCount, reposSuffix); - break; - - case NamedPipeMessages.Notification.Request.Identifier.MountSuccess: - if (this.TryValidatePath(request.Enlistment, out path, this.tracer)) - { - title = VFSForGitAutomountSuccessTitle; - message = string.Format(VFSForGitAutomountSuccessMessageFormat, Environment.NewLine, path); - } - - break; - - case NamedPipeMessages.Notification.Request.Identifier.MountFailure: - if (this.TryValidatePath(request.Enlistment, out path, this.tracer)) - { - title = VFSForGitAutomountErrorTitle; - message = string.Format(VFSForGitAutomountErrorMessageFormat, Environment.NewLine, path); - buttonTitle = VFSForGitAutomountButtonTitle; - args = $"{VFSForGitRemountActionPrefix} {path}"; - } - - break; - - case NamedPipeMessages.Notification.Request.Identifier.UpgradeAvailable: - title = string.Format(VFSForGitUpgradeTitleFormat, request.NewVersion); - message = string.Format(VFSForGitUpgradeMessage); - buttonTitle = VFSForGitUpgradeButtonTitle; - args = $"{VFSForGitUpgradeActionPrefix}"; - break; - } - - if (title != null && message != null) - { - this.toastNotifier.Notify(title, message, buttonTitle, args); - } - } - - public void UserResponseCallback(string args) - { - if (string.IsNullOrEmpty(args)) - { - this.tracer.RelatedError($"{nameof(this.UserResponseCallback)}: Received null arguments in Toaster callback."); - return; - } - - using (ITracer activity = this.tracer.StartActivity("GVFSToastCallback", EventLevel.Informational)) - { - string gvfsCmd = null; - bool elevate = false; - - if (args.StartsWith(VFSForGitUpgradeActionPrefix)) - { - this.tracer.RelatedInfo($"gvfs upgrade action."); - gvfsCmd = "gvfs upgrade --confirm"; - elevate = true; - } - else if (args.StartsWith(VFSForGitRemountActionPrefix)) - { - string path = args.Substring(VFSForGitRemountActionPrefix.Length, args.Length - VFSForGitRemountActionPrefix.Length); - if (this.TryValidatePath(path, out string enlistment, activity)) - { - this.tracer.RelatedInfo($"gvfs mount action {enlistment}."); - gvfsCmd = $"gvfs mount \"{enlistment}\""; - } - else - { - EventMetadata metadata = new EventMetadata(); - metadata.Add(nameof(args), args); - metadata.Add(nameof(path), path); - this.tracer.RelatedError(metadata, $"{nameof(this.UserResponseCallback)}- Invalid enlistment path specified in Toaster callback."); - } - } - else - { - this.tracer.RelatedError($"{nameof(this.UserResponseCallback)}- Unknown action({args}) specified in Toaster callback."); - } - - if (!string.IsNullOrEmpty(gvfsCmd)) - { - this.launchGVFSInCommandPrompt(gvfsCmd, elevate, activity); - } - } - } - - private bool TryValidatePath(string path, out string validatedPath, ITracer tracer) - { - try - { - validatedPath = Path.GetFullPath(path); - return true; - } - catch (Exception ex) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Exception", ex.ToString()); - metadata.Add("Path", path); - - tracer.RelatedError(metadata, $"{nameof(this.TryValidatePath)}: {path}. {ex.ToString()}"); - } - - validatedPath = null; - return false; - } - - private void launchGVFSInCommandPrompt(string fullGvfsCmd, bool elevate, ITracer tracer) - { - const string cmdPath = "CMD.exe"; - ProcessStartInfo processInfo = new ProcessStartInfo(cmdPath); - processInfo.UseShellExecute = true; - processInfo.RedirectStandardInput = false; - processInfo.RedirectStandardOutput = false; - processInfo.RedirectStandardError = false; - processInfo.WindowStyle = ProcessWindowStyle.Normal; - processInfo.CreateNoWindow = false; - - // /K option is so the user gets the time to read the output of the command and - // manually close the cmd window after that. - processInfo.Arguments = "/K " + fullGvfsCmd; - if (elevate) - { - processInfo.Verb = "runas"; - } - - tracer.RelatedInfo($"{nameof(this.UserResponseCallback)}- Running {cmdPath} /K {fullGvfsCmd}"); - - try - { - Process.Start(processInfo); - } - catch (Exception ex) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Exception", ex.ToString()); - metadata.Add(nameof(fullGvfsCmd), fullGvfsCmd); - metadata.Add(nameof(elevate), elevate); - - tracer.RelatedError(metadata, $"{nameof(this.launchGVFSInCommandPrompt)}: Error launching {fullGvfsCmd}. {ex.ToString()}"); - } - } - } -} diff --git a/GVFS/GVFS.Service.UI/IToastNotifier.cs b/GVFS/GVFS.Service.UI/IToastNotifier.cs deleted file mode 100644 index 60cd2f15b..000000000 --- a/GVFS/GVFS.Service.UI/IToastNotifier.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace GVFS.Service.UI -{ - public interface IToastNotifier - { - Action UserResponseCallback { get; set; } - void Notify(string title, string message, string actionButtonTitle, string callbackArgs); - } -} diff --git a/GVFS/GVFS.Service.UI/Program.cs b/GVFS/GVFS.Service.UI/Program.cs deleted file mode 100644 index 3c03bbc66..000000000 --- a/GVFS/GVFS.Service.UI/Program.cs +++ /dev/null @@ -1,46 +0,0 @@ -using GVFS.Common; -using GVFS.Common.Tracing; -using GVFS.PlatformLoader; -using System; - -namespace GVFS.Service.UI -{ - public static class Program - { - public static void Main(string[] args) - { - GVFSPlatformLoader.Initialize(); - - using (JsonTracer tracer = new JsonTracer("Microsoft.Git.GVFS.Service.UI", "Service.UI")) - { - string error; - string serviceUILogDirectory = GVFSPlatform.Instance.GetLogsDirectoryForGVFSComponent(GVFSConstants.Service.UIName); - if (!GVFSPlatform.Instance.FileSystem.TryCreateDirectoryWithAdminAndUserModifyPermissions(serviceUILogDirectory, out error)) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add(nameof(serviceUILogDirectory), serviceUILogDirectory); - metadata.Add(nameof(error), error); - tracer.RelatedWarning( - metadata, - "Failed to create service UI logs directory", - Keywords.Telemetry); - } - else - { - string logFilePath = GVFSEnlistment.GetNewGVFSLogFileName( - serviceUILogDirectory, - GVFSConstants.LogFileTypes.ServiceUI, - logId: Environment.UserName); - - tracer.AddLogFileEventListener(logFilePath, EventLevel.Informational, Keywords.Any); - } - - WinToastNotifier winToastNotifier = new WinToastNotifier(tracer); - GVFSToastRequestHandler toastRequestHandler = new GVFSToastRequestHandler(winToastNotifier, tracer); - GVFSServiceUI process = new GVFSServiceUI(tracer, toastRequestHandler); - - process.Start(args); - } - } - } -} \ No newline at end of file diff --git a/GVFS/GVFS.Service.UI/WinToastNotifier.cs b/GVFS/GVFS.Service.UI/WinToastNotifier.cs deleted file mode 100644 index 8cf364dfa..000000000 --- a/GVFS/GVFS.Service.UI/WinToastNotifier.cs +++ /dev/null @@ -1,103 +0,0 @@ -using GVFS.Common; -using GVFS.Common.Tracing; -using GVFS.Service.UI.Data; -using System; -using System.IO; -using System.Xml; -using System.Xml.Serialization; -using Windows.UI.Notifications; -using XmlDocument = Windows.Data.Xml.Dom.XmlDocument; - -namespace GVFS.Service.UI -{ - public class WinToastNotifier : IToastNotifier - { - private const string ServiceAppId = "GVFS"; - private const string GVFSIconName = "GitVirtualFileSystem.ico"; - private ITracer tracer; - - public WinToastNotifier(ITracer tracer) - { - this.tracer = tracer; - } - - public Action UserResponseCallback { get; set; } - - public void Notify(string title, string message, string actionButtonTitle, string callbackArgs) - { - // Reference: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts - ToastData toastData = new ToastData(); - - toastData.Visual = new VisualData(); - - BindingData binding = new BindingData(); - toastData.Visual.Binding = binding; - - // ToastGeneric- Our toast contains VFSForGit icon and text - binding.Template = "ToastGeneric"; - binding.Items = new XmlList(); - binding.Items.Add(new BindingItem.TextData(title)); - binding.Items.Add(new BindingItem.TextData(message)); - - string logo = "file:///" + Path.Combine(ProcessHelper.GetCurrentProcessLocation(), GVFSIconName); - binding.Items.Add(new BindingItem.ImageData() - { - Source = logo, - Placement = "appLogoOverride", - HintCrop = "circle" - }); - - if (!string.IsNullOrEmpty(actionButtonTitle)) - { - ActionsData actionsData = new ActionsData(); - actionsData.Actions = new XmlList(); - actionsData.Actions.Add(new ActionItem() - { - Content = actionButtonTitle, - Arguments = string.IsNullOrEmpty(callbackArgs) ? string.Empty : callbackArgs, - ActivationType = "background" - }); - - toastData.Actions = actionsData; - } - - XmlDocument toastXml = new XmlDocument(); - using (StringWriter stringWriter = new StringWriter()) - using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { OmitXmlDeclaration = true })) - { - XmlSerializer serializer = new XmlSerializer(toastData.GetType()); - XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(); - namespaces.Add(string.Empty, string.Empty); - - serializer.Serialize(xmlWriter, toastData, namespaces); - - toastXml.LoadXml(stringWriter.ToString()); - } - - ToastNotification toastNotification = new ToastNotification(toastXml); - toastNotification.Activated += this.ToastActivated; - toastNotification.Dismissed += this.ToastDismissed; - toastNotification.Failed += this.ToastFailed; - - ToastNotifier toastNotifier = ToastNotificationManager.CreateToastNotifier(ServiceAppId); - toastNotifier.Show(toastNotification); - } - - private void ToastActivated(ToastNotification sender, object e) - { - ToastActivatedEventArgs args = (ToastActivatedEventArgs)e; - - this.UserResponseCallback?.Invoke(args.Arguments); - } - - private void ToastDismissed(ToastNotification sender, ToastDismissedEventArgs e) - { - this.tracer.RelatedInfo($"{nameof(this.ToastDismissed)}: {e.Reason}"); - } - - private void ToastFailed(ToastNotification sender, ToastFailedEventArgs e) - { - this.tracer.RelatedInfo($"{nameof(this.ToastFailed)}: {e.ErrorCode.ToString()}"); - } - } -} diff --git a/GVFS/GVFS.Service.UI/XmlList.cs b/GVFS/GVFS.Service.UI/XmlList.cs deleted file mode 100644 index 06a2dad50..000000000 --- a/GVFS/GVFS.Service.UI/XmlList.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Xml; -using System.Xml.Schema; -using System.Xml.Serialization; - -namespace GVFS.Service.UI -{ - public class XmlList : List, IXmlSerializable where T : class - { - public XmlSchema GetSchema() - { - throw new NotImplementedException(); - } - - public void ReadXml(XmlReader reader) - { - throw new NotImplementedException(); - } - - public void WriteXml(XmlWriter writer) - { - XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); - ns.Add(string.Empty, string.Empty); - foreach (T item in this) - { - XmlSerializer xml = new XmlSerializer(item.GetType()); - xml.Serialize(writer, item, ns); - } - } - } -} diff --git a/GVFS/GVFS.Service/Configuration.cs b/GVFS/GVFS.Service/Configuration.cs index f5c8b65be..0e4ebe18e 100644 --- a/GVFS/GVFS.Service/Configuration.cs +++ b/GVFS/GVFS.Service/Configuration.cs @@ -11,7 +11,6 @@ public class Configuration private Configuration() { this.GVFSLocation = Path.Combine(AssemblyPath, GVFSPlatform.Instance.Constants.GVFSExecutableName); - this.GVFSServiceUILocation = Path.Combine(AssemblyPath, GVFSConstants.Service.UIName + GVFSPlatform.Instance.Constants.ExecutableExtension); } public static Configuration Instance @@ -36,6 +35,5 @@ public static string AssemblyPath } public string GVFSLocation { get; private set; } - public string GVFSServiceUILocation { get; private set; } } } diff --git a/GVFS/GVFS.Service/GVFS.Service.csproj b/GVFS/GVFS.Service/GVFS.Service.csproj index b557e3a41..cc8c4c9f8 100644 --- a/GVFS/GVFS.Service/GVFS.Service.csproj +++ b/GVFS/GVFS.Service/GVFS.Service.csproj @@ -8,7 +8,6 @@ - diff --git a/GVFS/GVFS.Service/GVFSService.Windows.cs b/GVFS/GVFS.Service/GVFSService.Windows.cs index 5b3048b74..f0eee8385 100644 --- a/GVFS/GVFS.Service/GVFSService.Windows.cs +++ b/GVFS/GVFS.Service/GVFSService.Windows.cs @@ -5,10 +5,8 @@ using GVFS.Platform.Windows; using GVFS.Service.Handlers; using System; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Runtime.Serialization; using System.Security.AccessControl; using System.ServiceProcess; using System.Threading; @@ -130,8 +128,6 @@ protected override void OnSessionChange(SessionChangeDescription changeDescripti { this.tracer.RelatedInfo("SessionLogon detected, sessionId: {0}", changeDescription.SessionId); - this.LaunchServiceUIIfNotRunning(changeDescription.SessionId); - using (ITracer activity = this.tracer.StartActivity("LogonAutomount", EventLevel.Informational)) { this.repoRegistry.AutoMountRepos( @@ -358,9 +354,6 @@ private void CreateAndConfigureProgramDataDirectories() // Ensure the ACLs are set correctly on any files or directories that were already created (e.g. after upgrading VFS4G) Directory.SetAccessControl(serviceDataRootPath, serviceDataRootSecurity); - - // Special rules for the Service.UI logs, as non-elevated users need to be be able to write - this.CreateAndConfigureLogDirectory(GVFSPlatform.Instance.GetLogsDirectoryForGVFSComponent(GVFSConstants.Service.UIName)); } private void CreateAndConfigureLogDirectory(string path) @@ -404,50 +397,5 @@ private DirectorySecurity GetServiceDirectorySecurity(string serviceDataRootPath return serviceDataRootSecurity; } - private void LaunchServiceUIIfNotRunning(int sessionId) - { - NamedPipeClient client; - using (client = new NamedPipeClient(GVFSConstants.Service.UIName)) - { - if (!client.Connect()) - { - this.tracer.RelatedError($"Could not connect with {GVFSConstants.Service.UIName}. Attempting to relaunch."); - - this.TerminateExistingProcess(GVFSConstants.Service.UIName, sessionId); - - CurrentUser currentUser = new CurrentUser(this.tracer, sessionId); - if (!currentUser.RunAs( - Configuration.Instance.GVFSServiceUILocation, - string.Empty)) - { - this.tracer.RelatedError("Could not start " + GVFSConstants.Service.UIName); - } - else - { - this.tracer.RelatedInfo($"Successfully launched {GVFSConstants.Service.UIName}. "); - } - } - } - } - - private void TerminateExistingProcess(string processName, int sessionId) - { - try - { - foreach (Process process in Process.GetProcessesByName(processName)) - { - if (process.SessionId == sessionId) - { - this.tracer.RelatedInfo($"{nameof(this.TerminateExistingProcess)}- Stopping {processName}, in session {sessionId}."); - - process.Kill(); - } - } - } - catch (Exception ex) - { - this.tracer.RelatedError("Could not find and kill existing instances of {0}: {1}", processName, ex.Message); - } - } } } diff --git a/GVFS/GVFS.Service/Handlers/NotificationHandler.cs b/GVFS/GVFS.Service/Handlers/NotificationHandler.cs index a7777b8fc..a0ec6876c 100644 --- a/GVFS/GVFS.Service/Handlers/NotificationHandler.cs +++ b/GVFS/GVFS.Service/Handlers/NotificationHandler.cs @@ -1,47 +1,16 @@ -using GVFS.Common; -using GVFS.Common.NamedPipes; +using GVFS.Common.NamedPipes; using GVFS.Common.Tracing; -using GVFS.Platform.Windows; -using System; -using System.Diagnostics; namespace GVFS.Service.Handlers { public class NotificationHandler : INotificationHandler { - private ITracer tracer; - public NotificationHandler(ITracer tracer) { - this.tracer = tracer; } public void SendNotification(NamedPipeMessages.Notification.Request request) { - using (NamedPipeClient client = new NamedPipeClient(GVFSConstants.Service.UIName)) - { - if (client.Connect()) - { - try - { - if (!client.TrySendRequest(request.ToMessage())) - { - this.tracer.RelatedInfo("Failed to send notification request to " + GVFSConstants.Service.UIName); - } - } - catch (Exception ex) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Exception", ex.ToString()); - metadata.Add("Identifier", request.Id); - this.tracer.RelatedError(metadata, $"{nameof(this.SendNotification)}- Could not send notification request({request.Id}. {ex.ToString()}"); - } - } - else - { - this.tracer.RelatedError($"{nameof(this.SendNotification)}- Could not connect with GVFS.Service.UI, failed to send notification request({request.Id}."); - } - } } } } diff --git a/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj b/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj index 6111e7220..efb890af3 100644 --- a/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj +++ b/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj @@ -8,7 +8,6 @@ - diff --git a/GVFS/GVFS.UnitTests/Windows/ServiceUI/GVFSToastRequestHandlerTests.cs b/GVFS/GVFS.UnitTests/Windows/ServiceUI/GVFSToastRequestHandlerTests.cs deleted file mode 100644 index 34e7073e9..000000000 --- a/GVFS/GVFS.UnitTests/Windows/ServiceUI/GVFSToastRequestHandlerTests.cs +++ /dev/null @@ -1,111 +0,0 @@ -using GVFS.Common.NamedPipes; -using GVFS.Service.UI; -using GVFS.UnitTests.Mock.Common; -using Moq; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace GVFS.UnitTests.Windows.ServiceUI -{ - [TestFixture] - public class GVFSToastRequestHandlerTests - { - private NamedPipeMessages.Notification.Request request; - private GVFSToastRequestHandler toastHandler; - private Mock mockToastNotifier; - private MockTracer tracer; - - [SetUp] - public void Setup() - { - this.tracer = new MockTracer(); - this.mockToastNotifier = new Mock(MockBehavior.Strict); - this.mockToastNotifier.SetupSet(toastNotifier => toastNotifier.UserResponseCallback = It.IsAny>()).Verifiable(); - this.toastHandler = new GVFSToastRequestHandler(this.mockToastNotifier.Object, this.tracer); - this.request = new NamedPipeMessages.Notification.Request(); - } - - [TestCase] - public void UpgradeToastIsActionableAndContainsVersionInfo() - { - const string version = "1.0.956749.2"; - - this.request.Id = NamedPipeMessages.Notification.Request.Identifier.UpgradeAvailable; - this.request.NewVersion = version; - - this.VerifyToastMessage( - expectedTitle: "New version " + version + " is available", - expectedMessage: "click Upgrade button", - expectedButtonTitle: "Upgrade", - expectedGVFSCmd: "gvfs upgrade --confirm"); - } - - [TestCase] - public void MountFailureToastIsActionableAndContainEnlistmentInfo() - { - const string enlistmentRoot = "D:\\Work\\OS"; - - this.request.Id = NamedPipeMessages.Notification.Request.Identifier.MountFailure; - this.request.Enlistment = enlistmentRoot; - - this.VerifyToastMessage( - expectedTitle: "VFS For Git Automount", - expectedMessage: enlistmentRoot, - expectedButtonTitle: "Retry", - expectedGVFSCmd: "gvfs mount " + enlistmentRoot); - } - - [TestCase] - public void MountStartIsNotActionableAndContainsEnlistmentCount() - { - const int enlistmentCount = 10; - - this.request.Id = NamedPipeMessages.Notification.Request.Identifier.AutomountStart; - this.request.EnlistmentCount = enlistmentCount; - - this.VerifyToastMessage( - expectedTitle: "VFS For Git Automount", - expectedMessage: "mount " + enlistmentCount.ToString() + " VFS For Git repos", - expectedButtonTitle: null, - expectedGVFSCmd: null); - } - - [TestCase] - public void UnknownToastRequestGetsIgnored() - { - this.request.Id = (NamedPipeMessages.Notification.Request.Identifier)10; - this.request.EnlistmentCount = 232; - this.request.Enlistment = "C:\\OS"; - - this.toastHandler.HandleToastRequest(this.tracer, this.request); - - this.mockToastNotifier.Verify( - toastNotifier => toastNotifier.Notify( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()), - Times.Never()); - } - - private void VerifyToastMessage( - string expectedTitle, - string expectedMessage, - string expectedButtonTitle, - string expectedGVFSCmd) - { - this.mockToastNotifier.Setup(toastNotifier => toastNotifier.Notify( - expectedTitle, - It.Is(message => message.Contains(expectedMessage)), - expectedButtonTitle, - expectedGVFSCmd)); - - this.toastHandler.HandleToastRequest(this.tracer, this.request); - this.mockToastNotifier.VerifyAll(); - } - } -} diff --git a/GVFS/GVFS/CommandLine/DiagnoseVerb.cs b/GVFS/GVFS/CommandLine/DiagnoseVerb.cs index 1d3a71639..3840bbbb4 100644 --- a/GVFS/GVFS/CommandLine/DiagnoseVerb.cs +++ b/GVFS/GVFS/CommandLine/DiagnoseVerb.cs @@ -133,13 +133,6 @@ protected override void Execute(GVFSEnlistment enlistment) this.ServiceName, copySubFolders: true); - // service ui - this.CopyAllFiles( - GVFSPlatform.Instance.GetCommonAppDataRootForGVFS(), - archiveFolderPath, - GVFSConstants.Service.UIName, - copySubFolders: true); - if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSConfig) { this.CopyFile(GVFSPlatform.Instance.GetSecureDataRootForGVFS(), archiveFolderPath, LocalGVFSConfig.FileName);