in GVFS/GVFS/CommandLine/RepairVerb.cs [37:221]
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();
}
}
}