Example #1
0
        private bool SetConfigSettings(GitProcess git, CacheServerInfo cacheServer)
        {
            string error;

            return(CacheServerInfo.TrySaveToConfig(git, cacheServer, out error) &&
                   GVFSVerb.TrySetGitConfigSettings(git));
        }
Example #2
0
        private ReturnCode ExecuteGVFSVerb <TVerb>(ITracer tracer)
            where TVerb : GVFSVerb, new()
        {
            try
            {
                ReturnCode    returnCode;
                StringBuilder commandOutput = new StringBuilder();
                using (StringWriter writer = new StringWriter(commandOutput))
                {
                    returnCode = GVFSVerb.Execute <TVerb>(this.EnlistmentRootPath, verb => verb.Output = writer);
                }

                tracer.RelatedEvent(
                    EventLevel.Informational,
                    typeof(TVerb).Name,
                    new EventMetadata
                {
                    { "Output", commandOutput.ToString() },
                    { "ReturnCode", returnCode }
                });

                return(returnCode);
            }
            catch (Exception e)
            {
                tracer.RelatedError(
                    new EventMetadata
                {
                    { "Verb", typeof(TVerb).Name },
                    { "Exception", e.Message }
                });

                return(ReturnCode.GenericError);
            }
        }
Example #3
0
 private void SetGitConfigSettings(GitProcess git)
 {
     if (!GVFSVerb.TrySetGitConfigSettings(git))
     {
         this.ReportErrorAndExit("Unable to configure git repo");
     }
 }
Example #4
0
        private bool TryMount(GVFSEnlistment enlistment, string mountExecutableLocation, out string errorMessage)
        {
            if (!GVFSVerb.TrySetRequiredGitConfigSettings(enlistment))
            {
                errorMessage = "Unable to configure git repo";
                return(false);
            }

            const string ParamPrefix = "--";

            if (GVFSPlatform.Instance.IsUnderConstruction)
            {
                mountExecutableLocation = Path.Combine(ProcessHelper.GetCurrentProcessLocation(), "gvfs.mount");
            }

            GVFSPlatform.Instance.StartBackgroundProcess(
                mountExecutableLocation,
                new[]
            {
                enlistment.EnlistmentRoot,
                ParamPrefix + GVFSConstants.VerbParameters.Mount.Verbosity,
                this.Verbosity,
                ParamPrefix + GVFSConstants.VerbParameters.Mount.Keywords,
                this.KeywordsCsv
            });

            if (GVFSPlatform.Instance.IsUnderConstruction)
            {
                // TODO(Mac): figure out the timing issue here on connecting to the pipe
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
            }

            return(GVFSEnlistment.WaitUntilMounted(enlistment.EnlistmentRoot, this.Unattended, out errorMessage));
        }
Example #5
0
        private bool TryMount(ITracer tracer, GVFSEnlistment enlistment, string mountExecutableLocation, out string errorMessage)
        {
            if (!GVFSVerb.TrySetRequiredGitConfigSettings(enlistment))
            {
                errorMessage = "Unable to configure git repo";
                return(false);
            }

            const string ParamPrefix = "--";

            GVFSPlatform.Instance.StartBackgroundProcess(
                tracer,
                mountExecutableLocation,
                new[]
            {
                enlistment.EnlistmentRoot,
                ParamPrefix + GVFSConstants.VerbParameters.Mount.Verbosity,
                this.Verbosity,
                ParamPrefix + GVFSConstants.VerbParameters.Mount.Keywords,
                this.KeywordsCsv,
                ParamPrefix + GVFSConstants.VerbParameters.Mount.StartedByService,
                this.StartedByService.ToString()
            });

            return(GVFSEnlistment.WaitUntilMounted(enlistment.EnlistmentRoot, this.Unattended, out errorMessage));
        }
Example #6
0
        private bool TryMount(ITracer tracer, GVFSEnlistment enlistment, string mountExecutableLocation, out string errorMessage)
        {
            if (!GVFSVerb.TrySetRequiredGitConfigSettings(enlistment))
            {
                errorMessage = "Unable to configure git repo";
                return(false);
            }

            const string ParamPrefix = "--";

            tracer.RelatedInfo($"{nameof(this.TryMount)}: Launching background process('{mountExecutableLocation}') for {enlistment.EnlistmentRoot}");

            GVFSPlatform.Instance.StartBackgroundVFS4GProcess(
                tracer,
                mountExecutableLocation,
                new[]
            {
                enlistment.EnlistmentRoot,
                ParamPrefix + GVFSConstants.VerbParameters.Mount.Verbosity,
                this.Verbosity,
                ParamPrefix + GVFSConstants.VerbParameters.Mount.Keywords,
                this.KeywordsCsv,
                ParamPrefix + GVFSConstants.VerbParameters.Mount.StartedByService,
                this.StartedByService.ToString(),
                ParamPrefix + GVFSConstants.VerbParameters.Mount.StartedByVerb,
                true.ToString()
            });

            tracer.RelatedInfo($"{nameof(this.TryMount)}: Waiting for repo to be mounted");
            return(GVFSEnlistment.WaitUntilMounted(tracer, enlistment.EnlistmentRoot, this.Unattended, out errorMessage));
        }
Example #7
0
        private ReturnCode RunAndRecordGVFSVerb <TVerb>(string archiveFolderPath, string outputFileName)
            where TVerb : GVFSVerb, new()
        {
            try
            {
                using (FileStream file = new FileStream(Path.Combine(archiveFolderPath, outputFileName), FileMode.CreateNew))
                    using (StreamWriter writer = new StreamWriter(file))
                    {
                        return(GVFSVerb.Execute <TVerb>(
                                   this.EnlistmentRootPath,
                                   verb =>
                        {
                            verb.Output = writer;
                            verb.ServiceName = this.ServiceName;
                        }));
                    }
            }
            catch (Exception e)
            {
                this.WriteMessage(string.Format(
                                      "Verb {0} failed with exception {1}",
                                      typeof(TVerb),
                                      e));

                return(ReturnCode.GenericError);
            }
        }
Example #8
0
        private ReturnCode RunAndRecordGVFSVerb <TVerb>(string archiveFolderPath, string outputFileName, Action <TVerb> customConfigureVerb = null)
            where TVerb : GVFSVerb, new()
        {
            try
            {
                using (FileStream file = new FileStream(Path.Combine(archiveFolderPath, outputFileName), FileMode.CreateNew))
                    using (StreamWriter writer = new StreamWriter(file))
                    {
                        customConfigureVerb = customConfigureVerb ?? new Action <TVerb>(verb => { });
                        Action <TVerb> composedVerbConfiguration;
                        composedVerbConfiguration = verb =>
                        {
                            customConfigureVerb(verb);
                            verb.Output      = writer;
                            verb.ServiceName = this.ServiceName;
                        };

                        return(GVFSVerb.Execute <TVerb>(this.EnlistmentRootPath, composedVerbConfiguration));
                    }
            }
            catch (Exception e)
            {
                this.WriteMessage(string.Format(
                                      "Verb {0} failed with exception {1}",
                                      typeof(TVerb),
                                      e));

                return(ReturnCode.GenericError);
            }
        }
Example #9
0
        private bool TryMount(GVFSEnlistment enlistment, string mountExeLocation, out string errorMessage)
        {
            if (!GVFSVerb.TrySetGitConfigSettings(enlistment))
            {
                errorMessage = "Unable to configure git repo";
                return(false);
            }

            const string ParamPrefix = "--";

            ProcessHelper.StartBackgroundProcess(
                mountExeLocation,
                string.Join(
                    " ",
                    enlistment.EnlistmentRoot,
                    ParamPrefix + GVFSConstants.VerbParameters.Mount.Verbosity,
                    this.Verbosity,
                    ParamPrefix + GVFSConstants.VerbParameters.Mount.Keywords,
                    this.KeywordsCsv,
                    this.ShowDebugWindow ? ParamPrefix + GVFSConstants.VerbParameters.Mount.DebugWindow : string.Empty),
                createWindow: this.ShowDebugWindow);

            return(GVFSEnlistment.WaitUntilMounted(enlistment.EnlistmentRoot, this.Unattended, out errorMessage));
        }
Example #10
0
        public override void Execute()
        {
            if (string.IsNullOrWhiteSpace(this.EnlistmentRootPath))
            {
                this.EnlistmentRootPath = Environment.CurrentDirectory;
            }

            GVFSEnlistment enlistment = GVFSEnlistment.CreateWithoutRepoUrlFromDirectory(
                this.EnlistmentRootPath,
                GitProcess.GetInstalledGitBinPath());

            if (enlistment == null)
            {
                this.ReportErrorAndExit("'gvfs repair' must be run within a GVFS enlistment");
            }

            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'
");
            }

            if (!ConsoleHelper.ShowStatusWhileRunning(
                    () =>
            {
                return(GVFSVerb.Execute <StatusVerb>(enlistment.EnlistmentRoot, verb => verb.Output = new StringWriter()) != ReturnCode.Success);
            },
                    "Checking 'gvfs status'",
                    this.Output,
                    showSpinner: true,
                    suppressGvfsLogMessage: true))
            {
                this.ReportErrorAndExit("You can only run 'gvfs repair' if GVFS is not mounted. Run 'gvfs unmount' and try again.");
            }

            this.Output.WriteLine();

            using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "RepairVerb"))
            {
                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Repair),
                    EventLevel.Verbose,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    enlistment.CacheServerUrl,
                    new EventMetadata
                {
                    { "Confirmed", this.Confirmed }
                });

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

                // Repair ESENT Databases
                jobs.Add(new BackgroundOperationDatabaseRepairJob(tracer, this.Output, enlistment));
                jobs.Add(new BlobSizeDatabaseRepairJob(tracer, this.Output, enlistment));
                jobs.Add(new PlaceholderDatabaseRepairJob(tracer, this.Output, enlistment));
                jobs.Add(new RepoMetadataDatabaseRepairJob(tracer, this.Output, enlistment));

                jobs.Add(new GitHeadRepairJob(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>();
                        if (job.TryFixIssues(repairMessages))
                        {
                            this.WriteMessage(tracer, "Repair succeeded");
                        }
                        else
                        {
                            this.WriteMessage(tracer, "Repair failed. Run 'gvfs log' for more info.");
                        }

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

                    this.Output.WriteLine();
                }
            }
        }
Example #11
0
 public VerbAbortedException(GVFSVerb verb)
 {
     this.Verb = verb;
 }
Example #12
0
        private Result CreateClone(
            ITracer tracer,
            GVFSEnlistment enlistment,
            GitObjectsHttpRequestor objectRequestor,
            GitRefs refs,
            string branch)
        {
            Result initRepoResult = this.TryInitRepo(tracer, refs, enlistment);

            if (!initRepoResult.Success)
            {
                return(initRepoResult);
            }

            PhysicalFileSystem fileSystem = new PhysicalFileSystem();
            string             errorMessage;

            if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out errorMessage))
            {
                return(new Result("Error configuring alternate: " + errorMessage));
            }

            GitRepo        gitRepo    = new GitRepo(tracer, enlistment, fileSystem);
            GVFSContext    context    = new GVFSContext(tracer, fileSystem, gitRepo, enlistment);
            GVFSGitObjects gitObjects = new GVFSGitObjects(context, objectRequestor);

            if (!this.TryDownloadCommit(
                    refs.GetTipCommitId(branch),
                    enlistment,
                    objectRequestor,
                    gitObjects,
                    gitRepo,
                    out errorMessage))
            {
                return(new Result(errorMessage));
            }

            if (!GVFSVerb.TrySetRequiredGitConfigSettings(enlistment) ||
                !GVFSVerb.TrySetOptionalGitConfigSettings(enlistment))
            {
                return(new Result("Unable to configure git repo"));
            }

            CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);

            if (!cacheServerResolver.TrySaveUrlToLocalConfig(objectRequestor.CacheServer, out errorMessage))
            {
                return(new Result("Unable to configure cache server: " + errorMessage));
            }

            GitProcess git = new GitProcess(enlistment);
            string     originBranchName = "origin/" + branch;

            GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName);
            if (createBranchResult.ExitCodeIsFailure)
            {
                return(new Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output));
            }

            File.WriteAllText(
                Path.Combine(enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Head),
                "ref: refs/heads/" + branch);

            if (!this.TryDownloadRootGitAttributes(enlistment, gitObjects, gitRepo, out errorMessage))
            {
                return(new Result(errorMessage));
            }

            this.CreateGitScript(enlistment);

            string installHooksError;

            if (!HooksInstaller.InstallHooks(context, out installHooksError))
            {
                tracer.RelatedError(installHooksError);
                return(new Result(installHooksError));
            }

            GitProcess.Result forceCheckoutResult = git.ForceCheckout(branch);
            if (forceCheckoutResult.ExitCodeIsFailure && forceCheckoutResult.Errors.IndexOf("unable to read tree") > 0)
            {
                // It is possible to have the above TryDownloadCommit() fail because we
                // already have the commit and root tree we intend to check out, but
                // don't have a tree further down the working directory. If we fail
                // checkout here, its' because we don't have these trees and the
                // read-object hook is not available yet. Force downloading the commit
                // again and retry the checkout.

                if (!this.TryDownloadCommit(
                        refs.GetTipCommitId(branch),
                        enlistment,
                        objectRequestor,
                        gitObjects,
                        gitRepo,
                        out errorMessage,
                        checkLocalObjectCache: false))
                {
                    return(new Result(errorMessage));
                }

                forceCheckoutResult = git.ForceCheckout(branch);
            }

            if (forceCheckoutResult.ExitCodeIsFailure)
            {
                string[]      errorLines     = forceCheckoutResult.Errors.Split('\n');
                StringBuilder checkoutErrors = new StringBuilder();
                foreach (string gitError in errorLines)
                {
                    if (IsForceCheckoutErrorCloneFailure(gitError))
                    {
                        checkoutErrors.AppendLine(gitError);
                    }
                }

                if (checkoutErrors.Length > 0)
                {
                    string error = "Could not complete checkout of branch: " + branch + ", " + checkoutErrors.ToString();
                    tracer.RelatedError(error);
                    return(new Result(error));
                }
            }

            if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGVFSRoot, out errorMessage))
            {
                tracer.RelatedError(errorMessage);
                return(new Result(errorMessage));
            }

            try
            {
                RepoMetadata.Instance.SaveCloneMetadata(tracer, enlistment);
                this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment);
            }
            catch (Exception e)
            {
                tracer.RelatedError(e.ToString());
                return(new Result(e.Message));
            }
            finally
            {
                RepoMetadata.Shutdown();
            }

            // Prepare the working directory folder for GVFS last to ensure that gvfs mount will fail if gvfs clone has failed
            Exception exception;
            string    prepFileSystemError;

            if (!GVFSPlatform.Instance.KernelDriver.TryPrepareFolderForCallbacks(enlistment.WorkingDirectoryRoot, out prepFileSystemError, out exception))
            {
                EventMetadata metadata = new EventMetadata();
                metadata.Add(nameof(prepFileSystemError), prepFileSystemError);
                if (exception != null)
                {
                    metadata.Add("Exception", exception.ToString());
                }

                tracer.RelatedError(metadata, $"{nameof(this.CreateClone)}: TryPrepareFolderForCallbacks failed");
                return(new Result(prepFileSystemError));
            }

            return(new Result(true));
        }
Example #13
0
        private Result CreateClone(
            ITracer tracer,
            GVFSEnlistment enlistment,
            GitObjectsHttpRequestor objectRequestor,
            GitRefs refs,
            string branch)
        {
            Result initRepoResult = this.TryInitRepo(tracer, refs, enlistment);

            if (!initRepoResult.Success)
            {
                return(initRepoResult);
            }

            PhysicalFileSystem fileSystem = new PhysicalFileSystem();
            string             errorMessage;

            if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out errorMessage))
            {
                return(new Result("Error configuring alternate: " + errorMessage));
            }

            GitRepo        gitRepo    = new GitRepo(tracer, enlistment, fileSystem);
            GVFSContext    context    = new GVFSContext(tracer, fileSystem, gitRepo, enlistment);
            GVFSGitObjects gitObjects = new GVFSGitObjects(context, objectRequestor);

            if (!this.TryDownloadCommit(
                    refs.GetTipCommitId(branch),
                    enlistment,
                    objectRequestor,
                    gitObjects,
                    gitRepo,
                    out errorMessage))
            {
                return(new Result(errorMessage));
            }

            if (!GVFSVerb.TrySetRequiredGitConfigSettings(enlistment) ||
                !GVFSVerb.TrySetOptionalGitConfigSettings(enlistment))
            {
                return(new Result("Unable to configure git repo"));
            }

            CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);

            if (!cacheServerResolver.TrySaveUrlToLocalConfig(objectRequestor.CacheServer, out errorMessage))
            {
                return(new Result("Unable to configure cache server: " + errorMessage));
            }

            GitProcess git = new GitProcess(enlistment);
            string     originBranchName = "origin/" + branch;

            GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName);
            if (createBranchResult.HasErrors)
            {
                return(new Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output));
            }

            File.WriteAllText(
                Path.Combine(enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Head),
                "ref: refs/heads/" + branch);

            File.AppendAllText(
                Path.Combine(enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Info.SparseCheckoutPath),
                GVFSConstants.GitPathSeparatorString + GVFSConstants.SpecialGitFiles.GitAttributes + "\n");

            if (!this.TryDownloadRootGitAttributes(enlistment, gitObjects, gitRepo, out errorMessage))
            {
                return(new Result(errorMessage));
            }

            this.CreateGitScript(enlistment);

            string installHooksError;

            if (!HooksInstaller.InstallHooks(context, out installHooksError))
            {
                tracer.RelatedError(installHooksError);
                return(new Result(installHooksError));
            }

            GitProcess.Result forceCheckoutResult = git.ForceCheckout(branch);
            if (forceCheckoutResult.HasErrors)
            {
                string[]      errorLines     = forceCheckoutResult.Errors.Split('\n');
                StringBuilder checkoutErrors = new StringBuilder();
                foreach (string gitError in errorLines)
                {
                    if (IsForceCheckoutErrorCloneFailure(gitError))
                    {
                        checkoutErrors.AppendLine(gitError);
                    }
                }

                if (checkoutErrors.Length > 0)
                {
                    string error = "Could not complete checkout of branch: " + branch + ", " + checkoutErrors.ToString();
                    tracer.RelatedError(error);
                    return(new Result(error));
                }
            }

            if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGVFSRoot, out errorMessage))
            {
                tracer.RelatedError(errorMessage);
                return(new Result(errorMessage));
            }

            try
            {
                RepoMetadata.Instance.SaveCloneMetadata(tracer, enlistment);
                this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment);
            }
            catch (Exception e)
            {
                tracer.RelatedError(e.ToString());
                return(new Result(e.Message));
            }
            finally
            {
                RepoMetadata.Shutdown();
            }

            // Prepare the working directory folder for GVFS last to ensure that gvfs mount will fail if gvfs clone has failed
            string prepFileSystemError;

            if (!GVFSPlatform.Instance.KernelDriver.TryPrepareFolderForCallbacks(enlistment.WorkingDirectoryRoot, out prepFileSystemError))
            {
                tracer.RelatedError(prepFileSystemError);
                return(new Result(prepFileSystemError));
            }

            return(new Result(true));
        }
Example #14
0
 private bool SetConfigSettings(GitProcess git)
 {
     return(this.enlistment.TrySetCacheServerUrlConfig() &&
            GVFSVerb.TrySetGitConfigSettings(git));
 }
Example #15
0
        public CloneVerb.Result CreateClone(GitRefs refs, string branch)
        {
            CloneVerb.Result initRepoResult = this.TryInitRepo(refs, this.enlistment);
            if (!initRepoResult.Success)
            {
                return(initRepoResult);
            }

            string errorMessage;

            if (!this.enlistment.TryConfigureAlternate(out errorMessage))
            {
                return(new CloneVerb.Result("Error configuring alternate: " + errorMessage));
            }

            PhysicalFileSystem fileSystem = new PhysicalFileSystem();
            GitRepo            gitRepo    = new GitRepo(this.tracer, this.enlistment, fileSystem);
            GVFSGitObjects     gitObjects = new GVFSGitObjects(new GVFSContext(this.tracer, fileSystem, gitRepo, this.enlistment), this.objectRequestor);

            if (!gitObjects.TryEnsureCommitIsLocal(refs.GetTipCommitId(branch), commitDepth: 2))
            {
                return(new CloneVerb.Result("Could not download tip commits from: " + Uri.EscapeUriString(this.objectRequestor.CacheServer.ObjectsEndpointUrl)));
            }

            if (!GVFSVerb.TrySetGitConfigSettings(this.enlistment))
            {
                return(new CloneVerb.Result("Unable to configure git repo"));
            }

            CacheServerResolver cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment);

            if (!cacheServerResolver.TrySaveUrlToLocalConfig(this.objectRequestor.CacheServer, out errorMessage))
            {
                return(new CloneVerb.Result("Unable to configure cache server: " + errorMessage));
            }

            GitProcess git = new GitProcess(this.enlistment);
            string     originBranchName = "origin/" + branch;

            GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName);
            if (createBranchResult.HasErrors)
            {
                return(new CloneVerb.Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output));
            }

            File.WriteAllText(
                Path.Combine(this.enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Head),
                "ref: refs/heads/" + branch);

            File.AppendAllText(
                Path.Combine(this.enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Info.SparseCheckoutPath),
                GVFSConstants.GitPathSeparatorString + GVFSConstants.SpecialGitFiles.GitAttributes + "\n");

            CloneVerb.Result hydrateResult = this.HydrateRootGitAttributes(gitObjects, gitRepo, branch);
            if (!hydrateResult.Success)
            {
                return(hydrateResult);
            }

            this.CreateGitScript();

            GitProcess.Result forceCheckoutResult = git.ForceCheckout(branch);
            if (forceCheckoutResult.HasErrors)
            {
                string[]      errorLines     = forceCheckoutResult.Errors.Split('\n');
                StringBuilder checkoutErrors = new StringBuilder();
                foreach (string gitError in errorLines)
                {
                    if (IsForceCheckoutErrorCloneFailure(gitError))
                    {
                        checkoutErrors.AppendLine(gitError);
                    }
                }

                if (checkoutErrors.Length > 0)
                {
                    string error = "Could not complete checkout of branch: " + branch + ", " + checkoutErrors.ToString();
                    this.tracer.RelatedError(error);
                    return(new CloneVerb.Result(error));
                }
            }

            GitProcess.Result updateIndexresult = git.UpdateIndexVersion4();
            if (updateIndexresult.HasErrors)
            {
                string error = "Could not update index, error: " + updateIndexresult.Errors;
                this.tracer.RelatedError(error);
                return(new CloneVerb.Result(error));
            }

            string installHooksError;

            if (!HooksInstaller.InstallHooks(this.enlistment, out installHooksError))
            {
                this.tracer.RelatedError(installHooksError);
                return(new CloneVerb.Result(installHooksError));
            }

            if (!RepoMetadata.TryInitialize(this.tracer, this.enlistment.DotGVFSRoot, out errorMessage))
            {
                this.tracer.RelatedError(errorMessage);
                return(new CloneVerb.Result(errorMessage));
            }

            try
            {
                RepoMetadata.Instance.SaveCurrentDiskLayoutVersion();
            }
            catch (Exception e)
            {
                this.tracer.RelatedError(e.ToString());
                return(new CloneVerb.Result(e.Message));
            }
            finally
            {
                RepoMetadata.Shutdown();
            }

            // Prepare the working directory folder for GVFS last to ensure that gvfs mount will fail if gvfs clone has failed
            string prepGVFltError;

            if (!GVFltCallbacks.TryPrepareFolderForGVFltCallbacks(this.enlistment.WorkingDirectoryRoot, out prepGVFltError))
            {
                this.tracer.RelatedError(prepGVFltError);
                return(new CloneVerb.Result(prepGVFltError));
            }

            return(new CloneVerb.Result(true));
        }