From 704411b3d3c31c09b10a81c957ac7a675885c0b6 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Wed, 30 Jun 2021 15:37:15 -0400 Subject: [PATCH 1/2] Delete ProductUpgradeTimer This timer is responsible for checking if there is a new VFS for Git version on a timer, then launches a notification to GVFS.Service.UI. I was hoping to delete all of GVFS.Service.UI, but we need the toast notifications for when we attempt to auto-mount and have a failure. Signed-off-by: Derrick Stolee --- GVFS/GVFS.Service/GVFSService.Windows.cs | 13 -- GVFS/GVFS.Service/ProductUpgradeTimer.cs | 261 ----------------------- 2 files changed, 274 deletions(-) delete mode 100644 GVFS/GVFS.Service/ProductUpgradeTimer.cs diff --git a/GVFS/GVFS.Service/GVFSService.Windows.cs b/GVFS/GVFS.Service/GVFSService.Windows.cs index 701e25caad..90ef0922be 100644 --- a/GVFS/GVFS.Service/GVFSService.Windows.cs +++ b/GVFS/GVFS.Service/GVFSService.Windows.cs @@ -26,7 +26,6 @@ public class GVFSService : ServiceBase private string serviceName; private string serviceDataLocation; private RepoRegistry repoRegistry; - private ProductUpgradeTimer productUpgradeTimer; private WindowsRequestHandler requestHandler; private INotificationHandler notificationHandler; @@ -36,7 +35,6 @@ public GVFSService(JsonTracer tracer) this.serviceName = GVFSConstants.Service.ServiceName; this.CanHandleSessionChangeEvent = true; this.notificationHandler = new NotificationHandler(tracer); - this.productUpgradeTimer = new ProductUpgradeTimer(tracer, this.notificationHandler); } public void Run() @@ -74,12 +72,6 @@ public void Run() EnableAndAttachProjFSHandler.TryEnablePrjFlt(activity, out error); } - // Start product upgrade timer only after attempting to enable prjflt. - // On Windows server (where PrjFlt is not inboxed) this helps avoid - // a race between TryEnablePrjFlt() and installer pre-check which is - // performed by UpgradeTimer in parallel. - this.productUpgradeTimer.Start(); - this.serviceStopped.WaitOne(); } } @@ -98,11 +90,6 @@ public void StopRunning() try { - if (this.productUpgradeTimer != null) - { - this.productUpgradeTimer.Stop(); - } - if (this.tracer != null) { this.tracer.RelatedInfo("Stopping"); diff --git a/GVFS/GVFS.Service/ProductUpgradeTimer.cs b/GVFS/GVFS.Service/ProductUpgradeTimer.cs deleted file mode 100644 index ee37448851..0000000000 --- a/GVFS/GVFS.Service/ProductUpgradeTimer.cs +++ /dev/null @@ -1,261 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.NamedPipes; -using GVFS.Common.NuGetUpgrade; -using GVFS.Common.Tracing; -using GVFS.Service.Handlers; -using GVFS.Upgrader; -using System; -using System.IO; -using System.Threading; - -namespace GVFS.Service -{ - public class ProductUpgradeTimer : IDisposable - { - private static readonly TimeSpan TimeInterval = TimeSpan.FromDays(1); - private JsonTracer tracer; - private PhysicalFileSystem fileSystem; - private Timer timer; - private INotificationHandler notificationHandler; - - public ProductUpgradeTimer(JsonTracer tracer, INotificationHandler notificationHandler) - { - this.tracer = tracer; - this.notificationHandler = notificationHandler; - this.fileSystem = new PhysicalFileSystem(); - } - - public void Start() - { - if (!GVFSEnlistment.IsUnattended(this.tracer)) - { - // Adding 60 seconds wait time here. This gives VFSForGit installer/upgrader - // sufficient enough time to launch GVFS.Service.UI that is needed to display - // Upgrade available toaster. - TimeSpan startTime = TimeSpan.FromSeconds(60); - - this.tracer.RelatedInfo("Starting auto upgrade checks."); - this.timer = new Timer( - this.TimerCallback, - state: null, - dueTime: startTime, - period: TimeInterval); - } - else - { - this.tracer.RelatedInfo("No upgrade checks scheduled, GVFS is running in unattended mode."); - } - } - - public void Stop() - { - this.tracer.RelatedInfo("Stopping auto upgrade checks"); - this.Dispose(); - } - - public void Dispose() - { - if (this.timer != null) - { - this.timer.Dispose(); - this.timer = null; - } - } - - private static EventMetadata CreateEventMetadata(Exception e) - { - EventMetadata metadata = new EventMetadata(); - if (e != null) - { - metadata.Add("Exception", e.ToString()); - } - - return metadata; - } - - private void TimerCallback(object unusedState) - { - string errorMessage = null; - - using (ITracer activity = this.tracer.StartActivity("Checking for product upgrades.", EventLevel.Informational)) - { - try - { - ProductUpgraderInfo info = new ProductUpgraderInfo( - this.tracer, - this.fileSystem); - - ProductUpgrader.TryCreateUpgrader( - this.tracer, - this.fileSystem, - new LocalGVFSConfig(), - credentialStore: null, - dryRun: false, - noVerify: false, - newUpgrader: out ProductUpgrader productUpgrader, - error: out errorMessage); - - if (productUpgrader == null) - { - string message = string.Format( - "{0}.{1}: failed to create upgrader: {2}", - nameof(ProductUpgradeTimer), - nameof(this.TimerCallback), - errorMessage); - - activity.RelatedWarning( - metadata: new EventMetadata(), - message: message, - keywords: Keywords.Telemetry); - - info.RecordHighestAvailableVersion(highestAvailableVersion: null); - return; - } - - if (!productUpgrader.SupportsAnonymousVersionQuery) - { - // If this is a NuGetUpgrader that does not support anonymous version query, - // fall back to using the GitHubUpgrader, to preserve existing behavior. - // Once we have completely transitioned to using the anonymous endpoint, - // we can remove this code. - if (productUpgrader is NuGetUpgrader) - { - productUpgrader = GitHubUpgrader.Create( - this.tracer, - this.fileSystem, - new LocalGVFSConfig(), - dryRun: false, - noVerify: false, - error: out errorMessage); - - if (productUpgrader == null) - { - string gitHubUpgraderFailedMessage = string.Format( - "{0}.{1}: GitHubUpgrader.Create failed to create upgrader: {2}", - nameof(ProductUpgradeTimer), - nameof(this.TimerCallback), - errorMessage); - - activity.RelatedWarning( - metadata: new EventMetadata(), - message: gitHubUpgraderFailedMessage, - keywords: Keywords.Telemetry); - - info.RecordHighestAvailableVersion(highestAvailableVersion: null); - return; - } - } - else - { - errorMessage = string.Format( - "{0}.{1}: Configured Product Upgrader does not support anonymous version queries.", - nameof(ProductUpgradeTimer), - nameof(this.TimerCallback), - errorMessage); - - activity.RelatedWarning( - metadata: new EventMetadata(), - message: errorMessage, - keywords: Keywords.Telemetry); - - info.RecordHighestAvailableVersion(highestAvailableVersion: null); - return; - } - } - - InstallerPreRunChecker prerunChecker = new InstallerPreRunChecker(this.tracer, string.Empty); - if (!prerunChecker.TryRunPreUpgradeChecks(out errorMessage)) - { - string message = string.Format( - "{0}.{1}: PreUpgradeChecks failed with: {2}", - nameof(ProductUpgradeTimer), - nameof(this.TimerCallback), - errorMessage); - - activity.RelatedWarning( - metadata: new EventMetadata(), - message: message, - keywords: Keywords.Telemetry); - - info.RecordHighestAvailableVersion(highestAvailableVersion: null); - return; - } - - if (!productUpgrader.UpgradeAllowed(out errorMessage)) - { - errorMessage = errorMessage ?? - $"{nameof(ProductUpgradeTimer)}.{nameof(this.TimerCallback)}: Upgrade is not allowed, but no reason provided."; - activity.RelatedWarning( - metadata: new EventMetadata(), - message: errorMessage, - keywords: Keywords.Telemetry); - - info.RecordHighestAvailableVersion(highestAvailableVersion: null); - return; - } - - if (!this.TryQueryForNewerVersion( - activity, - productUpgrader, - out Version newerVersion, - out errorMessage)) - { - string message = string.Format( - "{0}.{1}: TryQueryForNewerVersion failed with: {2}", - nameof(ProductUpgradeTimer), - nameof(this.TimerCallback), - errorMessage); - - activity.RelatedWarning( - metadata: new EventMetadata(), - message: message, - keywords: Keywords.Telemetry); - - info.RecordHighestAvailableVersion(highestAvailableVersion: null); - return; - } - - info.RecordHighestAvailableVersion(highestAvailableVersion: newerVersion); - - if (newerVersion != null) - { - this.DisplayUpgradeAvailableToast(newerVersion.ToString()); - } - } - catch (Exception ex) - { - this.tracer.RelatedWarning( - CreateEventMetadata(ex), - "Exception encountered recording highest available version"); - } - } - } - - private bool TryQueryForNewerVersion(ITracer tracer, ProductUpgrader productUpgrader, out Version newVersion, out string errorMessage) - { - errorMessage = null; - tracer.RelatedInfo($"Querying server for latest version..."); - - if (!productUpgrader.TryQueryNewestVersion(out newVersion, out string detailedError)) - { - errorMessage = "Could not fetch new version info. " + detailedError; - return false; - } - - string logMessage = newVersion == null ? "No newer versions available." : $"Newer version available: {newVersion}."; - tracer.RelatedInfo(logMessage); - - return true; - } - - private void DisplayUpgradeAvailableToast(string version) - { - NamedPipeMessages.Notification.Request request = new NamedPipeMessages.Notification.Request(); - request.Id = NamedPipeMessages.Notification.Request.Identifier.UpgradeAvailable; - request.NewVersion = version; - - this.notificationHandler.SendNotification(request); - } - } -} From a17c95a9e2642bfc9882bf4970eedd2ae59758b7 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Wed, 30 Jun 2021 16:05:51 -0400 Subject: [PATCH 2/2] Delete custom upgrader This leaves 'gvfs upgrade' non-functional Signed-off-by: Derrick Stolee --- GVFS.sln | 6 - GVFS/GVFS.Common/GVFSPlatform.cs | 29 - GVFS/GVFS.Common/GitHubUpgrader.cs | 687 --------------- GVFS/GVFS.Common/InstallerPreRunChecker.cs | 218 ----- .../NuGetUpgrade/InstallActionInfo.cs | 49 -- .../NuGetUpgrade/InstallManifest.cs | 50 -- .../NuGetUpgrade/InstallManifestPlatform.cs | 20 - GVFS/GVFS.Common/NuGetUpgrade/NuGetFeed.cs | 278 ------ .../GVFS.Common/NuGetUpgrade/NuGetUpgrader.cs | 799 ------------------ .../NuGetUpgrade/OrgNuGetUpgrader.cs | 244 ------ GVFS/GVFS.Common/ProductUpgrader.cs | 258 ------ .../GVFS.Common/ProductUpgraderInfo.Shared.cs | 59 -- GVFS/GVFS.Common/ProductUpgraderInfo.cs | 102 --- .../ProductUpgraderPlatformStrategy.cs | 38 - GVFS/GVFS.Hooks/GVFS.Hooks.csproj | 3 - .../HooksPlatform/GVFSHooksPlatform.cs | 10 - GVFS/GVFS.Hooks/Program.cs | 26 - GVFS/GVFS.Payload/GVFS.Payload.csproj | 2 - GVFS/GVFS.Payload/layout.bat | 1 - .../WindowsPlatform.Shared.cs | 15 - GVFS/GVFS.Platform.Windows/WindowsPlatform.cs | 24 - .../WindowsProductUpgraderPlatformStrategy.cs | 75 -- GVFS/GVFS.Service/GVFSService.Windows.cs | 6 +- .../Common/InstallManifestTests.cs | 140 --- .../Common/NuGetUpgrade/NuGetUpgraderTests.cs | 455 ---------- .../NuGetUpgrade/OrgNuGetUpgraderTests.cs | 192 ----- .../Common/ProductUpgraderInfoTests.cs | 81 -- .../Common/TryCreateProductUpgraderTests.cs | 260 ------ GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj | 1 - .../Mock/Common/MockPlatform.cs | 22 - .../MockProductUpgraderPlatformStrategy.cs | 32 - .../GVFS.UnitTests/Mock/MockGitHubUpgrader.cs | 261 ------ .../Mock/MockInstallerPreRunChecker.cs | 114 --- .../Upgrader/ProductUpgraderTests.cs | 130 --- .../Upgrader/UpgradeOrchestratorTests.cs | 250 ------ ...radeOrchestratorWithGitHubUpgraderTests.cs | 324 ------- GVFS/GVFS.UnitTests/Upgrader/UpgradeTests.cs | 191 ----- .../Windows/Upgrader/UpgradeVerbTests.cs | 256 ------ .../Upgrader/WindowsNuGetUpgraderTests.cs | 60 -- GVFS/GVFS.Upgrader/GVFS.Upgrader.csproj | 16 - GVFS/GVFS.Upgrader/Program.cs | 16 - GVFS/GVFS.Upgrader/UpgradeOptions.cs | 22 - GVFS/GVFS.Upgrader/UpgradeOrchestrator.cs | 389 --------- .../UpgradeOrchestratorFactory.cs | 10 - .../WindowsUpgradeOrchestrator.cs | 55 -- GVFS/GVFS/CommandLine/DiagnoseVerb.cs | 24 - GVFS/GVFS/CommandLine/LogVerb.cs | 2 - GVFS/GVFS/CommandLine/UpgradeVerb.cs | 326 +------ 48 files changed, 3 insertions(+), 6625 deletions(-) delete mode 100644 GVFS/GVFS.Common/GitHubUpgrader.cs delete mode 100644 GVFS/GVFS.Common/InstallerPreRunChecker.cs delete mode 100644 GVFS/GVFS.Common/NuGetUpgrade/InstallActionInfo.cs delete mode 100644 GVFS/GVFS.Common/NuGetUpgrade/InstallManifest.cs delete mode 100644 GVFS/GVFS.Common/NuGetUpgrade/InstallManifestPlatform.cs delete mode 100644 GVFS/GVFS.Common/NuGetUpgrade/NuGetFeed.cs delete mode 100644 GVFS/GVFS.Common/NuGetUpgrade/NuGetUpgrader.cs delete mode 100644 GVFS/GVFS.Common/NuGetUpgrade/OrgNuGetUpgrader.cs delete mode 100644 GVFS/GVFS.Common/ProductUpgrader.cs delete mode 100644 GVFS/GVFS.Common/ProductUpgraderInfo.Shared.cs delete mode 100644 GVFS/GVFS.Common/ProductUpgraderInfo.cs delete mode 100644 GVFS/GVFS.Common/ProductUpgraderPlatformStrategy.cs delete mode 100644 GVFS/GVFS.Platform.Windows/WindowsProductUpgraderPlatformStrategy.cs delete mode 100644 GVFS/GVFS.UnitTests/Common/InstallManifestTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Common/NuGetUpgrade/NuGetUpgraderTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Common/NuGetUpgrade/OrgNuGetUpgraderTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Common/ProductUpgraderInfoTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Common/TryCreateProductUpgraderTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Mock/Common/MockProductUpgraderPlatformStrategy.cs delete mode 100644 GVFS/GVFS.UnitTests/Mock/MockGitHubUpgrader.cs delete mode 100644 GVFS/GVFS.UnitTests/Mock/MockInstallerPreRunChecker.cs delete mode 100644 GVFS/GVFS.UnitTests/Upgrader/ProductUpgraderTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Upgrader/UpgradeOrchestratorTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Upgrader/UpgradeOrchestratorWithGitHubUpgraderTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Upgrader/UpgradeTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Windows/Upgrader/UpgradeVerbTests.cs delete mode 100644 GVFS/GVFS.UnitTests/Windows/Upgrader/WindowsNuGetUpgraderTests.cs delete mode 100644 GVFS/GVFS.Upgrader/GVFS.Upgrader.csproj delete mode 100644 GVFS/GVFS.Upgrader/Program.cs delete mode 100644 GVFS/GVFS.Upgrader/UpgradeOptions.cs delete mode 100644 GVFS/GVFS.Upgrader/UpgradeOrchestrator.cs delete mode 100644 GVFS/GVFS.Upgrader/UpgradeOrchestratorFactory.cs delete mode 100644 GVFS/GVFS.Upgrader/WindowsUpgradeOrchestrator.cs diff --git a/GVFS.sln b/GVFS.sln index 3806b86627..80a2cbf0e8 100644 --- a/GVFS.sln +++ b/GVFS.sln @@ -39,8 +39,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GVFS.Tests", "GVFS\GVFS.Tes EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GVFS.UnitTests", "GVFS\GVFS.UnitTests\GVFS.UnitTests.csproj", "{1A46C414-7F39-4EF0-B216-A88033D18678}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GVFS.Upgrader", "GVFS\GVFS.Upgrader\GVFS.Upgrader.csproj", "{F8D96536-0F2C-4B40-8516-D2C0516C66EC}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GVFS.VirtualFileSystemHook", "GVFS\GVFS.VirtualFileSystemHook\GVFS.VirtualFileSystemHook.vcxproj", "{2D23AB54-541F-4ABC-8DCA-08C199E97ABB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GVFS.Virtualization", "GVFS\GVFS.Virtualization\GVFS.Virtualization.csproj", "{EC90AF5D-E018-4248-85D6-9DB1898D710E}" @@ -129,10 +127,6 @@ Global {1A46C414-7F39-4EF0-B216-A88033D18678}.Debug|x64.Build.0 = Debug|Any CPU {1A46C414-7F39-4EF0-B216-A88033D18678}.Release|x64.ActiveCfg = Release|Any CPU {1A46C414-7F39-4EF0-B216-A88033D18678}.Release|x64.Build.0 = Release|Any CPU - {F8D96536-0F2C-4B40-8516-D2C0516C66EC}.Debug|x64.ActiveCfg = Debug|Any CPU - {F8D96536-0F2C-4B40-8516-D2C0516C66EC}.Debug|x64.Build.0 = Debug|Any CPU - {F8D96536-0F2C-4B40-8516-D2C0516C66EC}.Release|x64.ActiveCfg = Release|Any CPU - {F8D96536-0F2C-4B40-8516-D2C0516C66EC}.Release|x64.Build.0 = Release|Any CPU {2D23AB54-541F-4ABC-8DCA-08C199E97ABB}.Debug|x64.ActiveCfg = Debug|x64 {2D23AB54-541F-4ABC-8DCA-08C199E97ABB}.Debug|x64.Build.0 = Debug|x64 {2D23AB54-541F-4ABC-8DCA-08C199E97ABB}.Release|x64.ActiveCfg = Release|x64 diff --git a/GVFS/GVFS.Common/GVFSPlatform.cs b/GVFS/GVFS.Common/GVFSPlatform.cs index 0e834aaebf..7c252d4934 100644 --- a/GVFS/GVFS.Common/GVFSPlatform.cs +++ b/GVFS/GVFS.Common/GVFSPlatform.cs @@ -78,28 +78,8 @@ public static void Register(GVFSPlatform platform) public abstract bool IsElevated(); public abstract string GetCurrentUser(); public abstract string GetUserIdFromLoginSessionId(int sessionId, ITracer tracer); - - /// - /// Get the directory for upgrades that is permissioned to - /// require elevated privileges to modify. This can be used for - /// data that we don't want normal user accounts to modify. - /// - public abstract string GetUpgradeProtectedDataDirectory(); - - /// - /// Directory that upgrader log directory should be placed - /// in. There can be multiple log directories, so this is the - /// containing directory to place them in. - /// - public abstract string GetUpgradeLogDirectoryParentDirectory(); public abstract string GetSystemInstallerLogPath(); - /// - /// Directory that contains the file indicating that a new - /// version is available. - /// - public abstract string GetUpgradeHighestAvailableVersionDirectory(); - public abstract void ConfigureVisualStudio(string gitBinPath, ITracer tracer); public abstract bool TryCopyPanicLogs(string copyToDir, out string error); @@ -125,10 +105,6 @@ public abstract FileBasedLock CreateFileBasedLock( ITracer tracer, string lockPath); - public abstract ProductUpgraderPlatformStrategy CreateProductUpgraderPlatformInteractions( - PhysicalFileSystem fileSystem, - ITracer tracer); - public bool TryGetNormalizedPathRoot(string path, out string pathRoot, out string errorMessage) { pathRoot = null; @@ -229,11 +205,6 @@ public string MountExecutableName { get { return "GVFS.Mount" + this.ExecutableExtension; } } - - public string GVFSUpgraderExecutableName - { - get { return "GVFS.Upgrader" + this.ExecutableExtension; } - } } public class UnderConstructionFlags diff --git a/GVFS/GVFS.Common/GitHubUpgrader.cs b/GVFS/GVFS.Common/GitHubUpgrader.cs deleted file mode 100644 index b2543db256..0000000000 --- a/GVFS/GVFS.Common/GitHubUpgrader.cs +++ /dev/null @@ -1,687 +0,0 @@ -using GVFS.Common.FileSystem; -using GVFS.Common.Git; -using GVFS.Common.Tracing; -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Json; -using System.Threading.Tasks; - -namespace GVFS.Common -{ - public class GitHubUpgrader : ProductUpgrader - { - private const string GitHubReleaseURL = @"https://api.github.com/repos/microsoft/vfsforgit/releases"; - private const string JSONMediaType = @"application/vnd.github.v3+json"; - private const string UserAgent = @"GVFS_Auto_Upgrader"; - private const string CommonInstallerArgs = "/VERYSILENT /CLOSEAPPLICATIONS /SUPPRESSMSGBOXES /NORESTART"; - private const string GVFSInstallerArgs = CommonInstallerArgs + " /REMOUNTREPOS=false"; - private const string GitInstallerArgs = CommonInstallerArgs + " /ALLOWDOWNGRADE=1"; - private const string GitAssetId = "Git"; - private const string GVFSAssetId = "GVFS"; - private const string GitInstallerFileNamePrefix = "Git-"; - private const string GVFSSigner = "Microsoft Corporation"; - private const string GVFSCertIssuer = "Microsoft Code Signing PCA"; - private const string GitSigner = "Johannes Schindelin"; - private const string GitCertIssuer = "COMODO RSA Code Signing CA"; - - private static readonly HashSet GVFSInstallerFileNamePrefixCandidates = new HashSet(GVFSPlatform.Instance.Constants.PathComparer) - { - "SetupGVFS", - "VFSForGit" - }; - - private Version newestVersion; - private Release newestRelease; - - public GitHubUpgrader( - string currentVersion, - ITracer tracer, - PhysicalFileSystem fileSystem, - GitHubUpgraderConfig upgraderConfig, - bool dryRun = false, - bool noVerify = false) - : base(currentVersion, tracer, dryRun, noVerify, fileSystem) - { - this.Config = upgraderConfig; - } - - public GitHubUpgraderConfig Config { get; private set; } - - public override bool SupportsAnonymousVersionQuery { get => true; } - - public static GitHubUpgrader Create( - ITracer tracer, - PhysicalFileSystem fileSystem, - LocalGVFSConfig gvfsConfig, - bool dryRun, - bool noVerify, - out string error) - { - return Create(tracer, fileSystem, dryRun, noVerify, gvfsConfig, out error); - } - - public static GitHubUpgrader Create( - ITracer tracer, - PhysicalFileSystem fileSystem, - bool dryRun, - bool noVerify, - LocalGVFSConfig localConfig, - out string error) - { - GitHubUpgrader upgrader = null; - GitHubUpgraderConfig gitHubUpgraderConfig = new GitHubUpgraderConfig(tracer, localConfig); - - if (!gitHubUpgraderConfig.TryLoad(out error)) - { - return null; - } - - if (gitHubUpgraderConfig.ConfigError()) - { - gitHubUpgraderConfig.ConfigAlertMessage(out error); - return null; - } - - upgrader = new GitHubUpgrader( - ProcessHelper.GetCurrentProcessVersion(), - tracer, - fileSystem, - gitHubUpgraderConfig, - dryRun, - noVerify); - - return upgrader; - } - - public override bool UpgradeAllowed(out string message) - { - return this.Config.UpgradeAllowed(out message); - } - - public override bool TryQueryNewestVersion( - out Version newVersion, - out string message) - { - List releases; - - newVersion = null; - if (this.TryFetchReleases(out releases, out message)) - { - foreach (Release nextRelease in releases) - { - Version releaseVersion = null; - - if (nextRelease.Ring <= this.Config.UpgradeRing && - nextRelease.TryParseVersion(out releaseVersion) && - releaseVersion > this.installedVersion) - { - newVersion = releaseVersion; - this.newestVersion = releaseVersion; - this.newestRelease = nextRelease; - message = $"New GVFS version {newVersion.ToString()} available in ring {this.Config.UpgradeRing}."; - break; - } - } - - if (newVersion == null) - { - message = $"Great news, you're all caught up on upgrades in the {this.Config.UpgradeRing} ring!"; - } - - return true; - } - - return false; - } - - public override bool TryDownloadNewestVersion(out string errorMessage) - { - if (!this.TryCreateAndConfigureDownloadDirectory(this.tracer, out errorMessage)) - { - this.tracer.RelatedError($"{nameof(GitHubUpgrader)}.{nameof(this.TryCreateAndConfigureDownloadDirectory)} failed. {errorMessage}"); - return false; - } - - bool downloadedGit = false; - bool downloadedGVFS = false; - - foreach (Asset asset in this.newestRelease.Assets) - { - bool targetOSMatch = string.Equals(Path.GetExtension(asset.Name), GVFSPlatform.Instance.Constants.InstallerExtension, GVFSPlatform.Instance.Constants.PathComparison); - bool isGitAsset = this.IsGitAsset(asset); - bool isGVFSAsset = isGitAsset ? false : this.IsGVFSAsset(asset); - if (!targetOSMatch || (!isGVFSAsset && !isGitAsset)) - { - continue; - } - - if (!this.TryDownloadAsset(asset, out errorMessage)) - { - errorMessage = $"Could not download {(isGVFSAsset ? GVFSAssetId : GitAssetId)} installer. {errorMessage}"; - return false; - } - else - { - downloadedGit = isGitAsset ? true : downloadedGit; - downloadedGVFS = isGVFSAsset ? true : downloadedGVFS; - } - } - - if (!downloadedGit || !downloadedGVFS) - { - errorMessage = $"Could not find {(!downloadedGit ? GitAssetId : GVFSAssetId)} installer in the latest release."; - return false; - } - - errorMessage = null; - return true; - } - - public override bool TryRunInstaller(InstallActionWrapper installActionWrapper, out string error) - { - string localError; - - this.TryGetGitVersion(out GitVersion newGitVersion, out localError); - - if (!installActionWrapper( - () => - { - if (!this.TryInstallUpgrade(GitAssetId, newGitVersion.ToString(), out localError)) - { - return false; - } - - return true; - }, - $"Installing Git version: {newGitVersion}")) - { - error = localError; - return false; - } - - if (!installActionWrapper( - () => - { - if (!this.TryInstallUpgrade(GVFSAssetId, this.newestVersion.ToString(), out localError)) - { - return false; - } - - return true; - }, - $"Installing GVFS version: {this.newestVersion}")) - { - error = localError; - return false; - } - - this.LogVersionInfo(this.newestVersion, newGitVersion, "Newly Installed Version"); - - error = null; - return true; - } - - public override bool TryCleanup(out string error) - { - error = string.Empty; - if (this.newestRelease == null) - { - return true; - } - - foreach (Asset asset in this.newestRelease.Assets) - { - Exception exception; - if (!this.TryDeleteDownloadedAsset(asset, out exception)) - { - error += $"Could not delete {asset.LocalPath}. {exception.ToString()}." + Environment.NewLine; - } - } - - if (!string.IsNullOrEmpty(error)) - { - error.TrimEnd(Environment.NewLine.ToCharArray()); - return false; - } - - error = null; - return true; - } - - protected virtual bool TryDeleteDownloadedAsset(Asset asset, out Exception exception) - { - return this.fileSystem.TryDeleteFile(asset.LocalPath, out exception); - } - - protected virtual bool TryDownloadAsset(Asset asset, out string errorMessage) - { - errorMessage = null; - - string downloadPath = ProductUpgraderInfo.GetAssetDownloadsPath(); - string localPath = Path.Combine(downloadPath, asset.Name); - WebClient webClient = new WebClient(); - - try - { - webClient.DownloadFile(asset.DownloadURL, localPath); - asset.LocalPath = localPath; - } - catch (WebException webException) - { - errorMessage = "Download error: " + webException.Message; - this.TraceException(webException, nameof(this.TryDownloadAsset), $"Error downloading asset {asset.Name}."); - return false; - } - - return true; - } - - protected virtual bool TryFetchReleases(out List releases, out string errorMessage) - { - HttpClient client = new HttpClient(); - - client.DefaultRequestHeaders.Accept.Clear(); - client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(JSONMediaType)); - client.DefaultRequestHeaders.Add("User-Agent", UserAgent); - - releases = null; - errorMessage = null; - - try - { - Stream result = client.GetStreamAsync(GitHubReleaseURL).GetAwaiter().GetResult(); - - DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List)); - releases = serializer.ReadObject(result) as List; - return true; - } - catch (HttpRequestException exception) - { - errorMessage = string.Format("Network error: could not connect to GitHub({0}). {1}", GitHubReleaseURL, exception.Message); - this.TraceException(exception, nameof(this.TryFetchReleases), $"Error fetching release info."); - } - catch (TaskCanceledException exception) - { - // GetStreamAsync can also throw a TaskCanceledException to indicate a timeout - // https://github.com/dotnet/corefx/issues/20296 - errorMessage = string.Format("Network error: could not connect to GitHub({0}). {1}", GitHubReleaseURL, exception.Message); - this.TraceException(exception, nameof(this.TryFetchReleases), $"Error fetching release info."); - } - catch (SerializationException exception) - { - errorMessage = string.Format("Parse error: could not parse releases info from GitHub({0}). {1}", GitHubReleaseURL, exception.Message); - this.TraceException(exception, nameof(this.TryFetchReleases), $"Error parsing release info."); - } - - return false; - } - - protected virtual void RunInstaller(string path, string args, string certCN, string issuerCN, out int exitCode, out string error) - { - using (Stream stream = this.fileSystem.OpenFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, false)) - { - string expectedCNPrefix = $"CN={certCN}, "; - string expectecIssuerCNPrefix = $"CN={issuerCN}"; - string subject; - string issuer; - if (!GVFSPlatform.Instance.TryVerifyAuthenticodeSignature(path, out subject, out issuer, out error)) - { - exitCode = -1; - return; - } - - if (!subject.StartsWith(expectedCNPrefix) || !issuer.StartsWith(expectecIssuerCNPrefix)) - { - exitCode = -1; - error = $"Installer {path} is signed by unknown signer."; - this.tracer.RelatedError($"Installer {path} is signed by unknown signer. Signed by {subject}, issued by {issuer} expected signer is {certCN}, issuer {issuerCN}."); - return; - } - - this.RunInstaller(path, args, out exitCode, out error); - } - } - - private bool TryGetGitVersion(out GitVersion gitVersion, out string error) - { - error = null; - - foreach (Asset asset in this.newestRelease.Assets) - { - if (asset.Name.StartsWith(GitInstallerFileNamePrefix) && - GitVersion.TryParseInstallerName(asset.Name, GVFSPlatform.Instance.Constants.InstallerExtension, out gitVersion)) - { - return true; - } - } - - error = "Could not find Git version info in newest release"; - gitVersion = null; - - return false; - } - - private bool TryInstallUpgrade(string assetId, string version, out string consoleError) - { - bool installSuccess = false; - EventMetadata metadata = new EventMetadata(); - metadata.Add("Upgrade Step", nameof(this.TryInstallUpgrade)); - metadata.Add("AssetId", assetId); - metadata.Add("Version", version); - - using (ITracer activity = this.tracer.StartActivity($"{nameof(this.TryInstallUpgrade)}", EventLevel.Informational, metadata)) - { - if (!this.TryRunInstaller(assetId, out installSuccess, out consoleError) || - !installSuccess) - { - this.tracer.RelatedError(metadata, $"{nameof(this.TryInstallUpgrade)} failed. {consoleError}"); - return false; - } - - activity.RelatedInfo("Successfully installed GVFS version: " + version); - } - - return installSuccess; - } - - private bool TryRunInstaller(string assetId, out bool installationSucceeded, out string error) - { - error = null; - installationSucceeded = false; - - int exitCode = 0; - bool launched = this.TryRunInstallerForAsset(assetId, out exitCode, out error); - installationSucceeded = exitCode == 0; - - return launched; - } - - private bool TryRunInstallerForAsset(string assetId, out int installerExitCode, out string error) - { - error = null; - installerExitCode = 0; - - bool installerIsRun = false; - string path; - string installerArgs; - if (this.TryGetLocalInstallerPath(assetId, out path, out installerArgs)) - { - if (!this.dryRun) - { - string logFilePath = GVFSEnlistment.GetNewLogFileName( - ProductUpgraderInfo.GetLogDirectoryPath(), - Path.GetFileNameWithoutExtension(path), - this.UpgradeInstanceId, - this.fileSystem); - - string args = installerArgs + " /Log=" + logFilePath; - string certCN = null; - string issuerCN = null; - switch (assetId) - { - case GVFSAssetId: - { - certCN = GVFSSigner; - issuerCN = GVFSCertIssuer; - break; - } - - case GitAssetId: - { - certCN = GitSigner; - issuerCN = GitCertIssuer; - break; - } - } - - this.RunInstaller(path, args, certCN, issuerCN, out installerExitCode, out error); - - if (installerExitCode != 0 && string.IsNullOrEmpty(error)) - { - error = assetId + " installer failed. Error log: " + logFilePath; - } - } - - installerIsRun = true; - } - else - { - error = "Could not find downloaded installer for " + assetId; - } - - return installerIsRun; - } - - private bool TryGetLocalInstallerPath(string assetId, out string path, out string args) - { - foreach (Asset asset in this.newestRelease.Assets) - { - if (string.Equals(Path.GetExtension(asset.Name), GVFSPlatform.Instance.Constants.InstallerExtension, GVFSPlatform.Instance.Constants.PathComparison)) - { - path = asset.LocalPath; - if (assetId == GitAssetId && this.IsGitAsset(asset)) - { - args = GitInstallerArgs; - return true; - } - - if (assetId == GVFSAssetId && this.IsGVFSAsset(asset)) - { - args = GVFSInstallerArgs; - return true; - } - } - } - - path = null; - args = null; - return false; - } - - private bool IsGVFSAsset(Asset asset) - { - return this.AssetInstallerNameCompare(asset, GVFSInstallerFileNamePrefixCandidates); - } - - private bool IsGitAsset(Asset asset) - { - return this.AssetInstallerNameCompare(asset, new string[] { GitInstallerFileNamePrefix }); - } - - private bool AssetInstallerNameCompare(Asset asset, IEnumerable expectedFileNamePrefixes) - { - foreach (string fileNamePrefix in expectedFileNamePrefixes) - { - if (asset.Name.StartsWith(fileNamePrefix, GVFSPlatform.Instance.Constants.PathComparison)) - { - return true; - } - } - - return false; - } - - private void LogVersionInfo( - Version gvfsVersion, - GitVersion gitVersion, - string message) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add(nameof(gvfsVersion), gvfsVersion.ToString()); - metadata.Add(nameof(gitVersion), gitVersion.ToString()); - - this.tracer.RelatedEvent(EventLevel.Informational, message, metadata); - } - - public class GitHubUpgraderConfig - { - public GitHubUpgraderConfig(ITracer tracer, LocalGVFSConfig localGVFSConfig) - { - this.Tracer = tracer; - this.LocalConfig = localGVFSConfig; - } - - public enum RingType - { - // The values here should be ascending. - // Invalid - User has set an incorrect ring - // NoConfig - User has Not set any ring yet - // None - User has set a valid "None" ring - // (Fast should be greater than Slow, - // Slow should be greater than None, None greater than Invalid.) - // This is required for the correct implementation of Ring based - // upgrade logic. - Invalid = 0, - NoConfig = None - 1, - None = 10, - Slow = None + 1, - Fast = Slow + 1, - } - - public RingType UpgradeRing { get; private set; } - public LocalGVFSConfig LocalConfig { get; private set; } - private ITracer Tracer { get; set; } - - public bool TryLoad(out string error) - { - this.UpgradeRing = RingType.NoConfig; - - string ringConfig = null; - string loadError = "Could not read GVFS Config." + Environment.NewLine + GVFSConstants.UpgradeVerbMessages.SetUpgradeRingCommand; - - if (!this.LocalConfig.TryGetConfig(GVFSConstants.LocalGVFSConfig.UpgradeRing, out ringConfig, out error)) - { - error = loadError; - return false; - } - - this.ParseUpgradeRing(ringConfig); - return true; - } - - public void ParseUpgradeRing(string ringConfig) - { - if (string.IsNullOrEmpty(ringConfig)) - { - this.UpgradeRing = RingType.None; - return; - } - - RingType ringType; - if (Enum.TryParse(ringConfig, ignoreCase: true, result: out ringType) && - Enum.IsDefined(typeof(RingType), ringType) && - ringType != RingType.Invalid) - { - this.UpgradeRing = ringType; - } - else - { - this.UpgradeRing = RingType.Invalid; - } - } - - public bool ConfigError() - { - return this.UpgradeRing == RingType.Invalid; - } - - public bool UpgradeAllowed(out string message) - { - if (this.UpgradeRing == RingType.Slow || this.UpgradeRing == RingType.Fast) - { - message = null; - return true; - } - - this.ConfigAlertMessage(out message); - return false; - } - - public void ConfigAlertMessage(out string message) - { - message = null; - - if (this.UpgradeRing == GitHubUpgraderConfig.RingType.None) - { - message = GVFSConstants.UpgradeVerbMessages.NoneRingConsoleAlert + Environment.NewLine + GVFSConstants.UpgradeVerbMessages.SetUpgradeRingCommand; - } - - if (this.UpgradeRing == GitHubUpgraderConfig.RingType.NoConfig) - { - message = GVFSConstants.UpgradeVerbMessages.NoRingConfigConsoleAlert + Environment.NewLine + GVFSConstants.UpgradeVerbMessages.SetUpgradeRingCommand; - } - - if (this.UpgradeRing == GitHubUpgraderConfig.RingType.Invalid) - { - string ring; - string error; - string prefix = string.Empty; - if (this.LocalConfig.TryGetConfig(GVFSConstants.LocalGVFSConfig.UpgradeRing, out ring, out error)) - { - prefix = $"Invalid upgrade ring `{ring}` specified in gvfs config. "; - } - - message = prefix + Environment.NewLine + GVFSConstants.UpgradeVerbMessages.SetUpgradeRingCommand; - } - } - } - - [DataContract(Name = "asset")] - protected class Asset - { - [DataMember(Name = "name")] - public string Name { get; set; } - - [DataMember(Name = "size")] - public long Size { get; set; } - - [DataMember(Name = "browser_download_url")] - public Uri DownloadURL { get; set; } - - [IgnoreDataMember] - public string LocalPath { get; set; } - } - - [DataContract(Name = "release")] - protected class Release - { - [DataMember(Name = "name")] - public string Name { get; set; } - - [DataMember(Name = "tag_name")] - public string Tag { get; set; } - - [DataMember(Name = "prerelease")] - public bool PreRelease { get; set; } - - [DataMember(Name = "assets")] - public List Assets { get; set; } - - [IgnoreDataMember] - public GitHubUpgraderConfig.RingType Ring - { - get - { - return this.PreRelease == true ? GitHubUpgraderConfig.RingType.Fast : GitHubUpgraderConfig.RingType.Slow; - } - } - - public bool TryParseVersion(out Version version) - { - version = null; - - if (this.Tag.StartsWith("v", StringComparison.CurrentCultureIgnoreCase)) - { - return Version.TryParse(this.Tag.Substring(1), out version); - } - - return false; - } - } - } -} diff --git a/GVFS/GVFS.Common/InstallerPreRunChecker.cs b/GVFS/GVFS.Common/InstallerPreRunChecker.cs deleted file mode 100644 index 021f48f06e..0000000000 --- a/GVFS/GVFS.Common/InstallerPreRunChecker.cs +++ /dev/null @@ -1,218 +0,0 @@ -using GVFS.Common; -using GVFS.Common.Git; -using GVFS.Common.Tracing; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading; - -namespace GVFS.Upgrader -{ - public class InstallerPreRunChecker - { - private ITracer tracer; - - public InstallerPreRunChecker(ITracer tracer, string commandToRerun) - { - this.tracer = tracer; - this.CommandToRerun = commandToRerun; - } - - protected string CommandToRerun { private get; set; } - - public virtual bool TryRunPreUpgradeChecks(out string consoleError) - { - using (ITracer activity = this.tracer.StartActivity(nameof(this.TryRunPreUpgradeChecks), EventLevel.Informational)) - { - if (this.IsUnattended()) - { - consoleError = $"{GVFSConstants.UpgradeVerbMessages.GVFSUpgrade} is not supported in unattended mode"; - this.tracer.RelatedWarning($"{nameof(this.TryRunPreUpgradeChecks)}: {consoleError}"); - return false; - } - - if (!this.IsGVFSUpgradeAllowed(out consoleError)) - { - return false; - } - - activity.RelatedInfo($"Successfully finished pre upgrade checks. Okay to run {GVFSConstants.UpgradeVerbMessages.GVFSUpgrade}."); - } - - consoleError = null; - return true; - } - - // TODO: Move repo mount calls to GVFS.Upgrader project. - // https://github.com/Microsoft/VFSForGit/issues/293 - public virtual bool TryMountAllGVFSRepos(out string consoleError) - { - return this.TryRunGVFSWithArgs("service --mount-all", out consoleError); - } - - public virtual bool TryUnmountAllGVFSRepos(out string consoleError) - { - consoleError = null; - this.tracer.RelatedInfo("Unmounting any mounted GVFS repositories."); - - using (ITracer activity = this.tracer.StartActivity(nameof(this.TryUnmountAllGVFSRepos), EventLevel.Informational)) - { - if (!this.TryRunGVFSWithArgs("service --unmount-all", out consoleError)) - { - this.tracer.RelatedError($"{nameof(this.TryUnmountAllGVFSRepos)}: {consoleError}"); - return false; - } - - activity.RelatedInfo("Successfully unmounted repositories."); - } - - return true; - } - - public virtual bool IsInstallationBlockedByRunningProcess(out string consoleError) - { - consoleError = null; - - // While checking for blocking processes like GVFS.Mount immediately after un-mounting, - // then sometimes GVFS.Mount shows up as running. But if the check is done after waiting - // for some time, then eventually GVFS.Mount goes away. The retry loop below is to help - // account for this delay between the time un-mount call returns and when GVFS.Mount - // actually quits. - this.tracer.RelatedInfo("Checking if GVFS or dependent processes are running."); - int retryCount = 10; - HashSet processList = null; - while (retryCount > 0) - { - if (!this.IsBlockingProcessRunning(out processList)) - { - break; - } - - Thread.Sleep(TimeSpan.FromMilliseconds(250)); - retryCount--; - } - - if (processList.Count > 0) - { - consoleError = string.Join( - Environment.NewLine, - "Blocking processes are running.", - $"Run {this.CommandToRerun} again after quitting these processes - " + string.Join(", ", processList.ToArray())); - this.tracer.RelatedWarning($"{nameof(this.IsInstallationBlockedByRunningProcess)}: {consoleError}"); - return false; - } - - return true; - } - - protected virtual bool IsElevated() - { - return GVFSPlatform.Instance.IsElevated(); - } - - protected virtual bool IsGVFSUpgradeSupported() - { - return GVFSPlatform.Instance.KernelDriver.IsGVFSUpgradeSupported(); - } - - protected virtual bool IsServiceInstalledAndNotRunning() - { - GVFSPlatform.Instance.IsServiceInstalledAndRunning(GVFSConstants.Service.ServiceName, out bool isInstalled, out bool isRunning); - - return isInstalled && !isRunning; - } - - protected virtual bool IsUnattended() - { - return GVFSEnlistment.IsUnattended(this.tracer); - } - - protected virtual bool IsBlockingProcessRunning(out HashSet processes) - { - int currentProcessId = Process.GetCurrentProcess().Id; - Process[] allProcesses = Process.GetProcesses(); - HashSet matchingNames = new HashSet(); - - foreach (Process process in allProcesses) - { - if (process.Id == currentProcessId || !GVFSPlatform.Instance.Constants.UpgradeBlockingProcesses.Contains(process.ProcessName)) - { - continue; - } - - matchingNames.Add(process.ProcessName + " pid:" + process.Id); - } - - processes = matchingNames; - return processes.Count > 0; - } - - protected virtual bool TryRunGVFSWithArgs(string args, out string consoleError) - { - string gvfsDirectory = ProcessHelper.GetProgramLocation(GVFSPlatform.Instance.Constants.ProgramLocaterCommand, GVFSPlatform.Instance.Constants.GVFSExecutableName); - if (!string.IsNullOrEmpty(gvfsDirectory)) - { - string gvfsPath = Path.Combine(gvfsDirectory, GVFSPlatform.Instance.Constants.GVFSExecutableName); - - ProcessResult processResult = ProcessHelper.Run(gvfsPath, args); - if (processResult.ExitCode == 0) - { - consoleError = null; - return true; - } - else - { - consoleError = string.IsNullOrEmpty(processResult.Errors) ? $"`gvfs {args}` failed." : processResult.Errors; - return false; - } - } - else - { - consoleError = $"Could not locate {GVFSPlatform.Instance.Constants.GVFSExecutableName}"; - return false; - } - } - - private bool IsGVFSUpgradeAllowed(out string consoleError) - { - bool isConfirmed = string.Equals(this.CommandToRerun, GVFSPlatform.Instance.Constants.UpgradeConfirmCommandMessage, StringComparison.OrdinalIgnoreCase); - string adviceText = null; - if (!this.IsElevated()) - { - adviceText = GVFSPlatform.Instance.Constants.RunUpdateMessage; - consoleError = string.Join( - Environment.NewLine, - "The installer needs to be run with elevated permissions.", - adviceText); - this.tracer.RelatedWarning($"{nameof(this.IsGVFSUpgradeAllowed)}: Upgrade is not installable. {consoleError}"); - return false; - } - - if (!this.IsGVFSUpgradeSupported()) - { - consoleError = string.Join( - Environment.NewLine, - $"{GVFSConstants.UpgradeVerbMessages.GVFSUpgrade} is only supported after the \"Windows Projected File System\" optional feature has been enabled by a manual installation of VFS for Git, and only on versions of Windows that support this feature.", - "Check your team's documentation for how to upgrade."); - this.tracer.RelatedWarning(metadata: null, message:$"{nameof(this.IsGVFSUpgradeAllowed)}: Upgrade is not installable. {consoleError}", keywords: Keywords.Telemetry); - return false; - } - - if (this.IsServiceInstalledAndNotRunning()) - { - adviceText = $"To install, run {GVFSPlatform.Instance.Constants.StartServiceCommandMessage} and run {GVFSPlatform.Instance.Constants.UpgradeConfirmCommandMessage}."; - consoleError = string.Join( - Environment.NewLine, - "GVFS Service is not running.", - adviceText); - this.tracer.RelatedWarning($"{nameof(this.IsGVFSUpgradeAllowed)}: Upgrade is not installable. {consoleError}"); - return false; - } - - consoleError = null; - return true; - } - } -} diff --git a/GVFS/GVFS.Common/NuGetUpgrade/InstallActionInfo.cs b/GVFS/GVFS.Common/NuGetUpgrade/InstallActionInfo.cs deleted file mode 100644 index 10a247b124..0000000000 --- a/GVFS/GVFS.Common/NuGetUpgrade/InstallActionInfo.cs +++ /dev/null @@ -1,49 +0,0 @@ -namespace GVFS.Common.NuGetUpgrade -{ - public class InstallActionInfo - { - /// - /// Well known tokens that will be replaced when encountered in an Arguments field. - /// - public const string ManifestEntryInstallationIdToken = "installation_id"; - public const string ManifestEntryLogDirectoryToken = "log_directory"; - public const string ManifestEntryInstallerBaseDirectoryToken = "installer_base_path"; - - public InstallActionInfo(string name, string version, string args, string installerRelativePath, string command) - { - this.Name = name; - this.Version = version; - this.Args = args; - this.InstallerRelativePath = installerRelativePath; - this.Command = command; - } - - /// - /// The arguments that should be passed to the install command - /// - public string Args { get; } - - /// - /// User friendly name for the install action - /// - public string Name { get; } - - /// - /// The path to the application or document to start. The path - /// is relative to the content directory of the NuGet package. - /// - public string InstallerRelativePath { get; } - - /// - /// The version of the component that this entry installs - /// - public string Version { get; } - - /// - /// The command to run. If this is present, the command is run - /// directly (with the processed args), and the - /// InstallerRelativePath property is ignored. - /// - public string Command { get; } - } -} diff --git a/GVFS/GVFS.Common/NuGetUpgrade/InstallManifest.cs b/GVFS/GVFS.Common/NuGetUpgrade/InstallManifest.cs deleted file mode 100644 index 4592a07469..0000000000 --- a/GVFS/GVFS.Common/NuGetUpgrade/InstallManifest.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Newtonsoft.Json; -using System.Collections.Generic; -using System.IO; - -namespace GVFS.Common.NuGetUpgrade -{ - /// - /// Details on the upgrade included in this package, including information - /// on what packages are included and how to install them. - /// - public class InstallManifest - { - public const string WindowsPlatformKey = "Windows"; - - public InstallManifest() - { - this.PlatformInstallManifests = new Dictionary(); - } - - /// - /// Install manifests for different platforms. - /// - public Dictionary PlatformInstallManifests { get; private set; } - - public static InstallManifest FromJsonFile(string path) - { - using (StreamReader streamReader = File.OpenText(path)) - { - return InstallManifest.FromJson(streamReader); - } - } - - public static InstallManifest FromJsonString(string json) - { - return JsonConvert.DeserializeObject(json); - } - - public static InstallManifest FromJson(StreamReader stream) - { - JsonSerializer serializer = new JsonSerializer(); - return (InstallManifest)serializer.Deserialize(stream, typeof(InstallManifest)); - } - - public void AddPlatformInstallManifest(string platform, IEnumerable entries) - { - InstallManifestPlatform platformManifest = new InstallManifestPlatform(entries); - this.PlatformInstallManifests.Add(platform, platformManifest); - } - } -} diff --git a/GVFS/GVFS.Common/NuGetUpgrade/InstallManifestPlatform.cs b/GVFS/GVFS.Common/NuGetUpgrade/InstallManifestPlatform.cs deleted file mode 100644 index a5ebfaf3f5..0000000000 --- a/GVFS/GVFS.Common/NuGetUpgrade/InstallManifestPlatform.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace GVFS.Common.NuGetUpgrade -{ - public class InstallManifestPlatform - { - public InstallManifestPlatform() - { - this.InstallActions = new List(); - } - - public InstallManifestPlatform(IEnumerable entries) - { - this.InstallActions = entries?.ToList() ?? new List(); - } - - public List InstallActions { get; } - } -} diff --git a/GVFS/GVFS.Common/NuGetUpgrade/NuGetFeed.cs b/GVFS/GVFS.Common/NuGetUpgrade/NuGetFeed.cs deleted file mode 100644 index ccfffa6542..0000000000 --- a/GVFS/GVFS.Common/NuGetUpgrade/NuGetFeed.cs +++ /dev/null @@ -1,278 +0,0 @@ -using GVFS.Common.Tracing; -using NuGet.Commands; -using NuGet.Common; -using NuGet.Configuration; -using NuGet.Packaging.Core; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace GVFS.Common.NuGetUpgrade -{ - /// - /// Handles interactions with a NuGet Feed. - /// - public class NuGetFeed : IDisposable - { - // This is the SHA256 Certificate Thumbrint we expect packages from Microsoft to be signed with - private const string TrustedMicrosoftCertFingerprintOld = "3F9001EA83C560D712C24CF213C3D312CB3BFF51EE89435D3430BD06B5D0EECE"; - private const string TrustedMicrosoftCertFingerprintNew = "AA12DA22A49BCE7D5C1AE64CC1F3D892F150DA76140F210ABD2CBFFCA2C18A27"; - - private readonly ITracer tracer; - private readonly string feedUrl; - private readonly string feedName; - private readonly string downloadFolder; - private readonly bool platformSupportsEncryption; - - private SourceRepository sourceRepository; - private string personalAccessToken; - private SourceCacheContext sourceCacheContext; - private ILogger nuGetLogger; - - public NuGetFeed( - string feedUrl, - string feedName, - string downloadFolder, - string personalAccessToken, - bool platformSupportsEncryption, - ITracer tracer) - { - this.feedUrl = feedUrl; - this.feedName = feedName; - this.downloadFolder = downloadFolder; - this.personalAccessToken = personalAccessToken; - this.tracer = tracer; - - // Configure the NuGet SourceCacheContext - - // - Direct download packages - do not download to global - // NuGet cache. This is set in NullSourceCacheContext.Instance - // - NoCache - Do not cache package version lists - this.sourceCacheContext = NullSourceCacheContext.Instance.Clone(); - this.sourceCacheContext.NoCache = true; - this.platformSupportsEncryption = platformSupportsEncryption; - - this.nuGetLogger = new Logger(this.tracer); - this.SetSourceRepository(); - } - - public void Dispose() - { - this.sourceRepository = null; - this.sourceCacheContext?.Dispose(); - this.sourceCacheContext = null; - } - - public virtual void SetCredentials(string credential) - { - this.personalAccessToken = credential; - - this.SetSourceRepository(); - } - - /// - /// Query a NuGet feed for list of packages that match the packageId. - /// - /// - /// List of packages that match query parameters - public virtual async Task> QueryFeedAsync(string packageId) - { - PackageMetadataResource packageMetadataResource = await this.sourceRepository.GetResourceAsync(); - IEnumerable queryResults = await packageMetadataResource.GetMetadataAsync( - packageId, - includePrerelease: false, - includeUnlisted: false, - sourceCacheContext: this.sourceCacheContext, - log: this.nuGetLogger, - token: CancellationToken.None); - - return queryResults.ToList(); - } - - /// - /// Download the specified packageId from the NuGet feed. - /// - /// PackageIdentity to download. - /// Path to the downloaded package. - public virtual async Task DownloadPackageAsync(PackageIdentity packageId) - { - string downloadPath = Path.Combine(this.downloadFolder, $"{this.feedName}.zip"); - PackageDownloadContext packageDownloadContext = new PackageDownloadContext( - this.sourceCacheContext, - this.downloadFolder, - true); - - DownloadResource downloadResource = await this.sourceRepository.GetResourceAsync(); - - using (DownloadResourceResult downloadResourceResult = await downloadResource.GetDownloadResourceResultAsync( - packageId, - packageDownloadContext, - globalPackagesFolder: string.Empty, - logger : this.nuGetLogger, - token: CancellationToken.None)) - { - if (downloadResourceResult.Status != DownloadResourceResultStatus.Available) - { - throw new Exception($"Download of NuGet package failed. DownloadResult Status: {downloadResourceResult.Status}"); - } - - using (FileStream fileStream = File.Create(downloadPath)) - { - downloadResourceResult.PackageStream.CopyTo(fileStream); - } - } - - return downloadPath; - } - - public virtual bool VerifyPackage(string packagePath) - { - VerifyArgs verifyArgs = new VerifyArgs() - { - Verifications = new VerifyArgs.Verification[] { VerifyArgs.Verification.All }, - PackagePath = packagePath, - CertificateFingerprint = new List - { - TrustedMicrosoftCertFingerprintOld, - TrustedMicrosoftCertFingerprintNew, - }, - Logger = this.nuGetLogger - }; - - VerifyCommandRunner verifyCommandRunner = new VerifyCommandRunner(); - int result = verifyCommandRunner.ExecuteCommandAsync(verifyArgs).Result; - return result == 0; - } - - protected static EventMetadata CreateEventMetadata(Exception e = null) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Area", nameof(NuGetFeed)); - if (e != null) - { - metadata.Add("Exception", e.ToString()); - } - - return metadata; - } - - private static PackageSourceCredential BuildCredentialsFromPAT(string personalAccessToken, bool storePasswordInClearText) - { - // The storePasswordInClearText property is used to control whether the password - // is written to NuGet config files in clear text or not. It also controls whether the - // password is stored encrypted in memory or not. The ability to encrypt / decrypt the password - // is not supported in non-windows platforms at this point. - // We do not actually write out config files or store the password (except in memory). As in our - // usage of NuGet functionality we do not write out config files, it is OK to not set this property - // (with the tradeoff being the password is not encrypted in memory, and we need to make sure that new code - // does not start to write out config files). - return PackageSourceCredential.FromUserInput( - "VfsForGitNugetUpgrader", - "PersonalAccessToken", - personalAccessToken, - storePasswordInClearText: storePasswordInClearText); - } - - private void SetSourceRepository() - { - this.sourceRepository = Repository.Factory.GetCoreV3(this.feedUrl); - if (!string.IsNullOrEmpty(this.personalAccessToken)) - { - this.sourceRepository.PackageSource.Credentials = BuildCredentialsFromPAT(this.personalAccessToken, !this.platformSupportsEncryption); - } - } - - /// - /// Implementation of logger used by NuGet library. It takes all output - /// and redirects it to the GVFS logger. - /// - private class Logger : ILogger - { - private ITracer tracer; - - public Logger(ITracer tracer) - { - this.tracer = tracer; - } - - public void Log(LogLevel level, string data) - { - string message = $"NuGet Logger: ({level}): {data}"; - switch (level) - { - case LogLevel.Debug: - case LogLevel.Verbose: - case LogLevel.Minimal: - case LogLevel.Information: - this.tracer.RelatedInfo(message); - break; - case LogLevel.Warning: - this.tracer.RelatedWarning(message); - break; - case LogLevel.Error: - this.tracer.RelatedWarning(message); - break; - default: - this.tracer.RelatedWarning(message); - break; - } - } - - public void Log(ILogMessage message) - { - this.Log(message.Level, message.Message); - } - - public Task LogAsync(LogLevel level, string data) - { - this.Log(level, data); - return Task.CompletedTask; - } - - public Task LogAsync(ILogMessage message) - { - this.Log(message); - return Task.CompletedTask; - } - - public void LogDebug(string data) - { - this.Log(LogLevel.Debug, data); - } - - public void LogError(string data) - { - this.Log(LogLevel.Error, data); - } - - public void LogInformation(string data) - { - this.Log(LogLevel.Information, data); - } - - public void LogInformationSummary(string data) - { - this.Log(LogLevel.Information, data); - } - - public void LogMinimal(string data) - { - this.Log(LogLevel.Minimal, data); - } - - public void LogVerbose(string data) - { - this.Log(LogLevel.Verbose, data); - } - - public void LogWarning(string data) - { - this.Log(LogLevel.Warning, data); - } - } - } -} diff --git a/GVFS/GVFS.Common/NuGetUpgrade/NuGetUpgrader.cs b/GVFS/GVFS.Common/NuGetUpgrade/NuGetUpgrader.cs deleted file mode 100644 index ff724ec6aa..0000000000 --- a/GVFS/GVFS.Common/NuGetUpgrade/NuGetUpgrader.cs +++ /dev/null @@ -1,799 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.Git; -using GVFS.Common.Tracing; -using NuGet.Packaging.Core; -using NuGet.Protocol.Core.Types; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Threading; - -namespace GVFS.Common.NuGetUpgrade -{ - public class NuGetUpgrader : ProductUpgrader - { - protected readonly NuGetUpgraderConfig nuGetUpgraderConfig; - protected Version highestVersionAvailable; - - private const string ContentDirectoryName = "content"; - private const string InstallManifestFileName = "install-manifest.json"; - private const string ExtractedInstallerDirectoryName = "InstallerTemp"; - - private InstallManifest installManifest; - private NuGetFeed nuGetFeed; - private ICredentialStore credentialStore; - private bool isNuGetFeedInitialized; - - public NuGetUpgrader( - string currentVersion, - ITracer tracer, - PhysicalFileSystem fileSystem, - bool dryRun, - bool noVerify, - NuGetUpgraderConfig config, - string downloadFolder, - ICredentialStore credentialStore) - : this( - currentVersion, - tracer, - dryRun, - noVerify, - fileSystem, - config, - new NuGetFeed( - config.FeedUrl, - config.PackageFeedName, - downloadFolder, - null, - GVFSPlatform.Instance.UnderConstruction.SupportsNuGetEncryption, - tracer), - credentialStore, - GVFSPlatform.Instance.CreateProductUpgraderPlatformInteractions(fileSystem, tracer)) - { - } - - internal NuGetUpgrader( - string currentVersion, - ITracer tracer, - bool dryRun, - bool noVerify, - PhysicalFileSystem fileSystem, - NuGetUpgraderConfig config, - NuGetFeed nuGetFeed, - ICredentialStore credentialStore, - ProductUpgraderPlatformStrategy productUpgraderPlatformStrategy) - : base( - currentVersion, - tracer, - dryRun, - noVerify, - fileSystem, - productUpgraderPlatformStrategy) - { - this.nuGetUpgraderConfig = config; - - this.nuGetFeed = nuGetFeed; - this.credentialStore = credentialStore; - - // Extract the folder inside ProductUpgraderInfo.GetAssetDownloadsPath to ensure the - // correct ACLs are in place - this.ExtractedInstallerPath = Path.Combine( - ProductUpgraderInfo.GetAssetDownloadsPath(), - ExtractedInstallerDirectoryName); - } - - public string DownloadedPackagePath { get; private set; } - - public override bool SupportsAnonymousVersionQuery { get => false; } - - /// - /// Path to unzip the downloaded upgrade package - /// - private string ExtractedInstallerPath { get; } - - /// - /// Try to load a NuGetUpgrader from config settings. - /// Flag to indicate whether the system is configured to use a NuGetUpgrader. - /// A NuGetUpgrader can be set as the Upgrader to use, but it might not be properly configured. - /// - /// True if able to load a properly configured NuGetUpgrader - /// - public static bool TryCreate( - ITracer tracer, - PhysicalFileSystem fileSystem, - LocalGVFSConfig gvfsConfig, - ICredentialStore credentialStore, - bool dryRun, - bool noVerify, - out NuGetUpgrader nuGetUpgrader, - out bool isConfigured, - out string error) - { - NuGetUpgraderConfig upgraderConfig = new NuGetUpgraderConfig(tracer, gvfsConfig); - nuGetUpgrader = null; - isConfigured = false; - - if (!upgraderConfig.TryLoad(out error)) - { - nuGetUpgrader = null; - return false; - } - - if (!(isConfigured = upgraderConfig.IsConfigured(out error))) - { - return false; - } - - // At this point, we have determined that the system is set up to use - // the NuGetUpgrader - - if (!upgraderConfig.IsReady(out error)) - { - return false; - } - - nuGetUpgrader = new NuGetUpgrader( - ProcessHelper.GetCurrentProcessVersion(), - tracer, - fileSystem, - dryRun, - noVerify, - upgraderConfig, - ProductUpgraderInfo.GetAssetDownloadsPath(), - credentialStore); - - return true; - } - - /// - /// Performs a replacement on well known strings in the arguments field of a manifest entry. - /// - /// The unprocessed string to use as arguments to an install command - /// A unique installer ID to replace the installer_id token with. - /// The argument string with tokens replaced. - public static string ReplaceArgTokens(string src, string installationId, string logsDirectory, string installerBaseDirectory) - { - string dst = src - .Replace(NuGetUpgrader.ReplacementToken(InstallActionInfo.ManifestEntryLogDirectoryToken), logsDirectory) - .Replace(NuGetUpgrader.ReplacementToken(InstallActionInfo.ManifestEntryInstallationIdToken), installationId) - .Replace(NuGetUpgrader.ReplacementToken(InstallActionInfo.ManifestEntryInstallerBaseDirectoryToken), installerBaseDirectory); - return dst; - } - - public override void Dispose() - { - this.nuGetFeed?.Dispose(); - this.nuGetFeed = null; - base.Dispose(); - } - - public override bool UpgradeAllowed(out string message) - { - if (string.IsNullOrEmpty(this.nuGetUpgraderConfig.FeedUrl)) - { - message = "Nuget Feed URL has not been configured"; - return false; - } - else if (string.IsNullOrEmpty(this.nuGetUpgraderConfig.PackageFeedName)) - { - message = "NuGet package feed has not been configured"; - return false; - } - - message = null; - return true; - } - - public override bool TryQueryNewestVersion(out Version newVersion, out string message) - { - try - { - if (!this.EnsureNuGetFeedInitialized(out message)) - { - newVersion = null; - return false; - } - - IList queryResults = this.QueryFeed(firstAttempt: true); - - // Find the package with the highest version - IPackageSearchMetadata newestPackage = null; - foreach (IPackageSearchMetadata result in queryResults) - { - if (newestPackage == null || result.Identity.Version > newestPackage.Identity.Version) - { - newestPackage = result; - } - } - - if (newestPackage != null && - newestPackage.Identity.Version.Version > this.installedVersion) - { - this.highestVersionAvailable = newestPackage.Identity.Version.Version; - } - - newVersion = this.highestVersionAvailable; - - if (newVersion != null) - { - this.tracer.RelatedInfo($"{nameof(this.TryQueryNewestVersion)} - new version available: installedVersion: {this.installedVersion}, highestVersionAvailable: {newVersion}"); - message = $"New version {newestPackage.Identity.Version} is available."; - return true; - } - else if (newestPackage != null) - { - this.tracer.RelatedInfo($"{nameof(this.TryQueryNewestVersion)} - up-to-date"); - message = $"highest version available is {newestPackage.Identity.Version}, you are up-to-date"; - return true; - } - else - { - this.tracer.RelatedInfo($"{nameof(this.TryQueryNewestVersion)} - no versions available from feed."); - message = $"No versions available via feed."; - } - } - catch (Exception ex) - { - this.TraceException( - ex, - nameof(this.TryQueryNewestVersion), - "Exception encountered querying for newest version of upgrade package."); - message = ex.Message; - newVersion = null; - } - - return false; - } - - public override bool TryDownloadNewestVersion(out string errorMessage) - { - if (this.highestVersionAvailable == null) - { - // If we hit this code path, it indicates there was a - // programmer error. The expectation is that this - // method will only be called after - // TryQueryNewestVersion has been called, and - // indicates that a newer version is available. - errorMessage = "No new version to download. Query for newest version to ensure a new version is available before downloading."; - return false; - } - - if (!this.EnsureNuGetFeedInitialized(out errorMessage)) - { - return false; - } - - if (!this.TryCreateAndConfigureDownloadDirectory(this.tracer, out errorMessage)) - { - this.tracer.RelatedError($"{nameof(NuGetUpgrader)}.{nameof(this.TryCreateAndConfigureDownloadDirectory)} failed. {errorMessage}"); - return false; - } - - using (ITracer activity = this.tracer.StartActivity(nameof(this.TryDownloadNewestVersion), EventLevel.Informational)) - { - try - { - PackageIdentity packageId = this.GetPackageForVersion(this.highestVersionAvailable); - - if (packageId == null) - { - errorMessage = $"The specified version {this.highestVersionAvailable} was not found in the NuGet feed. Please check with your administrator to make sure the feed is set up correctly."; - return false; - } - - this.DownloadedPackagePath = this.nuGetFeed.DownloadPackageAsync(packageId).GetAwaiter().GetResult(); - } - catch (Exception ex) - { - this.TraceException( - activity, - ex, - nameof(this.TryDownloadNewestVersion), - "Exception encountered downloading newest version of upgrade package."); - errorMessage = ex.Message; - return false; - } - } - - if (!this.noVerify) - { - if (!this.nuGetFeed.VerifyPackage(this.DownloadedPackagePath)) - { - errorMessage = "Package signature validation failed. Check the upgrade logs for more details."; - this.tracer.RelatedError(errorMessage); - this.fileSystem.DeleteFile(this.DownloadedPackagePath); - return false; - } - } - - errorMessage = null; - return true; - } - - public override bool TryCleanup(out string error) - { - return this.TryRecursivelyDeleteInstallerDirectory(out error); - } - - public override bool TryRunInstaller(InstallActionWrapper installActionWrapper, out string error) - { - string localError = null; - int installerExitCode; - bool installSuccessful = true; - using (ITracer activity = this.tracer.StartActivity(nameof(this.TryRunInstaller), EventLevel.Informational)) - { - InstallActionInfo currentInstallAction = null; - try - { - string platformKey = GVFSPlatform.Instance.Name; - - if (!this.TryRecursivelyDeleteInstallerDirectory(out error)) - { - return false; - } - - if (!this.noVerify) - { - if (!this.nuGetFeed.VerifyPackage(this.DownloadedPackagePath)) - { - error = "Package signature validation failed. Check the upgrade logs for more details."; - activity.RelatedError(error); - this.fileSystem.DeleteFile(this.DownloadedPackagePath); - return false; - } - } - - this.UnzipPackage(); - this.installManifest = InstallManifest.FromJsonFile(Path.Combine(this.ExtractedInstallerPath, ContentDirectoryName, InstallManifestFileName)); - if (!this.installManifest.PlatformInstallManifests.TryGetValue(platformKey, out InstallManifestPlatform platformInstallManifest) || - platformInstallManifest == null) - { - activity.RelatedError($"Extracted InstallManifest from JSON, but there was no entry for {platformKey}."); - error = $"No entry in the manifest for the current platform ({platformKey}). Please verify the upgrade package."; - return false; - } - - activity.RelatedInfo($"Extracted InstallManifest from JSON. InstallActions: {platformInstallManifest.InstallActions.Count}"); - - foreach (InstallActionInfo entry in platformInstallManifest.InstallActions) - { - currentInstallAction = entry; - string installerBasePath = Path.Combine(this.ExtractedInstallerPath, ContentDirectoryName); - - string args = entry.Args ?? string.Empty; - - // Replace tokens on args - string processedArgs = NuGetUpgrader.ReplaceArgTokens(args, this.UpgradeInstanceId, ProductUpgraderInfo.GetLogDirectoryPath(), $"\"{installerBasePath}\""); - - activity.RelatedInfo( - "Running install action: Name: {0}, Version: {1}, InstallerPath: {2}, Command: {3}, RawArgs: {4}, ProcessedArgs: {5}", - entry.Name, - entry.Version, - entry.InstallerRelativePath ?? string.Empty, - entry.Command ?? string.Empty, - args, - processedArgs); - - string progressMessage = string.IsNullOrWhiteSpace(entry.Version) ? - $"Running {entry.Name}" : - $"Running {entry.Name} (version {entry.Version})"; - - installActionWrapper( - () => - { - if (!this.dryRun) - { - if (!string.IsNullOrEmpty(entry.Command)) - { - this.RunInstaller(entry.Command, processedArgs, out installerExitCode, out localError); - } - else - { - string installerPath = Path.Combine(installerBasePath, entry.InstallerRelativePath); - this.RunInstaller(installerPath, processedArgs, out installerExitCode, out localError); - } - } - else - { - // We add a sleep here to ensure - // the message for this install - // action is written to the - // console. Even though the - // message is written with a delay - // of 0, the messages are not - // always written out. If / when - // we can ensure that the message - // is written out to console, then - // we can remove this sleep. - Thread.Sleep(1500); - installerExitCode = 0; - } - - installSuccessful = installerExitCode == 0; - - return installSuccessful; - }, - progressMessage); - - if (!installSuccessful) - { - break; - } - } - } - catch (Exception ex) - { - localError = ex.Message; - installSuccessful = false; - } - - if (!installSuccessful) - { - this.SaveSystemInstallerLogs(); - - string installActionName = string.IsNullOrEmpty(currentInstallAction?.Name) ? - "installer" : - currentInstallAction.Name; - - error = string.IsNullOrEmpty(localError) ? - $"The {installActionName} failed, but no error message was provided by the failing command." : - $"The {installActionName} failed with the following error: {localError}"; - - activity.RelatedError($"Could not complete all install actions. The following error was encountered: {error}"); - return false; - } - else - { - activity.RelatedInfo($"Install actions completed successfully."); - error = null; - return true; - } - } - } - - protected static EventMetadata CreateEventMetadata(Exception e = null) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Area", nameof(NuGetFeed)); - if (e != null) - { - metadata.Add("Exception", e.ToString()); - } - - return metadata; - } - - private static string ReplacementToken(string tokenString) - { - return "{" + tokenString + "}"; - } - - private PackageIdentity GetPackageForVersion(Version version) - { - IList queryResults = this.QueryFeed(firstAttempt: true); - - IPackageSearchMetadata packageForVersion = null; - foreach (IPackageSearchMetadata result in queryResults) - { - if (result.Identity.Version.Version == version) - { - packageForVersion = result; - break; - } - } - - return packageForVersion?.Identity; - } - - private bool TryGetPersonalAccessToken(string credentialUrl, ITracer tracer, out string token, out string error) - { - return this.credentialStore.TryGetCredential(this.tracer, credentialUrl, out string username, out token, out error); - } - - private bool TryReacquirePersonalAccessToken(string credentialUrl, ITracer tracer, out string token, out string error) - { - if (!this.credentialStore.TryDeleteCredential(this.tracer, credentialUrl, username: null, password: null, error: out error)) - { - token = null; - return false; - } - - return this.TryGetPersonalAccessToken(credentialUrl, tracer, out token, out error); - } - - private void UnzipPackage() - { - ZipFile.ExtractToDirectory(this.DownloadedPackagePath, this.ExtractedInstallerPath); - } - - private bool TryRecursivelyDeleteInstallerDirectory(out string error) - { - error = null; - Exception e; - if (!this.fileSystem.TryDeleteDirectory(this.ExtractedInstallerPath, out e)) - { - if (e != null) - { - this.TraceException( - e, - nameof(this.TryRecursivelyDeleteInstallerDirectory), - $"Exception encountered while deleting {this.ExtractedInstallerPath}."); - } - - error = e?.Message ?? "Failed to delete directory, but no error was specified."; - return false; - } - - return true; - } - - private IList QueryFeed(bool firstAttempt) - { - try - { - return this.nuGetFeed.QueryFeedAsync(this.nuGetUpgraderConfig.PackageFeedName).GetAwaiter().GetResult(); - } - catch (Exception ex) when (firstAttempt && - this.IsAuthRelatedException(ex)) - { - // If we fail to query the feed due to an authorization error, then it is possible we have stale - // credentials, or credentials without the correct scope. Re-aquire fresh credentials and try again. - EventMetadata data = CreateEventMetadata(ex); - this.tracer.RelatedWarning(data, "Failed to query feed due to unauthorized error. Re-acquiring new credentials and trying again."); - - if (!this.TryRefreshCredentials(out string error)) - { - // If we were unable to re-acquire credentials, throw a new exception indicating that we tried to handle this, but were unable to. - throw new Exception($"Failed to query the feed for upgrade packages due to: {ex.Message}, and was not able to re-acquire new credentials due to: {error}", ex); - } - - // Now that we have re-acquired credentials, try again - but with the retry flag set to false. - return this.QueryFeed(firstAttempt: false); - } - catch (Exception ex) - { - EventMetadata data = CreateEventMetadata(ex); - string message = $"Error encountered when querying NuGet feed. Is first attempt: {firstAttempt}."; - this.tracer.RelatedWarning(data, message); - throw new Exception($"Failed to query the NuGet package feed due to error: {ex.Message}", ex); - } - } - - private bool IsAuthRelatedException(Exception ex) - { - // In observation, we have seen either an HttpRequestException directly, or - // a FatalProtocolException wrapping an HttpRequestException when we are not able - // to auth against the NuGet feed. - System.Net.Http.HttpRequestException httpRequestException = null; - if (ex is System.Net.Http.HttpRequestException) - { - httpRequestException = ex as System.Net.Http.HttpRequestException; - } - else if (ex is FatalProtocolException && - ex.InnerException is System.Net.Http.HttpRequestException) - { - httpRequestException = ex.InnerException as System.Net.Http.HttpRequestException; - } - - if (httpRequestException != null && - (httpRequestException.Message.Contains("401") || httpRequestException.Message.Contains("403"))) - { - return true; - } - - return false; - } - - private bool TryRefreshCredentials(out string error) - { - try - { - string authUrl; - if (!AzDevOpsOrgFromNuGetFeed.TryCreateCredentialQueryUrl(this.nuGetUpgraderConfig.FeedUrl, out authUrl, out error)) - { - return false; - } - - if (!this.TryReacquirePersonalAccessToken(authUrl, this.tracer, out string token, out error)) - { - return false; - } - - this.nuGetFeed.SetCredentials(token); - return true; - } - catch (Exception ex) - { - error = ex.Message; - this.TraceException(ex, nameof(this.TryRefreshCredentials), "Failed to refresh credentials."); - return false; - } - } - - private bool EnsureNuGetFeedInitialized(out string error) - { - if (!this.isNuGetFeedInitialized) - { - if (this.credentialStore == null) - { - throw new InvalidOperationException("Attempted to call method that requires authentication but no CredentialStore is configured."); - } - - string authUrl; - if (!AzDevOpsOrgFromNuGetFeed.TryCreateCredentialQueryUrl(this.nuGetUpgraderConfig.FeedUrl, out authUrl, out error)) - { - return false; - } - - if (!this.TryGetPersonalAccessToken(authUrl, this.tracer, out string token, out error)) - { - return false; - } - - this.nuGetFeed.SetCredentials(token); - this.isNuGetFeedInitialized = true; - } - - error = null; - return true; - } - - /// - /// Saves a copy of installer log from platform native installer in the - /// upgrader diagnose logs directory. On the Mac, it is not possible to - /// specify custom log file path as command line arg to the installer. - /// - private void SaveSystemInstallerLogs() - { - if (GVFSPlatform.Instance.SupportsSystemInstallLog) - { - string systemInstallerLog = GVFSPlatform.Instance.GetSystemInstallerLogPath(); - if (!string.IsNullOrEmpty(systemInstallerLog)) - { - string destinationPath = GVFSEnlistment.GetNewGVFSLogFileName( - ProductUpgraderInfo.GetLogDirectoryPath(), - GVFSConstants.LogFileTypes.UpgradeSystemInstaller, - this.UpgradeInstanceId); - - try - { - using (Stream sourceStream = this.fileSystem.OpenFileStream( - systemInstallerLog, - FileMode.Open, - FileAccess.Read, - FileShare.ReadWrite, - callFlushFileBuffers: false)) - using (Stream destStream = this.fileSystem.OpenFileStream( - destinationPath, - FileMode.Create, - FileAccess.Write, - FileShare.None, - callFlushFileBuffers: false)) - { - // Copy the last 100K from the system wide installer log. - // System wide installer log (/var/log/install.log) holds - // all messages from installd, including the ones that - // it generated while installing VFSForGit. We don't - // need to capture the whole file, which can be lengthy. - // From my testing, the last 100K captured immediately - // after upgrade, is found to be lengthy enough to - // contain all of Git + GCM + Service + VFSForGit - // installer log messages. - long hundredKB = 100 * 1024; - long copyFromOffset = sourceStream.Length > hundredKB ? sourceStream.Length - hundredKB : 0; - - sourceStream.Seek(copyFromOffset, SeekOrigin.Begin); - sourceStream.CopyTo(destStream); - } - } - catch (Exception ex) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Exception", ex.ToString()); - this.tracer.RelatedError( - metadata, - $"{nameof(this.SaveSystemInstallerLogs)} - Error saving native installer log file."); - } - } - else - { - this.tracer.RelatedError($"{nameof(this.SaveSystemInstallerLogs)} - Error getting native installer log file path."); - } - } - } - - public class NuGetUpgraderConfig - { - protected readonly ITracer tracer; - protected readonly LocalGVFSConfig localConfig; - - public NuGetUpgraderConfig(ITracer tracer, LocalGVFSConfig localGVFSConfig) - { - this.tracer = tracer; - this.localConfig = localGVFSConfig; - } - - public NuGetUpgraderConfig( - ITracer tracer, - LocalGVFSConfig localGVFSConfig, - string feedUrl, - string packageFeedName) - : this(tracer, localGVFSConfig) - { - this.FeedUrl = feedUrl; - this.PackageFeedName = packageFeedName; - } - - public string FeedUrl { get; private set; } - public string PackageFeedName { get; private set; } - public string CertificateFingerprint { get; private set; } - - /// - /// Check if the NuGetUpgrader is ready for use. A - /// NuGetUpgrader is considered ready if all required - /// config settings are present. - /// - public virtual bool IsReady(out string error) - { - if (string.IsNullOrEmpty(this.FeedUrl) || - string.IsNullOrEmpty(this.PackageFeedName)) - { - error = string.Join( - Environment.NewLine, - "One or more required settings for NuGetUpgrader are missing.", - $"Use `gvfs config [{GVFSConstants.LocalGVFSConfig.UpgradeFeedUrl} | {GVFSConstants.LocalGVFSConfig.UpgradeFeedPackageName}] ` to set the config."); - return false; - } - - error = null; - return true; - } - - /// - /// Check if the NuGetUpgrader is configured. - /// - public virtual bool IsConfigured(out string error) - { - if (string.IsNullOrEmpty(this.FeedUrl) && - string.IsNullOrEmpty(this.PackageFeedName)) - { - error = string.Join( - Environment.NewLine, - "NuGet upgrade server is not configured.", - $"Use `gvfs config [ {GVFSConstants.LocalGVFSConfig.UpgradeFeedUrl} | {GVFSConstants.LocalGVFSConfig.UpgradeFeedPackageName}] ` to set the config."); - return false; - } - - error = null; - return true; - } - - /// - /// Try to load the config for a NuGet upgrader. Returns false if there was an error reading the config. - /// - public virtual bool TryLoad(out string error) - { - string configValue; - if (!this.localConfig.TryGetConfig(GVFSConstants.LocalGVFSConfig.UpgradeFeedUrl, out configValue, out error)) - { - this.tracer.RelatedError(error); - return false; - } - - this.FeedUrl = configValue; - - if (!this.localConfig.TryGetConfig(GVFSConstants.LocalGVFSConfig.UpgradeFeedPackageName, out configValue, out error)) - { - this.tracer.RelatedError(error); - return false; - } - - this.PackageFeedName = configValue; - return true; - } - } - } -} diff --git a/GVFS/GVFS.Common/NuGetUpgrade/OrgNuGetUpgrader.cs b/GVFS/GVFS.Common/NuGetUpgrade/OrgNuGetUpgrader.cs deleted file mode 100644 index dd7f4852b8..0000000000 --- a/GVFS/GVFS.Common/NuGetUpgrade/OrgNuGetUpgrader.cs +++ /dev/null @@ -1,244 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.Git; -using GVFS.Common.Tracing; -using System; -using System.Net.Http; -using System.Runtime.Serialization; -using System.Threading.Tasks; - -namespace GVFS.Common.NuGetUpgrade -{ - public class OrgNuGetUpgrader : NuGetUpgrader - { - private HttpClient httpClient; - private string platform; - - public OrgNuGetUpgrader( - string currentVersion, - ITracer tracer, - PhysicalFileSystem fileSystem, - HttpClient httpClient, - bool dryRun, - bool noVerify, - OrgNuGetUpgraderConfig config, - string downloadFolder, - string platform, - ICredentialStore credentialStore) - : base( - currentVersion, - tracer, - fileSystem, - dryRun, - noVerify, - config, - downloadFolder, - credentialStore) - { - this.httpClient = httpClient; - this.platform = platform; - } - - public OrgNuGetUpgrader( - string currentVersion, - ITracer tracer, - PhysicalFileSystem fileSystem, - HttpClient httpClient, - bool dryRun, - bool noVerify, - OrgNuGetUpgraderConfig config, - string platform, - NuGetFeed nuGetFeed, - ICredentialStore credentialStore) - : base( - currentVersion, - tracer, - dryRun, - noVerify, - fileSystem, - config, - nuGetFeed, - credentialStore, - GVFSPlatform.Instance.CreateProductUpgraderPlatformInteractions(fileSystem, tracer)) - { - this.httpClient = httpClient; - this.platform = platform; - } - - public override bool SupportsAnonymousVersionQuery { get => true; } - - private OrgNuGetUpgraderConfig Config { get => this.nuGetUpgraderConfig as OrgNuGetUpgraderConfig; } - private string OrgInfoServerUrl { get => this.Config.OrgInfoServer; } - private string Ring { get => this.Config.UpgradeRing; } - - public static bool TryCreate( - ITracer tracer, - PhysicalFileSystem fileSystem, - LocalGVFSConfig gvfsConfig, - HttpClient httpClient, - ICredentialStore credentialStore, - bool dryRun, - bool noVerify, - out OrgNuGetUpgrader upgrader, - out string error) - { - OrgNuGetUpgraderConfig upgraderConfig = new OrgNuGetUpgraderConfig(tracer, gvfsConfig); - upgrader = null; - - if (!upgraderConfig.TryLoad(out error)) - { - upgrader = null; - return false; - } - - if (!upgraderConfig.IsConfigured(out error)) - { - return false; - } - - if (!upgraderConfig.IsReady(out error)) - { - return false; - } - - string platform = GVFSPlatform.Instance.Name; - - upgrader = new OrgNuGetUpgrader( - ProcessHelper.GetCurrentProcessVersion(), - tracer, - fileSystem, - httpClient, - dryRun, - noVerify, - upgraderConfig, - ProductUpgraderInfo.GetAssetDownloadsPath(), - platform, - credentialStore); - - return true; - } - - public override bool TryQueryNewestVersion(out Version newVersion, out string message) - { - newVersion = null; - - if (!AzDevOpsOrgFromNuGetFeed.TryParseOrg(this.Config.FeedUrl, out string orgName)) - { - message = "OrgNuGetUpgrader is not able to parse org name from NuGet Package Feed URL"; - return false; - } - - OrgInfoApiClient infoServer = new OrgInfoApiClient(this.httpClient, this.OrgInfoServerUrl); - - try - { - this.highestVersionAvailable = infoServer.QueryNewestVersion(orgName, this.platform, this.Ring); - } - catch (Exception exception) when (exception is HttpRequestException || - exception is TaskCanceledException) - { - // GetStringAsync can also throw a TaskCanceledException to indicate a timeout - // https://github.com/dotnet/corefx/issues/20296 - message = string.Format("Network error: could not connect to server ({0}). {1}", this.OrgInfoServerUrl, exception.Message); - this.TraceException(exception, nameof(this.TryQueryNewestVersion), "Error connecting to server."); - - return false; - } - catch (SerializationException exception) - { - message = string.Format("Parse error: could not parse response from server({0}). {1}", this.OrgInfoServerUrl, exception.Message); - this.TraceException(exception, nameof(this.TryQueryNewestVersion), "Error parsing response from server."); - - return false; - } - catch (Exception exception) when (exception is ArgumentException || - exception is FormatException || - exception is OverflowException) - { - message = string.Format("Unexpected response from server: could nor parse version({0}). {1}", this.OrgInfoServerUrl, exception.Message); - this.TraceException(exception, nameof(this.TryQueryNewestVersion), "Error parsing response from server."); - - return false; - } - - if (this.highestVersionAvailable != null && - this.highestVersionAvailable > this.installedVersion) - { - newVersion = this.highestVersionAvailable; - } - - if (newVersion != null) - { - this.tracer.RelatedInfo($"{nameof(this.TryQueryNewestVersion)} - new version available: installedVersion: {this.installedVersion}, highestVersionAvailable: {newVersion}"); - message = $"New version {newVersion} is available."; - return true; - } - else if (this.highestVersionAvailable != null) - { - this.tracer.RelatedInfo($"{nameof(this.TryQueryNewestVersion)} - up-to-date"); - message = $"Highest version available is {this.highestVersionAvailable}, you are up-to-date"; - return true; - } - else - { - this.tracer.RelatedInfo($"{nameof(this.TryQueryNewestVersion)} - no versions available from feed."); - message = "No versions available via endpoint."; - return true; - } - } - - public class OrgNuGetUpgraderConfig : NuGetUpgraderConfig - { - public OrgNuGetUpgraderConfig(ITracer tracer, LocalGVFSConfig localGVFSConfig) - : base(tracer, localGVFSConfig) - { - } - - public string OrgInfoServer { get; set; } - - public string UpgradeRing { get; set; } - - public override bool TryLoad(out string error) - { - if (!base.TryLoad(out error)) - { - return false; - } - - if (!this.localConfig.TryGetConfig(GVFSConstants.LocalGVFSConfig.OrgInfoServerUrl, out string orgInfoServerUrl, out error)) - { - this.tracer.RelatedError(error); - return false; - } - - this.OrgInfoServer = orgInfoServerUrl; - - if (!this.localConfig.TryGetConfig(GVFSConstants.LocalGVFSConfig.UpgradeRing, out string upgradeRing, out error)) - { - this.tracer.RelatedError(error); - return false; - } - - this.UpgradeRing = upgradeRing; - - return true; - } - - public override bool IsReady(out string error) - { - if (!base.IsReady(out error) || - string.IsNullOrEmpty(this.UpgradeRing) || - string.IsNullOrEmpty(this.OrgInfoServer)) - { - error = string.Join( - Environment.NewLine, - "One or more required settings for OrgNuGetUpgrader are missing.", - "Use `gvfs config [{GVFSConstants.LocalGVFSConfig.UpgradeFeedUrl} | {GVFSConstants.LocalGVFSConfig.UpgradeFeedPackageName} | {GVFSConstants.LocalGVFSConfig.UpgradeRing} | {GVFSConstants.LocalGVFSConfig.OrgInfoServerUrl}] ` to set the config."); - return false; - } - - return true; - } - } - } -} diff --git a/GVFS/GVFS.Common/ProductUpgrader.cs b/GVFS/GVFS.Common/ProductUpgrader.cs deleted file mode 100644 index b28330cc25..0000000000 --- a/GVFS/GVFS.Common/ProductUpgrader.cs +++ /dev/null @@ -1,258 +0,0 @@ -using GVFS.Common.FileSystem; -using GVFS.Common.Git; -using GVFS.Common.NuGetUpgrade; -using GVFS.Common.Tracing; -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; - -namespace GVFS.Common -{ - /// - /// Delegate to wrap install action steps in. - /// This can be used to report the beginning / end of each install step. - /// - /// The method to run inside wrapper - /// The message to display - /// success or failure return from the method run. - public delegate bool InstallActionWrapper(Func method, string message); - - public abstract class ProductUpgrader : IDisposable - { - protected readonly Version installedVersion; - protected readonly ITracer tracer; - protected readonly PhysicalFileSystem fileSystem; - - protected bool noVerify; - protected bool dryRun; - protected ProductUpgraderPlatformStrategy productUpgraderPlatformStrategy; - - protected ProductUpgrader( - string currentVersion, - ITracer tracer, - bool dryRun, - bool noVerify, - PhysicalFileSystem fileSystem) - : this( - currentVersion, - tracer, - dryRun, - noVerify, - fileSystem, - GVFSPlatform.Instance.CreateProductUpgraderPlatformInteractions(fileSystem, tracer)) - { - } - - protected ProductUpgrader( - string currentVersion, - ITracer tracer, - bool dryRun, - bool noVerify, - PhysicalFileSystem fileSystem, - ProductUpgraderPlatformStrategy productUpgraderPlatformStrategy) - { - this.installedVersion = new Version(currentVersion); - this.dryRun = dryRun; - this.noVerify = noVerify; - this.tracer = tracer; - this.fileSystem = fileSystem; - this.productUpgraderPlatformStrategy = productUpgraderPlatformStrategy; - } - - /// - /// For mocking purposes only - /// - protected ProductUpgrader() - { - } - - public abstract bool SupportsAnonymousVersionQuery { get; } - - public string UpgradeInstanceId { get; set; } = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - - public static bool TryCreateUpgrader( - ITracer tracer, - PhysicalFileSystem fileSystem, - LocalGVFSConfig gvfsConfig, - ICredentialStore credentialStore, - bool dryRun, - bool noVerify, - out ProductUpgrader newUpgrader, - out string error) - { - Dictionary entries; - if (!gvfsConfig.TryGetAllConfig(out entries, out error)) - { - newUpgrader = null; - return false; - } - - bool containsUpgradeFeedUrl = entries.ContainsKey(GVFSConstants.LocalGVFSConfig.UpgradeFeedUrl); - bool containsUpgradePackageName = entries.ContainsKey(GVFSConstants.LocalGVFSConfig.UpgradeFeedPackageName); - bool containsOrgInfoServerUrl = entries.ContainsKey(GVFSConstants.LocalGVFSConfig.OrgInfoServerUrl); - - if (containsUpgradeFeedUrl || containsUpgradePackageName) - { - // We are configured for NuGet - determine if we are using OrgNuGetUpgrader or not - if (containsOrgInfoServerUrl) - { - if (OrgNuGetUpgrader.TryCreate( - tracer, - fileSystem, - gvfsConfig, - new HttpClient(), - credentialStore, - dryRun, - noVerify, - out OrgNuGetUpgrader orgNuGetUpgrader, - out error)) - { - // We were successfully able to load a NuGetUpgrader - use that. - newUpgrader = orgNuGetUpgrader; - return true; - } - else - { - tracer.RelatedError($"{nameof(TryCreateUpgrader)}: Could not create organization based upgrader. {error}"); - newUpgrader = null; - return false; - } - } - else - { - if (NuGetUpgrader.TryCreate( - tracer, - fileSystem, - gvfsConfig, - credentialStore, - dryRun, - noVerify, - out NuGetUpgrader nuGetUpgrader, - out bool isConfigured, - out error)) - { - // We were successfully able to load a NuGetUpgrader - use that. - newUpgrader = nuGetUpgrader; - return true; - } - else - { - tracer.RelatedError($"{nameof(TryCreateUpgrader)}: Could not create NuGet based upgrader. {error}"); - newUpgrader = null; - return false; - } - } - } - else - { - newUpgrader = GitHubUpgrader.Create(tracer, fileSystem, gvfsConfig, dryRun, noVerify, out error); - if (newUpgrader == null) - { - tracer.RelatedError($"{nameof(TryCreateUpgrader)}: Could not create GitHub based upgrader. {error}"); - return false; - } - - return true; - } - } - - public abstract bool UpgradeAllowed(out string message); - - public abstract bool TryQueryNewestVersion(out Version newVersion, out string message); - - public abstract bool TryDownloadNewestVersion(out string errorMessage); - - public abstract bool TryRunInstaller(InstallActionWrapper installActionWrapper, out string error); - - public virtual bool TrySetupUpgradeApplicationDirectory(out string upgradeApplicationPath, out string error) - { - string upgradeApplicationDirectory = ProductUpgraderInfo.GetUpgradeApplicationDirectory(); - - if (!this.productUpgraderPlatformStrategy.TryPrepareApplicationDirectory(out error)) - { - upgradeApplicationPath = null; - return false; - } - - string currentPath = ProcessHelper.GetCurrentProcessLocation(); - error = null; - try - { - // Copying C:\Program Files\GVFS to inside of C:\Program Files\GVFS\ProgramData\GVFS.Upgrade\Tools - // directory causes a cycle(at some point we start copying C:\Program Files\GVFS\ProgramData\GVFS.Upgrade - // and its contents into C:\Program Files\GVFS\ProgramData\GVFS.Upgrade\Tools). The exclusion below is - // added to avoid this loop. - HashSet directoriesToExclude = new HashSet(GVFSPlatform.Instance.Constants.PathComparer); - - string secureDataRoot = GVFSPlatform.Instance.GetSecureDataRootForGVFS(); - directoriesToExclude.Add(secureDataRoot); - directoriesToExclude.Add(upgradeApplicationDirectory); - - this.tracer.RelatedInfo($"Copying contents of '{currentPath}' to '{upgradeApplicationDirectory}'," - + $"excluding '{upgradeApplicationDirectory}' and '{secureDataRoot}'"); - - this.fileSystem.CopyDirectoryRecursive(currentPath, upgradeApplicationDirectory, directoriesToExclude); - } - catch (UnauthorizedAccessException e) - { - error = string.Join( - Environment.NewLine, - "File copy error - " + e.Message, - $"Make sure you have write permissions to directory {upgradeApplicationDirectory} and run {GVFSPlatform.Instance.Constants.UpgradeConfirmCommandMessage} again."); - } - catch (IOException e) - { - error = "File copy error - " + e.Message; - this.TraceException(e, nameof(this.TrySetupUpgradeApplicationDirectory), $"Error copying {currentPath} to {upgradeApplicationDirectory}."); - } - - if (string.IsNullOrEmpty(error)) - { - // There was no error - set upgradeToolPath and return success. - upgradeApplicationPath = Path.Combine( - upgradeApplicationDirectory, - GVFSPlatform.Instance.Constants.GVFSUpgraderExecutableName); - return true; - } - else - { - // Encountered error - do not set upgrade tool path and return failure. - upgradeApplicationPath = null; - return false; - } - } - - public abstract bool TryCleanup(out string error); - - public void TraceException(Exception exception, string method, string message) - { - this.TraceException(this.tracer, exception, method, message); - } - - public void TraceException(ITracer tracer, Exception exception, string method, string message) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Method", method); - metadata.Add("Exception", exception.ToString()); - tracer.RelatedError(metadata, message); - } - - public virtual void Dispose() - { - } - - protected virtual bool TryCreateAndConfigureDownloadDirectory(ITracer tracer, out string error) - { - return this.productUpgraderPlatformStrategy.TryPrepareDownloadDirectory(out error); - } - - protected virtual void RunInstaller(string path, string args, out int exitCode, out string error) - { - ProcessResult processResult = ProcessHelper.Run(path, args); - - exitCode = processResult.ExitCode; - error = processResult.Errors; - } - } -} diff --git a/GVFS/GVFS.Common/ProductUpgraderInfo.Shared.cs b/GVFS/GVFS.Common/ProductUpgraderInfo.Shared.cs deleted file mode 100644 index 9a8fd367e4..0000000000 --- a/GVFS/GVFS.Common/ProductUpgraderInfo.Shared.cs +++ /dev/null @@ -1,59 +0,0 @@ -using GVFS.Common.Tracing; -using System; -using System.IO; - -namespace GVFS.Common -{ - public partial class ProductUpgraderInfo - { - public const string UpgradeDirectoryName = "GVFS.Upgrade"; - public const string LogDirectory = "UpgraderLogs"; - public const string DownloadDirectory = "Downloads"; - - /// - /// This is the name of the directory that the Upgrader Application is copied to - /// when running upgrade. It is called "Tools", as this is what the directory was - /// originally named, but has since been renamed in code to be more descriptive. - /// - public const string ApplicationDirectory = "Tools"; - public const string HighestAvailableVersionFileName = "HighestAvailableVersion"; - - public static bool IsLocalUpgradeAvailable(ITracer tracer, string highestAvailableVersionDirectory) - { - try - { - return File.Exists(GetHighestAvailableVersionFilePath(highestAvailableVersionDirectory)); - } - catch (Exception ex) when ( - ex is IOException || - ex is UnauthorizedAccessException || - ex is NotSupportedException) - { - if (tracer != null) - { - tracer.RelatedError( - CreateEventMetadata(ex), - "Exception encountered when determining if an upgrade is available."); - } - } - - return false; - } - - private static string GetHighestAvailableVersionFilePath(string highestAvailableVersionDirectory) - { - return Path.Combine(highestAvailableVersionDirectory, HighestAvailableVersionFileName); - } - - private static EventMetadata CreateEventMetadata(Exception e) - { - EventMetadata metadata = new EventMetadata(); - if (e != null) - { - metadata.Add("Exception", e.ToString()); - } - - return metadata; - } - } -} diff --git a/GVFS/GVFS.Common/ProductUpgraderInfo.cs b/GVFS/GVFS.Common/ProductUpgraderInfo.cs deleted file mode 100644 index ed097c733a..0000000000 --- a/GVFS/GVFS.Common/ProductUpgraderInfo.cs +++ /dev/null @@ -1,102 +0,0 @@ -using GVFS.Common.FileSystem; -using GVFS.Common.Tracing; -using System; -using System.IO; - -namespace GVFS.Common -{ - public partial class ProductUpgraderInfo - { - private ITracer tracer; - private PhysicalFileSystem fileSystem; - - public ProductUpgraderInfo(ITracer tracer, PhysicalFileSystem fileSystem) - { - this.tracer = tracer; - this.fileSystem = fileSystem; - } - - public static string CurrentGVFSVersion() - { - return ProcessHelper.GetCurrentProcessVersion(); - } - - public static string GetUpgradeProtectedDataDirectory() - { - return GVFSPlatform.Instance.GetUpgradeProtectedDataDirectory(); - } - - public static string GetUpgradeApplicationDirectory() - { - return Path.Combine( - GetUpgradeProtectedDataDirectory(), - ProductUpgraderInfo.ApplicationDirectory); - } - - public static string GetParentLogDirectoryPath() - { - return GVFSPlatform.Instance.GetUpgradeLogDirectoryParentDirectory(); - } - - public static string GetLogDirectoryPath() - { - return Path.Combine( - GVFSPlatform.Instance.GetUpgradeLogDirectoryParentDirectory(), - ProductUpgraderInfo.LogDirectory); - } - - public static string GetAssetDownloadsPath() - { - return Path.Combine( - GVFSPlatform.Instance.GetUpgradeProtectedDataDirectory(), - ProductUpgraderInfo.DownloadDirectory); - } - - public static string GetHighestAvailableVersionDirectory() - { - return GVFSPlatform.Instance.GetUpgradeHighestAvailableVersionDirectory(); - } - - public void DeleteAllInstallerDownloads() - { - try - { - this.fileSystem.DeleteDirectory(GetAssetDownloadsPath()); - } - catch (Exception ex) - { - if (this.tracer != null) - { - this.tracer.RelatedError($"{nameof(this.DeleteAllInstallerDownloads)}: Could not remove directory: {ProductUpgraderInfo.GetAssetDownloadsPath()}.{ex.ToString()}"); - } - } - } - - public void RecordHighestAvailableVersion(Version highestAvailableVersion) - { - string highestAvailableVersionFile = GetHighestAvailableVersionFilePath(GetHighestAvailableVersionDirectory()); - - if (highestAvailableVersion == null) - { - if (this.fileSystem.FileExists(highestAvailableVersionFile)) - { - this.fileSystem.DeleteFile(highestAvailableVersionFile); - - if (this.tracer != null) - { - this.tracer.RelatedInfo($"{nameof(this.RecordHighestAvailableVersion)}: Deleted upgrade reminder marker file"); - } - } - } - else - { - this.fileSystem.WriteAllText(highestAvailableVersionFile, highestAvailableVersion.ToString()); - - if (this.tracer != null) - { - this.tracer.RelatedInfo($"{nameof(this.RecordHighestAvailableVersion)}: Created upgrade reminder marker file"); - } - } - } - } -} diff --git a/GVFS/GVFS.Common/ProductUpgraderPlatformStrategy.cs b/GVFS/GVFS.Common/ProductUpgraderPlatformStrategy.cs deleted file mode 100644 index 776adeaa84..0000000000 --- a/GVFS/GVFS.Common/ProductUpgraderPlatformStrategy.cs +++ /dev/null @@ -1,38 +0,0 @@ -using GVFS.Common.FileSystem; -using GVFS.Common.Tracing; -using System; -using System.IO; - -namespace GVFS.Common -{ - public abstract class ProductUpgraderPlatformStrategy - { - public ProductUpgraderPlatformStrategy(PhysicalFileSystem fileSystem, ITracer tracer) - { - this.FileSystem = fileSystem; - this.Tracer = tracer; - } - - protected PhysicalFileSystem FileSystem { get; } - protected ITracer Tracer { get; } - - public abstract bool TryPrepareLogDirectory(out string error); - - public abstract bool TryPrepareApplicationDirectory(out string error); - - public abstract bool TryPrepareDownloadDirectory(out string error); - - protected void TraceException(Exception exception, string method, string message) - { - this.TraceException(this.Tracer, exception, method, message); - } - - protected void TraceException(ITracer tracer, Exception exception, string method, string message) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Method", method); - metadata.Add("Exception", exception.ToString()); - tracer.RelatedError(metadata, message); - } - } -} diff --git a/GVFS/GVFS.Hooks/GVFS.Hooks.csproj b/GVFS/GVFS.Hooks/GVFS.Hooks.csproj index 10ad576b7a..efe7842a7d 100644 --- a/GVFS/GVFS.Hooks/GVFS.Hooks.csproj +++ b/GVFS/GVFS.Hooks/GVFS.Hooks.csproj @@ -59,9 +59,6 @@ Common\ProcessResult.cs - - Common\ProductUpgraderInfo.Shared.cs - Common\Tracing\EventLevel.cs diff --git a/GVFS/GVFS.Hooks/HooksPlatform/GVFSHooksPlatform.cs b/GVFS/GVFS.Hooks/HooksPlatform/GVFSHooksPlatform.cs index 1fbf2aaf30..0c7cf7239f 100644 --- a/GVFS/GVFS.Hooks/HooksPlatform/GVFSHooksPlatform.cs +++ b/GVFS/GVFS.Hooks/HooksPlatform/GVFSHooksPlatform.cs @@ -37,19 +37,9 @@ public static bool TryGetNormalizedPath(string path, out string normalizedPath, return WindowsFileSystem.TryGetNormalizedPathImplementation(path, out normalizedPath, out errorMessage); } - public static string GetUpgradeHighestAvailableVersionDirectory() - { - return WindowsPlatform.GetUpgradeHighestAvailableVersionDirectoryImplementation(); - } - public static string GetGitGuiBlockedMessage() { return "To access the 'git gui' in a GVFS repo, please invoke 'git-gui.exe' instead."; } - - public static string GetUpgradeReminderNotification() - { - return WindowsPlatform.GetUpgradeReminderNotificationImplementation(); - } } } diff --git a/GVFS/GVFS.Hooks/Program.cs b/GVFS/GVFS.Hooks/Program.cs index eac434c5d5..4dc9aeb99e 100644 --- a/GVFS/GVFS.Hooks/Program.cs +++ b/GVFS/GVFS.Hooks/Program.cs @@ -65,8 +65,6 @@ public static void Main(string[] args) { RunLockRequest(args, unattended, ReleaseGVFSLock); } - - RunPostCommands(args, unattended); break; default: @@ -92,30 +90,6 @@ private static void RunPreCommands(string[] args) } } - private static void RunPostCommands(string[] args, bool unattended) - { - if (!unattended) - { - RemindUpgradeAvailable(); - } - } - - private static void RemindUpgradeAvailable() - { - // The idea is to generate a random number between 0 and 100. To make - // sure that the reminder is displayed only 10% of the times a git - // command is run, check that the random number is between 0 and 10, - // which will have a probability of 10/100 == 10%. - int reminderFrequency = 10; - int randomValue = random.Next(0, 100); - - if ((IsUpgradeMessageDeterministic() || randomValue <= reminderFrequency) && - ProductUpgraderInfo.IsLocalUpgradeAvailable(tracer: null, highestAvailableVersionDirectory: GVFSHooksPlatform.GetUpgradeHighestAvailableVersionDirectory())) - { - Console.WriteLine(Environment.NewLine + GVFSHooksPlatform.GetUpgradeReminderNotification()); - } - } - private static void ExitWithError(params string[] messages) { foreach (string message in messages) diff --git a/GVFS/GVFS.Payload/GVFS.Payload.csproj b/GVFS/GVFS.Payload/GVFS.Payload.csproj index c6f7004c5d..a976360f65 100644 --- a/GVFS/GVFS.Payload/GVFS.Payload.csproj +++ b/GVFS/GVFS.Payload/GVFS.Payload.csproj @@ -24,7 +24,6 @@ - @@ -50,7 +49,6 @@ $(OutputPath)\GVFS.ReadObjectHook.exe; $(OutputPath)\GVFS.Service.exe; $(OutputPath)\GVFS.Service.UI.exe; - $(OutputPath)\GVFS.Upgrader.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 10c7c8878d..85036a5018 100644 --- a/GVFS/GVFS.Payload/layout.bat +++ b/GVFS/GVFS.Payload/layout.bat @@ -55,7 +55,6 @@ 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%\GVFS.Upgrader\%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.Platform.Windows/WindowsPlatform.Shared.cs b/GVFS/GVFS.Platform.Windows/WindowsPlatform.Shared.cs index 2bbef5a2b0..67414dbfc7 100644 --- a/GVFS/GVFS.Platform.Windows/WindowsPlatform.Shared.cs +++ b/GVFS/GVFS.Platform.Windows/WindowsPlatform.Shared.cs @@ -128,21 +128,6 @@ public static bool TryGetGVFSEnlistmentRootImplementation(string directory, out return true; } - public static string GetUpgradeProtectedDataDirectoryImplementation() - { - return Path.Combine(GetSecureDataRootForGVFSImplementation(), ProductUpgraderInfo.UpgradeDirectoryName); - } - - public static string GetUpgradeHighestAvailableVersionDirectoryImplementation() - { - return GetUpgradeProtectedDataDirectoryImplementation(); - } - - public static string GetUpgradeReminderNotificationImplementation() - { - return $"A new version of VFS for Git is available. Run {UpgradeConfirmMessage} from an elevated command prompt to upgrade."; - } - [DllImport("kernel32.dll")] private static extern IntPtr GetStdHandle(StdHandle std); diff --git a/GVFS/GVFS.Platform.Windows/WindowsPlatform.cs b/GVFS/GVFS.Platform.Windows/WindowsPlatform.cs index 07ee383e9b..1f22f32482 100644 --- a/GVFS/GVFS.Platform.Windows/WindowsPlatform.cs +++ b/GVFS/GVFS.Platform.Windows/WindowsPlatform.cs @@ -333,28 +333,11 @@ public override string GetUserIdFromLoginSessionId(int sessionId, ITracer tracer } } - public override string GetUpgradeLogDirectoryParentDirectory() - { - return Path.Combine( - this.GetCommonAppDataRootForGVFS(), - ProductUpgraderInfo.UpgradeDirectoryName); - } - public override string GetSystemInstallerLogPath() { return null; } - public override string GetUpgradeHighestAvailableVersionDirectory() - { - return this.GetUpgradeProtectedDataDirectory(); - } - - public override string GetUpgradeProtectedDataDirectory() - { - return GetUpgradeProtectedDataDirectoryImplementation(); - } - public override Dictionary GetPhysicalDiskInfo(string path, bool sizeStatsOnly) => WindowsPhysicalDiskInfo.GetPhysicalDiskInfo(path, sizeStatsOnly); public override bool IsConsoleOutputRedirectedToFile() @@ -375,13 +358,6 @@ public override FileBasedLock CreateFileBasedLock( return new WindowsFileBasedLock(fileSystem, tracer, lockPath); } - public override ProductUpgraderPlatformStrategy CreateProductUpgraderPlatformInteractions( - PhysicalFileSystem fileSystem, - ITracer tracer) - { - return new WindowsProductUpgraderPlatformStrategy(fileSystem, tracer); - } - public override bool TryGetGVFSEnlistmentRoot(string directory, out string enlistmentRoot, out string errorMessage) { return WindowsPlatform.TryGetGVFSEnlistmentRootImplementation(directory, out enlistmentRoot, out errorMessage); diff --git a/GVFS/GVFS.Platform.Windows/WindowsProductUpgraderPlatformStrategy.cs b/GVFS/GVFS.Platform.Windows/WindowsProductUpgraderPlatformStrategy.cs deleted file mode 100644 index ccb6f07031..0000000000 --- a/GVFS/GVFS.Platform.Windows/WindowsProductUpgraderPlatformStrategy.cs +++ /dev/null @@ -1,75 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.Tracing; -using System; -using System.IO; - -namespace GVFS.Platform.Windows -{ - public class WindowsProductUpgraderPlatformStrategy : ProductUpgraderPlatformStrategy - { - public WindowsProductUpgraderPlatformStrategy(PhysicalFileSystem fileSystem, ITracer tracer) - : base(fileSystem, tracer) - { - } - - public override bool TryPrepareLogDirectory(out string error) - { - // Under normal circumstances - // ProductUpgraderInfo.GetLogDirectoryPath will have - // already been created by GVFS.Service. If for some - // reason it does not (e.g. the service failed to start), - // we need to create - // ProductUpgraderInfo.GetLogDirectoryPath() explicity to - // ensure that it has the correct ACLs (so that both admin - // and non-admin users can create log files). If the logs - // directory does not already exist, this call could fail - // when running as a non-elevated user. - string createDirectoryError; - if (!this.FileSystem.TryCreateDirectoryWithAdminAndUserModifyPermissions(ProductUpgraderInfo.GetLogDirectoryPath(), out createDirectoryError)) - { - error = $"ERROR: Unable to create directory `{ProductUpgraderInfo.GetLogDirectoryPath()}`"; - error += $"\n{createDirectoryError}"; - error += $"\n\nTry running {GVFSConstants.UpgradeVerbMessages.GVFSUpgrade} from an elevated command prompt."; - return false; - } - - error = null; - return true; - } - - public override bool TryPrepareApplicationDirectory(out string error) - { - string upgradeApplicationDirectory = ProductUpgraderInfo.GetUpgradeApplicationDirectory(); - - Exception deleteDirectoryException; - if (this.FileSystem.DirectoryExists(upgradeApplicationDirectory) && - !this.FileSystem.TryDeleteDirectory(upgradeApplicationDirectory, out deleteDirectoryException)) - { - error = $"Failed to delete {upgradeApplicationDirectory} - {deleteDirectoryException.Message}"; - - this.TraceException(deleteDirectoryException, nameof(this.TryPrepareApplicationDirectory), $"Error deleting {upgradeApplicationDirectory}."); - return false; - } - - if (!this.FileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissions( - this.Tracer, - upgradeApplicationDirectory, - out error)) - { - return false; - } - - error = null; - return true; - } - - public override bool TryPrepareDownloadDirectory(out string error) - { - return this.FileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissions( - this.Tracer, - ProductUpgraderInfo.GetAssetDownloadsPath(), - out error); - } - } -} diff --git a/GVFS/GVFS.Service/GVFSService.Windows.cs b/GVFS/GVFS.Service/GVFSService.Windows.cs index 90ef0922be..92d4fd4fc3 100644 --- a/GVFS/GVFS.Service/GVFSService.Windows.cs +++ b/GVFS/GVFS.Service/GVFSService.Windows.cs @@ -305,16 +305,14 @@ private void CreateAndConfigureProgramDataDirectories() DirectorySecurity serviceDataRootSecurity = this.GetServiceDirectorySecurity(serviceDataRootPath); - // Create GVFS.Service and GVFS.Upgrade related directories (if they don't already exist) + // Create GVFS.Service related directories (if they don't already exist) Directory.CreateDirectory(serviceDataRootPath, serviceDataRootSecurity); Directory.CreateDirectory(this.serviceDataLocation, serviceDataRootSecurity); - Directory.CreateDirectory(ProductUpgraderInfo.GetUpgradeProtectedDataDirectory(), serviceDataRootSecurity); // 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 upgrader logs, as non-elevated users need to be be able to write - this.CreateAndConfigureLogDirectory(ProductUpgraderInfo.GetLogDirectoryPath()); + // 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)); } diff --git a/GVFS/GVFS.UnitTests/Common/InstallManifestTests.cs b/GVFS/GVFS.UnitTests/Common/InstallManifestTests.cs deleted file mode 100644 index 0c3eec512d..0000000000 --- a/GVFS/GVFS.UnitTests/Common/InstallManifestTests.cs +++ /dev/null @@ -1,140 +0,0 @@ -using GVFS.Common.NuGetUpgrade; -using GVFS.Tests.Should; -using Newtonsoft.Json; -using NUnit.Framework; -using System.Collections.Generic; -using System.IO; - -namespace GVFS.UnitTests.Common -{ - [TestFixture] - public class JsonInstallManifestTests - { - private static int manifestEntryCount = 0; - - [TestCase] - public void CanReadExpectedJsonString() - { - string installManifestJsonString = -@" -{ - ""Version"" : ""1"", - ""PlatformInstallManifests"" : { - ""Windows"": { - ""InstallActions"": [ - { - ""Name"" : ""Git"", - ""Version"" : ""2.19.0.1.34"", - ""InstallerRelativePath"" : ""Installers\\Windows\\G4W\\Git-2.19.0.gvfs.1.34.gc7fb556-64-bit.exe"", - ""Args"" : ""/VERYSILENT /CLOSEAPPLICATIONS"" - }, - { - ""Name"" : ""PostGitInstall script"", - ""InstallerRelativePath"" : ""Installers\\Windows\\GSD\\postinstall.ps1"" - }, - ] - } - } -} -"; - InstallManifest installManifest = InstallManifest.FromJsonString(installManifestJsonString); - - installManifest.ShouldNotBeNull(); - InstallManifestPlatform platformInstallManifest = installManifest.PlatformInstallManifests[InstallManifest.WindowsPlatformKey]; - platformInstallManifest.ShouldNotBeNull(); - platformInstallManifest.InstallActions.Count.ShouldEqual(2); - - this.VerifyInstallActionInfo( - platformInstallManifest.InstallActions[0], - "Git", - "2.19.0.1.34", - "/VERYSILENT /CLOSEAPPLICATIONS", - "Installers\\Windows\\G4W\\Git-2.19.0.gvfs.1.34.gc7fb556-64-bit.exe"); - - this.VerifyInstallActionInfo( - platformInstallManifest.InstallActions[1], - "PostGitInstall script", - null, - null, - "Installers\\Windows\\GSD\\postinstall.ps1"); - } - - [TestCase] - public void CanDeserializeAndSerializeInstallManifest() - { - List entries = new List() - { - this.CreateInstallActionInfo(), - this.CreateInstallActionInfo() - }; - - InstallManifest installManifest = new InstallManifest(); - installManifest.AddPlatformInstallManifest(InstallManifest.WindowsPlatformKey, entries); - - JsonSerializer serializer = new JsonSerializer(); - - using (MemoryStream ms = new MemoryStream()) - using (StreamWriter streamWriter = new StreamWriter(ms)) - using (JsonWriter jsWriter = new JsonTextWriter(streamWriter)) - { - string output = JsonConvert.SerializeObject(installManifest); - serializer.Serialize(jsWriter, installManifest); - jsWriter.Flush(); - - ms.Seek(0, SeekOrigin.Begin); - - StreamReader streamReader = new StreamReader(ms); - InstallManifest deserializedInstallManifest = InstallManifest.FromJson(streamReader); - - this.VerifyInstallManifestsAreEqual(installManifest, deserializedInstallManifest); - } - } - - private InstallActionInfo CreateInstallActionInfo() - { - int entrySuffix = manifestEntryCount++; - return new InstallActionInfo( - name: $"Installer{entrySuffix}", - version: $"1.{entrySuffix}.1.2", - args: $"/nodowngrade{entrySuffix}", - installerRelativePath: $"installers/installer1{entrySuffix}", - command: string.Empty); - } - - private void VerifyInstallManifestsAreEqual(InstallManifest expected, InstallManifest actual) - { - actual.PlatformInstallManifests.Count.ShouldEqual(expected.PlatformInstallManifests.Count, $"The number of platforms ({actual.PlatformInstallManifests.Count}) do not match the expected number of platforms ({expected.PlatformInstallManifests.Count})."); - - foreach (KeyValuePair kvp in expected.PlatformInstallManifests) - { - this.VerifyPlatformManifestsAreEqual(kvp.Value, actual.PlatformInstallManifests[kvp.Key]); - } - } - - private void VerifyInstallActionInfo( - InstallActionInfo actualEntry, - string expectedName, - string expectedVersion, - string expectedArgs, - string expectedInstallerRelativePath) - { - actualEntry.Name.ShouldEqual(expectedName, "InstallActionInfo name does not match expected value"); - actualEntry.Version.ShouldEqual(expectedVersion, "InstallActionInfo version does not match expected value"); - actualEntry.Args.ShouldEqual(expectedArgs, "InstallActionInfo Args does not match expected value"); - actualEntry.InstallerRelativePath.ShouldEqual(expectedInstallerRelativePath, "InstallActionInfo InstallerRelativePath does not match expected value"); - } - - private void VerifyPlatformManifestsAreEqual(InstallManifestPlatform expected, InstallManifestPlatform actual) - { - actual.InstallActions.Count.ShouldEqual(expected.InstallActions.Count, $"The number of platforms ({actual.InstallActions.Count}) do not match the expected number of platforms ({expected.InstallActions.Count})."); - - for (int i = 0; i < actual.InstallActions.Count; i++) - { - actual.InstallActions[i].Version.ShouldEqual(expected.InstallActions[i].Version); - actual.InstallActions[i].Args.ShouldEqual(expected.InstallActions[i].Args); - actual.InstallActions[i].Name.ShouldEqual(expected.InstallActions[i].Name); - actual.InstallActions[i].InstallerRelativePath.ShouldEqual(expected.InstallActions[i].InstallerRelativePath); - } - } - } -} diff --git a/GVFS/GVFS.UnitTests/Common/NuGetUpgrade/NuGetUpgraderTests.cs b/GVFS/GVFS.UnitTests/Common/NuGetUpgrade/NuGetUpgraderTests.cs deleted file mode 100644 index 44a8795e88..0000000000 --- a/GVFS/GVFS.UnitTests/Common/NuGetUpgrade/NuGetUpgraderTests.cs +++ /dev/null @@ -1,455 +0,0 @@ -using GVFS.Common; -using GVFS.Common.Git; -using GVFS.Common.NuGetUpgrade; -using GVFS.Common.Tracing; -using GVFS.Tests.Should; -using GVFS.UnitTests.Category; -using GVFS.UnitTests.Mock.Common; -using GVFS.UnitTests.Mock.FileSystem; -using Moq; -using NuGet.Packaging.Core; -using NuGet.Protocol.Core.Types; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace GVFS.UnitTests.Common.NuGetUpgrade -{ - [TestFixture] - public class NuGetUpgraderTests - { - protected const string OlderVersion = "1.0.1185.0"; - protected const string CurrentVersion = "1.5.1185.0"; - protected const string NewerVersion = "1.6.1185.0"; - protected const string NewerVersion2 = "1.7.1185.0"; - - protected const string NuGetFeedUrl = "https://pkgs.dev.azure.com/contoso/packages"; - protected const string NuGetFeedName = "feedNameValue"; - - protected static Exception httpRequestAuthException = new System.Net.Http.HttpRequestException("Response status code does not indicate success: 401 (Unauthorized)."); - protected static Exception fatalProtocolAuthException = new FatalProtocolException("Unable to load the service index for source.", httpRequestAuthException); - - protected static Exception[] networkAuthFailures = - { - httpRequestAuthException, - fatalProtocolAuthException - }; - - protected NuGetUpgrader upgrader; - protected MockTracer tracer; - - protected NuGetUpgrader.NuGetUpgraderConfig upgraderConfig; - - protected Mock mockNuGetFeed; - protected MockFileSystem mockFileSystem; - protected Mock mockCredentialManager; - protected ProductUpgraderPlatformStrategy productUpgraderPlatformStrategy; - - protected string downloadDirectoryPath = Path.Combine( - $"mock:{Path.DirectorySeparatorChar}", - ProductUpgraderInfo.UpgradeDirectoryName, - ProductUpgraderInfo.DownloadDirectory); - - protected delegate void DownloadPackageAsyncCallback(PackageIdentity packageIdentity); - - public virtual ProductUpgraderPlatformStrategy CreateProductUpgraderPlatformStrategy() - { - return new MockProductUpgraderPlatformStrategy(this.mockFileSystem, this.tracer); - } - - [SetUp] - public void SetUp() - { - this.upgraderConfig = new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, NuGetFeedUrl, NuGetFeedName); - - this.tracer = new MockTracer(); - - this.mockNuGetFeed = new Mock( - NuGetFeedUrl, - NuGetFeedName, - this.downloadDirectoryPath, - null, - GVFSPlatform.Instance.UnderConstruction.SupportsNuGetEncryption, - this.tracer); - this.mockNuGetFeed.Setup(feed => feed.SetCredentials(It.IsAny())); - - this.mockFileSystem = new MockFileSystem( - new MockDirectory( - Path.GetDirectoryName(this.downloadDirectoryPath), - new[] { new MockDirectory(this.downloadDirectoryPath, null, null) }, - null)); - - this.mockCredentialManager = new Mock(); - string credentialManagerString = "value"; - string emptyString = string.Empty; - this.mockCredentialManager.Setup(foo => foo.TryGetCredential(It.IsAny(), It.IsAny(), out credentialManagerString, out credentialManagerString, out credentialManagerString)).Returns(true); - - this.productUpgraderPlatformStrategy = this.CreateProductUpgraderPlatformStrategy(); - - this.upgrader = new NuGetUpgrader( - CurrentVersion, - this.tracer, - false, - false, - this.mockFileSystem, - this.upgraderConfig, - this.mockNuGetFeed.Object, - this.mockCredentialManager.Object, - this.productUpgraderPlatformStrategy); - } - - [TearDown] - public void TearDown() - { - this.mockNuGetFeed.Object.Dispose(); - this.tracer.Dispose(); - } - - [TestCase] - public void TryQueryNewestVersion_NewVersionAvailable() - { - Version newVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion)), - }; - - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny())).ReturnsAsync(availablePackages); - - bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message); - - // Assert that we found the newer version - success.ShouldBeTrue(); - newVersion.ShouldNotBeNull(); - newVersion.ShouldEqual(new Version(NewerVersion)); - message.ShouldNotBeNull(); - } - - [TestCase] - public void TryQueryNewestVersion_MultipleNewVersionsAvailable() - { - Version newVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion2)), - }; - - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny())).ReturnsAsync(availablePackages); - - bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message); - - // Assert that we found the newest version - success.ShouldBeTrue(); - newVersion.ShouldNotBeNull(); - newVersion.ShouldEqual(new Version(NewerVersion2)); - message.ShouldNotBeNull(); - } - - [TestCase] - public void TryQueryNewestVersion_NoNewerVersionsAvailable() - { - Version newVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(OlderVersion)), - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - }; - - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny())).ReturnsAsync(availablePackages); - - bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message); - - // Assert that no new version was returned - success.ShouldBeTrue(); - newVersion.ShouldBeNull(); - } - - [TestCase] - [Category(CategoryConstants.ExceptionExpected)] - public void TryQueryNewestVersion_Exception() - { - Version newVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(OlderVersion)), - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - }; - - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny())).Throws(new Exception("Network Error")); - - bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message); - - // Assert that no new version was returned - success.ShouldBeFalse(); - newVersion.ShouldBeNull(); - message.ShouldNotBeNull(); - message.Any().ShouldBeTrue(); - } - - [TestCase] - public void CanDownloadNewestVersion() - { - Version actualNewestVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion)), - }; - - string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip"); - IPackageSearchMetadata newestAvailableVersion = availablePackages.Last(); - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages); - this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is(packageIdentity => packageIdentity == newestAvailableVersion.Identity))).ReturnsAsync(testDownloadPath); - this.mockNuGetFeed.Setup(foo => foo.VerifyPackage(It.IsAny())).Returns(true); - - bool success = this.upgrader.TryQueryNewestVersion(out actualNewestVersion, out message); - - // Assert that no new version was returned - success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}"); - actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version."); - - bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message); - downloadSuccessful.ShouldBeTrue(); - this.upgrader.DownloadedPackagePath.ShouldEqual(testDownloadPath); - this.mockNuGetFeed.Verify(nuGetFeed => nuGetFeed.VerifyPackage(It.IsAny()), Times.Once()); - } - - [TestCase] - [Category(CategoryConstants.ExceptionExpected)] - public void DownloadNewestVersion_HandleException() - { - Version newVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion)), - }; - - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny())).ReturnsAsync(availablePackages); - this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.IsAny())).Throws(new Exception("Network Error")); - this.mockNuGetFeed.Setup(foo => foo.VerifyPackage(It.IsAny())).Returns(true); - - bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message); - - success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}"); - newVersion.ShouldNotBeNull(); - - bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message); - downloadSuccessful.ShouldBeFalse(); - } - - [TestCase] - public void AttemptingToDownloadBeforeQueryingFails() - { - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion)), - }; - - IPackageSearchMetadata newestAvailableVersion = availablePackages.Last(); - - string downloadPath = "c:\\test_download_path"; - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages); - this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is(packageIdentity => packageIdentity == newestAvailableVersion.Identity))).ReturnsAsync(downloadPath); - - bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message); - downloadSuccessful.ShouldBeFalse(); - } - - [TestCase] - public void TestUpgradeAllowed() - { - // Properly Configured NuGet config - NuGetUpgrader.NuGetUpgraderConfig nuGetUpgraderConfig = - new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, NuGetFeedUrl, NuGetFeedName); - - NuGetUpgrader nuGetUpgrader = new NuGetUpgrader( - CurrentVersion, - this.tracer, - false, - false, - this.mockFileSystem, - nuGetUpgraderConfig, - this.mockNuGetFeed.Object, - this.mockCredentialManager.Object, - this.productUpgraderPlatformStrategy); - - nuGetUpgrader.UpgradeAllowed(out _).ShouldBeTrue("NuGetUpgrader config is complete: upgrade should be allowed."); - - // Empty FeedURL - nuGetUpgraderConfig = - new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, string.Empty, NuGetFeedName); - - nuGetUpgrader = new NuGetUpgrader( - CurrentVersion, - this.tracer, - false, - false, - this.mockFileSystem, - nuGetUpgraderConfig, - this.mockNuGetFeed.Object, - this.mockCredentialManager.Object, - this.productUpgraderPlatformStrategy); - - nuGetUpgrader.UpgradeAllowed(out string _).ShouldBeFalse("Upgrade without FeedURL configured should not be allowed."); - - // Empty packageFeedName - nuGetUpgraderConfig = - new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, NuGetFeedUrl, string.Empty); - - // Empty packageFeedName - nuGetUpgrader = new NuGetUpgrader( - CurrentVersion, - this.tracer, - false, - false, - this.mockFileSystem, - nuGetUpgraderConfig, - this.mockNuGetFeed.Object, - this.mockCredentialManager.Object, - this.productUpgraderPlatformStrategy); - - nuGetUpgrader.UpgradeAllowed(out string _).ShouldBeFalse("Upgrade without FeedName configured should not be allowed."); - } - - [TestCaseSource("networkAuthFailures")] - public void QueryNewestVersionReacquiresCredentialsOnAuthFailure(Exception exception) - { - Version actualNewestVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion)), - }; - - string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip"); - IPackageSearchMetadata newestAvailableVersion = availablePackages.Last(); - this.mockNuGetFeed.SetupSequence(foo => foo.QueryFeedAsync(It.IsAny())) - .Throws(exception) - .ReturnsAsync(availablePackages); - - // Setup the credential manager - string emptyString = string.Empty; - this.mockCredentialManager.Setup(foo => foo.TryDeleteCredential(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), out emptyString)).Returns(true); - - bool success = this.upgrader.TryQueryNewestVersion(out actualNewestVersion, out message); - - // Verify expectations - success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}"); - actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version."); - - this.mockNuGetFeed.Verify(nuGetFeed => nuGetFeed.QueryFeedAsync(It.IsAny()), Times.Exactly(2)); - - string outString = string.Empty; - this.mockCredentialManager.Verify(credentialManager => credentialManager.TryGetCredential(It.IsAny(), It.IsAny(), out outString, out outString, out outString), Times.Exactly(2)); - this.mockCredentialManager.Verify(credentialManager => credentialManager.TryDeleteCredential(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), out outString), Times.Exactly(1)); - } - - [TestCase] - public void WellKnownArgumentTokensReplaced() - { - string logDirectory = "mock:\\test_log_directory"; - string noTokenSourceString = "/arg no_token log_directory installation_id"; - NuGetUpgrader.ReplaceArgTokens(noTokenSourceString, "unique_id", logDirectory, "installerBase").ShouldEqual(noTokenSourceString, "String with no tokens should not be modifed"); - - string sourceStringWithTokens = "/arg /log {log_directory}_{installation_id}_{installer_base_path}"; - string expectedProcessedString = "/arg /log " + logDirectory + "_unique_id_installerBase"; - NuGetUpgrader.ReplaceArgTokens(sourceStringWithTokens, "unique_id", logDirectory, "installerBase").ShouldEqual(expectedProcessedString, "expected tokens have not been replaced"); - } - - [TestCase] - public void DownloadFailsOnNuGetPackageVerificationFailure() - { - Version actualNewestVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion)), - }; - - IPackageSearchMetadata newestAvailableVersion = availablePackages.Last(); - - string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip"); - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages); - this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is(packageIdentity => packageIdentity == newestAvailableVersion.Identity))) - .Callback(new DownloadPackageAsyncCallback( - (packageIdentity) => this.mockFileSystem.WriteAllText(testDownloadPath, "Package contents that will fail validation"))) - .ReturnsAsync(testDownloadPath); - this.mockNuGetFeed.Setup(foo => foo.VerifyPackage(It.IsAny())).Returns(false); - - bool success = this.upgrader.TryQueryNewestVersion(out actualNewestVersion, out message); - success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}"); - actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version."); - - bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message); - this.mockNuGetFeed.Verify(nuGetFeed => nuGetFeed.VerifyPackage(this.upgrader.DownloadedPackagePath), Times.Once()); - downloadSuccessful.ShouldBeFalse("Failure to verify NuGet package should cause download to fail."); - this.mockFileSystem.FileExists(testDownloadPath).ShouldBeFalse("VerifyPackage should delete invalid packages"); - } - - [TestCase] - public void DoNotVerifyNuGetPackageWhenNoVerifyIsSpecified() - { - NuGetUpgrader.NuGetUpgraderConfig nuGetUpgraderConfig = - new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, NuGetFeedUrl, NuGetFeedName); - - NuGetUpgrader nuGetUpgrader = new NuGetUpgrader( - CurrentVersion, - this.tracer, - false, - true, - this.mockFileSystem, - nuGetUpgraderConfig, - this.mockNuGetFeed.Object, - this.mockCredentialManager.Object, - this.productUpgraderPlatformStrategy); - - Version actualNewestVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion)), - }; - - IPackageSearchMetadata newestAvailableVersion = availablePackages.Last(); - - string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip"); - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages); - this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is(packageIdentity => packageIdentity == newestAvailableVersion.Identity))).ReturnsAsync(testDownloadPath); - this.mockNuGetFeed.Setup(foo => foo.VerifyPackage(It.IsAny())).Returns(false); - - bool success = nuGetUpgrader.TryQueryNewestVersion(out actualNewestVersion, out message); - success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}"); - actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version."); - - bool downloadSuccessful = nuGetUpgrader.TryDownloadNewestVersion(out message); - this.mockNuGetFeed.Verify(nuGetFeed => nuGetFeed.VerifyPackage(It.IsAny()), Times.Never()); - downloadSuccessful.ShouldBeTrue("Should be able to download package with verification issues when noVerify is specified"); - } - - protected IPackageSearchMetadata GeneratePackageSeachMetadata(Version version) - { - Mock mockPackageSearchMetaData = new Mock(); - NuGet.Versioning.NuGetVersion nuGetVersion = new NuGet.Versioning.NuGetVersion(version); - mockPackageSearchMetaData.Setup(foo => foo.Identity).Returns(new NuGet.Packaging.Core.PackageIdentity("generatedPackedId", nuGetVersion)); - - return mockPackageSearchMetaData.Object; - } - } -} diff --git a/GVFS/GVFS.UnitTests/Common/NuGetUpgrade/OrgNuGetUpgraderTests.cs b/GVFS/GVFS.UnitTests/Common/NuGetUpgrade/OrgNuGetUpgraderTests.cs deleted file mode 100644 index 8257840ba9..0000000000 --- a/GVFS/GVFS.UnitTests/Common/NuGetUpgrade/OrgNuGetUpgraderTests.cs +++ /dev/null @@ -1,192 +0,0 @@ -using GVFS.Common; -using GVFS.Common.Git; -using GVFS.Common.NuGetUpgrade; -using GVFS.Common.Tracing; -using GVFS.Tests.Should; -using GVFS.UnitTests.Category; -using GVFS.UnitTests.Mock.Common; -using GVFS.UnitTests.Mock.FileSystem; -using Moq; -using Moq.Protected; -using NuGet.Packaging.Core; -using NuGet.Protocol.Core.Types; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; - -namespace GVFS.UnitTests.Common.NuGetUpgrade -{ - [TestFixture] - public class OrgNuGetUpgraderTests - { - private const string CurrentVersion = "1.5.1185.0"; - private const string NewerVersion = "1.6.1185.0"; - - private const string DefaultUpgradeFeedPackageName = "package"; - private const string DefaultUpgradeFeedUrl = "https://pkgs.dev.azure.com/contoso/"; - private const string DefaultOrgInfoServerUrl = "https://www.contoso.com"; - private const string DefaultRing = "slow"; - - private OrgNuGetUpgrader upgrader; - - private MockTracer tracer; - - private OrgNuGetUpgrader.OrgNuGetUpgraderConfig upgraderConfig; - - private Mock mockNuGetFeed; - private MockFileSystem mockFileSystem; - private Mock mockCredentialManager; - private Mock httpMessageHandlerMock; - - private string downloadDirectoryPath = Path.Combine( - $"mock:{Path.DirectorySeparatorChar}", - ProductUpgraderInfo.UpgradeDirectoryName, - ProductUpgraderInfo.DownloadDirectory); - - private interface IHttpMessageHandlerProtectedMembers - { - Task SendAsync(HttpRequestMessage message, CancellationToken token); - } - - public static IEnumerable NetworkFailureCases() - { - yield return new HttpRequestException("Response status code does not indicate success: 401: (Unauthorized)"); - yield return new TaskCanceledException("Task canceled"); - } - - [SetUp] - public void SetUp() - { - MockLocalGVFSConfig mockGvfsConfig = new MockLocalGVFSConfigBuilder( - DefaultRing, - DefaultUpgradeFeedUrl, - DefaultUpgradeFeedPackageName, - DefaultOrgInfoServerUrl) - .WithUpgradeRing() - .WithUpgradeFeedPackageName() - .WithUpgradeFeedUrl() - .WithOrgInfoServerUrl() - .Build(); - - this.upgraderConfig = new OrgNuGetUpgrader.OrgNuGetUpgraderConfig(this.tracer, mockGvfsConfig); - this.upgraderConfig.TryLoad(out _); - - this.tracer = new MockTracer(); - - this.mockNuGetFeed = new Mock( - DefaultUpgradeFeedUrl, - DefaultUpgradeFeedPackageName, - this.downloadDirectoryPath, - null, - GVFSPlatform.Instance.UnderConstruction.SupportsNuGetEncryption, - this.tracer); - - this.mockFileSystem = new MockFileSystem( - new MockDirectory( - Path.GetDirectoryName(this.downloadDirectoryPath), - new[] { new MockDirectory(this.downloadDirectoryPath, null, null) }, - null)); - - this.mockCredentialManager = new Mock(); - string credentialManagerString = "value"; - string emptyString = string.Empty; - this.mockCredentialManager.Setup(foo => foo.TryGetCredential(It.IsAny(), It.IsAny(), out credentialManagerString, out credentialManagerString, out credentialManagerString)).Returns(true); - - this.httpMessageHandlerMock = new Mock(); - - this.httpMessageHandlerMock.Protected().As() - .Setup(m => m.SendAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new HttpResponseMessage() - { - StatusCode = HttpStatusCode.OK, - Content = new StringContent(this.ConstructResponseContent(NewerVersion)) - }); - - HttpClient httpClient = new HttpClient(this.httpMessageHandlerMock.Object); - - this.upgrader = new OrgNuGetUpgrader( - CurrentVersion, - this.tracer, - this.mockFileSystem, - httpClient, - false, - false, - this.upgraderConfig, - "windows", - this.mockNuGetFeed.Object, - this.mockCredentialManager.Object); - } - - [TestCase] - public void SupportsAnonymousQuery() - { - this.upgrader.SupportsAnonymousVersionQuery.ShouldBeTrue(); - } - - [TestCase] - public void TryQueryNewestVersion() - { - Version newVersion; - string message; - - bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message); - - success.ShouldBeTrue(); - newVersion.ShouldNotBeNull(); - newVersion.ShouldEqual(new Version(NewerVersion)); - message.ShouldNotBeNull(); - message.ShouldEqual($"New version {OrgNuGetUpgraderTests.NewerVersion} is available."); - } - - [TestCaseSource("NetworkFailureCases")] - public void HandlesNetworkErrors(Exception ex) - { - Version newVersion; - string message; - - this.httpMessageHandlerMock.Protected().As() - .Setup(m => m.SendAsync(It.IsAny(), It.IsAny())) - .ThrowsAsync(ex); - - bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message); - - success.ShouldBeFalse(); - newVersion.ShouldBeNull(); - message.ShouldNotBeNull(); - message.ShouldContain("Network error"); - } - - [TestCase] - public void HandlesEmptyVersion() - { - Version newVersion; - string message; - - this.httpMessageHandlerMock.Protected().As() - .Setup(m => m.SendAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new HttpResponseMessage() - { - StatusCode = HttpStatusCode.OK, - Content = new StringContent(this.ConstructResponseContent(string.Empty)) - }); - - bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message); - - success.ShouldBeTrue(); - newVersion.ShouldBeNull(); - message.ShouldNotBeNull(); - message.ShouldContain("No versions available"); - } - - private string ConstructResponseContent(string version) - { - return $"{{\"version\" : \"{version}\"}} "; - } - } -} diff --git a/GVFS/GVFS.UnitTests/Common/ProductUpgraderInfoTests.cs b/GVFS/GVFS.UnitTests/Common/ProductUpgraderInfoTests.cs deleted file mode 100644 index 9a64ca22a0..0000000000 --- a/GVFS/GVFS.UnitTests/Common/ProductUpgraderInfoTests.cs +++ /dev/null @@ -1,81 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.Git; -using GVFS.Common.Tracing; -using GVFS.Tests.Should; -using GVFS.UnitTests.Mock.Common; -using Moq; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace GVFS.UnitTests.Common -{ - [TestFixture] - public class ProductUpgraderInfoTests - { - private Mock mockFileSystem; - private ProductUpgraderInfo productUpgraderInfo; - - private string upgradeDirectory; - - private string expectedNewVersionExistsFileName = "HighestAvailableVersion"; - private string expectedNewVersionExistsFilePath; - private MockTracer tracer; - - [SetUp] - public void SetUp() - { - this.upgradeDirectory = ProductUpgraderInfo.GetHighestAvailableVersionDirectory(); - this.expectedNewVersionExistsFilePath = Path.Combine(this.upgradeDirectory, this.expectedNewVersionExistsFileName); - this.mockFileSystem = new Mock(); - - this.mockFileSystem.Setup(fileSystem => fileSystem.WriteAllText(this.expectedNewVersionExistsFilePath, It.IsAny())); - - this.tracer = new MockTracer(); - - this.productUpgraderInfo = new ProductUpgraderInfo( - this.tracer, - this.mockFileSystem.Object); - } - - [TearDown] - public void TearDown() - { - this.mockFileSystem = null; - this.productUpgraderInfo = null; - this.tracer = null; - } - - [TestCase] - public void RecordHighestVersion() - { - this.productUpgraderInfo.RecordHighestAvailableVersion(new Version("1.0.0.0")); - this.mockFileSystem.Verify(fileSystem => fileSystem.WriteAllText(this.expectedNewVersionExistsFilePath, It.IsAny()), Times.Once()); - } - - [TestCase] - public void RecordingEmptyVersionDeletesExistingHighestVersionFile() - { - this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.expectedNewVersionExistsFilePath)).Returns(true); - - this.productUpgraderInfo.RecordHighestAvailableVersion(null); - - this.mockFileSystem.Verify(fileSystem => fileSystem.FileExists(this.expectedNewVersionExistsFilePath), Times.Once()); - this.mockFileSystem.Verify(fileSystem => fileSystem.DeleteFile(this.expectedNewVersionExistsFilePath), Times.Once()); - } - - [TestCase] - public void RecordingEmptyVersionDoesNotDeleteNonExistingHighestVersionFile() - { - this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.expectedNewVersionExistsFilePath)).Returns(false); - - this.productUpgraderInfo.RecordHighestAvailableVersion(null); - - this.mockFileSystem.Verify(fileSystem => fileSystem.FileExists(this.expectedNewVersionExistsFilePath), Times.Once()); - this.mockFileSystem.Verify(fileSystem => fileSystem.DeleteFile(this.expectedNewVersionExistsFilePath), Times.Never()); - } - } -} diff --git a/GVFS/GVFS.UnitTests/Common/TryCreateProductUpgraderTests.cs b/GVFS/GVFS.UnitTests/Common/TryCreateProductUpgraderTests.cs deleted file mode 100644 index 50ae7778e5..0000000000 --- a/GVFS/GVFS.UnitTests/Common/TryCreateProductUpgraderTests.cs +++ /dev/null @@ -1,260 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.Git; -using GVFS.Common.NuGetUpgrade; -using GVFS.Tests.Should; -using GVFS.UnitTests.Mock.Common; -using Moq; -using NUnit.Framework; - -namespace GVFS.UnitTests.Common -{ - public class TryCreateProductUpgradeTests - { - private static string defaultUpgradeFeedPackageName = "package"; - private static string defaultUpgradeFeedUrl = "https://pkgs.dev.azure.com/contoso/"; - private static string defaultOrgInfoServerUrl = "https://www.contoso.com"; - private static string defaultRing = "slow"; - - private MockTracer tracer; - private Mock fileSystemMock; - private Mock credentialStoreMock; - - [SetUp] - public void Setup() - { - this.tracer = new MockTracer(); - - // It is important that creating a new Upgrader does not - // require credentials. We must be able to create an - // upgrader to query / check upgrade preconditions without - // requiring authorization. We create these mocks with - // strict behavior to validate methods on them are called - // unnecessarily. - this.credentialStoreMock = new Mock(MockBehavior.Strict); - this.fileSystemMock = new Mock(MockBehavior.Strict); - } - - [TearDown] - public void TearDown() - { - this.credentialStoreMock.VerifyAll(); - this.fileSystemMock.VerifyAll(); - } - - [TestCase] - public void CreatesNuGetUpgraderWhenConfigured() - { - MockLocalGVFSConfig gvfsConfig = this.ConstructDefaultMockNuGetConfigBuilder() - .Build(); - - bool success = ProductUpgrader.TryCreateUpgrader( - this.tracer, - this.fileSystemMock.Object, - gvfsConfig, - this.credentialStoreMock.Object, - false, - false, - out ProductUpgrader productUpgrader, - out string error); - - success.ShouldBeTrue(); - productUpgrader.ShouldNotBeNull(); - productUpgrader.ShouldBeOfType(); - error.ShouldBeNull(); - } - - [TestCase] - public void CreatesNuGetUpgraderWhenConfiguredWithNoRing() - { - MockLocalGVFSConfig gvfsConfig = this.ConstructDefaultMockNuGetConfigBuilder() - .WithNoUpgradeRing() - .Build(); - - bool success = ProductUpgrader.TryCreateUpgrader( - this.tracer, - this.fileSystemMock.Object, - gvfsConfig, - this.credentialStoreMock.Object, - false, - false, - out ProductUpgrader productUpgrader, - out string error); - - success.ShouldBeTrue(); - productUpgrader.ShouldNotBeNull(); - productUpgrader.ShouldBeOfType(); - error.ShouldBeNull(); - } - - [TestCase] - public void CreatesGitHubUpgraderWhenConfigured() - { - MockLocalGVFSConfig gvfsConfig = this.ConstructDefaultGitHubConfigBuilder() - .Build(); - - bool success = ProductUpgrader.TryCreateUpgrader( - this.tracer, - this.fileSystemMock.Object, - gvfsConfig, - this.credentialStoreMock.Object, - false, - false, - out ProductUpgrader productUpgrader, - out string error); - - success.ShouldBeTrue(); - productUpgrader.ShouldNotBeNull(); - productUpgrader.ShouldBeOfType(); - error.ShouldBeNull(); - } - - [TestCase] - public void CreatesOrgNuGetUpgrader() - { - MockLocalGVFSConfig gvfsConfig = this.ConstructDefaultMockOrgNuGetConfigBuilder() - .Build(); - - bool success = ProductUpgrader.TryCreateUpgrader( - this.tracer, - this.fileSystemMock.Object, - gvfsConfig, - this.credentialStoreMock.Object, - false, - false, - out ProductUpgrader productUpgrader, - out string error); - - success.ShouldBeTrue(); - productUpgrader.ShouldNotBeNull(); - productUpgrader.ShouldBeOfType(); - error.ShouldBeNull(); - } - - [TestCase] - public void NoUpgraderWhenNuGetFeedMissing() - { - MockLocalGVFSConfig gvfsConfig = this.ConstructDefaultMockNuGetConfigBuilder() - .WithNoUpgradeFeedUrl() - .Build(); - - bool success = ProductUpgrader.TryCreateUpgrader( - this.tracer, - this.fileSystemMock.Object, - gvfsConfig, - this.credentialStoreMock.Object, - false, - false, - out ProductUpgrader productUpgrader, - out string error); - - success.ShouldBeFalse(); - productUpgrader.ShouldBeNull(); - error.ShouldNotBeNull(); - } - - [TestCase] - public void NoOrgUpgraderWhenNuGetPackNameMissing() - { - MockLocalGVFSConfig gvfsConfig = this.ConstructDefaultMockOrgNuGetConfigBuilder() - .WithNoUpgradeFeedPackageName() - .Build(); - - bool success = ProductUpgrader.TryCreateUpgrader( - this.tracer, - this.fileSystemMock.Object, - gvfsConfig, - this.credentialStoreMock.Object, - false, - false, - out ProductUpgrader productUpgrader, - out string error); - - success.ShouldBeFalse(); - productUpgrader.ShouldBeNull(); - error.ShouldNotBeNull(); - } - - [TestCase] - public void NoOrgUpgraderWhenNuGetFeedMissing() - { - MockLocalGVFSConfig gvfsConfig = this.ConstructDefaultMockOrgNuGetConfigBuilder() - .WithNoUpgradeFeedUrl() - .Build(); - - bool success = ProductUpgrader.TryCreateUpgrader( - this.tracer, - this.fileSystemMock.Object, - gvfsConfig, - this.credentialStoreMock.Object, - false, - false, - out ProductUpgrader productUpgrader, - out string error); - - success.ShouldBeFalse(); - productUpgrader.ShouldBeNull(); - error.ShouldNotBeNull(); - } - - [TestCase] - public void NoUpgraderWhenNuGetPackNameMissing() - { - MockLocalGVFSConfig gvfsConfig = this.ConstructDefaultMockNuGetConfigBuilder() - .WithNoUpgradeFeedPackageName() - .Build(); - - bool success = ProductUpgrader.TryCreateUpgrader( - this.tracer, - this.fileSystemMock.Object, - gvfsConfig, - this.credentialStoreMock.Object, - false, - false, - out ProductUpgrader productUpgrader, - out string error); - - success.ShouldBeFalse(); - productUpgrader.ShouldBeNull(); - error.ShouldNotBeNull(); - } - - private MockLocalGVFSConfigBuilder ConstructDefaultMockNuGetConfigBuilder() - { - MockLocalGVFSConfigBuilder configBuilder = this.ConstructMockLocalGVFSConfigBuilder() - .WithUpgradeRing() - .WithUpgradeFeedPackageName() - .WithUpgradeFeedUrl(); - - return configBuilder; - } - - private MockLocalGVFSConfigBuilder ConstructDefaultMockOrgNuGetConfigBuilder() - { - MockLocalGVFSConfigBuilder configBuilder = this.ConstructMockLocalGVFSConfigBuilder() - .WithUpgradeRing() - .WithUpgradeFeedPackageName() - .WithUpgradeFeedUrl() - .WithOrgInfoServerUrl(); - - return configBuilder; - } - - private MockLocalGVFSConfigBuilder ConstructDefaultGitHubConfigBuilder() - { - MockLocalGVFSConfigBuilder configBuilder = this.ConstructMockLocalGVFSConfigBuilder() - .WithUpgradeRing(); - - return configBuilder; - } - - private MockLocalGVFSConfigBuilder ConstructMockLocalGVFSConfigBuilder() - { - return new MockLocalGVFSConfigBuilder( - defaultRing, - defaultUpgradeFeedUrl, - defaultUpgradeFeedPackageName, - defaultOrgInfoServerUrl); - } - } -} diff --git a/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj b/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj index 57ed82f97b..fe7648aacd 100644 --- a/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj +++ b/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj @@ -11,7 +11,6 @@ - diff --git a/GVFS/GVFS.UnitTests/Mock/Common/MockPlatform.cs b/GVFS/GVFS.UnitTests/Mock/Common/MockPlatform.cs index 1f379802a3..1d89320087 100644 --- a/GVFS/GVFS.UnitTests/Mock/Common/MockPlatform.cs +++ b/GVFS/GVFS.UnitTests/Mock/Common/MockPlatform.cs @@ -120,27 +120,12 @@ public override string GetLogsDirectoryForGVFSComponent(string componentName) public override Dictionary GetPhysicalDiskInfo(string path, bool sizeStatsOnly) { return new Dictionary(); - } - - public override string GetUpgradeProtectedDataDirectory() - { - return this.GetSecureDataRootForGVFSComponent(ProductUpgraderInfo.UpgradeDirectoryName); - } - - public override string GetUpgradeLogDirectoryParentDirectory() - { - return this.GetUpgradeProtectedDataDirectory(); } public override string GetSystemInstallerLogPath() { return "MockPath"; } - - public override string GetUpgradeHighestAvailableVersionDirectory() - { - return this.GetUpgradeProtectedDataDirectory(); - } public override bool IsConsoleOutputRedirectedToFile() { @@ -191,13 +176,6 @@ public override FileBasedLock CreateFileBasedLock(PhysicalFileSystem fileSystem, { return new MockFileBasedLock(fileSystem, tracer, lockPath); } - - public override ProductUpgraderPlatformStrategy CreateProductUpgraderPlatformInteractions( - PhysicalFileSystem fileSystem, - ITracer tracer) - { - return new MockProductUpgraderPlatformStrategy(fileSystem, tracer); - } public override bool TryKillProcessTree(int processId, out int exitCode, out string error) { diff --git a/GVFS/GVFS.UnitTests/Mock/Common/MockProductUpgraderPlatformStrategy.cs b/GVFS/GVFS.UnitTests/Mock/Common/MockProductUpgraderPlatformStrategy.cs deleted file mode 100644 index c622a2b48f..0000000000 --- a/GVFS/GVFS.UnitTests/Mock/Common/MockProductUpgraderPlatformStrategy.cs +++ /dev/null @@ -1,32 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.Tracing; - -namespace GVFS.UnitTests.Mock.Common -{ - public class MockProductUpgraderPlatformStrategy : ProductUpgraderPlatformStrategy - { - public MockProductUpgraderPlatformStrategy(PhysicalFileSystem fileSystem, ITracer tracer) - : base(fileSystem, tracer) - { - } - - public override bool TryPrepareLogDirectory(out string error) - { - error = null; - return true; - } - - public override bool TryPrepareApplicationDirectory(out string error) - { - error = null; - return true; - } - - public override bool TryPrepareDownloadDirectory(out string error) - { - error = null; - return true; - } - } -} diff --git a/GVFS/GVFS.UnitTests/Mock/MockGitHubUpgrader.cs b/GVFS/GVFS.UnitTests/Mock/MockGitHubUpgrader.cs deleted file mode 100644 index 56d6520e0f..0000000000 --- a/GVFS/GVFS.UnitTests/Mock/MockGitHubUpgrader.cs +++ /dev/null @@ -1,261 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.Tracing; -using System; -using System.Collections.Generic; -using System.IO; - -namespace GVFS.UnitTests.Mock.Upgrader -{ - public class MockGitHubUpgrader : GitHubUpgrader - { - private string expectedGVFSAssetName; - private string expectedGitAssetName; - private ActionType failActionTypes; - - public MockGitHubUpgrader( - string currentVersion, - ITracer tracer, - PhysicalFileSystem fileSystem, - GitHubUpgraderConfig config) : base(currentVersion, tracer, fileSystem, config) - { - this.DownloadedFiles = new List(); - this.InstallerArgs = new Dictionary>(); - } - - [Flags] - public enum ActionType - { - Invalid = 0, - FetchReleaseInfo = 0x1, - CopyTools = 0x2, - GitDownload = 0x4, - GVFSDownload = 0x8, - GitInstall = 0x10, - GVFSInstall = 0x20, - GVFSCleanup = 0x40, - GitCleanup = 0x80, - GitAuthenticodeCheck = 0x100, - GVFSAuthenticodeCheck = 0x200, - CreateDownloadDirectory = 0x400, - } - - public List DownloadedFiles { get; private set; } - public Dictionary> InstallerArgs { get; private set; } - public bool InstallerExeLaunched { get; set; } - private Release FakeUpgradeRelease { get; set; } - - public void SetDryRun(bool dryRun) - { - this.dryRun = dryRun; - } - - public void SetFailOnAction(ActionType failureType) - { - this.failActionTypes |= failureType; - } - - public void SetSucceedOnAction(ActionType failureType) - { - this.failActionTypes &= ~failureType; - } - - public void ResetFailedAction() - { - this.failActionTypes = ActionType.Invalid; - } - - public void PretendNewReleaseAvailableAtRemote(string upgradeVersion, GitHubUpgraderConfig.RingType remoteRing) - { - string assetDownloadURLPrefix = "https://github.com/Microsoft/VFSForGit/releases/download/v" + upgradeVersion; - Release release = new Release(); - - release.Name = "GVFS " + upgradeVersion; - release.Tag = "v" + upgradeVersion; - release.PreRelease = remoteRing == GitHubUpgraderConfig.RingType.Fast; - release.Assets = new List(); - - Random random = new Random(); - Asset gvfsAsset = new Asset(); - gvfsAsset.Name = "VFSForGit." + upgradeVersion + GVFSPlatform.Instance.Constants.InstallerExtension; - - // This is not cross-checked anywhere, random value is good. - gvfsAsset.Size = random.Next(int.MaxValue / 10, int.MaxValue / 2); - gvfsAsset.DownloadURL = new Uri(assetDownloadURLPrefix + "/VFSForGit." + upgradeVersion + GVFSPlatform.Instance.Constants.InstallerExtension); - release.Assets.Add(gvfsAsset); - - Asset gitAsset = new Asset(); - gitAsset.Name = "Git-2.17.1.gvfs.2.1.4.g4385455-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension; - gitAsset.Size = random.Next(int.MaxValue / 10, int.MaxValue / 2); - gitAsset.DownloadURL = new Uri(assetDownloadURLPrefix + "/Git-2.17.1.gvfs.2.1.4.g4385455-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension); - release.Assets.Add(gitAsset); - - this.expectedGVFSAssetName = gvfsAsset.Name; - this.expectedGitAssetName = gitAsset.Name; - this.FakeUpgradeRelease = release; - } - - public override bool TrySetupUpgradeApplicationDirectory(out string upgradeApplicationPath, out string error) - { - if (this.failActionTypes.HasFlag(ActionType.CopyTools)) - { - upgradeApplicationPath = null; - error = "Unable to copy upgrader tools"; - return false; - } - - upgradeApplicationPath = @"mock:\ProgramData\GVFS\GVFS.Upgrade\Tools\GVFS.Upgrader.exe"; - error = null; - return true; - } - - protected override bool TryCreateAndConfigureDownloadDirectory(ITracer tracer, out string error) - { - if (this.failActionTypes.HasFlag(ActionType.CreateDownloadDirectory)) - { - error = "Error creating download directory"; - return false; - } - - error = null; - return true; - } - - protected override bool TryDownloadAsset(Asset asset, out string errorMessage) - { - bool validAsset = true; - if (this.expectedGVFSAssetName.Equals(asset.Name, GVFSPlatform.Instance.Constants.PathComparison)) - { - if (this.failActionTypes.HasFlag(ActionType.GVFSDownload)) - { - errorMessage = "Error downloading GVFS from GitHub"; - return false; - } - } - else if (this.expectedGitAssetName.Equals(asset.Name, GVFSPlatform.Instance.Constants.PathComparison)) - { - if (this.failActionTypes.HasFlag(ActionType.GitDownload)) - { - errorMessage = "Error downloading Git from GitHub"; - return false; - } - } - else - { - validAsset = false; - } - - if (validAsset) - { - string fakeDownloadDirectory = @"mock:\ProgramData\GVFS\GVFS.Upgrade\Downloads"; - asset.LocalPath = Path.Combine(fakeDownloadDirectory, asset.Name); - this.DownloadedFiles.Add(asset.LocalPath); - - errorMessage = null; - return true; - } - - errorMessage = "Cannot download unknown asset."; - return false; - } - - protected override bool TryDeleteDownloadedAsset(Asset asset, out Exception exception) - { - if (this.expectedGVFSAssetName.Equals(asset.Name, GVFSPlatform.Instance.Constants.PathComparison)) - { - if (this.failActionTypes.HasFlag(ActionType.GVFSCleanup)) - { - exception = new Exception("Error deleting downloaded GVFS installer."); - return false; - } - - exception = null; - return true; - } - else if (this.expectedGitAssetName.Equals(asset.Name, GVFSPlatform.Instance.Constants.PathComparison)) - { - if (this.failActionTypes.HasFlag(ActionType.GitCleanup)) - { - exception = new Exception("Error deleting downloaded Git installer."); - return false; - } - - exception = null; - return true; - } - else - { - exception = new Exception("Unknown asset."); - return false; - } - } - - protected override bool TryFetchReleases(out List releases, out string errorMessage) - { - if (this.failActionTypes.HasFlag(ActionType.FetchReleaseInfo)) - { - releases = null; - errorMessage = "Error fetching upgrade release info."; - return false; - } - - releases = new List { this.FakeUpgradeRelease }; - errorMessage = null; - - return true; - } - - protected override void RunInstaller(string path, string args, string certCN, string issuerCN, out int exitCode, out string error) - { - string fileName = Path.GetFileName(path); - Dictionary installationInfo = new Dictionary(); - installationInfo.Add("Installer", fileName); - installationInfo.Add("Args", args); - - exitCode = 0; - error = null; - - if (fileName.Equals(this.expectedGitAssetName, GVFSPlatform.Instance.Constants.PathComparison)) - { - this.InstallerArgs.Add("Git", installationInfo); - this.InstallerExeLaunched = true; - if (this.failActionTypes.HasFlag(ActionType.GitInstall)) - { - exitCode = -1; - error = "Git installation failed"; - } - - if (this.failActionTypes.HasFlag(ActionType.GitAuthenticodeCheck)) - { - exitCode = -1; - error = "The contents of file C:\\ProgramData\\GVFS\\GVFS.Upgrade\\Tools\\Git-2.17.1.gvfs.2.1.4.g4385455-64-bit might have been changed by an unauthorized user or process, because the hash of the file does not match the hash stored in the digital signature. The script cannot run on the specified system. For more information, run Get-Help about_Signing."; - } - - return; - } - - if (fileName.Equals(this.expectedGVFSAssetName, GVFSPlatform.Instance.Constants.PathComparison)) - { - this.InstallerArgs.Add("GVFS", installationInfo); - this.InstallerExeLaunched = true; - if (this.failActionTypes.HasFlag(ActionType.GVFSInstall)) - { - exitCode = -1; - error = "GVFS installation failed"; - } - - if (this.failActionTypes.HasFlag(ActionType.GVFSAuthenticodeCheck)) - { - exitCode = -1; - error = "The contents of file C:\\ProgramData\\GVFS\\GVFS.Upgrade\\Tools\\SetupGVFS.1.0.18297.1.exe might have been changed by an unauthorized user or process, because the hash of the file does not match the hash stored in the digital signature. The script cannot run on the specified system. For more information, run Get-Help about_Signing."; - } - - return; - } - - exitCode = -1; - error = "Cannot launch unknown installer"; - return; - } - } -} diff --git a/GVFS/GVFS.UnitTests/Mock/MockInstallerPreRunChecker.cs b/GVFS/GVFS.UnitTests/Mock/MockInstallerPreRunChecker.cs deleted file mode 100644 index 348038f01f..0000000000 --- a/GVFS/GVFS.UnitTests/Mock/MockInstallerPreRunChecker.cs +++ /dev/null @@ -1,114 +0,0 @@ -using GVFS.Common.Tracing; -using GVFS.Upgrader; -using System; -using System.Collections.Generic; - -namespace GVFS.UnitTests.Mock.Upgrader -{ - public class MockInstallerPrerunChecker : InstallerPreRunChecker - { - public const string GitUpgradeCheckError = "Unable to upgrade Git"; - - private FailOnCheckType failOnCheck; - - public MockInstallerPrerunChecker(ITracer tracer) : base(tracer, string.Empty) - { - } - - [Flags] - public enum FailOnCheckType - { - Invalid = 0, - ProjFSEnabled = 0x1, - IsElevated = 0x2, - BlockingProcessesRunning = 0x4, - UnattendedMode = 0x8, - UnMountRepos = 0x10, - RemountRepos = 0x20, - IsServiceInstalledAndNotRunning = 0x40, - } - - public void SetReturnFalseOnCheck(FailOnCheckType prerunCheck) - { - this.failOnCheck |= prerunCheck; - } - - public void SetReturnTrueOnCheck(FailOnCheckType prerunCheck) - { - this.failOnCheck &= ~prerunCheck; - } - - public void Reset() - { - this.failOnCheck = FailOnCheckType.Invalid; - - this.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.UnattendedMode); - this.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.BlockingProcessesRunning); - this.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.IsServiceInstalledAndNotRunning); - } - - public void SetCommandToRerun(string command) - { - this.CommandToRerun = command; - } - - protected override bool IsServiceInstalledAndNotRunning() - { - return this.FakedResultOfCheck(FailOnCheckType.IsServiceInstalledAndNotRunning); - } - - protected override bool IsElevated() - { - return this.FakedResultOfCheck(FailOnCheckType.IsElevated); - } - - protected override bool IsGVFSUpgradeSupported() - { - return this.FakedResultOfCheck(FailOnCheckType.ProjFSEnabled); - } - - protected override bool IsUnattended() - { - return this.FakedResultOfCheck(FailOnCheckType.UnattendedMode); - } - - protected override bool IsBlockingProcessRunning(out HashSet processes) - { - processes = new HashSet(); - - bool isRunning = this.FakedResultOfCheck(FailOnCheckType.BlockingProcessesRunning); - if (isRunning) - { - processes.Add("GVFS.Mount"); - processes.Add("git"); - } - - return isRunning; - } - - protected override bool TryRunGVFSWithArgs(string args, out string error) - { - if (string.CompareOrdinal(args, "service --unmount-all") == 0) - { - bool result = this.FakedResultOfCheck(FailOnCheckType.UnMountRepos); - error = result == false ? "Unmount of some of the repositories failed." : null; - return result; - } - - if (string.CompareOrdinal(args, "service --mount-all") == 0) - { - bool result = this.FakedResultOfCheck(FailOnCheckType.RemountRepos); - error = result == false ? "Auto remount failed." : null; - return result; - } - - error = "Unknown GVFS command"; - return false; - } - - private bool FakedResultOfCheck(FailOnCheckType checkType) - { - return !this.failOnCheck.HasFlag(checkType); - } - } -} diff --git a/GVFS/GVFS.UnitTests/Upgrader/ProductUpgraderTests.cs b/GVFS/GVFS.UnitTests/Upgrader/ProductUpgraderTests.cs deleted file mode 100644 index 3b9989eea6..0000000000 --- a/GVFS/GVFS.UnitTests/Upgrader/ProductUpgraderTests.cs +++ /dev/null @@ -1,130 +0,0 @@ -using GVFS.Common; -using GVFS.Tests.Should; -using NUnit.Framework; -using System; - -namespace GVFS.UnitTests.Upgrader -{ - [TestFixture] - public class ProductUpgraderTests : UpgradeTests - { - [SetUp] - public override void Setup() - { - base.Setup(); - } - - [TestCase] - public void UpgradeAvailableOnFastWhileOnLocalNoneRing() - { - this.SimulateUpgradeAvailable( - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Fast, - remoteVersion: UpgradeTests.NewerThanLocalVersion, - localRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.None, - expectedReturn: true, - expectedUpgradeVersion: null); - } - - [TestCase] - public void UpgradeAvailableOnSlowWhileOnLocalNoneRing() - { - this.SimulateUpgradeAvailable( - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow, - remoteVersion: UpgradeTests.NewerThanLocalVersion, - localRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.None, - expectedReturn: true, - expectedUpgradeVersion: null); - } - - [TestCase] - public void UpgradeAvailableOnFastWhileOnLocalSlowRing() - { - this.SimulateUpgradeAvailable( - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Fast, - remoteVersion: UpgradeTests.NewerThanLocalVersion, - localRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow, - expectedReturn: true, - expectedUpgradeVersion: null); - } - - [TestCase] - public void UpgradeAvailableOnSlowWhileOnLocalSlowRing() - { - this.SimulateUpgradeAvailable( - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow, - remoteVersion: UpgradeTests.NewerThanLocalVersion, - localRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow, - expectedReturn: true, - expectedUpgradeVersion: UpgradeTests.NewerThanLocalVersion); - } - - [TestCase] - public void UpgradeAvailableOnFastWhileOnLocalFastRing() - { - this.SimulateUpgradeAvailable( - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Fast, - remoteVersion: UpgradeTests.NewerThanLocalVersion, - localRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Fast, - expectedReturn: true, - expectedUpgradeVersion: UpgradeTests.NewerThanLocalVersion); - } - - [TestCase] - public void UpgradeAvailableOnSlowWhileOnLocalFastRing() - { - this.SimulateUpgradeAvailable( - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow, - remoteVersion: UpgradeTests.NewerThanLocalVersion, - localRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Fast, - expectedReturn: true, - expectedUpgradeVersion:UpgradeTests.NewerThanLocalVersion); - } - - public override void NoneLocalRing() - { - throw new NotSupportedException(); - } - - public override void InvalidUpgradeRing() - { - throw new NotSupportedException(); - } - - public override void FetchReleaseInfo() - { - throw new NotSupportedException(); - } - - protected override ReturnCode RunUpgrade() - { - throw new NotSupportedException(); - } - - private void SimulateUpgradeAvailable( - GitHubUpgrader.GitHubUpgraderConfig.RingType remoteRing, - string remoteVersion, - GitHubUpgrader.GitHubUpgraderConfig.RingType localRing, - bool expectedReturn, - string expectedUpgradeVersion) - { - this.SetUpgradeRing(localRing.ToString()); - this.Upgrader.PretendNewReleaseAvailableAtRemote( - remoteVersion, - remoteRing); - - Version newVersion; - string message; - this.Upgrader.TryQueryNewestVersion(out newVersion, out message).ShouldEqual(expectedReturn); - - if (string.IsNullOrEmpty(expectedUpgradeVersion)) - { - newVersion.ShouldBeNull(); - } - else - { - newVersion.ShouldNotBeNull(); - newVersion.ShouldEqual(new Version(expectedUpgradeVersion)); - } - } - } -} \ No newline at end of file diff --git a/GVFS/GVFS.UnitTests/Upgrader/UpgradeOrchestratorTests.cs b/GVFS/GVFS.UnitTests/Upgrader/UpgradeOrchestratorTests.cs deleted file mode 100644 index 7491bf78da..0000000000 --- a/GVFS/GVFS.UnitTests/Upgrader/UpgradeOrchestratorTests.cs +++ /dev/null @@ -1,250 +0,0 @@ -using GVFS.Common; -using GVFS.Common.Git; -using GVFS.Common.Tracing; -using GVFS.Tests.Should; -using GVFS.UnitTests.Mock.Common; -using GVFS.UnitTests.Mock.FileSystem; -using GVFS.UnitTests.Mock.Upgrader; -using GVFS.Upgrader; -using Moq; -using NUnit.Framework; -using System; -using System.Collections.Generic; - -namespace GVFS.UnitTests.Upgrader -{ - [TestFixture] - public class UpgradeOrchestratorTests - { - private const string GVFSVersion = "1.1.18115.1"; - - private delegate void TryGetNewerVersionCallback(out System.Version version, out string message); - private delegate void UpgradeAllowedCallback(out string message); - private delegate void TryRunPreUpgradeChecksCallback(out string delegateMessage); - private delegate void TryDownloadNewestVersionCallback(out string message); - private delegate void TryCreateAndConfigureDownloadDirectoryCallback(ITracer tracer, out string message); - private delegate void TryRunInstallerCallback(InstallActionWrapper installActionWrapper, out string error); - - private MockTracer Tracer { get; set; } - private MockFileSystem FileSystem { get; set; } - private MockTextWriter Output { get; set; } - private MockInstallerPrerunChecker PreRunChecker { get; set; } - private Mock MoqLocalConfig { get; set; } - private Mock MoqUpgrader { get; set; } - - private UpgradeOrchestrator orchestrator { get; set; } - - [SetUp] - public void Setup() - { - this.Tracer = new MockTracer(); - this.FileSystem = new MockFileSystem(new MockDirectory(@"mock:\GVFS.Upgrades\Download", null, null)); - this.Output = new MockTextWriter(); - this.PreRunChecker = new MockInstallerPrerunChecker(this.Tracer); - this.PreRunChecker.Reset(); - this.MoqUpgrader = this.DefaultUpgrader(); - this.orchestrator = new WindowsUpgradeOrchestrator( - this.MoqUpgrader.Object, - this.Tracer, - this.FileSystem, - this.PreRunChecker, - input: null, - output: this.Output); - - this.SetUpgradeAvailable(new Version(GVFSVersion), error: null); - } - - [TestCase] - public void ExecuteSucceedsWhenUpgradeAvailable() - { - this.orchestrator.Execute(); - - this.VerifyOrchestratorInvokes( - upgradeAllowed: true, - queryNewestVersion: true, - downloadNewestVersion: true, - installNewestVersion: true, - cleanup: true); - - this.orchestrator.ExitCode.ShouldEqual(ReturnCode.Success); - } - - [TestCase] - public void ExecuteSucceedsWhenOnLatestVersion() - { - this.SetUpgradeAvailable(newVersion: null, error: null); - - this.orchestrator.Execute(); - - this.VerifyOrchestratorInvokes( - upgradeAllowed: true, - queryNewestVersion: true, - downloadNewestVersion: false, - installNewestVersion: false, - cleanup: true); - - this.orchestrator.ExitCode.ShouldEqual(ReturnCode.Success); - } - - [TestCase] - public void ExecuteFailsWhenGetNewVersionFails() - { - string errorMessage = "Authentication error."; - - this.SetUpgradeAvailable(newVersion: null, error: errorMessage); - - this.orchestrator.Execute(); - - this.VerifyOrchestratorInvokes( - upgradeAllowed: true, - queryNewestVersion: true, - downloadNewestVersion: false, - installNewestVersion: false, - cleanup: true); - - this.VerifyOutput("ERROR: Authentication error."); - - this.orchestrator.ExitCode.ShouldEqual(ReturnCode.GenericError); - } - - [TestCase] - public void ExecuteFailsWhenPrecheckFails() - { - this.PreRunChecker.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.IsElevated); - - this.orchestrator.Execute(); - - this.VerifyOrchestratorInvokes( - upgradeAllowed: true, - queryNewestVersion: false, - downloadNewestVersion: false, - installNewestVersion: false, - cleanup: true); - - this.orchestrator.ExitCode.ShouldEqual(ReturnCode.GenericError); - } - - [TestCase] - public void ExecuteFailsWhenDownloadFails() - { - this.MoqUpgrader.Setup(upgrader => upgrader.TryDownloadNewestVersion(out It.Ref.IsAny)) - .Callback(new TryDownloadNewestVersionCallback( - (out string delegateMessage) => - { - delegateMessage = "Download error."; - })) - .Returns(false); - - this.orchestrator.Execute(); - - this.VerifyOrchestratorInvokes( - upgradeAllowed: true, - queryNewestVersion: true, - downloadNewestVersion: true, - installNewestVersion: false, - cleanup: true); - - this.VerifyOutput("ERROR: Download error."); - - this.orchestrator.ExitCode.ShouldEqual(ReturnCode.GenericError); - } - - [TestCase] - public void ExecuteFailsWhenRunInstallerFails() - { - this.MoqUpgrader.Setup(upgrader => upgrader.TryRunInstaller(It.IsAny(), out It.Ref.IsAny)) - .Callback(new TryRunInstallerCallback((InstallActionWrapper installActionWrapper, out string delegateMessage) => - { - delegateMessage = "Installer error."; - })) - .Returns(false); - - this.orchestrator.Execute(); - - this.VerifyOrchestratorInvokes( - upgradeAllowed: true, - queryNewestVersion: true, - downloadNewestVersion: true, - installNewestVersion: true, - cleanup: true); - - this.VerifyOutput("ERROR: Installer error."); - - this.orchestrator.ExitCode.ShouldEqual(ReturnCode.GenericError); - } - - public Mock DefaultUpgrader() - { - Mock mockUpgrader = new Mock(); - - mockUpgrader.Setup(upgrader => upgrader.UpgradeAllowed(out It.Ref.IsAny)) - .Callback(new UpgradeAllowedCallback((out string delegateMessage) => - { - delegateMessage = string.Empty; - })) - .Returns(true); - - string message = string.Empty; - mockUpgrader.Setup(upgrader => upgrader.TryDownloadNewestVersion(out It.Ref.IsAny)).Returns(true); - mockUpgrader.Setup(upgrader => upgrader.TryRunInstaller(It.IsAny(), out message)).Returns(true); - mockUpgrader.Setup(upgrader => upgrader.TryCleanup(out It.Ref.IsAny)).Returns(true); - - return mockUpgrader; - } - - public void SetUpgradeAvailable(Version newVersion, string error) - { - bool upgradeResult = string.IsNullOrEmpty(error); - - this.MoqUpgrader.Setup(upgrader => upgrader.TryQueryNewestVersion(out It.Ref.IsAny, out It.Ref.IsAny)) - .Callback(new TryGetNewerVersionCallback((out System.Version delegateVersion, out string delegateMessage) => - { - delegateVersion = newVersion; - delegateMessage = error; - })) - .Returns(upgradeResult); - } - - public void VerifyOrchestratorInvokes( - bool upgradeAllowed, - bool queryNewestVersion, - bool downloadNewestVersion, - bool installNewestVersion, - bool cleanup) - { - this.MoqUpgrader.Verify( - upgrader => upgrader.UpgradeAllowed( - out It.Ref.IsAny), - upgradeAllowed ? Times.Once() : Times.Never()); - - this.MoqUpgrader.Verify( - upgrader => upgrader.TryQueryNewestVersion( - out It.Ref.IsAny, - out It.Ref.IsAny), - queryNewestVersion ? Times.Once() : Times.Never()); - - this.MoqUpgrader.Verify( - upgrader => upgrader.TryDownloadNewestVersion( - out It.Ref.IsAny), - downloadNewestVersion ? Times.Once() : Times.Never()); - - this.MoqUpgrader.Verify( - upgrader => upgrader.TryRunInstaller( - It.IsAny(), - out It.Ref.IsAny), - installNewestVersion ? Times.Once() : Times.Never()); - - this.MoqUpgrader.Verify( - upgrader => upgrader.TryCleanup( - out It.Ref.IsAny), - cleanup ? Times.Once() : Times.Never()); - } - - public void VerifyOutput(string expectedMessage) - { - this.Output.AllLines.ShouldContain( - new List() { expectedMessage }, - (line, expectedLine) => { return line.Contains(expectedLine); }); - } - } -} diff --git a/GVFS/GVFS.UnitTests/Upgrader/UpgradeOrchestratorWithGitHubUpgraderTests.cs b/GVFS/GVFS.UnitTests/Upgrader/UpgradeOrchestratorWithGitHubUpgraderTests.cs deleted file mode 100644 index fc455b8026..0000000000 --- a/GVFS/GVFS.UnitTests/Upgrader/UpgradeOrchestratorWithGitHubUpgraderTests.cs +++ /dev/null @@ -1,324 +0,0 @@ -using GVFS.Common; -using GVFS.Tests.Should; -using GVFS.UnitTests.Mock.Upgrader; -using GVFS.Upgrader; -using NUnit.Framework; -using System.Collections.Generic; - -namespace GVFS.UnitTests.Upgrader -{ - [TestFixture] - public class UpgradeOrchestratorWithGitHubUpgraderTests : UpgradeTests - { - private UpgradeOrchestrator orchestrator; - - [SetUp] - public override void Setup() - { - base.Setup(); - - this.orchestrator = new WindowsUpgradeOrchestrator( - this.Upgrader, - this.Tracer, - this.FileSystem, - this.PrerunChecker, - input: null, - output: this.Output); - this.PrerunChecker.SetCommandToRerun("`gvfs upgrade --confirm`"); - } - - [TestCase] - public void UpgradeNoError() - { - this.RunUpgrade().ShouldEqual(ReturnCode.Success); - this.Tracer.RelatedErrorEvents.ShouldBeEmpty(); - } - - [TestCase] - public void AutoUnmountError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.PrerunChecker.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.UnMountRepos); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "Unmount of some of the repositories failed." - }, - expectedErrors: new List - { - "Unmount of some of the repositories failed." - }); - } - - [TestCase] - public void AbortOnBlockingProcess() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.PrerunChecker.SetReturnTrueOnCheck(MockInstallerPrerunChecker.FailOnCheckType.BlockingProcessesRunning); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "ERROR: Blocking processes are running.", - $"Run `gvfs upgrade --confirm` again after quitting these processes - GVFS.Mount, git" - }, - expectedErrors: null, - expectedWarnings: new List - { - $"Run `gvfs upgrade --confirm` again after quitting these processes - GVFS.Mount, git" - }); - } - - [TestCase] - public void DownloadDirectoryCreationError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.CreateDownloadDirectory); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "Error creating download directory" - }, - expectedErrors: new List - { - "Error creating download directory" - }); - } - - [TestCase] - public void GVFSDownloadError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.GVFSDownload); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "Error downloading GVFS from GitHub" - }, - expectedErrors: new List - { - "Error downloading GVFS from GitHub" - }); - } - - [TestCase] - public void GitDownloadError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.GitDownload); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "Error downloading Git from GitHub" - }, - expectedErrors: new List - { - "Error downloading Git from GitHub" - }); - } - - [TestCase] - public void GitInstallationArgs() - { - this.RunUpgrade().ShouldEqual(ReturnCode.Success); - - Dictionary gitInstallerInfo; - this.Upgrader.InstallerArgs.ShouldBeNonEmpty(); - this.Upgrader.InstallerArgs.TryGetValue("Git", out gitInstallerInfo).ShouldBeTrue(); - - string args; - gitInstallerInfo.TryGetValue("Args", out args).ShouldBeTrue(); - args.ShouldContain(new string[] { "/VERYSILENT", "/CLOSEAPPLICATIONS", "/SUPPRESSMSGBOXES", "/NORESTART", "/Log" }); - } - - [TestCase] - public void GitInstallError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.GitInstall); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "Git installation failed" - }, - expectedErrors: new List - { - "Git installation failed" - }); - } - - [TestCase] - public void GitInstallerAuthenticodeError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.GitAuthenticodeCheck); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "hash of the file does not match the hash stored in the digital signature" - }, - expectedErrors: new List - { - "hash of the file does not match the hash stored in the digital signature" - }); - } - - [TestCase] - public void GVFSInstallationArgs() - { - this.RunUpgrade().ShouldEqual(ReturnCode.Success); - - Dictionary gitInstallerInfo; - this.Upgrader.InstallerArgs.ShouldBeNonEmpty(); - this.Upgrader.InstallerArgs.TryGetValue("GVFS", out gitInstallerInfo).ShouldBeTrue(); - - string args; - gitInstallerInfo.TryGetValue("Args", out args).ShouldBeTrue(); - args.ShouldContain(new string[] { "/VERYSILENT", "/CLOSEAPPLICATIONS", "/SUPPRESSMSGBOXES", "/NORESTART", "/Log", "/REMOUNTREPOS=false" }); - } - - [TestCase] - public void GVFSInstallError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.GVFSInstall); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "GVFS installation failed" - }, - expectedErrors: new List - { - "GVFS installation failed" - }); - } - - [TestCase] - public void GVFSInstallerAuthenticodeError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.GVFSAuthenticodeCheck); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "hash of the file does not match the hash stored in the digital signature" - }, - expectedErrors: new List - { - "hash of the file does not match the hash stored in the digital signature" - }); - } - - [TestCase] - public void GVFSCleanupError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.GVFSCleanup); - }, - expectedReturn: ReturnCode.Success, - expectedOutput: new List - { - }, - expectedErrors: new List - { - "Error deleting downloaded GVFS installer." - }); - } - - [TestCase] - public void GitCleanupError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.GitCleanup); - }, - expectedReturn: ReturnCode.Success, - expectedOutput: new List - { - }, - expectedErrors: new List - { - "Error deleting downloaded Git installer." - }); - } - - [TestCase] - public void RemountReposError() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.PrerunChecker.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.RemountRepos); - }, - expectedReturn: ReturnCode.Success, - expectedOutput: new List - { - "Auto remount failed." - }, - expectedErrors: new List - { - "Auto remount failed." - }); - } - - [TestCase] - public void DryRunDoesNotRunInstallerExes() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.Upgrader.SetDryRun(true); - this.Upgrader.InstallerExeLaunched = false; - this.SetUpgradeRing("Slow"); - this.Upgrader.PretendNewReleaseAvailableAtRemote( - upgradeVersion: NewerThanLocalVersion, - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow); - }, - expectedReturn: ReturnCode.Success, - expectedOutput: new List - { - "Installing Git", - "Installing GVFS", - "Upgrade completed successfully." - }, - expectedErrors: null); - - this.Upgrader.InstallerExeLaunched.ShouldBeFalse(); - } - - protected override ReturnCode RunUpgrade() - { - this.orchestrator.Execute(); - return this.orchestrator.ExitCode; - } - } -} diff --git a/GVFS/GVFS.UnitTests/Upgrader/UpgradeTests.cs b/GVFS/GVFS.UnitTests/Upgrader/UpgradeTests.cs deleted file mode 100644 index 7ea331d2a0..0000000000 --- a/GVFS/GVFS.UnitTests/Upgrader/UpgradeTests.cs +++ /dev/null @@ -1,191 +0,0 @@ -using GVFS.Common; -using GVFS.Tests.Should; -using GVFS.UnitTests.Category; -using GVFS.UnitTests.Mock.Common; -using GVFS.UnitTests.Mock.FileSystem; -using GVFS.UnitTests.Mock.Upgrader; -using NUnit.Framework; -using System; -using System.Collections.Generic; - -namespace GVFS.UnitTests.Upgrader -{ - public abstract class UpgradeTests - { - protected const string OlderThanLocalVersion = "1.0.17000.1"; - protected const string LocalGVFSVersion = "1.0.18115.1"; - protected const string NewerThanLocalVersion = "1.1.18115.1"; - - protected MockTracer Tracer { get; private set; } - protected MockFileSystem FileSystem { get; private set; } - protected MockTextWriter Output { get; private set; } - protected MockInstallerPrerunChecker PrerunChecker { get; private set; } - protected MockGitHubUpgrader Upgrader { get; private set; } - protected MockLocalGVFSConfig LocalConfig { get; private set; } - - public virtual void Setup() - { - this.Tracer = new MockTracer(); - this.FileSystem = new MockFileSystem(new MockDirectory(@"mock:\GVFS.Upgrades\Download", null, null)); - this.Output = new MockTextWriter(); - this.PrerunChecker = new MockInstallerPrerunChecker(this.Tracer); - this.LocalConfig = new MockLocalGVFSConfig(); - - this.Upgrader = new MockGitHubUpgrader( - LocalGVFSVersion, - this.Tracer, - this.FileSystem, - new GitHubUpgrader.GitHubUpgraderConfig(this.Tracer, this.LocalConfig)); - - this.PrerunChecker.Reset(); - this.Upgrader.PretendNewReleaseAvailableAtRemote( - upgradeVersion: NewerThanLocalVersion, - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow); - this.SetUpgradeRing("Slow"); - } - - [TestCase] - public virtual void NoneLocalRing() - { - string message = "Upgrade ring set to \"None\". No upgrade check was performed."; - this.ConfigureRunAndVerify( - configure: () => - { - this.SetUpgradeRing("None"); - }, - expectedReturn: ReturnCode.Success, - expectedOutput: new List - { - message - }, - expectedErrors: new List - { - }); - } - - [TestCase] - public virtual void InvalidUpgradeRing() - { - this.SetUpgradeRing("Invalid"); - - string expectedError = "Invalid upgrade ring `Invalid` specified in gvfs config."; - string errorString; - GitHubUpgrader.Create( - this.Tracer, - this.FileSystem, - dryRun: false, - noVerify: false, - localConfig: this.LocalConfig, - error: out errorString).ShouldBeNull(); - - errorString.ShouldContain(expectedError); - } - - [TestCase] - [Category(CategoryConstants.ExceptionExpected)] - public virtual void FetchReleaseInfo() - { - string errorString = "Error fetching upgrade release info."; - this.ConfigureRunAndVerify( - configure: () => - { - this.SetUpgradeRing("Fast"); - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.FetchReleaseInfo); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - errorString - }, - expectedErrors: new List - { - errorString - }); - } - - protected abstract ReturnCode RunUpgrade(); - - protected void ConfigureRunAndVerify( - Action configure, - ReturnCode expectedReturn, - List expectedOutput, - List expectedErrors, - List expectedWarnings = null) - { - configure(); - - this.RunUpgrade().ShouldEqual(expectedReturn); - - if (expectedOutput != null) - { - this.Output.AllLines.ShouldContain( - expectedOutput, - (line, expectedLine) => { return line.Contains(expectedLine); }); - } - - if (expectedErrors != null) - { - this.Tracer.RelatedErrorEvents.ShouldContain( - expectedErrors, - (error, expectedError) => { return error.Contains(expectedError); }); - } - - if (expectedWarnings != null) - { - this.Tracer.RelatedWarningEvents.ShouldContain( - expectedWarnings, - (warning, expectedWarning) => { return warning.Contains(expectedWarning); }); - } - } - - protected void SetUpgradeRing(string ringName) - { - GitHubUpgrader.GitHubUpgraderConfig.RingType ring; - if (!Enum.TryParse(ringName, ignoreCase: true, result: out ring)) - { - ring = GitHubUpgrader.GitHubUpgraderConfig.RingType.Invalid; - } - - string error; - if (ring == GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow || - ring == GitHubUpgrader.GitHubUpgraderConfig.RingType.Fast) - { - this.LocalConfig.TrySetConfig("upgrade.ring", ringName, out error); - this.VerifyConfig(ring, isUpgradeAllowed: true, isConfigError: false); - return; - } - - if (ring == GitHubUpgrader.GitHubUpgraderConfig.RingType.None) - { - this.LocalConfig.TrySetConfig("upgrade.ring", ringName, out error); - this.VerifyConfig(ring, isUpgradeAllowed: false, isConfigError: false); - return; - } - - if (ring == GitHubUpgrader.GitHubUpgraderConfig.RingType.Invalid) - { - this.LocalConfig.TrySetConfig("upgrade.ring", ringName, out error); - this.VerifyConfig(ring, isUpgradeAllowed: false, isConfigError: true); - return; - } - } - - protected void VerifyConfig( - GVFS.Common.GitHubUpgrader.GitHubUpgraderConfig.RingType ring, - bool isUpgradeAllowed, - bool isConfigError) - { - string error; - this.Upgrader.Config.TryLoad(out error).ShouldBeTrue(); - - Assert.AreEqual(ring, this.Upgrader.Config.UpgradeRing); - error.ShouldBeNull(); - - bool upgradeAllowed = this.Upgrader.UpgradeAllowed(out _); - bool configError = this.Upgrader.Config.ConfigError(); - - upgradeAllowed.ShouldEqual(isUpgradeAllowed); - configError.ShouldEqual(isConfigError); - } - } -} diff --git a/GVFS/GVFS.UnitTests/Windows/Upgrader/UpgradeVerbTests.cs b/GVFS/GVFS.UnitTests/Windows/Upgrader/UpgradeVerbTests.cs deleted file mode 100644 index 48cde9233c..0000000000 --- a/GVFS/GVFS.UnitTests/Windows/Upgrader/UpgradeVerbTests.cs +++ /dev/null @@ -1,256 +0,0 @@ -using GVFS.CommandLine; -using GVFS.Common; -using GVFS.Tests.Should; -using GVFS.UnitTests.Category; -using GVFS.UnitTests.Mock.Upgrader; -using GVFS.UnitTests.Upgrader; -using NUnit.Framework; -using System.Collections.Generic; - -namespace GVFS.UnitTests.Windows.Upgrader -{ - [TestFixture] - public class UpgradeVerbTests : UpgradeTests - { - private MockProcessLauncher processLauncher; - private UpgradeVerb upgradeVerb; - - [SetUp] - public override void Setup() - { - base.Setup(); - - this.processLauncher = new MockProcessLauncher(exitCode: 0, hasExited: true, startResult: true); - this.upgradeVerb = new UpgradeVerb( - this.Upgrader, - this.Tracer, - this.FileSystem, - this.PrerunChecker, - this.processLauncher, - this.Output); - this.upgradeVerb.Confirmed = false; - this.PrerunChecker.SetCommandToRerun("`gvfs upgrade`"); - } - - [TestCase] - public void UpgradeAvailabilityReporting() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.SetUpgradeRing("Slow"); - this.Upgrader.PretendNewReleaseAvailableAtRemote( - upgradeVersion: NewerThanLocalVersion, - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow); - }, - expectedReturn: ReturnCode.Success, - expectedOutput: new List - { - "New GVFS version " + NewerThanLocalVersion + " available in ring Slow", - "MockUpgradeInstallAdvice" - }, - expectedErrors: null); - } - - [TestCase] - public void DowngradePrevention() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.SetUpgradeRing("Slow"); - this.Upgrader.PretendNewReleaseAvailableAtRemote( - upgradeVersion: OlderThanLocalVersion, - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow); - }, - expectedReturn: ReturnCode.Success, - expectedOutput: new List - { - "Checking for GVFS upgrades...Succeeded", - "Great news, you're all caught up on upgrades in the Slow ring!" - }, - expectedErrors: null); - } - - [TestCase] - public void LaunchInstaller() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.SetUpgradeRing("Slow"); - this.upgradeVerb.Confirmed = true; - this.PrerunChecker.SetCommandToRerun("`gvfs upgrade --confirm`"); - }, - expectedReturn: ReturnCode.Success, - expectedOutput: new List - { - "New GVFS version " + NewerThanLocalVersion + " available in ring Slow", - "Launching upgrade tool..." - }, - expectedErrors:null); - - this.processLauncher.IsLaunched.ShouldBeTrue(); - } - - [TestCase] - [Category(CategoryConstants.ExceptionExpected)] - public override void NoneLocalRing() - { - base.NoneLocalRing(); - } - - [TestCase] - [Category(CategoryConstants.ExceptionExpected)] - public override void InvalidUpgradeRing() - { - base.InvalidUpgradeRing(); - } - - [TestCase] - [Category(CategoryConstants.ExceptionExpected)] - public void CopyTools() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.SetUpgradeRing("Slow"); - this.Upgrader.SetFailOnAction(MockGitHubUpgrader.ActionType.CopyTools); - this.upgradeVerb.Confirmed = true; - this.PrerunChecker.SetCommandToRerun("`gvfs upgrade --confirm`"); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "Could not launch upgrade tool. Unable to copy upgrader tools" - }, - expectedErrors: new List - { - "Could not launch upgrade tool. Unable to copy upgrader tools" - }); - } - - [TestCase] - public void ProjFSPreCheck() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.upgradeVerb.Confirmed = true; - this.PrerunChecker.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.ProjFSEnabled); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "ERROR: `gvfs upgrade` is only supported after the \"Windows Projected File System\" optional feature has been enabled by a manual installation of VFS for Git, and only on versions of Windows that support this feature.", - "Check your team's documentation for how to upgrade." - }, - expectedErrors: null, - expectedWarnings: new List - { - "`gvfs upgrade` is only supported after the \"Windows Projected File System\" optional feature has been enabled by a manual installation of VFS for Git, and only on versions of Windows that support this feature." - }); - } - - [TestCase] - public void IsGVFSServiceRunningPreCheck() - { - this.PrerunChecker.SetCommandToRerun("`gvfs upgrade --confirm`"); - this.ConfigureRunAndVerify( - configure: () => - { - this.upgradeVerb.Confirmed = true; - this.PrerunChecker.SetReturnTrueOnCheck(MockInstallerPrerunChecker.FailOnCheckType.IsServiceInstalledAndNotRunning); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "GVFS Service is not running.", - "To install, run MockStartServiceCommand and run MockUpgradeConfirmCommand." - }, - expectedErrors: null, - expectedWarnings: new List - { - "GVFS Service is not running." - }); - } - - [TestCase] - public void ElevatedRunPreCheck() - { - this.PrerunChecker.SetCommandToRerun("`gvfs upgrade --confirm`"); - this.ConfigureRunAndVerify( - configure: () => - { - this.upgradeVerb.Confirmed = true; - this.PrerunChecker.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.IsElevated); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "The installer needs to be run with elevated permissions.", - "MockRunUpdateMessage" - }, - expectedErrors: null, - expectedWarnings: new List - { - "The installer needs to be run with elevated permissions." - }); - } - - [TestCase] - public void UnAttendedModePreCheck() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.upgradeVerb.Confirmed = true; - this.PrerunChecker.SetReturnTrueOnCheck(MockInstallerPrerunChecker.FailOnCheckType.UnattendedMode); - }, - expectedReturn: ReturnCode.GenericError, - expectedOutput: new List - { - "`gvfs upgrade` is not supported in unattended mode" - }, - expectedErrors: null, - expectedWarnings: new List - { - "`gvfs upgrade` is not supported in unattended mode" - }); - } - - [TestCase] - public void DryRunLaunchesUpgradeTool() - { - this.ConfigureRunAndVerify( - configure: () => - { - this.upgradeVerb.DryRun = true; - this.SetUpgradeRing("Slow"); - this.Upgrader.PretendNewReleaseAvailableAtRemote( - upgradeVersion: NewerThanLocalVersion, - remoteRing: GitHubUpgrader.GitHubUpgraderConfig.RingType.Slow); - }, - expectedReturn: ReturnCode.Success, - expectedOutput: new List - { - "Installer launched in a new window." - }, - expectedErrors: null); - } - - protected override ReturnCode RunUpgrade() - { - try - { - this.upgradeVerb.Execute(); - } - catch (GVFSVerb.VerbAbortedException) - { - // ignore. exceptions are expected while simulating some failures. - } - - return this.upgradeVerb.ReturnCode; - } - } -} \ No newline at end of file diff --git a/GVFS/GVFS.UnitTests/Windows/Upgrader/WindowsNuGetUpgraderTests.cs b/GVFS/GVFS.UnitTests/Windows/Upgrader/WindowsNuGetUpgraderTests.cs deleted file mode 100644 index 59920dadbc..0000000000 --- a/GVFS/GVFS.UnitTests/Windows/Upgrader/WindowsNuGetUpgraderTests.cs +++ /dev/null @@ -1,60 +0,0 @@ -using GVFS.Common; -using GVFS.Platform.Windows; -using GVFS.Tests.Should; -using GVFS.UnitTests.Common.NuGetUpgrade; -using Moq; -using NuGet.Packaging.Core; -using NuGet.Protocol.Core.Types; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace GVFS.UnitTests.Windows.Common.Upgrader -{ - [TestFixture] - public class WindowsNuGetUpgraderTests : NuGetUpgraderTests - { - public override ProductUpgraderPlatformStrategy CreateProductUpgraderPlatformStrategy() - { - return new WindowsProductUpgraderPlatformStrategy(this.mockFileSystem, this.tracer); - } - - [TestCase] - public void TrySetupUpgradeApplicationDirectoryFailsIfCreateToolsDirectoryFails() - { - this.mockFileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed = false; - this.upgrader.TrySetupUpgradeApplicationDirectory(out string _, out string _).ShouldBeFalse(); - this.mockFileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed = true; - } - - [TestCase] - public void CanDownloadNewestVersionFailsIfDownloadDirectoryCreationFails() - { - Version actualNewestVersion; - string message; - List availablePackages = new List() - { - this.GeneratePackageSeachMetadata(new Version(CurrentVersion)), - this.GeneratePackageSeachMetadata(new Version(NewerVersion)), - }; - - string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip"); - IPackageSearchMetadata newestAvailableVersion = availablePackages.Last(); - this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages); - this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is(packageIdentity => packageIdentity == newestAvailableVersion.Identity))).ReturnsAsync(testDownloadPath); - - bool success = this.upgrader.TryQueryNewestVersion(out actualNewestVersion, out message); - - // Assert that no new version was returned - success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}"); - actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version."); - - this.mockFileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed = false; - bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message); - this.mockFileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed = true; - downloadSuccessful.ShouldBeFalse(); - } - } -} diff --git a/GVFS/GVFS.Upgrader/GVFS.Upgrader.csproj b/GVFS/GVFS.Upgrader/GVFS.Upgrader.csproj deleted file mode 100644 index f67c032125..0000000000 --- a/GVFS/GVFS.Upgrader/GVFS.Upgrader.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - Exe - net461 - - - - - - - - - - - diff --git a/GVFS/GVFS.Upgrader/Program.cs b/GVFS/GVFS.Upgrader/Program.cs deleted file mode 100644 index a77f4df5db..0000000000 --- a/GVFS/GVFS.Upgrader/Program.cs +++ /dev/null @@ -1,16 +0,0 @@ -using CommandLine; -using GVFS.PlatformLoader; - -namespace GVFS.Upgrader -{ - public class Program - { - public static void Main(string[] args) - { - GVFSPlatformLoader.Initialize(); - - Parser.Default.ParseArguments(args) - .WithParsed(options => UpgradeOrchestratorFactory.Create(options).Execute()); - } - } -} diff --git a/GVFS/GVFS.Upgrader/UpgradeOptions.cs b/GVFS/GVFS.Upgrader/UpgradeOptions.cs deleted file mode 100644 index eb648899fb..0000000000 --- a/GVFS/GVFS.Upgrader/UpgradeOptions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using CommandLine; - -namespace GVFS.Upgrader -{ - [Verb("UpgradeOrchestrator", HelpText = "Upgrade VFS for Git.")] - public class UpgradeOptions - { - [Option( - "dry-run", - Default = false, - Required = false, - HelpText = "Display progress and errors, but don't install GVFS")] - public bool DryRun { get; set; } - - [Option( - "no-verify", - Default = false, - Required = false, - HelpText = "Don't verify authenticode signature of installers")] - public bool NoVerify { get; set; } - } -} diff --git a/GVFS/GVFS.Upgrader/UpgradeOrchestrator.cs b/GVFS/GVFS.Upgrader/UpgradeOrchestrator.cs deleted file mode 100644 index 1f44830781..0000000000 --- a/GVFS/GVFS.Upgrader/UpgradeOrchestrator.cs +++ /dev/null @@ -1,389 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.Git; -using GVFS.Common.Tracing; -using System; -using System.IO; -using System.Text; - -namespace GVFS.Upgrader -{ - public abstract class UpgradeOrchestrator - { - protected InstallerPreRunChecker preRunChecker; - protected bool mount; - protected ITracer tracer; - - private const EventLevel DefaultEventLevel = EventLevel.Informational; - - private ProductUpgrader upgrader; - private string logDirectory = ProductUpgraderInfo.GetLogDirectoryPath(); - private string installationId; - private PhysicalFileSystem fileSystem; - private TextWriter output; - private TextReader input; - - public UpgradeOrchestrator( - ProductUpgrader upgrader, - ITracer tracer, - PhysicalFileSystem fileSystem, - InstallerPreRunChecker preRunChecker, - TextReader input, - TextWriter output) - { - this.upgrader = upgrader; - this.tracer = tracer; - this.fileSystem = fileSystem; - this.preRunChecker = preRunChecker; - this.output = output; - this.input = input; - this.mount = false; - this.ExitCode = ReturnCode.Success; - this.installationId = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - } - - public UpgradeOrchestrator(UpgradeOptions options) - : this() - { - this.DryRun = options.DryRun; - this.NoVerify = options.NoVerify; - } - - public UpgradeOrchestrator() - { - // CommandLine's Parser will create multiple instances of UpgradeOrchestrator, and we don't want - // multiple log files to get created. Defer tracer (and preRunChecker) creation until Execute() - this.tracer = null; - this.preRunChecker = null; - - this.fileSystem = new PhysicalFileSystem(); - this.output = Console.Out; - this.input = Console.In; - this.mount = false; - this.ExitCode = ReturnCode.Success; - this.installationId = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - } - - public ReturnCode ExitCode { get; private set; } - - public bool DryRun { get; } - - public bool NoVerify { get; } - - public void Execute() - { - string error = null; - string mountError = null; - Version newVersion = null; - - if (this.tracer == null) - { - this.tracer = this.CreateTracer(); - } - - if (this.preRunChecker == null) - { - this.preRunChecker = new InstallerPreRunChecker(this.tracer, GVFSPlatform.Instance.Constants.UpgradeConfirmCommandMessage); - } - - try - { - if (this.TryInitialize(out error)) - { - try - { - if (!this.TryRunUpgrade(out newVersion, out error)) - { - this.ExitCode = ReturnCode.GenericError; - } - } - finally - { - if (!this.TryMountRepositories(out mountError)) - { - mountError = Environment.NewLine + "WARNING: " + mountError; - this.output.WriteLine(mountError); - } - - this.DeletedDownloadedAssets(); - } - } - else - { - this.ExitCode = ReturnCode.GenericError; - } - - if (this.ExitCode == ReturnCode.GenericError) - { - StringBuilder sb = new StringBuilder(); - sb.AppendLine(); - sb.Append("ERROR: " + error); - - sb.AppendLine(); - sb.AppendLine(); - - sb.AppendLine($"Upgrade logs can be found at: {this.logDirectory} with file names that end with the installation ID: {this.installationId}."); - - this.output.WriteLine(sb.ToString()); - } - else - { - if (newVersion != null) - { - this.output.WriteLine($"{Environment.NewLine}Upgrade completed successfully{(string.IsNullOrEmpty(mountError) ? "." : ", but one or more repositories will need to be mounted manually.")}"); - } - } - } - finally - { - this.upgrader?.Dispose(); - } - - if (this.input == Console.In) - { - this.output.WriteLine("Press Enter to exit."); - this.input.ReadLine(); - } - - Environment.ExitCode = (int)this.ExitCode; - } - - protected bool LaunchInsideSpinner(Func method, string message) - { - return ConsoleHelper.ShowStatusWhileRunning( - method, - message, - this.output, - this.output == Console.Out && !GVFSPlatform.Instance.IsConsoleOutputRedirectedToFile(), - null); - } - - protected abstract bool TryMountRepositories(out string consoleError); - - private JsonTracer CreateTracer() - { - string logFilePath = GVFSEnlistment.GetNewGVFSLogFileName( - this.logDirectory, - GVFSConstants.LogFileTypes.UpgradeProcess, - logId: null, - fileSystem: this.fileSystem); - - JsonTracer jsonTracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "UpgradeProcess"); - - jsonTracer.AddLogFileEventListener( - logFilePath, - DefaultEventLevel, - Keywords.Any); - - return jsonTracer; - } - - private bool TryInitialize(out string errorMessage) - { - if (this.upgrader == null) - { - string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath(); - if (string.IsNullOrEmpty(gitBinPath)) - { - errorMessage = $"nameof(this.TryInitialize): Unable to locate git installation. Ensure git is installed and try again."; - return false; - } - - ICredentialStore credentialStore = new GitProcess(gitBinPath, workingDirectoryRoot: null); - - ProductUpgrader upgrader; - if (!ProductUpgrader.TryCreateUpgrader(this.tracer, this.fileSystem, new LocalGVFSConfig(), credentialStore, this.DryRun, this.NoVerify, out upgrader, out errorMessage)) - { - return false; - } - - // Configure the upgrader to have installer logs written to the same directory - // as the upgrader. - upgrader.UpgradeInstanceId = this.installationId; - this.upgrader = upgrader; - } - - errorMessage = null; - return true; - } - - private bool TryRunUpgrade(out Version newVersion, out string consoleError) - { - Version newGVFSVersion = null; - string error = null; - - if (!this.upgrader.UpgradeAllowed(out error)) - { - ProductUpgraderInfo productUpgraderInfo = new ProductUpgraderInfo( - this.tracer, - this.fileSystem); - productUpgraderInfo.DeleteAllInstallerDownloads(); - this.output.WriteLine(error); - consoleError = null; - newVersion = null; - return true; - } - - if (!this.LaunchInsideSpinner( - () => - { - if (!this.preRunChecker.TryRunPreUpgradeChecks(out error)) - { - return false; - } - - if (!this.TryCheckIfUpgradeAvailable(out newGVFSVersion, out error)) - { - return false; - } - - this.LogInstalledVersionInfo(); - - if (newGVFSVersion != null && !this.TryDownloadUpgrade(newGVFSVersion, out error)) - { - return false; - } - - return true; - }, - "Downloading")) - { - newVersion = null; - consoleError = error; - return false; - } - - if (newGVFSVersion == null) - { - newVersion = null; - consoleError = null; - return true; - } - - if (!this.LaunchInsideSpinner( - () => - { - if (!this.preRunChecker.TryUnmountAllGVFSRepos(out error)) - { - return false; - } - - this.mount = true; - - return true; - }, - "Unmounting repositories")) - { - newVersion = null; - consoleError = error; - return false; - } - - if (!this.LaunchInsideSpinner( - () => - { - if (!this.preRunChecker.IsInstallationBlockedByRunningProcess(out error)) - { - return false; - } - - return true; - }, - "Checking for blocking processes.")) - { - newVersion = null; - consoleError = error; - return false; - } - - if (!this.upgrader.TryRunInstaller(this.LaunchInsideSpinner, out consoleError)) - { - newVersion = null; - return false; - } - - newVersion = newGVFSVersion; - consoleError = null; - return true; - } - - private void DeletedDownloadedAssets() - { - string downloadsCleanupError; - if (!this.upgrader.TryCleanup(out downloadsCleanupError)) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Upgrade Step", nameof(this.DeletedDownloadedAssets)); - metadata.Add("Download cleanup error", downloadsCleanupError); - this.tracer.RelatedError(metadata, $"{nameof(this.DeletedDownloadedAssets)} failed."); - } - } - - private bool TryCheckIfUpgradeAvailable(out Version newestVersion, out string consoleError) - { - newestVersion = null; - consoleError = null; - - using (ITracer activity = this.tracer.StartActivity(nameof(this.TryCheckIfUpgradeAvailable), EventLevel.Informational)) - { - string message; - if (!this.upgrader.TryQueryNewestVersion(out newestVersion, out message)) - { - consoleError = message; - EventMetadata metadata = new EventMetadata(); - metadata.Add("Upgrade Step", nameof(this.TryCheckIfUpgradeAvailable)); - this.tracer.RelatedError(metadata, $"{nameof(this.upgrader.TryQueryNewestVersion)} failed. {consoleError}"); - return false; - } - - if (newestVersion == null) - { - this.output.WriteLine(message); - this.tracer.RelatedInfo($"No new upgrade releases available. {message}"); - return true; - } - - activity.RelatedInfo("New release found - latest available version: {0}", newestVersion); - } - - return true; - } - - private bool TryDownloadUpgrade(Version version, out string consoleError) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Upgrade Step", nameof(this.TryDownloadUpgrade)); - metadata.Add("Version", version.ToString()); - - using (ITracer activity = this.tracer.StartActivity($"{nameof(this.TryDownloadUpgrade)}", EventLevel.Informational, metadata)) - { - if (!this.upgrader.TryDownloadNewestVersion(out consoleError)) - { - this.tracer.RelatedError(metadata, $"{nameof(this.upgrader.TryDownloadNewestVersion)} failed. {consoleError}"); - return false; - } - - activity.RelatedInfo("Successfully downloaded version: " + version.ToString()); - } - - return true; - } - - private void LogInstalledVersionInfo() - { - EventMetadata metadata = new EventMetadata(); - string installedGVFSVersion = ProcessHelper.GetCurrentProcessVersion(); - metadata.Add(nameof(installedGVFSVersion), installedGVFSVersion); - - GitVersion installedGitVersion = null; - string error = null; - string gitPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath(); - if (!string.IsNullOrEmpty(gitPath) && GitProcess.TryGetVersion(gitPath, out installedGitVersion, out error)) - { - metadata.Add(nameof(installedGitVersion), installedGitVersion.ToString()); - } - - this.tracer.RelatedEvent(EventLevel.Informational, "Installed Version", metadata); - } - } -} diff --git a/GVFS/GVFS.Upgrader/UpgradeOrchestratorFactory.cs b/GVFS/GVFS.Upgrader/UpgradeOrchestratorFactory.cs deleted file mode 100644 index a2d9c5cb38..0000000000 --- a/GVFS/GVFS.Upgrader/UpgradeOrchestratorFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace GVFS.Upgrader -{ - public static class UpgradeOrchestratorFactory - { - public static UpgradeOrchestrator Create(UpgradeOptions options) - { - return new WindowsUpgradeOrchestrator(options); - } - } -} diff --git a/GVFS/GVFS.Upgrader/WindowsUpgradeOrchestrator.cs b/GVFS/GVFS.Upgrader/WindowsUpgradeOrchestrator.cs deleted file mode 100644 index 206819d4e0..0000000000 --- a/GVFS/GVFS.Upgrader/WindowsUpgradeOrchestrator.cs +++ /dev/null @@ -1,55 +0,0 @@ -using GVFS.Common; -using GVFS.Common.FileSystem; -using GVFS.Common.Tracing; -using System.IO; - -namespace GVFS.Upgrader -{ - public class WindowsUpgradeOrchestrator : UpgradeOrchestrator - { - public WindowsUpgradeOrchestrator( - ProductUpgrader upgrader, - ITracer tracer, - PhysicalFileSystem fileSystem, - InstallerPreRunChecker preRunChecker, - TextReader input, - TextWriter output) - : base(upgrader, tracer, fileSystem, preRunChecker, input, output) - { - } - - public WindowsUpgradeOrchestrator(UpgradeOptions options) - : base(options) - { - } - - protected override bool TryMountRepositories(out string consoleError) - { - string errorMessage = string.Empty; - if (this.mount && !this.LaunchInsideSpinner( - () => - { - string mountError; - if (!this.preRunChecker.TryMountAllGVFSRepos(out mountError)) - { - EventMetadata metadata = new EventMetadata(); - metadata.Add("Upgrade Step", nameof(this.TryMountRepositories)); - metadata.Add("Mount Error", mountError); - this.tracer.RelatedError(metadata, $"{nameof(this.preRunChecker.TryMountAllGVFSRepos)} failed."); - errorMessage += mountError; - return false; - } - - return true; - }, - "Mounting repositories")) - { - consoleError = errorMessage; - return false; - } - - consoleError = null; - return true; - } - } -} diff --git a/GVFS/GVFS/CommandLine/DiagnoseVerb.cs b/GVFS/GVFS/CommandLine/DiagnoseVerb.cs index 0074a88c9d..1d3a716394 100644 --- a/GVFS/GVFS/CommandLine/DiagnoseVerb.cs +++ b/GVFS/GVFS/CommandLine/DiagnoseVerb.cs @@ -140,30 +140,6 @@ protected override void Execute(GVFSEnlistment enlistment) GVFSConstants.Service.UIName, copySubFolders: true); - if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSUpgrade) - { - // upgrader - this.CopyAllFiles( - ProductUpgraderInfo.GetParentLogDirectoryPath(), - archiveFolderPath, - DeprecatedUpgradeLogsDirectory, - copySubFolders: true, - targetFolderName: Path.Combine(ProductUpgraderInfo.UpgradeDirectoryName, DeprecatedUpgradeLogsDirectory)); - - this.CopyAllFiles( - ProductUpgraderInfo.GetParentLogDirectoryPath(), - archiveFolderPath, - ProductUpgraderInfo.LogDirectory, - copySubFolders: true, - targetFolderName: Path.Combine(ProductUpgraderInfo.UpgradeDirectoryName, ProductUpgraderInfo.LogDirectory)); - - this.LogDirectoryEnumeration( - ProductUpgraderInfo.GetUpgradeProtectedDataDirectory(), - Path.Combine(archiveFolderPath, ProductUpgraderInfo.UpgradeDirectoryName), - ProductUpgraderInfo.DownloadDirectory, - "downloaded-assets.txt"); - } - if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSConfig) { this.CopyFile(GVFSPlatform.Instance.GetSecureDataRootForGVFS(), archiveFolderPath, LocalGVFSConfig.FileName); diff --git a/GVFS/GVFS/CommandLine/LogVerb.cs b/GVFS/GVFS/CommandLine/LogVerb.cs index b604403494..416a91c6f8 100644 --- a/GVFS/GVFS/CommandLine/LogVerb.cs +++ b/GVFS/GVFS/CommandLine/LogVerb.cs @@ -64,8 +64,6 @@ public override void Execute() string serviceLogsRoot = GVFSPlatform.Instance.GetLogsDirectoryForGVFSComponent(GVFSConstants.Service.ServiceName); this.DisplayMostRecent(serviceLogsRoot, GVFSConstants.LogFileTypes.Service); - - this.DisplayMostRecent(ProductUpgraderInfo.GetLogDirectoryPath(), GVFSConstants.LogFileTypes.UpgradePrefix); } else { diff --git a/GVFS/GVFS/CommandLine/UpgradeVerb.cs b/GVFS/GVFS/CommandLine/UpgradeVerb.cs index 54f1c809f6..855715657a 100644 --- a/GVFS/GVFS/CommandLine/UpgradeVerb.cs +++ b/GVFS/GVFS/CommandLine/UpgradeVerb.cs @@ -1,9 +1,7 @@ using CommandLine; using GVFS.Common; using GVFS.Common.FileSystem; -using GVFS.Common.Git; using GVFS.Common.Tracing; -using GVFS.Upgrader; using System; using System.Diagnostics; using System.IO; @@ -20,27 +18,18 @@ public class UpgradeVerb : GVFSVerb.ForNoEnlistment private ITracer tracer; private PhysicalFileSystem fileSystem; - private ProductUpgrader upgrader; - private InstallerPreRunChecker prerunChecker; private ProcessLauncher processLauncher; - private ProductUpgraderPlatformStrategy productUpgraderPlatformStrategy; - public UpgradeVerb( - ProductUpgrader upgrader, ITracer tracer, PhysicalFileSystem fileSystem, - InstallerPreRunChecker prerunChecker, ProcessLauncher processWrapper, TextWriter output) { - this.upgrader = upgrader; this.tracer = tracer; this.fileSystem = fileSystem; - this.prerunChecker = prerunChecker; this.processLauncher = processWrapper; this.Output = output; - this.productUpgraderPlatformStrategy = GVFSPlatform.Instance.CreateProductUpgraderPlatformInteractions(fileSystem, tracer); } public UpgradeVerb() @@ -78,320 +67,7 @@ protected override string VerbName public override void Execute() { - string error; - if (!this.TryInitializeUpgrader(out error) || !this.TryRunProductUpgrade()) - { - this.ReportErrorAndExit(this.tracer, ReturnCode.GenericError, error); - } - } - - private bool TryInitializeUpgrader(out string error) - { - if (this.DryRun && this.Confirmed) - { - error = $"{DryRunOption} and {ConfirmOption} arguments are not compatible."; - return false; - } - - if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSUpgrade) - { - error = null; - if (this.upgrader == null) - { - this.productUpgraderPlatformStrategy = GVFSPlatform.Instance.CreateProductUpgraderPlatformInteractions(this.fileSystem, tracer: null); - if (!this.productUpgraderPlatformStrategy.TryPrepareLogDirectory(out error)) - { - return false; - } - - JsonTracer jsonTracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "UpgradeVerb"); - string logFilePath = GVFSEnlistment.GetNewGVFSLogFileName( - ProductUpgraderInfo.GetLogDirectoryPath(), - GVFSConstants.LogFileTypes.UpgradeVerb); - jsonTracer.AddLogFileEventListener(logFilePath, EventLevel.Informational, Keywords.Any); - - this.tracer = jsonTracer; - this.prerunChecker = new InstallerPreRunChecker(this.tracer, this.Confirmed ? GVFSPlatform.Instance.Constants.UpgradeConfirmCommandMessage : GVFSConstants.UpgradeVerbMessages.GVFSUpgrade); - - string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath(); - if (string.IsNullOrEmpty(gitBinPath)) - { - error = $"nameof(this.TryInitializeUpgrader): Unable to locate git installation. Ensure git is installed and try again."; - return false; - } - - ICredentialStore credentialStore = new GitProcess(gitBinPath, workingDirectoryRoot: null); - - ProductUpgrader upgrader; - if (ProductUpgrader.TryCreateUpgrader(this.tracer, this.fileSystem, new LocalGVFSConfig(), credentialStore, this.DryRun, this.NoVerify, out upgrader, out error)) - { - this.upgrader = upgrader; - } - else - { - error = $"ERROR: {error}"; - } - } - - return this.upgrader != null; - } - else - { - error = $"ERROR: {GVFSConstants.UpgradeVerbMessages.GVFSUpgrade} is not supported on this operating system."; - return false; - } - } - - private bool TryRunProductUpgrade() - { - string errorOutputFormat = Environment.NewLine + "ERROR: {0}"; - string message = null; - string cannotInstallReason = null; - Version newestVersion = null; - - bool isInstallable = this.TryCheckUpgradeInstallable(out cannotInstallReason); - if (this.ShouldRunUpgraderTool() && !isInstallable) - { - this.ReportInfoToConsole($"Cannot upgrade GVFS on this machine."); - this.Output.WriteLine(errorOutputFormat, cannotInstallReason); - return false; - } - - if (!this.upgrader.UpgradeAllowed(out message)) - { - ProductUpgraderInfo productUpgraderInfo = new ProductUpgraderInfo( - this.tracer, - this.fileSystem); - productUpgraderInfo.DeleteAllInstallerDownloads(); - productUpgraderInfo.RecordHighestAvailableVersion(highestAvailableVersion: null); - this.ReportInfoToConsole(message); - return true; - } - - if (!this.TryRunUpgradeChecks(out newestVersion, out message)) - { - this.Output.WriteLine(errorOutputFormat, message); - this.tracer.RelatedError($"{nameof(this.TryRunProductUpgrade)}: Upgrade checks failed. {message}"); - return false; - } - - if (newestVersion == null) - { - // Make sure there a no asset installers remaining in the Downloads directory. This can happen if user - // upgraded by manually downloading and running asset installers. - ProductUpgraderInfo productUpgraderInfo = new ProductUpgraderInfo( - this.tracer, - this.fileSystem); - productUpgraderInfo.DeleteAllInstallerDownloads(); - this.ReportInfoToConsole(message); - return true; - } - - if (this.ShouldRunUpgraderTool()) - { - this.ReportInfoToConsole(message); - - if (!isInstallable) - { - this.tracer.RelatedError($"{nameof(this.TryRunProductUpgrade)}: {message}"); - this.Output.WriteLine(errorOutputFormat, message); - return false; - } - - // If we are on a platform that does not support nuget verification, and user has not - // specified the --no-verify flag, then print a helpful message here. - if (!GVFSPlatform.Instance.UnderConstruction.SupportsNuGetVerification && !this.NoVerify) - { - string packageVerificationNotSupportedMessage = @" -NuGet package verification is not supported on this platform. In order to run upgrade, you must run upgrade without NuGet package verification. -To run upgrade without NuGet verification include the --no-verify option. -"; - this.ReportInfoToConsole(packageVerificationNotSupportedMessage); - return false; - } - - if (!this.TryRunInstaller(out message)) - { - this.tracer.RelatedError($"{nameof(this.TryRunProductUpgrade)}: Could not launch upgrade tool. {message}"); - this.Output.WriteLine(errorOutputFormat, "Could not launch upgrade tool. " + message); - return false; - } - } - else - { - string advisoryMessage = string.Join( - Environment.NewLine, - GVFSConstants.UpgradeVerbMessages.UnmountRepoWarning, - GVFSPlatform.Instance.Constants.UpgradeInstallAdviceMessage); - this.ReportInfoToConsole(message + Environment.NewLine + Environment.NewLine + advisoryMessage + Environment.NewLine); - } - - return true; - } - - private bool TryRunUpgradeChecks( - out Version latestVersion, - out string error) - { - bool upgradeCheckSuccess = false; - string errorMessage = null; - Version version = null; - - this.ShowStatusWhileRunning( - () => - { - upgradeCheckSuccess = this.TryCheckUpgradeAvailable(out version, out errorMessage); - return upgradeCheckSuccess; - }, - "Checking for GVFS upgrades", - suppressGvfsLogMessage: true); - - latestVersion = version; - error = errorMessage; - - return upgradeCheckSuccess; - } - - private bool TryRunInstaller(out string consoleError) - { - string upgraderPath = null; - string errorMessage = null; - bool supportsInlineUpgrade = GVFSPlatform.Instance.Constants.SupportsUpgradeWhileRunning; - - this.ReportInfoToConsole("Launching upgrade tool..."); - - if (!this.TryCopyUpgradeTool(out upgraderPath, out consoleError)) - { - return false; - } - - if (!this.TryLaunchUpgradeTool( - upgraderPath, - runUpgradeInline: supportsInlineUpgrade, - consoleError: out errorMessage)) - { - return false; - } - - if (supportsInlineUpgrade) - { - this.processLauncher.WaitForExit(); - this.ReportInfoToConsole($"{Environment.NewLine}Upgrade completed."); - } - else - { - this.ReportInfoToConsole($"{Environment.NewLine}Installer launched in a new window. Do not run any git or gvfs commands until the installer has completed."); - } - - consoleError = null; - return true; - } - - private bool TryCopyUpgradeTool(out string upgraderExePath, out string consoleError) - { - upgraderExePath = null; - - using (ITracer activity = this.tracer.StartActivity(nameof(this.TryCopyUpgradeTool), EventLevel.Informational)) - { - if (!this.upgrader.TrySetupUpgradeApplicationDirectory(out upgraderExePath, out consoleError)) - { - return false; - } - - activity.RelatedInfo($"Successfully Copied upgrade tool to {upgraderExePath}"); - } - - return true; - } - - private bool TryLaunchUpgradeTool(string path, bool runUpgradeInline, out string consoleError) - { - using (ITracer activity = this.tracer.StartActivity(nameof(this.TryLaunchUpgradeTool), EventLevel.Informational)) - { - Exception exception; - string args = string.Empty + (this.DryRun ? $" {DryRunOption}" : string.Empty) + (this.NoVerify ? $" {NoVerifyOption}" : string.Empty); - - // If the upgrade application is being run "inline" with the current process, then do not run the installer via the - // shell - we want the upgrade process to inherit the current terminal's stdin / stdout / sterr - if (!this.processLauncher.TryStart(path, args, !runUpgradeInline, out exception)) - { - if (exception != null) - { - consoleError = exception.Message; - this.tracer.RelatedError($"Error launching upgrade tool. {exception.ToString()}"); - } - else - { - consoleError = "Error launching upgrade tool"; - } - - return false; - } - - activity.RelatedInfo("Successfully launched upgrade tool."); - } - - consoleError = null; - return true; - } - - private bool TryCheckUpgradeAvailable( - out Version latestVersion, - out string error) - { - latestVersion = null; - error = null; - - using (ITracer activity = this.tracer.StartActivity(nameof(this.TryCheckUpgradeAvailable), EventLevel.Informational)) - { - bool checkSucceeded = false; - Version version = null; - - checkSucceeded = this.upgrader.TryQueryNewestVersion(out version, out error); - if (!checkSucceeded) - { - return false; - } - - string currentVersion = ProcessHelper.GetCurrentProcessVersion(); - latestVersion = version; - - string message = latestVersion == null ? - $"Successfully checked for VFSForGit upgrades. Local version ({currentVersion}) is up-to-date." : - $"Successfully checked for VFSForGit upgrades. A new version is available: {latestVersion}, local version is: {currentVersion}."; - - activity.RelatedInfo(message); - } - - return true; - } - - private bool TryCheckUpgradeInstallable(out string consoleError) - { - consoleError = null; - - using (ITracer activity = this.tracer.StartActivity(nameof(this.TryCheckUpgradeInstallable), EventLevel.Informational)) - { - if (!this.prerunChecker.TryRunPreUpgradeChecks( - out consoleError)) - { - return false; - } - - activity.RelatedInfo("Upgrade is installable."); - } - - return true; - } - - private bool ShouldRunUpgraderTool() - { - return this.Confirmed || this.DryRun; - } - - private void ReportInfoToConsole(string message, params object[] args) - { - this.Output.WriteLine(message, args); + this.ReportErrorAndExit(this.tracer, ReturnCode.GenericError, "failed to upgrade"); } public class ProcessLauncher