Beispiel #1
0
        public void EventsAreFilteredByVerbosity()
        {
            using (JsonEtwTracer tracer = new JsonEtwTracer("Microsoft-GVFS-Test", "EventsAreFilteredByVerbosity1"))
                using (MockListener listener = new MockListener(EventLevel.Informational, Keywords.Any))
                {
                    tracer.AddInProcEventListener(listener);

                    tracer.RelatedEvent(EventLevel.Informational, "ShouldReceive", metadata: null);
                    listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldReceive"));

                    tracer.RelatedEvent(EventLevel.Verbose, "ShouldNotReceive", metadata: null);
                    listener.EventNamesRead.ShouldNotContain(name => name.Equals("ShouldNotReceive"));
                }

            using (JsonEtwTracer tracer = new JsonEtwTracer("Microsoft-GVFS-Test", "EventsAreFilteredByVerbosity2"))
                using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.Any))
                {
                    tracer.AddInProcEventListener(listener);

                    tracer.RelatedEvent(EventLevel.Informational, "ShouldReceive", metadata: null);
                    listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldReceive"));

                    tracer.RelatedEvent(EventLevel.Verbose, "ShouldAlsoReceive", metadata: null);
                    listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldAlsoReceive"));
                }
        }
Beispiel #2
0
        private Result TryClone(JsonEtwTracer tracer, GVFSEnlistment enlistment)
        {
            this.CheckGitVersion(enlistment);

            Result pipeResult;

            using (NamedPipeServer pipeServer = this.StartNamedPipe(enlistment, out pipeResult))
            {
                if (!pipeResult.Success)
                {
                    return(pipeResult);
                }

                HttpGitObjects httpGitObjects = new HttpGitObjects(tracer, enlistment, Environment.ProcessorCount);
                this.ValidateGVFSVersion(enlistment, httpGitObjects, tracer);

                GitRefs refs = httpGitObjects.QueryInfoRefs(this.SingleBranch ? this.Branch : null);

                if (refs == null)
                {
                    return(new Result("Could not query info/refs from: " + Uri.EscapeUriString(enlistment.RepoUrl)));
                }

                if (this.Branch == null)
                {
                    this.Branch = refs.GetDefaultBranch();

                    EventMetadata metadata = new EventMetadata();
                    metadata.Add("Branch", this.Branch);
                    tracer.RelatedEvent(EventLevel.Informational, "CloneDefaultRemoteBranch", metadata);
                }
                else
                {
                    if (!refs.HasBranch(this.Branch))
                    {
                        EventMetadata metadata = new EventMetadata();
                        metadata.Add("Branch", this.Branch);
                        tracer.RelatedEvent(EventLevel.Warning, "CloneBranchDoesNotExist", metadata);

                        string errorMessage = string.Format("Remote branch {0} not found in upstream origin", this.Branch);
                        return(new Result(errorMessage));
                    }
                }

                if (!enlistment.TryCreateEnlistmentFolders())
                {
                    string error = "Could not create enlistment directory";
                    tracer.RelatedError(error);
                    return(new Result(error));
                }

                this.CheckAntiVirusExclusion(enlistment);

                CloneHelper cloneHelper = new CloneHelper(tracer, enlistment, httpGitObjects);
                return(cloneHelper.CreateClone(refs, this.Branch));
            }
        }
Beispiel #3
0
        private Result TryClone(JsonEtwTracer tracer, GVFSEnlistment enlistment, CacheServerInfo cacheServer, RetryConfig retryConfig)
        {
            Result pipeResult;

            using (NamedPipeServer pipeServer = this.StartNamedPipe(tracer, enlistment, out pipeResult))
            {
                if (!pipeResult.Success)
                {
                    return(pipeResult);
                }

                using (GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig))
                {
                    GitRefs refs = objectRequestor.QueryInfoRefs(this.SingleBranch ? this.Branch : null);

                    if (refs == null)
                    {
                        return(new Result("Could not query info/refs from: " + Uri.EscapeUriString(enlistment.RepoUrl)));
                    }

                    if (this.Branch == null)
                    {
                        this.Branch = refs.GetDefaultBranch();

                        EventMetadata metadata = new EventMetadata();
                        metadata.Add("Branch", this.Branch);
                        tracer.RelatedEvent(EventLevel.Informational, "CloneDefaultRemoteBranch", metadata);
                    }
                    else
                    {
                        if (!refs.HasBranch(this.Branch))
                        {
                            EventMetadata metadata = new EventMetadata();
                            metadata.Add("Branch", this.Branch);
                            tracer.RelatedEvent(EventLevel.Warning, "CloneBranchDoesNotExist", metadata);

                            string errorMessage = string.Format("Remote branch {0} not found in upstream origin", this.Branch);
                            return(new Result(errorMessage));
                        }
                    }

                    if (!enlistment.TryCreateEnlistmentFolders())
                    {
                        string error = "Could not create enlistment directory";
                        tracer.RelatedError(error);
                        return(new Result(error));
                    }

                    CloneHelper cloneHelper = new CloneHelper(tracer, enlistment, objectRequestor);
                    return(cloneHelper.CreateClone(refs, this.Branch));
                }
            }
        }
Beispiel #4
0
        public void EventsAreFilteredByKeyword()
        {
            // Network filters all but network out
            using (JsonEtwTracer tracer = new JsonEtwTracer("Microsoft-GVFS-Test", "EventsAreFilteredByKeyword1"))
                using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.Network))
                {
                    tracer.AddInProcEventListener(listener);

                    tracer.RelatedEvent(EventLevel.Informational, "ShouldReceive", metadata: null, keyword: Keywords.Network);
                    listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldReceive"));

                    tracer.RelatedEvent(EventLevel.Verbose, "ShouldNotReceive", metadata: null);
                    listener.EventNamesRead.ShouldNotContain(name => name.Equals("ShouldNotReceive"));
                }

            // Any filters nothing out
            using (JsonEtwTracer tracer = new JsonEtwTracer("Microsoft-GVFS-Test", "EventsAreFilteredByKeyword2"))
                using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.Any))
                {
                    tracer.AddInProcEventListener(listener);

                    tracer.RelatedEvent(EventLevel.Informational, "ShouldReceive", metadata: null, keyword: Keywords.Network);
                    listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldReceive"));

                    tracer.RelatedEvent(EventLevel.Verbose, "ShouldAlsoReceive", metadata: null);
                    listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldAlsoReceive"));
                }

            // None filters everything out (including events marked as none)
            using (JsonEtwTracer tracer = new JsonEtwTracer("Microsoft-GVFS-Test", "EventsAreFilteredByKeyword3"))
                using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.None))
                {
                    tracer.AddInProcEventListener(listener);

                    tracer.RelatedEvent(EventLevel.Informational, "ShouldNotReceive", metadata: null, keyword: Keywords.Network);
                    listener.EventNamesRead.ShouldBeEmpty();

                    tracer.RelatedEvent(EventLevel.Verbose, "ShouldAlsoNotReceive", metadata: null);
                    listener.EventNamesRead.ShouldBeEmpty();
                }
        }
Beispiel #5
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "Prefetch"))
            {
                if (this.Verbose)
                {
                    tracer.AddDiagnosticConsoleEventListener(EventLevel.Informational, Keywords.Any);
                }

                string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment);

                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Prefetch),
                    EventLevel.Informational,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    cacheServerUrl);

                RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes));

                CacheServerInfo cacheServer = this.ResolvedCacheServer;
                GVFSConfig      gvfsConfig  = this.GVFSConfig;
                if (!this.SkipVersionCheck)
                {
                    string authErrorMessage;
                    if (!this.ShowStatusWhileRunning(
                            () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage),
                            "Authenticating"))
                    {
                        this.ReportErrorAndExit(tracer, "Unable to prefetch because authentication failed");
                    }

                    if (gvfsConfig == null)
                    {
                        gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);
                    }

                    if (cacheServer == null)
                    {
                        CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
                        cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerUrl, gvfsConfig);
                    }

                    this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: false);

                    this.Output.WriteLine("Configured cache server: " + cacheServer);
                }

                this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, gvfsConfig, cacheServer);

                try
                {
                    EventMetadata metadata = new EventMetadata();
                    metadata.Add("Commits", this.Commits);
                    metadata.Add("Files", this.Files);
                    metadata.Add("Folders", this.Folders);
                    metadata.Add("FoldersListFile", this.FoldersListFile);
                    metadata.Add("HydrateFiles", this.HydrateFiles);
                    tracer.RelatedEvent(EventLevel.Informational, "PerformPrefetch", metadata);

                    GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig);

                    if (this.Commits)
                    {
                        if (!string.IsNullOrWhiteSpace(this.Files) ||
                            !string.IsNullOrWhiteSpace(this.Folders) ||
                            !string.IsNullOrWhiteSpace(this.FoldersListFile))
                        {
                            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");
                        }

                        PhysicalFileSystem fileSystem = new PhysicalFileSystem();
                        using (FileBasedLock prefetchLock = new FileBasedLock(
                                   fileSystem,
                                   tracer,
                                   Path.Combine(enlistment.GitPackRoot, PrefetchCommitsAndTreesLock),
                                   enlistment.EnlistmentRoot,
                                   cleanupStaleLock: false,
                                   overwriteExistingLock: true))
                        {
                            this.WaitUntilLockIsAcquired(tracer, prefetchLock);
                            this.PrefetchCommits(tracer, enlistment, objectRequestor, cacheServer);
                        }
                    }
                    else
                    {
                        this.PrefetchBlobs(tracer, enlistment, objectRequestor, cacheServer);
                    }
                }
                catch (VerbAbortedException)
                {
                    throw;
                }
                catch (AggregateException aggregateException)
                {
                    this.Output.WriteLine(
                        "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(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.GetGVFSLogMessage(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;
                }
            }
        }
Beispiel #6
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "Prefetch"))
            {
                if (this.Verbose)
                {
                    tracer.AddDiagnosticConsoleEventListener(EventLevel.Informational, Keywords.Any);
                }
                else
                {
                    tracer.AddPrettyConsoleEventListener(EventLevel.Error, Keywords.Any);
                }

                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Prefetch),
                    EventLevel.Informational,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    enlistment.CacheServerUrl);

                try
                {
                    EventMetadata metadata = new EventMetadata();
                    metadata.Add("Commits", this.Commits);
                    metadata.Add("PathWhitelist", this.PathWhitelist);
                    metadata.Add("PathWhitelistFile", this.PathWhitelistFile);
                    tracer.RelatedEvent(EventLevel.Informational, "PerformPrefetch", metadata);

                    if (this.Commits)
                    {
                        if (!string.IsNullOrEmpty(this.PathWhitelistFile) ||
                            !string.IsNullOrWhiteSpace(this.PathWhitelist))
                        {
                            this.ReportErrorAndExit("Cannot supply both --commits (-c) and --folders (-f)");
                        }

                        PrefetchHelper prefetchHelper = new PrefetchHelper(
                            tracer,
                            enlistment,
                            DownloadThreadCount);

                        if (this.Verbose)
                        {
                            prefetchHelper.TryPrefetchCommitsAndTrees();
                        }
                        else
                        {
                            this.ShowStatusWhileRunning(
                                () => { return(prefetchHelper.TryPrefetchCommitsAndTrees()); },
                                "Fetching commits and trees");
                        }

                        return;
                    }

                    FetchHelper fetchHelper = new FetchHelper(
                        tracer,
                        enlistment,
                        ChunkSize,
                        SearchThreadCount,
                        DownloadThreadCount,
                        IndexThreadCount);

                    if (!FetchHelper.TryLoadPathWhitelist(tracer, this.PathWhitelist, this.PathWhitelistFile, enlistment, fetchHelper.PathWhitelist))
                    {
                        Environment.ExitCode = (int)ReturnCode.GenericError;
                        return;
                    }

                    GitProcess        gitProcess = new GitProcess(enlistment);
                    GitProcess.Result result     = gitProcess.RevParse(GVFSConstants.HeadCommitName);
                    if (result.HasErrors)
                    {
                        tracer.RelatedError(result.Errors);
                        this.Output.WriteLine(result.Errors);
                        Environment.ExitCode = (int)ReturnCode.GenericError;
                        return;
                    }

                    string      headCommitId = result.Output;
                    Func <bool> doPrefetch   =
                        () =>
                    {
                        try
                        {
                            fetchHelper.FastFetch(headCommitId.Trim(), isBranch: false);
                            return(!fetchHelper.HasFailures);
                        }
                        catch (FetchHelper.FetchException e)
                        {
                            tracer.RelatedError(e.Message);
                            return(false);
                        }
                    };

                    if (this.Verbose)
                    {
                        doPrefetch();
                    }
                    else
                    {
                        this.ShowStatusWhileRunning(doPrefetch, "Fetching blobs");
                    }

                    if (fetchHelper.HasFailures)
                    {
                        Environment.ExitCode = 1;
                    }
                }
                catch (AggregateException aggregateException)
                {
                    this.Output.WriteLine("Cannot prefetch @ {0}:", enlistment.EnlistmentRoot);
                    foreach (Exception innerException in aggregateException.Flatten().InnerExceptions)
                    {
                        tracer.RelatedError(
                            new EventMetadata
                        {
                            { "Verb", typeof(PrefetchVerb).Name },
                            { "ErrorMessage", $"Unhandled {innerException.GetType().Name}: {innerException.Message}" },
                            { "Exception", innerException.ToString() }
                        });
                    }

                    Environment.ExitCode = (int)ReturnCode.GenericError;
                }
                catch (VerbAbortedException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    this.Output.WriteLine("Cannot prefetch @ {0}:", enlistment.EnlistmentRoot);
                    tracer.RelatedError(
                        new EventMetadata
                    {
                        { "Verb", typeof(PrefetchVerb).Name },
                        { "ErrorMessage", $"Unhandled {e.GetType().Name}: {e.Message}" },
                        { "Exception", e.ToString() }
                    });
                }
            }
        }
Beispiel #7
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "Prefetch"))
            {
                if (this.Verbose)
                {
                    tracer.AddDiagnosticConsoleEventListener(EventLevel.Informational, Keywords.Any);
                }
                else
                {
                    tracer.AddPrettyConsoleEventListener(EventLevel.Error, Keywords.Any);
                }

                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Prefetch),
                    EventLevel.Informational,
                    Keywords.Any);

                RetryConfig retryConfig;
                string      error;
                if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error))
                {
                    tracer.RelatedError("Failed to determine GVFS timeout and max retries: " + error);
                    Environment.Exit((int)ReturnCode.GenericError);
                }

                retryConfig.Timeout = TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes);

                CacheServerInfo cache;
                if (!CacheServerInfo.TryDetermineCacheServer(null, tracer, enlistment, retryConfig, out cache, out error))
                {
                    tracer.RelatedError(error);
                    Environment.ExitCode = (int)ReturnCode.GenericError;
                    return;
                }

                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    cache.Url);

                try
                {
                    EventMetadata metadata = new EventMetadata();
                    metadata.Add("Commits", this.Commits);
                    metadata.Add("PathWhitelist", this.PathWhitelist);
                    metadata.Add("PathWhitelistFile", this.PathWhitelistFile);
                    tracer.RelatedEvent(EventLevel.Informational, "PerformPrefetch", metadata);

                    GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cache, retryConfig);
                    if (this.Commits)
                    {
                        this.PrefetchCommits(tracer, enlistment, objectRequestor);
                    }
                    else
                    {
                        this.PrefetchBlobs(tracer, enlistment, objectRequestor);
                    }
                }
                catch (VerbAbortedException)
                {
                    throw;
                }
                catch (AggregateException aggregateException)
                {
                    this.Output.WriteLine(
                        "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot),
                        enlistment.EnlistmentRoot);
                    foreach (Exception innerException in aggregateException.Flatten().InnerExceptions)
                    {
                        tracer.RelatedError(
                            new EventMetadata
                        {
                            { "Verb", typeof(PrefetchVerb).Name },
                            { "ErrorMessage", $"Unhandled {innerException.GetType().Name}: {innerException.Message}" },
                            { "Exception", innerException.ToString() }
                        });
                    }

                    Environment.ExitCode = (int)ReturnCode.GenericError;
                }
                catch (Exception e)
                {
                    this.Output.WriteLine(
                        "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot),
                        enlistment.EnlistmentRoot);
                    tracer.RelatedError(
                        new EventMetadata
                    {
                        { "Verb", typeof(PrefetchVerb).Name },
                        { "ErrorMessage", $"Unhandled {e.GetType().Name}: {e.Message}" },
                        { "Exception", e.ToString() }
                    });
                }
            }
        }
Beispiel #8
0
        private Result TryClone(JsonEtwTracer tracer, GVFSEnlistment enlistment)
        {
            this.CheckVolumeSupportsDeleteNotifications(tracer, enlistment);
            this.CheckGitVersion(enlistment);

            Result pipeResult;

            using (NamedPipeServer pipeServer = this.StartNamedPipe(enlistment, out pipeResult))
            {
                if (!pipeResult.Success)
                {
                    return(pipeResult);
                }

                using (ConfigHttpRequestor configRequestor = new ConfigHttpRequestor(tracer, enlistment))
                {
                    GVFSConfig config = configRequestor.QueryGVFSConfig();
                    this.ValidateGVFSVersion(enlistment, config, tracer);
                }

                using (GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, Environment.ProcessorCount))
                {
                    GitRefs refs = objectRequestor.QueryInfoRefs(this.SingleBranch ? this.Branch : null);

                    if (refs == null)
                    {
                        return(new Result("Could not query info/refs from: " + Uri.EscapeUriString(enlistment.RepoUrl)));
                    }

                    if (this.Branch == null)
                    {
                        this.Branch = refs.GetDefaultBranch();

                        EventMetadata metadata = new EventMetadata();
                        metadata.Add("Branch", this.Branch);
                        tracer.RelatedEvent(EventLevel.Informational, "CloneDefaultRemoteBranch", metadata);
                    }
                    else
                    {
                        if (!refs.HasBranch(this.Branch))
                        {
                            EventMetadata metadata = new EventMetadata();
                            metadata.Add("Branch", this.Branch);
                            tracer.RelatedEvent(EventLevel.Warning, "CloneBranchDoesNotExist", metadata);

                            string errorMessage = string.Format("Remote branch {0} not found in upstream origin", this.Branch);
                            return(new Result(errorMessage));
                        }
                    }

                    if (!enlistment.TryCreateEnlistmentFolders())
                    {
                        string error = "Could not create enlistment directory";
                        tracer.RelatedError(error);
                        return(new Result(error));
                    }

                    // Only check Defender exclusions if not mounting, otherwise let mount take care of it.
                    if (this.NoMount)
                    {
                        this.CheckAntiVirusExclusion(enlistment);
                    }

                    CloneHelper cloneHelper = new CloneHelper(tracer, enlistment, objectRequestor);
                    return(cloneHelper.CreateClone(refs, this.Branch));
                }
            }
        }
Beispiel #9
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            string errorMessage = null;

            if (!HooksInstaller.InstallHooks(enlistment, out errorMessage))
            {
                this.ReportErrorAndExit("Error installing hooks: " + errorMessage);
            }

            string mountExeLocation = null;

            using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "PreMount"))
            {
                CacheServerInfo cacheServer = this.ResolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment);

                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.MountVerb),
                    EventLevel.Verbose,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    cacheServer.Url,
                    new EventMetadata
                {
                    { "Unattended", this.Unattended },
                    { "IsElevated", ProcessHelper.IsAdminElevated() },
                });

                // TODO 1050199: Once the service is an optional component, GVFS should only attempt to attach
                // the filter via the service if the service is present\enabled
                if (!ProjFSFilter.IsServiceRunning(tracer) ||
                    !ProjFSFilter.IsNativeLibInstalled(tracer, new PhysicalFileSystem()) ||
                    !ProjFSFilter.TryAttach(tracer, enlistment.EnlistmentRoot, out errorMessage))
                {
                    tracer.RelatedInfo($"{nameof(MountVerb)}.{nameof(this.Execute)}: Enabling and attaching ProjFS through service");

                    if (!this.ShowStatusWhileRunning(
                            () => { return(this.TryEnableAndAttachGvFltThroughService(enlistment.EnlistmentRoot, out errorMessage)); },
                            $"Attaching {ProjFSFilter.ServiceName} to volume"))
                    {
                        this.ReportErrorAndExit(tracer, ReturnCode.FilterError, errorMessage);
                    }
                }

                RetryConfig retryConfig = null;
                GVFSConfig  gvfsConfig  = this.DownloadedGVFSConfig;
                if (!this.SkipVersionCheck)
                {
                    string authErrorMessage = null;
                    if (!this.ShowStatusWhileRunning(
                            () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage),
                            "Authenticating"))
                    {
                        this.Output.WriteLine("    WARNING: " + authErrorMessage);
                        this.Output.WriteLine("    Mount will proceed, but new files cannot be accessed until GVFS can authenticate.");
                    }

                    if (gvfsConfig == null)
                    {
                        if (retryConfig == null)
                        {
                            retryConfig = this.GetRetryConfig(tracer, enlistment);
                        }

                        gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);
                    }

                    this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: true);

                    CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
                    cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, gvfsConfig);
                    this.Output.WriteLine("Configured cache server: " + cacheServer);
                }

                this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, gvfsConfig, cacheServer);

                if (!this.ShowStatusWhileRunning(
                        () => { return(this.PerformPreMountValidation(tracer, enlistment, out mountExeLocation, out errorMessage)); },
                        "Validating repo"))
                {
                    this.ReportErrorAndExit(tracer, errorMessage);
                }

                if (!this.SkipVersionCheck)
                {
                    string error;
                    if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGVFSRoot, out error))
                    {
                        this.ReportErrorAndExit(tracer, error);
                    }

                    try
                    {
                        EventMetadata metadata = new EventMetadata();
                        metadata.Add(nameof(RepoMetadata.Instance.EnlistmentId), RepoMetadata.Instance.EnlistmentId);
                        metadata.Add("Enlistment", enlistment);
                        tracer.RelatedEvent(EventLevel.Informational, "EnlistmentInfo", metadata, Keywords.Telemetry);

                        GitProcess        git          = new GitProcess(enlistment, new PhysicalFileSystem());
                        GitProcess.Result configResult = git.SetInLocalConfig(GVFSConstants.GitConfig.EnlistmentId, RepoMetadata.Instance.EnlistmentId, replaceAll: true);
                        if (configResult.HasErrors)
                        {
                            error = "Could not update config with enlistment id, error: " + configResult.Errors;
                            tracer.RelatedWarning(error);
                        }
                    }
                    finally
                    {
                        RepoMetadata.Shutdown();
                    }
                }
            }

            if (!this.ShowStatusWhileRunning(
                    () => { return(this.TryMount(enlistment, mountExeLocation, out errorMessage)); },
                    "Mounting"))
            {
                this.ReportErrorAndExit(errorMessage);
            }

            if (!this.Unattended)
            {
                if (!this.ShowStatusWhileRunning(
                        () => { return(this.RegisterMount(enlistment, out errorMessage)); },
                        "Registering for automount"))
                {
                    this.Output.WriteLine("    WARNING: " + errorMessage);
                }
            }
        }