예제 #1
0
        private void MountAndStartWorkingDirectoryCallbacks(GVFSContext context)
        {
            HttpGitObjects httpGitObjects = new HttpGitObjects(context.Tracer, context.Enlistment, Environment.ProcessorCount);

            if (!httpGitObjects.TryRefreshCredentials())
            {
                this.FailMountAndExit("Failed to obtain git credentials");
            }

            this.gitObjects     = new GVFSGitObjects(context, httpGitObjects);
            this.gvfltCallbacks = this.CreateOrReportAndExit(() => new GVFltCallbacks(context, this.gitObjects), "Failed to create src folder callbacks");

            try
            {
                string error;
                if (!this.gvfltCallbacks.TryStart(out error))
                {
                    this.FailMountAndExit("Error: {0}. \r\nPlease confirm that gvfs clone completed without error.", error);
                }
            }
            catch (Exception e)
            {
                this.FailMountAndExit("Failed to initialize src folder callbacks. {0}", e.ToString());
            }

            this.AcquireFolderLocks(context);

            this.heartbeat = new HeartbeatThread(this.tracer);
            this.heartbeat.Start();
        }
예제 #2
0
        public void GetPlaceholderInformationHandlerCancelledDuringNetworkRequest()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        new MockBlobSizes(),
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    MockTracer mockTracker = this.Repo.Context.Tracer as MockTracer;
                    mockTracker.WaitRelatedEventName = "GVFltGetPlaceholderInformationAsyncHandler_GetProjectedGVFltFileInfoAndShaCancelled";
                    gitIndexProjection.ThrowOperationCanceledExceptionOnProjectionRequest = true;
                    mockGvFlt.OnGetPlaceholderInformation(1, "test.txt", 0, 0, 0, 0, 1, "UnitTests").ShouldEqual(HResult.Pending);

                    // Cancelling in the middle of GetPlaceholderInformation in the middle of a network request should not result in placeholder
                    // getting created
                    mockTracker.WaitForRelatedEvent();
                    mockGvFlt.CreatedPlaceholders.ShouldNotContain(entry => entry == "test.txt");
                    gitIndexProjection.PlaceholdersCreated.ShouldNotContain(entry => entry == "test.txt");

                    callbacks.Stop();
                }
        }
예제 #3
0
        public void GetPlaceholderInformationHandlerCancelledDuringAsyncCallback()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        new MockBlobSizes(),
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    gitIndexProjection.BlockGetProjectedFileInfo(willWaitForRequest: true);
                    mockGvFlt.OnGetPlaceholderInformation(1, "test.txt", 0, 0, 0, 0, 1, "UnitTests").ShouldEqual(HResult.Pending);
                    gitIndexProjection.WaitForGetProjectedFileInfo();
                    mockGvFlt.OnCancelCommand(1);
                    gitIndexProjection.UnblockGetProjectedFileInfo();

                    // Cancelling in the middle of GetPlaceholderInformation still allows it to create placeholders when the cancellation does not
                    // interrupt network requests
                    mockGvFlt.WaitForPlaceholderCreate();
                    gitIndexProjection.WaitForPlaceholderCreate();
                    mockGvFlt.CreatedPlaceholders.ShouldContain(entry => entry == "test.txt");
                    gitIndexProjection.PlaceholdersCreated.ShouldContain(entry => entry == "test.txt");

                    callbacks.Stop();
                }
        }
예제 #4
0
        public void OnStartDirectoryEnumerationReturnsPendingWhenResultsNotInMemory()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        new MockBlobSizes(),
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    Guid enumerationGuid = Guid.NewGuid();
                    gitIndexProjection.EnumerationInMemory = false;
                    mockGvFlt.OnStartDirectoryEnumeration(1, enumerationGuid, "test").ShouldEqual(HResult.Pending);
                    mockGvFlt.WaitForCompletionStatus().ShouldEqual(HResult.Ok);
                    mockGvFlt.OnEndDirectoryEnumeration(enumerationGuid).ShouldEqual(HResult.Ok);
                    callbacks.Stop();
                }
        }
예제 #5
0
        public void OnGetFileStreamReturnsInternalErrorWhenPlaceholderVersionDoesNotMatchExpected()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        blobSizes: null,
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    Guid enumerationGuid = Guid.NewGuid();

                    byte[] contentId = GVFltCallbacks.ConvertShaToContentId("0123456789012345678901234567890123456789");
                    byte[] epochId   = new byte[] { GVFltCallbacks.PlaceholderVersion + 1 };

                    mockGvFlt.OnGetFileStream(
                        commandId: 1,
                        relativePath: "test.txt",
                        byteOffset: 0,
                        length: 100,
                        streamGuid: Guid.NewGuid(),
                        contentId: contentId,
                        epochId: epochId,
                        triggeringProcessId: 2,
                        triggeringProcessImageFileName: "UnitTest").ShouldEqual(NtStatus.InternalError);
                }
        }
예제 #6
0
        public void GetPlaceholderInformationHandlerPathProjected()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        new MockBlobSizes(),
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    mockGvFlt.OnGetPlaceholderInformation(1, "test.txt", 0, 0, 0, 0, 1, "UnitTests").ShouldEqual(HResult.Pending);
                    mockGvFlt.WaitForCompletionStatus().ShouldEqual(HResult.Ok);
                    mockGvFlt.CreatedPlaceholders.ShouldContain(entry => entry == "test.txt");
                    gitIndexProjection.PlaceholdersCreated.ShouldContain(entry => entry == "test.txt");

                    callbacks.Stop();
                }
        }
예제 #7
0
        private void PrepareSrcFolder(ITracer tracer, GVFSEnlistment enlistment)
        {
            string error;

            if (!GVFltCallbacks.TryPrepareFolderForGVFltCallbacks(enlistment.WorkingDirectoryRoot, out error))
            {
                this.WriteErrorAndExit(tracer, "Failed to recreate the virtualization root: " + error);
            }
        }
예제 #8
0
        private void UnmountAndStopWorkingDirectoryCallbacks()
        {
            this.ReleaseFolderLocks();

            if (this.gvfltCallbacks != null)
            {
                this.gvfltCallbacks.Stop();
                this.gvfltCallbacks.Dispose();
                this.gvfltCallbacks = null;
            }
        }
예제 #9
0
        public void CannotDeleteIndexOrPacks()
        {
            GVFltCallbacks.DoesPathAllowDelete(string.Empty).ShouldEqual(true);

            GVFltCallbacks.DoesPathAllowDelete(@".git\index").ShouldEqual(false);
            GVFltCallbacks.DoesPathAllowDelete(@".git\INDEX").ShouldEqual(false);

            GVFltCallbacks.DoesPathAllowDelete(@".git\index.lock").ShouldEqual(true);
            GVFltCallbacks.DoesPathAllowDelete(@".git\INDEX.lock").ShouldEqual(true);
            GVFltCallbacks.DoesPathAllowDelete(@".git\objects\pack").ShouldEqual(true);
            GVFltCallbacks.DoesPathAllowDelete(@".git\objects\pack-temp").ShouldEqual(true);
            GVFltCallbacks.DoesPathAllowDelete(@".git\objects\pack\pack-1e88df2a4e234c82858cfe182070645fb96d6131.pack").ShouldEqual(true);
            GVFltCallbacks.DoesPathAllowDelete(@".git\objects\pack\pack-1e88df2a4e234c82858cfe182070645fb96d6131.idx").ShouldEqual(true);
        }
예제 #10
0
        private void MountAndStartWorkingDirectoryCallbacks(GVFSContext context)
        {
            HttpGitObjects httpGitObjects = new HttpGitObjects(context.Tracer, context.Enlistment, Environment.ProcessorCount);

            if (!httpGitObjects.TryRefreshCredentials())
            {
                this.FailMountAndExit("Failed to obtain git credentials");
            }

            // Checking the disk layout version is done before this point in GVFS.CommandLine.MountVerb.PreExecute
            RepoMetadata repoMetadata = new RepoMetadata(this.enlistment.DotGVFSRoot);

            this.gitObjects     = new GVFSGitObjects(context, httpGitObjects);
            this.gvfltCallbacks = this.CreateOrReportAndExit(() => new GVFltCallbacks(context, this.gitObjects, repoMetadata), "Failed to create src folder callbacks");

            int    persistedVersion;
            string error;

            if (!repoMetadata.TryGetOnDiskLayoutVersion(out persistedVersion, out error))
            {
                this.FailMountAndExit("Error: {0}", error);
            }

            if (!repoMetadata.OnDiskVersionUsesAlwaysExclude())
            {
                // Want this as close to repoMetadata.SaveCurrentDiskLayoutVersion() as possible to avoid possible corrupt states.
                this.UpdateToAlwaysExcludeFile(repoMetadata);
            }

            try
            {
                if (!this.gvfltCallbacks.TryStart(out error))
                {
                    this.FailMountAndExit("Error: {0}. \r\nPlease confirm that gvfs clone completed without error.", error);
                }
            }
            catch (Exception e)
            {
                this.FailMountAndExit("Failed to initialize src folder callbacks. {0}", e.ToString());
            }

            repoMetadata.SaveCurrentDiskLayoutVersion();
            repoMetadata.SetAlwaysExcludeInvalid(false);

            this.AcquireFolderLocks(context);

            this.heartbeat = new HeartbeatThread(this.tracer, this.gvfltCallbacks);
            this.heartbeat.Start();
        }
예제 #11
0
        public void OnGetFileStreamHandlesCancellationDuringWriteAction()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        new MockBlobSizes(),
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    Guid enumerationGuid = Guid.NewGuid();

                    byte[] contentId          = GVFltCallbacks.ConvertShaToContentId("0123456789012345678901234567890123456789");
                    byte[] placeholderVersion = GVFltCallbacks.GetPlaceholderVersionId();

                    uint fileLength = 100;
                    MockGVFSGitObjects mockGVFSGitObjects = this.Repo.GitObjects as MockGVFSGitObjects;
                    mockGVFSGitObjects.FileLength = fileLength;

                    MockTracer mockTracker = this.Repo.Context.Tracer as MockTracer;
                    mockTracker.WaitRelatedEventName = "GVFltGetFileStreamHandlerAsyncHandler_OperationCancelled";

                    mockGvFlt.BlockCreateWriteBuffer(willWaitForRequest: true);
                    mockGvFlt.OnGetFileStream(
                        commandId: 1,
                        relativePath: "test.txt",
                        byteOffset: 0,
                        length: fileLength,
                        streamGuid: Guid.NewGuid(),
                        contentId: contentId,
                        providerId: placeholderVersion,
                        triggeringProcessId: 2,
                        triggeringProcessImageFileName: "UnitTest").ShouldEqual(HResult.Pending);

                    mockGvFlt.WaitForCreateWriteBuffer();
                    mockGvFlt.OnCancelCommand(1);
                    mockGvFlt.UnblockCreateWriteBuffer();
                    mockTracker.WaitForRelatedEvent();

                    callbacks.Stop();
                }
        }
예제 #12
0
        private void MountAndStartWorkingDirectoryCallbacks(GVFSContext context, CacheServerInfo cache)
        {
            string error;

            if (!context.Enlistment.Authentication.TryRefreshCredentials(context.Tracer, out error))
            {
                this.FailMountAndExit("Failed to obtain git credentials: " + error);
            }

            // Checking the disk layout version is done before this point in GVFS.CommandLine.MountVerb
            RepoMetadata            repoMetadata    = new RepoMetadata(this.enlistment.DotGVFSRoot);
            GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(context.Tracer, context.Enlistment, cache, this.retryConfig);

            this.gitObjects     = new GVFSGitObjects(context, objectRequestor);
            this.gvfltCallbacks = this.CreateOrReportAndExit(() => new GVFltCallbacks(context, this.gitObjects, repoMetadata), "Failed to create src folder callbacks");

            int persistedVersion;

            if (!repoMetadata.TryGetOnDiskLayoutVersion(out persistedVersion, out error))
            {
                this.FailMountAndExit("Error: {0}", error);
            }

            try
            {
                if (!this.gvfltCallbacks.TryStart(out error))
                {
                    this.FailMountAndExit("Error: {0}. \r\nPlease confirm that gvfs clone completed without error.", error);
                }
            }
            catch (Exception e)
            {
                this.FailMountAndExit("Failed to initialize src folder callbacks. {0}", e.ToString());
            }

            try
            {
                repoMetadata.SaveCurrentDiskLayoutVersion();
            }
            catch (Exception ex)
            {
                this.FailMountAndExit("Failed to update repo disk layout version: {0}", ex.ToString());
            }

            this.AcquireFolderLocks(context);

            this.heartbeat = new HeartbeatThread(this.tracer, this.gvfltCallbacks);
            this.heartbeat.Start();
        }
예제 #13
0
        private void MountAndStartWorkingDirectoryCallbacks(CacheServerInfo cache)
        {
            string error;

            if (!this.context.Enlistment.Authentication.TryRefreshCredentials(this.context.Tracer, out error))
            {
                this.FailMountAndExit("Failed to obtain git credentials: " + error);
            }

            GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(this.context.Tracer, this.context.Enlistment, cache, this.retryConfig);

            this.gitObjects     = new GVFSGitObjects(this.context, objectRequestor);
            this.gvfltCallbacks = this.CreateOrReportAndExit(() => new GVFltCallbacks(this.context, this.gitObjects, RepoMetadata.Instance), "Failed to create src folder callbacks");

            int majorVersion;
            int minorVersion;

            if (!RepoMetadata.Instance.TryGetOnDiskLayoutVersion(out majorVersion, out minorVersion, out error))
            {
                this.FailMountAndExit("Error: {0}", error);
            }

            if (majorVersion != RepoMetadata.DiskLayoutVersion.CurrentMajorVersion)
            {
                this.FailMountAndExit(
                    "Error: On disk version ({0}) does not match current version ({1})",
                    majorVersion,
                    RepoMetadata.DiskLayoutVersion.CurrentMajorVersion);
            }

            try
            {
                if (!this.gvfltCallbacks.TryStart(out error))
                {
                    this.FailMountAndExit("Error: {0}. \r\nPlease confirm that gvfs clone completed without error.", error);
                }
            }
            catch (Exception e)
            {
                this.FailMountAndExit("Failed to initialize src folder callbacks. {0}", e.ToString());
            }

            this.AcquireFolderLocks();

            this.heartbeat = new HeartbeatThread(this.tracer, this.gvfltCallbacks);
            this.heartbeat.Start();
        }
예제 #14
0
        public void OnGetFileStreamHandlesGvWriteFailure()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        blobSizes: null,
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    Guid enumerationGuid = Guid.NewGuid();

                    byte[] contentId = GVFltCallbacks.ConvertShaToContentId("0123456789012345678901234567890123456789");
                    byte[] epochId   = GVFltCallbacks.GetEpochId();

                    uint fileLength = 100;
                    MockGVFSGitObjects mockGVFSGitObjects = this.Repo.GitObjects as MockGVFSGitObjects;
                    mockGVFSGitObjects.FileLength = fileLength;

                    MockTracer mockTracker = this.Repo.Context.Tracer as MockTracer;
                    mockTracker.WaitRelatedEventName = "GVFltGetFileStreamHandlerAsyncHandler_OperationCancelled";

                    mockGvFlt.WriteFileReturnStatus = NtStatus.InternalError;
                    mockGvFlt.OnGetFileStream(
                        commandId: 1,
                        relativePath: "test.txt",
                        byteOffset: 0,
                        length: fileLength,
                        streamGuid: Guid.NewGuid(),
                        contentId: contentId,
                        epochId: epochId,
                        triggeringProcessId: 2,
                        triggeringProcessImageFileName: "UnitTest").ShouldEqual(NtStatus.Pending);

                    mockGvFlt.WaitForCompletionStatus().ShouldEqual(mockGvFlt.WriteFileReturnStatus);

                    callbacks.Stop();
                }
        }
예제 #15
0
 public void IsPathMonitoredForWrites()
 {
     GVFltCallbacks.IsPathMonitoredForWrites(string.Empty).ShouldEqual(false);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\index").ShouldEqual(true);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\INDEX").ShouldEqual(true);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\index.lock").ShouldEqual(false);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\INDEX.lock").ShouldEqual(false);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\head").ShouldEqual(true);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\HEAD").ShouldEqual(true);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\head.lock").ShouldEqual(false);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\HEAD.lock").ShouldEqual(false);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\refs\heads\master").ShouldEqual(true);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\refs\heads\users\testuser\feature_branch").ShouldEqual(true);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\refs\remotes").ShouldEqual(false);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\refs\remotes\master").ShouldEqual(false);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\objects\pack").ShouldEqual(false);
     GVFltCallbacks.IsPathMonitoredForWrites(@".git\objects").ShouldEqual(false);
 }
예제 #16
0
        public void OnGetFileStreamReturnsPendingAndCompletesWithSuccessWhenNoFailures()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        new MockBlobSizes(),
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    Guid enumerationGuid = Guid.NewGuid();

                    byte[] contentId          = GVFltCallbacks.ConvertShaToContentId("0123456789012345678901234567890123456789");
                    byte[] placeholderVersion = GVFltCallbacks.GetPlaceholderVersionId();

                    uint fileLength = 100;
                    MockGVFSGitObjects mockGVFSGitObjects = this.Repo.GitObjects as MockGVFSGitObjects;
                    mockGVFSGitObjects.FileLength   = fileLength;
                    mockGvFlt.WriteFileReturnResult = HResult.Ok;

                    mockGvFlt.OnGetFileStream(
                        commandId: 1,
                        relativePath: "test.txt",
                        byteOffset: 0,
                        length: fileLength,
                        streamGuid: Guid.NewGuid(),
                        contentId: contentId,
                        providerId: placeholderVersion,
                        triggeringProcessId: 2,
                        triggeringProcessImageFileName: "UnitTest").ShouldEqual(HResult.Pending);

                    mockGvFlt.WaitForCompletionStatus().ShouldEqual(HResult.Ok);

                    callbacks.Stop();
                }
        }
예제 #17
0
        private void FailMountAndExit(string error, params object[] args)
        {
            this.currentState = MountState.MountFailed;

            this.tracer.RelatedError(error, args);
            if (this.showDebugWindow)
            {
                Console.WriteLine("\nPress Enter to Exit");
                Console.ReadLine();
            }

            if (this.gvfltCallbacks != null)
            {
                this.gvfltCallbacks.Dispose();
                this.gvfltCallbacks = null;
            }

            Environment.Exit((int)ReturnCode.GenericError);
        }
예제 #18
0
        public void GetPlaceholderInformationHandlerPathNotProjected()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        blobSizes: null,
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    mockGvFlt.OnGetPlaceholderInformation(1, "doesNotExist", 0, 0, 0, 0, 1, "UnitTests").ShouldEqual(NtStatus.ObjectNameNotFound);
                }
        }
예제 #19
0
        public void GetPlaceholderInformationHandlerCancelledBeforeSchedulingAsync()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test.txt" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        new MockBlobSizes(),
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    gitIndexProjection.BlockIsPathProjected(willWaitForRequest: true);

                    Task.Run(() =>
                    {
                        // Wait for OnGetPlaceholderInformation to call IsPathProjected and then while it's blocked there
                        // call OnCancelCommand
                        gitIndexProjection.WaitForIsPathProjected();
                        mockGvFlt.OnCancelCommand(1);
                        gitIndexProjection.UnblockIsPathProjected();
                    });

                    mockGvFlt.OnGetPlaceholderInformation(1, "test.txt", 0, 0, 0, 0, 1, "UnitTests").ShouldEqual(HResult.Pending);

                    // Cancelling before GetPlaceholderInformation has registered the command results in placeholders being created
                    mockGvFlt.WaitForPlaceholderCreate();
                    gitIndexProjection.WaitForPlaceholderCreate();
                    mockGvFlt.CreatedPlaceholders.ShouldContain(entry => entry == "test.txt");
                    gitIndexProjection.PlaceholdersCreated.ShouldContain(entry => entry == "test.txt");

                    callbacks.Stop();
                }
        }
예제 #20
0
        public void OnStartDirectoryEnumerationReturnsSuccessWhenResultsInMemory()
        {
            using (MockVirtualizationInstance mockGvFlt = new MockVirtualizationInstance())
                using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { "test" }))
                {
                    GVFltCallbacks callbacks = new GVFltCallbacks(
                        this.Repo.Context,
                        this.Repo.GitObjects,
                        RepoMetadata.Instance,
                        blobSizes: null,
                        gvflt: mockGvFlt,
                        gitIndexProjection: gitIndexProjection,
                        reliableBackgroundOperations: new MockReliableBackgroundOperations());

                    string error;
                    callbacks.TryStart(out error).ShouldEqual(true);

                    Guid enumerationGuid = Guid.NewGuid();
                    gitIndexProjection.EnumerationInMemory = true;
                    mockGvFlt.OnStartDirectoryEnumeration(1, enumerationGuid, "test").ShouldEqual(NtStatus.Success);
                    mockGvFlt.OnEndDirectoryEnumeration(enumerationGuid).ShouldEqual(NtStatus.Success);
                }
        }
예제 #21
0
        public CloneVerb.Result CreateClone(GitRefs refs, string branch)
        {
            GitObjects gitObjects = new GitObjects(this.tracer, this.enlistment, this.objectRequestor);

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

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

            GitProcess git = new GitProcess(this.enlistment);

            if (!this.SetConfigSettings(git, this.objectRequestor.CacheServer))
            {
                return(new CloneVerb.Result("Unable to configure git repo"));
            }

            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, 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));
            }

            using (RepoMetadata repoMetadata = new RepoMetadata(this.enlistment.DotGVFSRoot))
            {
                repoMetadata.SaveCurrentDiskLayoutVersion();
            }

            // 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));
        }
예제 #22
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);
            GVFSGitObjects gitObjects = new GVFSGitObjects(new GVFSContext(tracer, fileSystem, gitRepo, enlistment), 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);

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

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

            string installHooksError;

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

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

            try
            {
                RepoMetadata.Instance.SaveCloneMetadata(tracer, enlistment);
                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.Result configResult = git.SetInLocalConfig(GVFSConstants.GitConfig.EnlistmentId, RepoMetadata.Instance.EnlistmentId, replaceAll: true);
                if (configResult.HasErrors)
                {
                    string error = "Could not update config with enlistment id, error: " + configResult.Errors;
                    tracer.RelatedWarning(error);
                }
            }
            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 prepGVFltError;

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

            return(new Result(true));
        }