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)); }
public override bool TryPrepareApplicationDirectory(out string error) { string rootDirectoryPath = ProductUpgraderInfo.GetUpgradesDirectoryPath(); string toolsDirectoryPath = Path.Combine(rootDirectoryPath, ProductUpgrader.ToolsDirectory); Exception deleteDirectoryException; if (this.FileSystem.DirectoryExists(toolsDirectoryPath) && !this.FileSystem.TryDeleteDirectory(toolsDirectoryPath, out deleteDirectoryException)) { error = $"Failed to delete {toolsDirectoryPath} - {deleteDirectoryException.Message}"; this.TraceException(deleteDirectoryException, nameof(this.TryPrepareApplicationDirectory), $"Error deleting {toolsDirectoryPath}."); return(false); } if (!this.FileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissions( this.Tracer, toolsDirectoryPath, out error)) { return(false); } error = null; return(true); }
public override bool TryPrepareLogDirectory(out string error) { // Under normal circumstances // ProductUpgraderInfo.GetLogDirectoryPath will have // already been created by Scalar.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 {ScalarConstants.UpgradeVerbMessages.ScalarUpgrade} from an elevated command prompt."; return(false); } error = null; return(true); }
internal NuGetUpgrader( string currentVersion, ITracer tracer, bool dryRun, bool noVerify, PhysicalFileSystem fileSystem, NuGetUpgraderConfig config, NuGetFeed nuGetFeed, ICredentialStore credentialStore) : base( currentVersion, tracer, dryRun, noVerify, fileSystem) { 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); }
private void TimerCallback(object unusedState) { string errorMessage = null; InstallerPreRunChecker prerunChecker = new InstallerPreRunChecker(this.tracer, string.Empty); IProductUpgrader productUpgrader; bool deleteExistingDownloads = true; if (ProductUpgraderFactory.TryCreateUpgrader(out productUpgrader, this.tracer, out errorMessage)) { if (prerunChecker.TryRunPreUpgradeChecks(out string _) && this.TryDownloadUpgrade(productUpgrader, out errorMessage)) { deleteExistingDownloads = false; } } if (errorMessage != null) { this.tracer.RelatedError(errorMessage); } if (deleteExistingDownloads) { ProductUpgraderInfo.DeleteAllInstallerDownloads(); } }
private bool TryInitializeUpgrader(out string error) { if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSUpgrade) { error = null; if (this.upgrader == null) { 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 ? GVFSConstants.UpgradeVerbMessages.GVFSUpgradeConfirm : GVFSConstants.UpgradeVerbMessages.GVFSUpgrade); IProductUpgrader upgrader; if (ProductUpgraderFactory.TryCreateUpgrader(out upgrader, this.tracer, 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 void CreateAndConfigureUpgradeLogDirectory() { string upgradeLogsPath = ProductUpgraderInfo.GetLogDirectoryPath(); DirectorySecurity upgradeLogsSecurity = this.GetUpgradeLogsDirectorySecurity(upgradeLogsPath); Directory.CreateDirectory(upgradeLogsPath, upgradeLogsSecurity); try { // Call SetAccessControl in case the directory already existed // (in which case the above CreateDirectory was a no-op) Directory.SetAccessControl(upgradeLogsPath, upgradeLogsSecurity); } catch (UnauthorizedAccessException e) { // UnauthorizedAccessException can occur when the upgrade logs directory was // created by a non-elevated user running 'gvfs upgrade'. Only the owner // is allowed to modify the ACLs, and if the logs directory was created by // the user running 'gvfs upgrade' then the Adminstrators group is not the owner. EventMetadata metadata = new EventMetadata(); metadata.Add("Exception", e.ToString()); metadata.Add( TracingConstants.MessageKey.InfoMessage, $"{nameof(this.CreateAndConfigureUpgradeLogDirectory)}: UnauthorizedAccessException when setting log directory ACLs"); this.tracer.RelatedEvent(EventLevel.Informational, "LogDirACL_UnauthorizedAccessException", metadata); // To avoid the ownership issues, rename the old log directory, create a new one, and migrate over // all of the contents of the old directory. this.MigrateUpgradeLogsToDirectoryWithFreshACLs(); } }
/// <summary> /// 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. /// </summary> 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."); } } }
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 void MigrateUpgradeLogsToDirectoryWithFreshACLs() { string upgradeLogsPath = ProductUpgraderInfo.GetLogDirectoryPath(); string tempUpgradeLogsPath = Path.Combine( Path.GetDirectoryName(upgradeLogsPath), ProductUpgraderInfo.LogDirectory + "_" + Guid.NewGuid().ToString("N")); this.tracer.RelatedInfo($"{nameof(this.MigrateUpgradeLogsToDirectoryWithFreshACLs)}: Renaming '{upgradeLogsPath}' to '{tempUpgradeLogsPath}'"); Directory.Move(upgradeLogsPath, tempUpgradeLogsPath); this.tracer.RelatedInfo($"{nameof(this.MigrateUpgradeLogsToDirectoryWithFreshACLs)}: Creating new '{upgradeLogsPath}' directory with appropriate ACLs"); DirectorySecurity upgradeLogsSecurity = this.GetUpgradeLogsDirectorySecurity(upgradeLogsPath); Directory.CreateDirectory(upgradeLogsPath, upgradeLogsSecurity); try { DirectoryInfo tempDirectoryInfo = new DirectoryInfo(tempUpgradeLogsPath); this.tracer.RelatedInfo($"Moving directories from '{tempUpgradeLogsPath}' to '{upgradeLogsPath}'"); foreach (DirectoryInfo logDirectoryInfo in tempDirectoryInfo.EnumerateDirectories(searchPattern: "*", searchOption: SearchOption.TopDirectoryOnly)) { Directory.Move(logDirectoryInfo.FullName, Path.Combine(upgradeLogsPath, logDirectoryInfo.Name)); } this.tracer.RelatedInfo($"Moving files from '{tempUpgradeLogsPath}' to '{upgradeLogsPath}'"); foreach (FileInfo logFileInfo in tempDirectoryInfo.EnumerateFiles(searchPattern: "*", searchOption: SearchOption.TopDirectoryOnly)) { File.Move(logFileInfo.FullName, Path.Combine(upgradeLogsPath, logFileInfo.Name)); } FileSystemInfo[] remainingChildren = tempDirectoryInfo.GetFileSystemInfos(); if (remainingChildren.Length > 0) { this.tracer.RelatedWarning( $"{nameof(this.MigrateUpgradeLogsToDirectoryWithFreshACLs)}: Skipping delete of old directory, {remainingChildren.Length} items still present on disk"); } else { PhysicalFileSystem fileSystem = new PhysicalFileSystem(); fileSystem.DeleteDirectory(tempUpgradeLogsPath, recursive: false); } } catch (Exception e) { EventMetadata metadata = new EventMetadata(); metadata.Add("Exception", e.ToString()); metadata.Add(nameof(tempUpgradeLogsPath), tempUpgradeLogsPath); metadata.Add(nameof(upgradeLogsPath), upgradeLogsPath); this.tracer.RelatedWarning( metadata, $"{nameof(this.MigrateUpgradeLogsToDirectoryWithFreshACLs)}: Caught exception migrating files from the old upgrade log directory"); } }
public override void Execute() { this.ValidatePathParameter(this.EnlistmentRootPathParameter); this.Output.WriteLine("Most recent log files:"); string errorMessage; string enlistmentRoot; if (!GVFSPlatform.Instance.TryGetGVFSEnlistmentRoot(this.EnlistmentRootPathParameter, out enlistmentRoot, out errorMessage)) { this.ReportErrorAndExit( "Error: '{0}' is not a valid GVFS enlistment", this.EnlistmentRootPathParameter); } string gvfsLogsRoot = Path.Combine( enlistmentRoot, GVFSPlatform.Instance.Constants.DotGVFSRoot, GVFSConstants.DotGVFS.LogName); if (this.LogType == null) { this.DisplayMostRecent(gvfsLogsRoot, GVFSConstants.LogFileTypes.Clone); // By using MountPrefix ("mount") DisplayMostRecent will display either mount_verb, mount_upgrade, or mount_process, whichever is more recent this.DisplayMostRecent(gvfsLogsRoot, GVFSConstants.LogFileTypes.MountPrefix); this.DisplayMostRecent(gvfsLogsRoot, GVFSConstants.LogFileTypes.Prefetch); this.DisplayMostRecent(gvfsLogsRoot, GVFSConstants.LogFileTypes.Dehydrate); this.DisplayMostRecent(gvfsLogsRoot, GVFSConstants.LogFileTypes.Repair); this.DisplayMostRecent(gvfsLogsRoot, GVFSConstants.LogFileTypes.Sparse); string serviceLogsRoot = Path.Combine( GVFSPlatform.Instance.GetDataRootForGVFSComponent(GVFSConstants.Service.ServiceName), GVFSConstants.Service.LogDirectory); this.DisplayMostRecent(serviceLogsRoot, GVFSConstants.LogFileTypes.Service); this.DisplayMostRecent(ProductUpgraderInfo.GetLogDirectoryPath(), GVFSConstants.LogFileTypes.UpgradePrefix); } else { string logFile = FindNewestFileInFolder(gvfsLogsRoot, this.LogType); if (logFile == null) { this.ReportErrorAndExit("No log file found"); } else { foreach (string line in File.ReadAllLines(logFile)) { this.Output.WriteLine(line); } } } }
/// <summary> /// Try to load a NuGetUpgrader from config settings. /// <isConfigured>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. /// </isConfigured> /// <Returns>True if able to load a properly configured NuGetUpgrader<Returns> /// </summary> public static bool TryCreate( ITracer tracer, PhysicalFileSystem fileSystem, bool dryRun, bool noVerify, out NuGetUpgrader nuGetUpgrader, out bool isConfigured, out string error) { NuGetUpgraderConfig upgraderConfig = new NuGetUpgraderConfig(tracer, new LocalGVFSConfig()); 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); } string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath(); if (string.IsNullOrEmpty(gitBinPath)) { error = $"NuGetUpgrader: Unable to locate git installation. Ensure git is installed and try again."; return(false); } ICredentialStore credentialStore = new GitProcess(gitBinPath, workingDirectoryRoot: null, gvfsHooksRoot: null); nuGetUpgrader = new NuGetUpgrader( ProcessHelper.GetCurrentProcessVersion(), tracer, fileSystem, dryRun, noVerify, upgraderConfig, ProductUpgraderInfo.GetAssetDownloadsPath(), credentialStore); return(true); }
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) { // 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); } 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 ? GVFSConstants.UpgradeVerbMessages.GVFSUpgradeConfirm : GVFSConstants.UpgradeVerbMessages.GVFSUpgrade); ProductUpgrader upgrader; if (ProductUpgrader.TryCreateUpgrader(this.tracer, this.fileSystem, 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); } }
public void SetUp() { this.upgradeDirectory = GVFSPlatform.Instance.GetDataRootForGVFSComponent(ProductUpgraderInfo.UpgradeDirectoryName); this.expectedNewVersionExistsFilePath = Path.Combine(this.upgradeDirectory, this.expectedNewVersionExistsFileName); this.mockFileSystem = new Mock <PhysicalFileSystem>(); this.mockFileSystem.Setup(fileSystem => fileSystem.WriteAllText(this.expectedNewVersionExistsFilePath, It.IsAny <string>())); this.tracer = new MockTracer(); this.productUpgraderInfo = new ProductUpgraderInfo( this.tracer, this.mockFileSystem.Object); }
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 (randomValue <= reminderFrequency && ProductUpgraderInfo.IsLocalUpgradeAvailable(tracer: null)) { Console.WriteLine(Environment.NewLine + GVFSConstants.UpgradeVerbMessages.ReminderNotification); } }
public void SetUp() { this.upgradeDirectory = ProductUpgraderInfo.GetHighestAvailableVersionDirectory(); this.expectedNewVersionExistsFilePath = Path.Combine(this.upgradeDirectory, this.expectedNewVersionExistsFileName); this.mockFileSystem = new Mock <PhysicalFileSystem>(); this.mockFileSystem.Setup(fileSystem => fileSystem.WriteAllText(this.expectedNewVersionExistsFilePath, It.IsAny <string>())); this.tracer = new MockTracer(); this.productUpgraderInfo = new ProductUpgraderInfo( this.tracer, this.mockFileSystem.Object); }
private void CreateAndConfigureProgramDataDirectories() { string serviceDataRootPath = ScalarPlatform.Instance.GetSecureDataRootForScalar(); // Create Scalar.Service and Scalar.Upgrade related directories (if they don't already exist) // TODO #136: Determine if we still should be creating Scalar.Service here DirectoryEx.CreateDirectory(serviceDataRootPath); DirectoryEx.CreateDirectory(this.serviceDataLocation); DirectoryEx.CreateDirectory(ProductUpgraderInfo.GetUpgradeProtectedDataDirectory()); // Special rules for the upgrader logs and registry, as non-elevated users need to be be able to write this.CreateAndConfigureUserWriteableDirectory(this.repoRegistryLocation); this.CreateAndConfigureUserWriteableDirectory(ProductUpgraderInfo.GetLogDirectoryPath()); this.CreateAndConfigureUserWriteableDirectory(ScalarPlatform.Instance.GetLogsDirectoryForGVFSComponent(ScalarConstants.Service.UIName)); }
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()); } }
/// <summary> /// Try to load a NuGetUpgrader from config settings. /// <isConfigured>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. /// </isConfigured> /// <Returns>True if able to load a properly configured NuGetUpgrader<Returns> /// </summary> public static bool TryCreate( ITracer tracer, PhysicalFileSystem fileSystem, LocalScalarConfig scalarConfig, ICredentialStore credentialStore, bool dryRun, bool noVerify, out NuGetUpgrader nuGetUpgrader, out bool isConfigured, out string error) { NuGetUpgraderConfig upgraderConfig = new NuGetUpgraderConfig(tracer, scalarConfig); 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); }
private void CreateAndConfigureProgramDataDirectories() { string serviceDataRootPath = Path.GetDirectoryName(this.serviceDataLocation); DirectorySecurity serviceDataRootSecurity = this.GetServiceDirectorySecurity(serviceDataRootPath); // Create GVFS.Service and GVFS.Upgrade 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.CreateAndConfigureUpgradeLogDirectory(); }
private void CreateAndConfigureUpgradeLogDirectory() { string upgradeLogsPath = ProductUpgraderInfo.GetLogDirectoryPath(); string error; if (!GVFSPlatform.Instance.FileSystem.TryCreateDirectoryWithAdminAndUserModifyPermissions(upgradeLogsPath, out error)) { EventMetadata metadata = new EventMetadata(); metadata.Add("Area", EtwArea); metadata.Add(nameof(upgradeLogsPath), upgradeLogsPath); metadata.Add(nameof(error), error); this.tracer.RelatedWarning( metadata, $"{nameof(this.CreateAndConfigureUpgradeLogDirectory)}: Failed to create upgrade logs directory", Keywords.Telemetry); } }
public UpgradeOrchestrator() { string logFilePath = GVFSEnlistment.GetNewGVFSLogFileName( ProductUpgraderInfo.GetLogDirectoryPath(), GVFSConstants.LogFileTypes.UpgradeProcess); JsonTracer jsonTracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "UpgradeProcess"); jsonTracer.AddLogFileEventListener( logFilePath, DefaultEventLevel, Keywords.Any); this.tracer = jsonTracer; this.preRunChecker = new InstallerPreRunChecker(this.tracer, GVFSConstants.UpgradeVerbMessages.GVFSUpgradeConfirm); this.output = Console.Out; this.input = Console.In; this.mount = false; this.ExitCode = ReturnCode.Success; }
public override bool TryPrepareDownloadDirectory(out string error) { string directory = ProductUpgraderInfo.GetAssetDownloadsPath(); Exception deleteDirectoryException; if (this.FileSystem.DirectoryExists(directory) && !this.FileSystem.TryDeleteDirectory(directory, out deleteDirectoryException)) { error = $"Failed to delete {directory} - {deleteDirectoryException.Message}"; this.TraceException(deleteDirectoryException, nameof(this.TryPrepareDownloadDirectory), $"Error deleting {directory}."); return(false); } this.FileSystem.CreateDirectory(directory); error = null; return(true); }
private bool TryDownloadUpgrade(IProductUpgrader productUpgrader, out string errorMessage) { using (ITracer activity = this.tracer.StartActivity("Checking for product upgrades.", EventLevel.Informational)) { Version newerVersion = null; string detailedError = null; if (!productUpgrader.UpgradeAllowed(out errorMessage)) { return(false); } if (!productUpgrader.TryQueryNewestVersion(out newerVersion, out detailedError)) { errorMessage = "Could not fetch new version info. " + detailedError; return(false); } if (newerVersion == null) { // Already up-to-date // 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.DeleteAllInstallerDownloads(); errorMessage = null; return(true); } if (productUpgrader.TryDownloadNewestVersion(out detailedError)) { errorMessage = null; return(true); } else { errorMessage = "Could not download product upgrade. " + detailedError; return(false); } } }
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); }
protected override void Execute(GVFSEnlistment enlistment) { string diagnosticsRoot = Path.Combine(enlistment.DotGVFSRoot, "diagnostics"); if (!Directory.Exists(diagnosticsRoot)) { Directory.CreateDirectory(diagnosticsRoot); } string archiveFolderPath = Path.Combine(diagnosticsRoot, "gvfs_" + DateTime.Now.ToString("yyyyMMdd_HHmmss")); Directory.CreateDirectory(archiveFolderPath); using (FileStream diagnosticLogFile = new FileStream(Path.Combine(archiveFolderPath, "diagnostics.log"), FileMode.CreateNew)) using (this.diagnosticLogFileWriter = new StreamWriter(diagnosticLogFile)) { this.WriteMessage("Collecting diagnostic info into temp folder " + archiveFolderPath); this.WriteMessage(string.Empty); this.WriteMessage("gvfs version " + ProcessHelper.GetCurrentProcessVersion()); GitVersion gitVersion = null; string error = null; if (!string.IsNullOrEmpty(enlistment.GitBinPath) && GitProcess.TryGetVersion(enlistment.GitBinPath, out gitVersion, out error)) { this.WriteMessage("git version " + gitVersion.ToString()); } else { this.WriteMessage("Could not determine git version. " + error); } this.WriteMessage(enlistment.GitBinPath); this.WriteMessage(string.Empty); this.WriteMessage("Enlistment root: " + enlistment.EnlistmentRoot); this.WriteMessage("Cache Server: " + CacheServerResolver.GetCacheServerFromConfig(enlistment)); string localCacheRoot; string gitObjectsRoot; this.GetLocalCachePaths(enlistment, out localCacheRoot, out gitObjectsRoot); string actualLocalCacheRoot = !string.IsNullOrWhiteSpace(localCacheRoot) ? localCacheRoot : gitObjectsRoot; this.WriteMessage("Local Cache: " + actualLocalCacheRoot); this.WriteMessage(string.Empty); this.PrintDiskSpaceInfo(actualLocalCacheRoot, this.EnlistmentRootPathParameter); this.RecordVersionInformation(); this.ShowStatusWhileRunning( () => this.RunAndRecordGVFSVerb <StatusVerb>(archiveFolderPath, "gvfs_status.txt") != ReturnCode.Success || this.RunAndRecordGVFSVerb <UnmountVerb>(archiveFolderPath, "gvfs_unmount.txt", verb => verb.SkipLock = true) == ReturnCode.Success, "Unmounting", suppressGvfsLogMessage: true); this.ShowStatusWhileRunning( () => { // .gvfs this.CopyAllFiles(enlistment.EnlistmentRoot, archiveFolderPath, GVFSPlatform.Instance.Constants.DotGVFSRoot, copySubFolders: false); // driver if (this.FlushKernelDriverLogs()) { string kernelLogsFolderPath = GVFSPlatform.Instance.KernelDriver.LogsFolderPath; // This copy sometimes fails because the OS has an exclusive lock on the etl files. The error is not actionable // for the user so we don't write the error message to stdout, just to our own log file. this.CopyAllFiles(Path.GetDirectoryName(kernelLogsFolderPath), archiveFolderPath, Path.GetFileName(kernelLogsFolderPath), copySubFolders: false, hideErrorsFromStdout: true); } // .git this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Root, copySubFolders: false); this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Hooks.Root, copySubFolders: false); this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Info.Root, copySubFolders: false); this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Logs.Root, copySubFolders: true); this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Refs.Root, copySubFolders: true); this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Objects.Info.Root, copySubFolders: false); this.LogDirectoryEnumeration(enlistment.WorkingDirectoryRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGit.Objects.Root), GVFSConstants.DotGit.Objects.Pack.Root, "packs-local.txt"); this.LogLooseObjectCount(enlistment.WorkingDirectoryRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGit.Objects.Root), GVFSConstants.DotGit.Objects.Root, "objects-local.txt"); // databases this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSPlatform.Instance.Constants.DotGVFSRoot), GVFSConstants.DotGVFS.Databases.Name, copySubFolders: false); // local cache this.CopyLocalCacheData(archiveFolderPath, localCacheRoot, gitObjectsRoot); // corrupt objects this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSPlatform.Instance.Constants.DotGVFSRoot), GVFSConstants.DotGVFS.CorruptObjectsName, copySubFolders: false); // service this.CopyAllFiles( GVFSPlatform.Instance.GetDataRootForGVFS(), archiveFolderPath, this.ServiceName, copySubFolders: true); if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSUpgrade) { // upgrader this.CopyAllFiles( ProductUpgraderInfo.GetUpgradesDirectoryPath(), archiveFolderPath, DeprecatedUpgradeLogsDirectory, copySubFolders: true, targetFolderName: Path.Combine(ProductUpgraderInfo.UpgradeDirectoryName, DeprecatedUpgradeLogsDirectory)); this.CopyAllFiles( ProductUpgraderInfo.GetUpgradesDirectoryPath(), archiveFolderPath, ProductUpgraderInfo.LogDirectory, copySubFolders: true, targetFolderName: Path.Combine(ProductUpgraderInfo.UpgradeDirectoryName, ProductUpgraderInfo.LogDirectory)); this.LogDirectoryEnumeration( ProductUpgraderInfo.GetUpgradesDirectoryPath(), Path.Combine(archiveFolderPath, ProductUpgraderInfo.UpgradeDirectoryName), ProductUpgraderInfo.DownloadDirectory, "downloaded-assets.txt"); } if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSConfig) { this.CopyFile(GVFSPlatform.Instance.GetDataRootForGVFS(), archiveFolderPath, LocalGVFSConfig.FileName); } return(true); }, "Copying logs"); this.ShowStatusWhileRunning( () => this.RunAndRecordGVFSVerb <MountVerb>(archiveFolderPath, "gvfs_mount.txt") == ReturnCode.Success, "Mounting", suppressGvfsLogMessage: true); this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSPlatform.Instance.Constants.DotGVFSRoot), "logs", copySubFolders: false); } string zipFilePath = archiveFolderPath + ".zip"; this.ShowStatusWhileRunning( () => { ZipFile.CreateFromDirectory(archiveFolderPath, zipFilePath); this.fileSystem.DeleteDirectory(archiveFolderPath); return(true); }, "Creating zip file", suppressGvfsLogMessage: true); this.Output.WriteLine(); this.Output.WriteLine("Diagnostics complete. All of the gathered info, as well as all of the output above, is captured in"); this.Output.WriteLine(zipFilePath); }
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 = InstallManifest.WindowsPlatformKey; 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 installerPath = Path.Combine(this.ExtractedInstallerPath, ContentDirectoryName, entry.InstallerRelativePath); string args = entry.Args ?? string.Empty; // Replace tokens on args string processedArgs = NuGetUpgrader.ReplaceArgTokens(args, this.UpgradeInstanceId, ProductUpgraderInfo.GetLogDirectoryPath()); activity.RelatedInfo( "Running install action: Name: {0}, Version: {1}, InstallerPath: {2} RawArgs: {3}, ProcessedArgs: {4}", entry.Name, entry.Version, installerPath, args, processedArgs); string progressMessage = string.IsNullOrWhiteSpace(entry.Version) ? $"Running {entry.Name}" : $"Running {entry.Name} (version {entry.Version})"; installActionWrapper( () => { if (!this.dryRun) { 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) { 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); } } }
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.Confirmed && !isInstallable) { this.ReportInfoToConsole($"Cannot upgrade GVFS on this machine."); this.Output.WriteLine(errorOutputFormat, cannotInstallReason); this.tracer.RelatedError($"{nameof(this.TryRunProductUpgrade)}: Upgrade is not installable. {cannotInstallReason}"); return(false); } if (!this.upgrader.UpgradeAllowed(out message)) { ProductUpgraderInfo.DeleteAllInstallerDownloads(); 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.DeleteAllInstallerDownloads(); this.ReportInfoToConsole(message); return(true); } if (this.Confirmed) { this.ReportInfoToConsole(message); if (!isInstallable) { this.tracer.RelatedError($"{nameof(this.TryRunProductUpgrade)}: {message}"); this.Output.WriteLine(errorOutputFormat, message); 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, GVFSConstants.UpgradeVerbMessages.UpgradeInstallAdvice); this.ReportInfoToConsole(message + Environment.NewLine + Environment.NewLine + advisoryMessage + Environment.NewLine); } return(true); }
public void TearDown() { this.mockFileSystem = null; this.productUpgraderInfo = null; this.tracer = null; }