示例#1
0
        private GVFSEnlistment CreateEnlistment(string enlistmentRootPath)
        {
            string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath();

            if (string.IsNullOrWhiteSpace(gitBinPath))
            {
                this.ReportErrorAndExit("Error: " + GVFSConstants.GitIsNotInstalledError);
            }

            GVFSEnlistment enlistment = null;

            try
            {
                enlistment = GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, gitBinPath, ProcessHelper.GetCurrentProcessLocation(), authentication: null);
                if (enlistment == null)
                {
                    this.ReportErrorAndExit(
                        "Error: '{0}' is not a valid GVFS enlistment",
                        enlistmentRootPath);
                }
            }
            catch (InvalidRepoException e)
            {
                this.ReportErrorAndExit(
                    "Error: '{0}' is not a valid GVFS enlistment. {1}",
                    enlistmentRootPath,
                    e.Message);
            }

            return(enlistment);
        }
示例#2
0
        private GVFSEnlistment CreateEnlistment(string enlistmentRootPath)
        {
            string gitBinPath = GitProcess.GetInstalledGitBinPath();
            string hooksPath  = ProcessHelper.WhereDirectory(GVFSConstants.GVFSHooksExecutableName);

            return(GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, gitBinPath, hooksPath));
        }
示例#3
0
        private GVFSEnlistment CreateEnlistment(string enlistmentRootPath)
        {
            string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath();
            string hooksPath  = ProcessHelper.GetProgramLocation(GVFSPlatform.Instance.Constants.ProgramLocaterCommand, GVFSPlatform.Instance.Constants.GVFSHooksExecutableName);

            return(GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, gitBinPath, hooksPath, authentication: null));
        }
示例#4
0
        private bool IsValidRepo(string repoRoot)
        {
            WindowsGitInstallation windowsGitInstallation = new WindowsGitInstallation();
            string         gitBinPath = windowsGitInstallation.GetInstalledGitBinPath();
            string         hooksPath  = ProcessHelper.WhereDirectory(GVFSPlatform.Instance.Constants.GVFSHooksExecutableName);
            GVFSEnlistment enlistment = null;

            try
            {
                enlistment = GVFSEnlistment.CreateFromDirectory(repoRoot, gitBinPath, hooksPath, authentication: null);
            }
            catch (InvalidRepoException e)
            {
                EventMetadata metadata = new EventMetadata();
                metadata.Add(nameof(repoRoot), repoRoot);
                metadata.Add(nameof(gitBinPath), gitBinPath);
                metadata.Add(nameof(hooksPath), hooksPath);
                metadata.Add("Exception", e.ToString());
                this.tracer.RelatedInfo(metadata, $"{nameof(this.IsValidRepo)}: Found invalid repo");

                return(false);
            }

            return(true);
        }
示例#5
0
        protected bool TrySetGitConfig(ITracer tracer, string enlistmentRoot, Dictionary <string, string> configSettings)
        {
            GVFSEnlistment enlistment;

            try
            {
                enlistment = GVFSEnlistment.CreateFromDirectory(
                    enlistmentRoot,
                    GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath(),
                    authentication: null);
            }
            catch (InvalidRepoException e)
            {
                EventMetadata metadata = new EventMetadata();
                metadata.Add("Exception", e.ToString());
                metadata.Add(nameof(enlistmentRoot), enlistmentRoot);
                tracer.RelatedError(metadata, $"{nameof(this.TrySetGitConfig)}: Failed to create GVFSEnlistment from directory");
                return(false);
            }

            GitProcess git = enlistment.CreateGitProcess();

            foreach (string key in configSettings.Keys)
            {
                GitProcess.Result result = git.SetInLocalConfig(key, configSettings[key]);
                if (result.ExitCodeIsFailure)
                {
                    tracer.RelatedError("Could not set git config setting {0}. Error: {1}", key, result.Errors);
                    return(false);
                }
            }

            return(true);
        }
示例#6
0
        private bool IsValidRepo(string repoRoot)
        {
            string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath();

            string hooksVersion = null;
            string error        = null;

            if (GVFSPlatform.Instance.TryGetGVFSHooksVersion(out hooksVersion, out error))
            {
                try
                {
                    GVFSEnlistment enlistment = GVFSEnlistment.CreateFromDirectory(
                        repoRoot,
                        gitBinPath,
                        authentication: null);
                }
                catch (InvalidRepoException e)
                {
                    EventMetadata metadata = new EventMetadata();
                    metadata.Add(nameof(repoRoot), repoRoot);
                    metadata.Add(nameof(gitBinPath), gitBinPath);
                    metadata.Add("Exception", e.ToString());
                    this.tracer.RelatedInfo(metadata, $"{nameof(this.IsValidRepo)}: Found invalid repo");

                    return(false);
                }
            }
            else
            {
                this.tracer.RelatedError($"{nameof(this.IsValidRepo)}: {nameof(GVFSPlatform.Instance.TryGetGVFSHooksVersion)} failed. {error}");
                return(false);
            }

            return(true);
        }
示例#7
0
            private GVFSEnlistment CreateEnlistment(string enlistmentRootPath, GitAuthentication authentication)
            {
                string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath();

                if (string.IsNullOrWhiteSpace(gitBinPath))
                {
                    this.ReportErrorAndExit("Error: " + GVFSConstants.GitIsNotInstalledError);
                }

                GVFSEnlistment enlistment = null;

                try
                {
                    enlistment = GVFSEnlistment.CreateFromDirectory(
                        enlistmentRootPath,
                        gitBinPath,
                        authentication,
                        createWithoutRepoURL: !this.validateOriginURL);
                }
                catch (InvalidRepoException e)
                {
                    this.ReportErrorAndExit(
                        "Error: '{0}' is not a valid GVFS enlistment. {1}",
                        enlistmentRootPath,
                        e.Message);
                }

                return(enlistment);
            }
示例#8
0
        private GVFSEnlistment CreateEnlistment(string enlistmentRootPath)
        {
            GVFSPlatform.Register(new WindowsPlatform());
            string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath();
            string hooksPath  = ProcessHelper.WhereDirectory(GVFSConstants.GVFSHooksExecutableName);

            return(GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, gitBinPath, hooksPath));
        }
        public override IssueType HasIssue(List <string> messages)
        {
            GitProcess git = new GitProcess(this.Enlistment);

            GitProcess.Result result = git.GetOriginUrl();
            if (result.HasErrors)
            {
                if (result.Errors.Length == 0)
                {
                    messages.Add("Remote 'origin' is not configured for this repo. You can fix this by running 'git remote add origin <repourl>'");
                    return(IssueType.CantFix);
                }
                else if (result.Errors.Contains("--local"))
                {
                    // example error: '--local can only be used inside a git repository'
                    // Corrupting the git config does not cause git to not recognize the current folder as "not a git repository".
                    // This is a symptom of deeper issues such as missing HEAD file or refs folders.
                    messages.Add("An issue was found that may be a side-effect of other issues. Fix them with 'gvfs repair --confirm' then 'gvfs repair' again.");
                    return(IssueType.CantFix);
                }

                messages.Add("Could not read origin url: " + result.Errors);
                return(IssueType.Fixable);
            }

            // At this point, we've confirmed that the repo url can be gotten, so we have to
            // reinitialize the GitProcess with a valid repo url for 'git credential fill'
            string repoUrl = null;

            try
            {
                GVFSEnlistment enlistment = GVFSEnlistment.CreateFromDirectory(
                    this.Enlistment.EnlistmentRoot,
                    this.Enlistment.GitBinPath,
                    this.Enlistment.GVFSHooksRoot);
                git     = new GitProcess(enlistment);
                repoUrl = enlistment.RepoUrl;
            }
            catch (InvalidRepoException)
            {
                messages.Add("An issue was found that may be a side-effect of other issues. Fix them with 'gvfs repair --confirm' then 'gvfs repair' again.");
                return(IssueType.CantFix);
            }

            string username;
            string password;

            if (!git.TryGetCredentials(this.Tracer, repoUrl, out username, out password))
            {
                messages.Add("Authentication failed. Run 'gvfs log' for more info.");
                messages.Add(".git\\config is valid and remote 'origin' is set, but may have a typo:");
                messages.Add(result.Output.Trim());
                return(IssueType.CantFix);
            }

            return(IssueType.None);
        }
示例#10
0
            private GVFSEnlistment CreateEnlistment(string enlistmentRootPath, GitAuthentication authentication)
            {
                string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath();

                if (string.IsNullOrWhiteSpace(gitBinPath))
                {
                    this.ReportErrorAndExit("Error: " + GVFSConstants.GitIsNotInstalledError);
                }

                string hooksPath = null;

                if (GVFSPlatform.Instance.UnderConstruction.RequiresDeprecatedGitHooksLoader)
                {
                    // On Windows, the soon-to-be deprecated GitHooksLoader tries to call out to the hooks process without
                    // its full path, so we have to pass the path along to our background git processes via the PATH
                    // environment variable. On Mac this is not needed because we just copy our own hook directly into
                    // the .git/hooks folder, and once Windows does the same, this hooksPath can be removed (from here
                    // and all the classes that handle it on the way to GitProcess)

                    hooksPath = ProcessHelper.WhereDirectory(GVFSPlatform.Instance.Constants.GVFSHooksExecutableName);
                    if (hooksPath == null)
                    {
                        this.ReportErrorAndExit("Could not find " + GVFSPlatform.Instance.Constants.GVFSHooksExecutableName);
                    }
                }

                GVFSEnlistment enlistment = null;

                try
                {
                    if (this.validateOriginURL)
                    {
                        enlistment = GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, gitBinPath, hooksPath, authentication);
                    }
                    else
                    {
                        enlistment = GVFSEnlistment.CreateWithoutRepoUrlFromDirectory(enlistmentRootPath, gitBinPath, hooksPath, authentication);
                    }

                    if (enlistment == null)
                    {
                        this.ReportErrorAndExit(
                            "Error: '{0}' is not a valid GVFS enlistment",
                            enlistmentRootPath);
                    }
                }
                catch (InvalidRepoException e)
                {
                    this.ReportErrorAndExit(
                        "Error: '{0}' is not a valid GVFS enlistment. {1}",
                        enlistmentRootPath,
                        e.Message);
                }

                return(enlistment);
            }
示例#11
0
        public override IssueType HasIssue(List <string> messages)
        {
            GitProcess git = new GitProcess(this.Enlistment);

            GitProcess.ConfigResult originResult = git.GetOriginUrl();
            string error;
            string originUrl;

            if (!originResult.TryParseAsString(out originUrl, out error))
            {
                if (error.Contains("--local"))
                {
                    // example error: '--local can only be used inside a git repository'
                    // Corrupting the git config does not cause git to not recognize the current folder as "not a git repository".
                    // This is a symptom of deeper issues such as missing HEAD file or refs folders.
                    messages.Add("An issue was found that may be a side-effect of other issues. Fix them with 'gvfs repair --confirm' then 'gvfs repair' again.");
                    return(IssueType.CantFix);
                }

                messages.Add("Could not read origin url: " + error);
                return(IssueType.Fixable);
            }

            if (originUrl == null)
            {
                messages.Add("Remote 'origin' is not configured for this repo. You can fix this by running 'git remote add origin <repourl>'");
                return(IssueType.CantFix);
            }

            // We've validated the repo URL, so now make sure we can authenticate
            try
            {
                GVFSEnlistment enlistment = GVFSEnlistment.CreateFromDirectory(
                    this.Enlistment.EnlistmentRoot,
                    this.Enlistment.GitBinPath,
                    this.Enlistment.GVFSHooksRoot,
                    authentication: null);

                string authError;
                if (!enlistment.Authentication.TryInitialize(this.Tracer, enlistment, out authError))
                {
                    messages.Add("Authentication failed. Run 'gvfs log' for more info.");
                    messages.Add(".git\\config is valid and remote 'origin' is set, but may have a typo:");
                    messages.Add(originUrl.Trim());
                    return(IssueType.CantFix);
                }
            }
            catch (InvalidRepoException)
            {
                messages.Add("An issue was found that may be a side-effect of other issues. Fix them with 'gvfs repair --confirm' then 'gvfs repair' again.");
                return(IssueType.CantFix);
            }

            return(IssueType.None);
        }
示例#12
0
            private GVFSEnlistment CreateEnlistment(string enlistmentRootPath)
            {
                string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath();

                if (string.IsNullOrWhiteSpace(gitBinPath))
                {
                    this.ReportErrorAndExit("Error: " + GVFSConstants.GitIsNotInstalledError);
                }

                string hooksPath;

                if (GVFSPlatform.Instance.IsUnderConstruction)
                {
                    hooksPath = "hooksUnderConstruction";
                }
                else
                {
                    hooksPath = ProcessHelper.WhereDirectory(GVFSPlatform.Instance.Constants.GVFSHooksExecutableName);
                    if (hooksPath == null)
                    {
                        this.ReportErrorAndExit("Could not find " + GVFSPlatform.Instance.Constants.GVFSHooksExecutableName);
                    }
                }

                GVFSEnlistment enlistment = null;

                try
                {
                    if (this.validateOriginURL)
                    {
                        enlistment = GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, gitBinPath, hooksPath);
                    }
                    else
                    {
                        enlistment = GVFSEnlistment.CreateWithoutRepoUrlFromDirectory(enlistmentRootPath, gitBinPath, hooksPath);
                    }

                    if (enlistment == null)
                    {
                        this.ReportErrorAndExit(
                            "Error: '{0}' is not a valid GVFS enlistment",
                            enlistmentRootPath);
                    }
                }
                catch (InvalidRepoException e)
                {
                    this.ReportErrorAndExit(
                        "Error: '{0}' is not a valid GVFS enlistment. {1}",
                        enlistmentRootPath,
                        e.Message);
                }

                return(enlistment);
            }
示例#13
0
        private GVFSEnlistment CreateEnlistment(string enlistmentRootPath)
        {
            string gitBinPath = GitProcess.GetInstalledGitBinPath();

            if (string.IsNullOrWhiteSpace(gitBinPath))
            {
                this.ReportErrorAndExit("Error: " + GVFSConstants.GitIsNotInstalledError);
            }

            if (string.IsNullOrWhiteSpace(enlistmentRootPath))
            {
                enlistmentRootPath = Environment.CurrentDirectory;
            }

            string hooksPath = ProcessHelper.WhereDirectory(GVFSConstants.GVFSHooksExecutableName);

            if (hooksPath == null)
            {
                this.ReportErrorAndExit("Could not find " + GVFSConstants.GVFSHooksExecutableName);
            }

            GVFSEnlistment enlistment = null;

            try
            {
                enlistment = GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, null, gitBinPath, hooksPath);
                if (enlistment == null)
                {
                    this.ReportErrorAndExit(
                        "Error: '{0}' is not a valid GVFS enlistment",
                        enlistmentRootPath);
                }
            }
            catch (InvalidRepoException e)
            {
                this.ReportErrorAndExit(
                    "Error: '{0}' is not a valid GVFS enlistment. {1}",
                    enlistmentRootPath,
                    e.Message);
            }

            return(enlistment);
        }
示例#14
0
        private bool IsValidRepo(string repoRoot)
        {
            string         gitBinPath = GitProcess.GetInstalledGitBinPath();
            string         hooksPath  = ProcessHelper.WhereDirectory(GVFSConstants.GVFSHooksExecutableName);
            GVFSEnlistment enlistment = null;

            try
            {
                enlistment = GVFSEnlistment.CreateFromDirectory(repoRoot, gitBinPath, hooksPath);
            }
            catch (InvalidRepoException)
            {
                return(false);
            }

            if (enlistment == null)
            {
                return(false);
            }

            return(true);
        }
示例#15
0
        protected bool TrySetGitConfig(ITracer tracer, string enlistmentRoot, Dictionary <string, string> configSettings, out string errorMessage)
        {
            errorMessage = null;

            GVFSEnlistment enlistment = GVFSEnlistment.CreateFromDirectory(
                enlistmentRoot,
                GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath(),
                ProcessHelper.GetCurrentProcessLocation());
            GitProcess git = enlistment.CreateGitProcess();

            foreach (string key in configSettings.Keys)
            {
                GitProcess.Result result = git.SetInLocalConfig(key, configSettings[key]);
                if (result.HasErrors)
                {
                    tracer.RelatedError("Could not set git config setting {0}. Error: {1}", key, result.Errors);
                    return(false);
                }
            }

            return(true);
        }
示例#16
0
        private bool IsValidRepo(string repoRoot)
        {
            string         gitBinPath = GitProcess.GetInstalledGitBinPath();
            string         hooksPath  = this.GetGVFSHooksPathAndCheckVersion(tracer: null);
            GVFSEnlistment enlistment = null;

            try
            {
                enlistment = GVFSEnlistment.CreateFromDirectory(repoRoot, gitBinPath, hooksPath);
            }
            catch (InvalidRepoException)
            {
                return(false);
            }

            if (enlistment == null)
            {
                return(false);
            }

            return(true);
        }
示例#17
0
        private bool IsValidRepo(string repoRoot)
        {
            WindowsGitInstallation windowsGitInstallation = new WindowsGitInstallation();
            string         gitBinPath = windowsGitInstallation.GetInstalledGitBinPath();
            string         hooksPath  = ProcessHelper.WhereDirectory(GVFSPlatform.Instance.Constants.GVFSHooksExecutableName);
            GVFSEnlistment enlistment = null;

            try
            {
                enlistment = GVFSEnlistment.CreateFromDirectory(repoRoot, gitBinPath, hooksPath, authentication: null);
            }
            catch (InvalidRepoException)
            {
                return(false);
            }

            if (enlistment == null)
            {
                return(false);
            }

            return(true);
        }
示例#18
0
        private GVFSEnlistment CreateEnlistment(string enlistmentRootPath)
        {
            string gitBinPath = GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath();

            return(GVFSEnlistment.CreateFromDirectory(enlistmentRootPath, gitBinPath, authentication: null));
        }
示例#19
0
        public override void Execute()
        {
            this.ValidatePathParameter(this.EnlistmentRootPathParameter);

            this.CheckGVFSHooksVersion(tracer: null, hooksVersion: out _);

            if (!Directory.Exists(this.EnlistmentRootPathParameter))
            {
                this.ReportErrorAndExit($"Path '{this.EnlistmentRootPathParameter}' does not exist");
            }

            string errorMessage;
            string enlistmentRoot;

            if (!GVFSPlatform.Instance.TryGetGVFSEnlistmentRoot(this.EnlistmentRootPathParameter, out enlistmentRoot, out errorMessage))
            {
                this.ReportErrorAndExit("'gvfs repair' must be run within a GVFS enlistment");
            }

            GVFSEnlistment enlistment = null;

            try
            {
                enlistment = GVFSEnlistment.CreateFromDirectory(
                    this.EnlistmentRootPathParameter,
                    GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath(),
                    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 GVFS 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 GVFS is not mounted",
                    this.Output,
                    showSpinner: true,
                    gvfsLogEnlistmentRoot: null))
            {
                this.ReportErrorAndExit("You can only run 'gvfs repair' if GVFS is not mounted. Run 'gvfs unmount' and try again.");
            }

            this.Output.WriteLine();

            using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "RepairVerb", enlistment.GetEnlistmentId(), mountId: null))
            {
                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Repair),
                    EventLevel.Verbose,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    "N/A",
                    new EventMetadata
                {
                    { "Confirmed", this.Confirmed },
                    { "IsElevated", GVFSPlatform.Instance.IsElevated() },
                    { "NamedPipename", enlistment.NamedPipeName },
                    { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
                });

                List <RepairJob> jobs = new List <RepairJob>();

                // Repair databases
                jobs.Add(new BackgroundOperationDatabaseRepairJob(tracer, this.Output, enlistment));
                jobs.Add(new RepoMetadataDatabaseRepairJob(tracer, this.Output, enlistment));
                jobs.Add(new VFSForGitDatabaseRepairJob(tracer, this.Output, enlistment));
                jobs.Add(new BlobSizeDatabaseRepairJob(tracer, this.Output, enlistment));

                // Repair .git folder files
                jobs.Add(new GitHeadRepairJob(tracer, this.Output, enlistment));
                jobs.Add(new GitIndexRepairJob(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.GetGVFSLogMessage(enlistment.EnlistmentRoot));
                            break;
                        }

                        this.WriteMessages(tracer, repairMessages);
                    }
                    else
                    {
                        this.WriteMessage(tracer, "Run 'gvfs repair --confirm' to attempt a repair");
                    }

                    this.Output.WriteLine();
                }
            }
        }