private bool TryInitializeUpgrader(out string error) { if (this.DryRun && this.Confirmed) { error = $"{DryRunOption} and {ConfirmOption} arguments are not compatible."; return(false); } if (GSDPlatform.Instance.UnderConstruction.SupportsGSDUpgrade) { error = null; if (this.upgrader == null) { this.productUpgraderPlatformStrategy = GSDPlatform.Instance.CreateProductUpgraderPlatformInteractions(this.fileSystem, tracer: null); if (!this.productUpgraderPlatformStrategy.TryPrepareLogDirectory(out error)) { return(false); } JsonTracer jsonTracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "UpgradeVerb"); string logFilePath = GSDEnlistment.GetNewGSDLogFileName( ProductUpgraderInfo.GetLogDirectoryPath(), GSDConstants.LogFileTypes.UpgradeVerb); jsonTracer.AddLogFileEventListener(logFilePath, EventLevel.Informational, Keywords.Any); this.tracer = jsonTracer; this.prerunChecker = new InstallerPreRunChecker(this.tracer, this.Confirmed ? GSDConstants.UpgradeVerbMessages.GSDUpgradeConfirm : GSDConstants.UpgradeVerbMessages.GSDUpgrade); string gitBinPath = GSDPlatform.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, gvfsHooksRoot: null); ProductUpgrader upgrader; if (ProductUpgrader.TryCreateUpgrader(this.tracer, this.fileSystem, new LocalGSDConfig(), credentialStore, this.DryRun, this.NoVerify, out upgrader, out error)) { this.upgrader = upgrader; } else { error = $"ERROR: {error}"; } } return(this.upgrader != null); } else { error = $"ERROR: {GSDConstants.UpgradeVerbMessages.GSDUpgrade} is not supported on this operating system."; return(false); } }
private static void StartLogFile(string enlistmentRoot, JsonTracer tracer) { if (!tracer.HasLogFileEventListener) { tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName( Path.Combine(enlistmentRoot, GSDPlatform.Instance.Constants.DotGSDRoot, GSDConstants.DotGSD.LogName), GSDConstants.LogFileTypes.MountUpgrade), EventLevel.Informational, Keywords.Any); tracer.WriteStartEvent(enlistmentRoot, repoUrl: "N/A", cacheServerUrl: "N/A"); } }
private JsonTracer CreateTracer(GSDEnlistment enlistment, EventLevel verbosity, Keywords keywords) { JsonTracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "GSDMount", enlistment.GetEnlistmentId(), enlistment.GetMountId()); tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName(enlistment.GSDLogsRoot, GSDConstants.LogFileTypes.MountProcess), verbosity, keywords); if (this.ShowDebugWindow) { tracer.AddDiagnosticConsoleEventListener(verbosity, keywords); } return(tracer); }
private JsonTracer CreateTracer() { string logFilePath = GSDEnlistment.GetNewGSDLogFileName( this.logDirectory, GSDConstants.LogFileTypes.UpgradeProcess, this.fileSystem); JsonTracer jsonTracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "UpgradeProcess"); jsonTracer.AddLogFileEventListener( logFilePath, DefaultEventLevel, Keywords.Any); return(jsonTracer); }
protected override void OnStart(string[] args) { if (this.serviceThread != null) { throw new InvalidOperationException("Cannot start service twice in a row."); } // TODO: 865304 Used for functional tests and development only. Replace with a smarter appConfig-based solution string serviceName = args.FirstOrDefault(arg => arg.StartsWith(ServiceNameArgPrefix)); if (serviceName != null) { this.serviceName = serviceName.Substring(ServiceNameArgPrefix.Length); } string serviceLogsDirectoryPath = Path.Combine( GSDPlatform.Instance.GetDataRootForGSDComponent(this.serviceName), GSDConstants.Service.LogDirectory); // Create the logs directory explicitly *before* creating a log file event listener to ensure that it // and its ancestor directories are created with the correct ACLs. this.CreateServiceLogsDirectory(serviceLogsDirectoryPath); this.tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName(serviceLogsDirectoryPath, GSDConstants.LogFileTypes.Service), EventLevel.Verbose, Keywords.Any); try { this.serviceDataLocation = GSDPlatform.Instance.GetDataRootForGSDComponent(this.serviceName); this.CreateAndConfigureProgramDataDirectories(); this.Start(); } catch (Exception e) { this.LogExceptionAndExit(e, nameof(this.OnStart)); } }
private static GSDService CreateService(JsonTracer tracer, string[] args) { string serviceName = args.FirstOrDefault(arg => arg.StartsWith(GSDService.ServiceNameArgPrefix, StringComparison.OrdinalIgnoreCase)); if (serviceName != null) { serviceName = serviceName.Substring(GSDService.ServiceNameArgPrefix.Length); } else { serviceName = GSDConstants.Service.ServiceName; } GSDPlatform gvfsPlatform = GSDPlatform.Instance; string logFilePath = Path.Combine( gvfsPlatform.GetDataRootForGSDComponent(serviceName), GSDConstants.Service.LogDirectory); Directory.CreateDirectory(logFilePath); tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName(logFilePath, GSDConstants.LogFileTypes.Service), EventLevel.Informational, Keywords.Any); string serviceDataLocation = gvfsPlatform.GetDataRootForGSDComponent(serviceName); RepoRegistry repoRegistry = new RepoRegistry( tracer, new PhysicalFileSystem(), serviceDataLocation, new GSDMountProcess(tracer), new NotificationHandler(tracer)); return(new GSDService(tracer, serviceName, repoRegistry)); }
protected override void Execute(GSDEnlistment enlistment) { using (JsonTracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "Prefetch")) { if (this.Verbose) { tracer.AddDiagnosticConsoleEventListener(EventLevel.Informational, Keywords.Any); } string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment); tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName(enlistment.GSDLogsRoot, GSDConstants.LogFileTypes.Prefetch), EventLevel.Informational, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cacheServerUrl); try { EventMetadata metadata = new EventMetadata(); metadata.Add("Commits", this.Commits); metadata.Add("Files", this.Files); metadata.Add("Folders", this.Folders); metadata.Add("FileListFile", this.FilesListFile); metadata.Add("FoldersListFile", this.FoldersListFile); metadata.Add("FilesFromStdIn", this.FilesFromStdIn); metadata.Add("FoldersFromStdIn", this.FoldersFromStdIn); metadata.Add("HydrateFiles", this.HydrateFiles); tracer.RelatedEvent(EventLevel.Informational, "PerformPrefetch", metadata); if (this.Commits) { if (!string.IsNullOrWhiteSpace(this.Files) || !string.IsNullOrWhiteSpace(this.Folders) || !string.IsNullOrWhiteSpace(this.FoldersListFile) || !string.IsNullOrWhiteSpace(this.FilesListFile) || this.FilesFromStdIn || this.FoldersFromStdIn) { this.ReportErrorAndExit(tracer, "You cannot prefetch commits and blobs at the same time."); } if (this.HydrateFiles) { this.ReportErrorAndExit(tracer, "You can only specify --hydrate with --files or --folders"); } GitObjectsHttpRequestor objectRequestor; CacheServerInfo cacheServer; this.InitializeServerConnection( tracer, enlistment, cacheServerUrl, out objectRequestor, out cacheServer); this.PrefetchCommits(tracer, enlistment, objectRequestor, cacheServer); } else { string headCommitId; List <string> filesList; List <string> foldersList; FileBasedDictionary <string, string> lastPrefetchArgs; this.LoadBlobPrefetchArgs(tracer, enlistment, out headCommitId, out filesList, out foldersList, out lastPrefetchArgs); if (BlobPrefetcher.IsNoopPrefetch(tracer, lastPrefetchArgs, headCommitId, filesList, foldersList, this.HydrateFiles)) { Console.WriteLine("All requested files are already available. Nothing new to prefetch."); } else { GitObjectsHttpRequestor objectRequestor; CacheServerInfo cacheServer; this.InitializeServerConnection( tracer, enlistment, cacheServerUrl, out objectRequestor, out cacheServer); this.PrefetchBlobs(tracer, enlistment, headCommitId, filesList, foldersList, lastPrefetchArgs, objectRequestor, cacheServer); } } } catch (VerbAbortedException) { throw; } catch (AggregateException aggregateException) { this.Output.WriteLine( "Cannot prefetch {0}. " + ConsoleHelper.GetGSDLogMessage(enlistment.EnlistmentRoot), enlistment.EnlistmentRoot); foreach (Exception innerException in aggregateException.Flatten().InnerExceptions) { tracer.RelatedError( new EventMetadata { { "Verb", typeof(PrefetchVerb).Name }, { "Exception", innerException.ToString() } }, $"Unhandled {innerException.GetType().Name}: {innerException.Message}"); } Environment.ExitCode = (int)ReturnCode.GenericError; } catch (Exception e) { this.Output.WriteLine( "Cannot prefetch {0}. " + ConsoleHelper.GetGSDLogMessage(enlistment.EnlistmentRoot), enlistment.EnlistmentRoot); tracer.RelatedError( new EventMetadata { { "Verb", typeof(PrefetchVerb).Name }, { "Exception", e.ToString() } }, $"Unhandled {e.GetType().Name}: {e.Message}"); Environment.ExitCode = (int)ReturnCode.GenericError; } } }
protected override void Execute(GSDEnlistment enlistment) { string errorMessage = null; string mountExecutableLocation = null; using (JsonTracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "ExecuteMount")) { PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem); GSDContext context = new GSDContext(tracer, fileSystem, gitRepo, enlistment); if (!HooksInstaller.InstallHooks(context, out errorMessage)) { this.ReportErrorAndExit("Error installing hooks: " + errorMessage); } CacheServerInfo cacheServer = this.ResolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment); tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName(enlistment.GSDLogsRoot, GSDConstants.LogFileTypes.MountVerb), EventLevel.Verbose, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cacheServer.Url, new EventMetadata { { "Unattended", this.Unattended }, { "IsElevated", GSDPlatform.Instance.IsElevated() }, { "NamedPipeName", enlistment.NamedPipeName }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, }); RetryConfig retryConfig = null; ServerGSDConfig serverGSDConfig = this.DownloadedGSDConfig; if (!this.SkipVersionCheck) { string authErrorMessage; if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage)) { this.Output.WriteLine(" WARNING: " + authErrorMessage); this.Output.WriteLine(" Mount will proceed, but new files cannot be accessed until GSD can authenticate."); } if (serverGSDConfig == null) { if (retryConfig == null) { retryConfig = this.GetRetryConfig(tracer, enlistment); } serverGSDConfig = this.QueryGSDConfig(tracer, enlistment, retryConfig); } this.ValidateClientVersions(tracer, enlistment, serverGSDConfig, showWarnings: true); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, serverGSDConfig); this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGSDConfig, cacheServer); if (!this.ShowStatusWhileRunning( () => { return(this.PerformPreMountValidation(tracer, enlistment, out mountExecutableLocation, out errorMessage)); }, "Validating repo")) { this.ReportErrorAndExit(tracer, errorMessage); } if (!this.SkipVersionCheck) { string error; if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGSDRoot, out error)) { this.ReportErrorAndExit(tracer, error); } try { GitProcess git = new GitProcess(enlistment); this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment); } finally { RepoMetadata.Shutdown(); } } if (!this.ShowStatusWhileRunning( () => { return(this.TryMount(tracer, enlistment, mountExecutableLocation, out errorMessage)); }, "Mounting")) { this.ReportErrorAndExit(tracer, errorMessage); } if (!this.Unattended) { tracer.RelatedInfo($"{nameof(this.Execute)}: Registering for automount"); if (this.ShowStatusWhileRunning( () => { return(this.RegisterMount(enlistment, out errorMessage)); }, "Registering for automount")) { tracer.RelatedInfo($"{nameof(this.Execute)}: Registered for automount"); } else { this.Output.WriteLine(" WARNING: " + errorMessage); tracer.RelatedInfo($"{nameof(this.Execute)}: Failed to register for automount"); } } } }
public override void Execute() { int exitCode = 0; this.ValidatePathParameter(this.EnlistmentRootPathParameter); this.ValidatePathParameter(this.LocalCacheRoot); string fullEnlistmentRootPathParameter; string normalizedEnlistmentRootPath = this.GetCloneRoot(out fullEnlistmentRootPathParameter); if (!string.IsNullOrWhiteSpace(this.LocalCacheRoot)) { string fullLocalCacheRootPath = Path.GetFullPath(this.LocalCacheRoot); string errorMessage; string normalizedLocalCacheRootPath; if (!GSDPlatform.Instance.FileSystem.TryGetNormalizedPath(fullLocalCacheRootPath, out normalizedLocalCacheRootPath, out errorMessage)) { this.ReportErrorAndExit($"Failed to determine normalized path for '--local-cache-path' path {fullLocalCacheRootPath}: {errorMessage}"); } if (normalizedLocalCacheRootPath.StartsWith( Path.Combine(normalizedEnlistmentRootPath, GSDConstants.WorkingDirectoryRootName), StringComparison.OrdinalIgnoreCase)) { this.ReportErrorAndExit("'--local-cache-path' cannot be inside the src folder"); } } this.CheckNotInsideExistingRepo(normalizedEnlistmentRootPath); this.BlockEmptyCacheServerUrl(this.CacheServerUrl); try { GSDEnlistment enlistment; Result cloneResult = new Result(false); CacheServerInfo cacheServer = null; ServerGSDConfig serverGSDConfig = null; using (JsonTracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "GSDClone")) { cloneResult = this.TryCreateEnlistment(fullEnlistmentRootPathParameter, normalizedEnlistmentRootPath, out enlistment); if (cloneResult.Success) { tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName(enlistment.GSDLogsRoot, GSDConstants.LogFileTypes.Clone), EventLevel.Informational, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, this.CacheServerUrl, new EventMetadata { { "Branch", this.Branch }, { "LocalCacheRoot", this.LocalCacheRoot }, { "SingleBranch", this.SingleBranch }, { "NoMount", this.NoMount }, { "NoPrefetch", this.NoPrefetch }, { "Unattended", this.Unattended }, { "IsElevated", GSDPlatform.Instance.IsElevated() }, { "NamedPipeName", enlistment.NamedPipeName }, { "ProcessID", Process.GetCurrentProcess().Id }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, { nameof(fullEnlistmentRootPathParameter), fullEnlistmentRootPathParameter }, }); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheServerUrl); string resolvedLocalCacheRoot; if (string.IsNullOrWhiteSpace(this.LocalCacheRoot)) { string localCacheRootError; if (!LocalCacheResolver.TryGetDefaultLocalCacheRoot(enlistment, out resolvedLocalCacheRoot, out localCacheRootError)) { this.ReportErrorAndExit( tracer, $"Failed to determine the default location for the local GSD cache: `{localCacheRootError}`"); } } else { resolvedLocalCacheRoot = Path.GetFullPath(this.LocalCacheRoot); } this.Output.WriteLine("Clone parameters:"); this.Output.WriteLine(" Repo URL: " + enlistment.RepoUrl); this.Output.WriteLine(" Branch: " + (string.IsNullOrWhiteSpace(this.Branch) ? "Default" : this.Branch)); this.Output.WriteLine(" Cache Server: " + cacheServer); this.Output.WriteLine(" Local Cache: " + resolvedLocalCacheRoot); this.Output.WriteLine(" Destination: " + enlistment.EnlistmentRoot); string authErrorMessage; if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage)) { this.ReportErrorAndExit(tracer, "Cannot clone because authentication failed: " + authErrorMessage); } RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); serverGSDConfig = this.QueryGSDConfig(tracer, enlistment, retryConfig); cacheServer = this.ResolveCacheServer(tracer, cacheServer, cacheServerResolver, serverGSDConfig); this.ValidateClientVersions(tracer, enlistment, serverGSDConfig, showWarnings: true); this.ShowStatusWhileRunning( () => { cloneResult = this.TryClone(tracer, enlistment, cacheServer, retryConfig, serverGSDConfig, resolvedLocalCacheRoot); return(cloneResult.Success); }, "Cloning", normalizedEnlistmentRootPath); } if (!cloneResult.Success) { tracer.RelatedError(cloneResult.ErrorMessage); } } if (cloneResult.Success) { if (!this.NoPrefetch) { ReturnCode result = this.Execute <PrefetchVerb>( enlistment, verb => { verb.Commits = true; verb.SkipVersionCheck = true; verb.ResolvedCacheServer = cacheServer; verb.ServerGSDConfig = serverGSDConfig; }); if (result != ReturnCode.Success) { this.Output.WriteLine("\r\nError during prefetch @ {0}", fullEnlistmentRootPathParameter); exitCode = (int)result; } } if (this.NoMount) { this.Output.WriteLine("\r\nIn order to mount, first cd to within your enlistment, then call: "); this.Output.WriteLine("gvfs mount"); } else { this.Execute <MountVerb>( enlistment, verb => { verb.SkipMountedCheck = true; verb.SkipVersionCheck = true; verb.ResolvedCacheServer = cacheServer; verb.DownloadedGSDConfig = serverGSDConfig; }); GitProcess git = new GitProcess(enlistment); git.ForceCheckoutAllFiles(); } } else { this.Output.WriteLine("\r\nCannot clone @ {0}", fullEnlistmentRootPathParameter); this.Output.WriteLine("Error: {0}", cloneResult.ErrorMessage); exitCode = (int)ReturnCode.GenericError; } } catch (AggregateException e) { this.Output.WriteLine("Cannot clone @ {0}:", fullEnlistmentRootPathParameter); foreach (Exception ex in e.Flatten().InnerExceptions) { this.Output.WriteLine("Exception: {0}", ex.ToString()); } exitCode = (int)ReturnCode.GenericError; } catch (VerbAbortedException) { throw; } catch (Exception e) { this.ReportErrorAndExit("Cannot clone @ {0}: {1}", fullEnlistmentRootPathParameter, e.ToString()); } Environment.Exit(exitCode); }
public override void Execute() { this.ValidatePathParameter(this.EnlistmentRootPathParameter); string hooksPath = this.GetGSDHooksPathAndCheckVersion(tracer: null, hooksVersion: out _); if (!Directory.Exists(this.EnlistmentRootPathParameter)) { this.ReportErrorAndExit($"Path '{this.EnlistmentRootPathParameter}' does not exist"); } string errorMessage; string enlistmentRoot; if (!GSDPlatform.Instance.TryGetGSDEnlistmentRoot(this.EnlistmentRootPathParameter, out enlistmentRoot, out errorMessage)) { this.ReportErrorAndExit("'gvfs repair' must be run within a GSD enlistment"); } GSDEnlistment enlistment = null; try { enlistment = GSDEnlistment.CreateFromDirectory( this.EnlistmentRootPathParameter, GSDPlatform.Instance.GitInstallation.GetInstalledGitBinPath(), hooksPath, authentication: null, createWithoutRepoURL: true); } catch (InvalidRepoException e) { this.ReportErrorAndExit($"Failed to initialize enlistment, error: {e.Message}"); } if (!this.Confirmed) { this.Output.WriteLine( @"WARNING: THIS IS AN EXPERIMENTAL FEATURE This command detects and repairs issues that prevent a GSD repo from mounting. A few such checks are currently implemented, and some of them can be repaired. More repairs and more checks are coming soon. Without --confirm, it will non-invasively check if repairs are necessary. To actually execute any necessary repair(s), run 'gvfs repair --confirm' "); } string error; if (!DiskLayoutUpgrade.TryCheckDiskLayoutVersion(tracer: null, enlistmentRoot: enlistment.EnlistmentRoot, error: out error)) { this.ReportErrorAndExit(error); } if (!ConsoleHelper.ShowStatusWhileRunning( () => { // Don't use 'gvfs status' here. The repo may be corrupt such that 'gvfs status' cannot run normally, // causing repair to continue when it shouldn't. using (NamedPipeClient pipeClient = new NamedPipeClient(enlistment.NamedPipeName)) { if (!pipeClient.Connect()) { return(true); } } return(false); }, "Checking that GSD is not mounted", this.Output, showSpinner: true, gvfsLogEnlistmentRoot: null)) { this.ReportErrorAndExit("You can only run 'gvfs repair' if GSD is not mounted. Run 'gvfs unmount' and try again."); } this.Output.WriteLine(); using (JsonTracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "RepairVerb", enlistment.GetEnlistmentId(), mountId: null)) { tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName(enlistment.GSDLogsRoot, GSDConstants.LogFileTypes.Repair), EventLevel.Verbose, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, "N/A", new EventMetadata { { "Confirmed", this.Confirmed }, { "IsElevated", GSDPlatform.Instance.IsElevated() }, { "NamedPipename", enlistment.NamedPipeName }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, }); List <RepairJob> jobs = new List <RepairJob>(); // Repair databases jobs.Add(new RepoMetadataDatabaseRepairJob(tracer, this.Output, enlistment)); // Repair .git folder files jobs.Add(new GitHeadRepairJob(tracer, this.Output, enlistment)); jobs.Add(new GitConfigRepairJob(tracer, this.Output, enlistment)); Dictionary <RepairJob, List <string> > healthy = new Dictionary <RepairJob, List <string> >(); Dictionary <RepairJob, List <string> > cantFix = new Dictionary <RepairJob, List <string> >(); Dictionary <RepairJob, List <string> > fixable = new Dictionary <RepairJob, List <string> >(); foreach (RepairJob job in jobs) { List <string> messages = new List <string>(); switch (job.HasIssue(messages)) { case RepairJob.IssueType.None: healthy[job] = messages; break; case RepairJob.IssueType.CantFix: cantFix[job] = messages; break; case RepairJob.IssueType.Fixable: fixable[job] = messages; break; } } foreach (RepairJob job in healthy.Keys) { this.WriteMessage(tracer, string.Format("{0, -30}: Healthy", job.Name)); this.WriteMessages(tracer, healthy[job]); } if (healthy.Count > 0) { this.Output.WriteLine(); } foreach (RepairJob job in cantFix.Keys) { this.WriteMessage(tracer, job.Name); this.WriteMessages(tracer, cantFix[job]); this.Indent(); this.WriteMessage(tracer, "'gvfs repair' does not currently support fixing this problem"); this.Output.WriteLine(); } foreach (RepairJob job in fixable.Keys) { this.WriteMessage(tracer, job.Name); this.WriteMessages(tracer, fixable[job]); this.Indent(); if (this.Confirmed) { List <string> repairMessages = new List <string>(); switch (job.TryFixIssues(repairMessages)) { case RepairJob.FixResult.Success: this.WriteMessage(tracer, "Repair succeeded"); break; case RepairJob.FixResult.ManualStepsRequired: this.WriteMessage(tracer, "Repair succeeded, but requires some manual steps before remounting."); break; case RepairJob.FixResult.Failure: this.WriteMessage(tracer, "Repair failed. " + ConsoleHelper.GetGSDLogMessage(enlistment.EnlistmentRoot)); break; } this.WriteMessages(tracer, repairMessages); } else { this.WriteMessage(tracer, "Run 'gvfs repair --confirm' to attempt a repair"); } this.Output.WriteLine(); } } }