Esempio n. 1
0
        public override bool TryInstallGitCommandHooks(GVFSContext context, string executingDirectory, string hookName, string commandHookPath, out string errorMessage)
        {
            // The GitHooksLoader requires the following setup to invoke a hook:
            //      Copy GithooksLoader.exe to hook-name.exe
            //      Create a text file named hook-name.hooks that lists the applications to execute for the hook, one application per line

            string gitHooksloaderPath = Path.Combine(executingDirectory, GVFSConstants.DotGit.Hooks.LoaderExecutable);

            if (!HooksInstaller.TryHooksInstallationAction(
                    () => HooksInstaller.CopyHook(context, gitHooksloaderPath, commandHookPath + GVFSPlatform.Instance.Constants.ExecutableExtension),
                    out errorMessage))
            {
                errorMessage = "Failed to copy " + GVFSConstants.DotGit.Hooks.LoaderExecutable + " to " + commandHookPath + GVFSPlatform.Instance.Constants.ExecutableExtension + "\n" + errorMessage;
                return(false);
            }

            if (!HooksInstaller.TryHooksInstallationAction(
                    () => WindowsGitHooksInstaller.CreateHookCommandConfig(context, hookName, commandHookPath),
                    out errorMessage))
            {
                errorMessage = "Failed to create " + commandHookPath + GVFSConstants.GitConfig.HooksExtension + "\n" + errorMessage;
                return(false);
            }

            return(true);
        }
 public void MergeHooksDataThrowsOnFoundGVFSHooks()
 {
     Assert.Throws <HooksInstaller.HooksConfigurationException>(
         () => HooksInstaller.MergeHooksData(
             new string[] { "first", GVFSPlatform.Instance.Constants.GVFSHooksExecutableName },
             Filename,
             this.expectedAbsoluteGvfsHookPath));
 }
 public void MergeHooksDataThrowsOnFoundGSDHooks()
 {
     Assert.Throws<HooksInstaller.HooksConfigurationException>(
         () => HooksInstaller.MergeHooksData(
             new string[] { "first", GSDPlatform.Instance.Constants.GSDHooksExecutableName },
             Filename,
             GSDConstants.DotGit.Hooks.PreCommandHookName));
 }
        public void MergeHooksDataEmptyConfig()
        {
            string result = HooksInstaller.MergeHooksData(new string[] { }, Filename, GVFSConstants.DotGit.Hooks.PreCommandHookName);
            IEnumerable <string> resultLines = result
                                               .Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
                                               .Where(line => !line.StartsWith("#"));

            resultLines.Single().ShouldEqual(this.expectedAbsoluteGvfsHookPath);
        }
        public void MergeHooksDataEmptyConfig()
        {
            string result = HooksInstaller.MergeHooksData(new string[] { }, Filename, GSDConstants.DotGit.Hooks.PreCommandHookName);
            IEnumerable<string> resultLines = result
                .Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
                .Where(line => !line.StartsWith("#"));

            resultLines.Single().ShouldEqual(GSDPlatform.Instance.Constants.GSDHooksExecutableName);
        }
        public void MergeHooksDataDiscardBlankLines()
        {
            string result = HooksInstaller.MergeHooksData(new string[] { "first", "second", string.Empty, " " }, Filename, GVFSConstants.DotGit.Hooks.PreCommandHookName);
            IEnumerable <string> resultLines = result
                                               .Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
                                               .Where(line => !line.StartsWith("#"));

            resultLines.Count().ShouldEqual(3);
            resultLines.ElementAt(0).ShouldEqual("first");
            resultLines.ElementAt(1).ShouldEqual("second");
            resultLines.ElementAt(2).ShouldEqual(this.expectedAbsoluteGvfsHookPath);
        }
Esempio n. 7
0
        public void MergeHooksDataPostCommandFirst()
        {
            string result = HooksInstaller.MergeHooksData(new string[] { "first", "second" }, Filename, GVFSConstants.DotGit.Hooks.PostCommandHookName);
            IEnumerable <string> resultLines = result
                                               .Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
                                               .Where(line => !line.StartsWith("#"));

            resultLines.Count().ShouldEqual(3);
            resultLines.ElementAt(0).ShouldEqual(GVFSConstants.GVFSHooksExecutableName);
            resultLines.ElementAt(1).ShouldEqual("first");
            resultLines.ElementAt(2).ShouldEqual("second");
        }
Esempio n. 8
0
        private static string MergeHooks(GVFSContext context, string configSettingName, string hookName)
        {
            GitProcess configProcess = new GitProcess(context.Enlistment);
            string     filename;

            string[] defaultHooksLines = { };

            if (configProcess.TryGetFromConfig(configSettingName, forceOutsideEnlistment: true, value: out filename) && filename != null)
            {
                filename          = filename.Trim(' ', '\n');
                defaultHooksLines = File.ReadAllLines(filename);
            }

            return(HooksInstaller.MergeHooksData(defaultHooksLines, filename, hookName));
        }
Esempio n. 9
0
        public void Mount(EventLevel verbosity, Keywords keywords)
        {
            this.currentState = MountState.Mounting;

            // We must initialize repo metadata before starting the pipe server so it
            // can immediately handle status requests
            string error;

            if (!RepoMetadata.TryInitialize(this.tracer, this.enlistment.DotGVFSRoot, out error))
            {
                this.FailMountAndExit("Failed to load repo metadata: " + error);
            }

            string gitObjectsRoot;

            if (!RepoMetadata.Instance.TryGetGitObjectsRoot(out gitObjectsRoot, out error))
            {
                this.FailMountAndExit("Failed to determine git objects root from repo metadata: " + error);
            }

            string localCacheRoot;

            if (!RepoMetadata.Instance.TryGetLocalCacheRoot(out localCacheRoot, out error))
            {
                this.FailMountAndExit("Failed to determine local cache path from repo metadata: " + error);
            }

            string blobSizesRoot;

            if (!RepoMetadata.Instance.TryGetBlobSizesRoot(out blobSizesRoot, out error))
            {
                this.FailMountAndExit("Failed to determine blob sizes root from repo metadata: " + error);
            }

            this.tracer.RelatedEvent(
                EventLevel.Informational,
                "CachePathsLoaded",
                new EventMetadata
            {
                { "gitObjectsRoot", gitObjectsRoot },
                { "localCacheRoot", localCacheRoot },
                { "blobSizesRoot", blobSizesRoot },
            });

            this.enlistment.InitializeCachePaths(localCacheRoot, gitObjectsRoot, blobSizesRoot);

            using (NamedPipeServer pipeServer = this.StartNamedPipe())
            {
                this.tracer.RelatedEvent(
                    EventLevel.Informational,
                    $"{nameof(this.Mount)}_StartedNamedPipe",
                    new EventMetadata {
                    { "NamedPipeName", this.enlistment.NamedPipeName }
                });

                this.context = this.CreateContext();

                if (this.context.Unattended)
                {
                    this.tracer.RelatedEvent(EventLevel.Critical, GVFSConstants.UnattendedEnvironmentVariable, null);
                }

                this.ValidateMountPoints();

                string errorMessage;
                if (!HooksInstaller.TryUpdateHooks(this.context, out errorMessage))
                {
                    this.FailMountAndExit(errorMessage);
                }

                GVFSPlatform.Instance.ConfigureVisualStudio(this.enlistment.GitBinPath, this.tracer);

                this.MountAndStartWorkingDirectoryCallbacks(this.cacheServer);

                Console.Title = "GVFS " + ProcessHelper.GetCurrentProcessVersion() + " - " + this.enlistment.EnlistmentRoot;

                this.tracer.RelatedEvent(
                    EventLevel.Informational,
                    "Mount",
                    new EventMetadata
                {
                    // Use TracingConstants.MessageKey.InfoMessage rather than TracingConstants.MessageKey.CriticalMessage
                    // as this message should not appear as an error
                    { TracingConstants.MessageKey.InfoMessage, "Virtual repo is ready" },
                },
                    Keywords.Telemetry);

                this.currentState = MountState.Ready;

                this.unmountEvent.WaitOne();
            }
        }
Esempio n. 10
0
 public void MergeHooksDataThrowsOnFoundGVFSHooks()
 {
     Assert.Throws <HooksInstaller.HooksConfigurationException>(
         () => HooksInstaller.MergeHooksData(new string[] { "first", "gvfs.hooks.exe" }, Filename, GVFSConstants.DotGit.Hooks.PreCommandHookName));
 }
Esempio n. 11
0
        protected override void Execute(GSDEnlistment enlistment)
        {
            string errorMessage            = null;
            string mountExecutableLocation = null;

            using (JsonTracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "ExecuteMount"))
            {
                PhysicalFileSystem fileSystem = new PhysicalFileSystem();
                GitRepo            gitRepo    = new GitRepo(tracer, enlistment, fileSystem);
                GSDContext         context    = new GSDContext(tracer, fileSystem, gitRepo, enlistment);

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

                CacheServerInfo cacheServer = this.ResolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment);

                tracer.AddLogFileEventListener(
                    GSDEnlistment.GetNewGSDLogFileName(enlistment.GSDLogsRoot, GSDConstants.LogFileTypes.MountVerb),
                    EventLevel.Verbose,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    cacheServer.Url,
                    new EventMetadata
                {
                    { "Unattended", this.Unattended },
                    { "IsElevated", GSDPlatform.Instance.IsElevated() },
                    { "NamedPipeName", enlistment.NamedPipeName },
                    { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
                });

                RetryConfig     retryConfig     = null;
                ServerGSDConfig serverGSDConfig = this.DownloadedGSDConfig;
                if (!this.SkipVersionCheck)
                {
                    string authErrorMessage;
                    if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage))
                    {
                        this.Output.WriteLine("    WARNING: " + authErrorMessage);
                        this.Output.WriteLine("    Mount will proceed, but new files cannot be accessed until GSD can authenticate.");
                    }

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

                        serverGSDConfig = this.QueryGSDConfig(tracer, enlistment, retryConfig);
                    }

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

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

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

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

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

                    try
                    {
                        GitProcess git = new GitProcess(enlistment);
                        this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment);
                    }
                    finally
                    {
                        RepoMetadata.Shutdown();
                    }
                }

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

                if (!this.Unattended)
                {
                    tracer.RelatedInfo($"{nameof(this.Execute)}: Registering for automount");

                    if (this.ShowStatusWhileRunning(
                            () => { return(this.RegisterMount(enlistment, out errorMessage)); },
                            "Registering for automount"))
                    {
                        tracer.RelatedInfo($"{nameof(this.Execute)}: Registered for automount");
                    }
                    else
                    {
                        this.Output.WriteLine("    WARNING: " + errorMessage);
                        tracer.RelatedInfo($"{nameof(this.Execute)}: Failed to register for automount");
                    }
                }
            }
        }
Esempio n. 12
0
        private Result CreateClone(
            ITracer tracer,
            GSDEnlistment 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);
            GSDContext    context    = new GSDContext(tracer, fileSystem, gitRepo, enlistment);
            GSDGitObjects gitObjects = new GSDGitObjects(context, objectRequestor);

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

            if (!GSDVerb.TrySetRequiredGitConfigSettings(enlistment) ||
                !GSDVerb.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.WorkingDirectoryBackingRoot, GSDConstants.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));
            }

            // TODO: Move this to be after the mount?
            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 (!RepoMetadata.TryInitialize(tracer, enlistment.DotGSDRoot, 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();
            }

            return(new Result(true));
        }