Пример #1
0
        public async Task DisposingProjectDisposesProjectBuilder()
        {
            // When a project is disposed, all project builders should be shut down

            await RemoteBuildEngineManager.RecycleAllBuilders();

            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

            FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");
            FilePath projectFile;

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                var project = (DotNetProject)sol.Items.FirstOrDefault(p => p.Name == "App");
                projectFile = project.FileName;
                await project.GetReferencedAssemblies(sol.Configurations [0].Selector);

                Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
                Assert.AreEqual(1, await RemoteBuildEngineManager.CountActiveBuildersForProject(project.FileName));

                sol.RootFolder.Items.Remove(project);
                project.Dispose();

                Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
                Assert.AreEqual(1, RemoteBuildEngineManager.EnginesCount);
                Assert.AreEqual(0, await RemoteBuildEngineManager.CountActiveBuildersForProject(project.FileName));
            }
            Assert.AreEqual(0, await RemoteBuildEngineManager.CountActiveBuildersForProject(projectFile));
            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);
            Assert.AreEqual(0, RemoteBuildEngineManager.EnginesCount);
        }
Пример #2
0
        public async Task UseCorrentProjectDependencyWhenNotBuildingReferencesOnCleanBuilder()
        {
            // Same as above, but now project dependencies are not included in the build.
            // The project should still pick the right dependency

            FilePath solFile = Util.GetSampleProject("sln-config-mapping", "sln-config-mapping.sln");
            var      sol     = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile);

            var lib  = sol.Items.First(i => i.Name == "lib");
            var lib2 = sol.Items.First(i => i.Name == "lib2");
            var app  = sol.Items.First(i => i.Name == "app");

            // Build the library in Debug and Release modes, to make sure all assemblies are generated
            // Also, the last build is Release, so that the project in memory is configured for reelase

            await lib.Build(Util.GetMonitor(false), sol.Configurations ["Debug|x86"].Selector, true);

            await lib.Build(Util.GetMonitor(false), sol.Configurations ["Release|x86"].Selector, true);

            await RemoteBuildEngineManager.RecycleAllBuilders();

            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

            // Build the app in Debug mode. It should still pick the Extra dependency
            await app.Build(Util.GetMonitor(false), sol.Configurations ["Debug|x86"].Selector, false);

            Assert.IsTrue(File.Exists(app.ItemDirectory.Combine("bin", "Debug", "libextra.dll")));
        }
Пример #3
0
        public async Task ParallelBuilds()
        {
            // Check that the project system can start two builds in parallel.

            await RemoteBuildEngineManager.RecycleAllBuilders();

            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

            var currentSetting = Runtime.Preferences.ParallelBuild.Value;

            try {
                Runtime.Preferences.ParallelBuild.Set(true);

                FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");
                using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                    // DepMain depends on both Dep1 and Dep2.

                    var demMain = sol.Items.FirstOrDefault(p => p.Name == "DepMain");
                    var dep1    = sol.Items.FirstOrDefault(p => p.Name == "Dep1");
                    var dep2    = sol.Items.FirstOrDefault(p => p.Name == "Dep2");

                    InitBuildSyncEvent(dep1);
                    InitBuildSyncEvent(dep2);

                    // Start the build
                    var build1 = demMain.Build(Util.GetMonitor(), sol.Configurations [0].Selector, true);

                    // Wait for sync signal from projects Dep1 and Dep2, which will mean that
                    // both projects started building in parallel

                    var syncAll = Task.WhenAll(WaitForBuildSyncEvent(dep1), WaitForBuildSyncEvent(dep2));

                    //NOTE: this has a longer timeout because otherwise it sometimes times out
                    //maybe something to do with the fact it compiles tasks
                    if (await Task.WhenAny(syncAll, Task.Delay(timeoutMs)) != syncAll)
                    {
                        Assert.Fail("Not all builds were started");
                    }

                    // Finish the build
                    SignalBuildToContinue(dep1);
                    SignalBuildToContinue(dep2);

                    if (await Task.WhenAny(build1, Task.Delay(timeoutMs)) != build1)
                    {
                        Assert.Fail("Build did not end in time");
                    }

                    Assert.AreEqual(0, build1.Result.ErrorCount);
                }
            } finally {
                Runtime.Preferences.ParallelBuild.Set(currentSetting);
            }
        }
Пример #4
0
        public async Task RecoverFromBuilderCrash()
        {
            await RemoteBuildEngineManager.RecycleAllBuilders();

            string projFile = Util.GetSampleProject("builder-manager-tests", "crasher", "ConsoleProject.csproj");

            using (var p = (Project)await Services.ProjectService.ReadSolutionItem(Util.GetMonitor(), projFile)) {
                var result = await p.Build(Util.GetMonitor(), ConfigurationSelector.Default);

                Assert.AreEqual(1, result.ErrorCount, "#1");
            }
        }
Пример #5
0
        public async Task ConcurrentLongAndShortOperations()
        {
            // Tests that when a short operation is started while a long operation is in progress,
            // a new builder is created to execute the short operation

            await RemoteBuildEngineManager.RecycleAllBuilders();

            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

            FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                var project1 = sol.Items.FirstOrDefault(p => p.Name == "SyncBuildProject");
                var project2 = (Project)sol.Items.FirstOrDefault(p => p.Name == "App");

                InitBuildSyncEvent(project1);

                // Start the build
                var build1 = project1.Build(Util.GetMonitor(), sol.Configurations [0].Selector);

                // Wait for the build to reach the sync task
                await WaitForBuildSyncEvent(project1);

                // The build is now in progess. Start a short operation.
                var context = new TargetEvaluationContext {
                    BuilderQueue = BuilderQueue.ShortOperations
                };
                var build2 = project2.RunTarget(Util.GetMonitor(), "QuickTarget", sol.Configurations [0].Selector, context);

                if (await Task.WhenAny(build2, Task.Delay(5000)) != build2)
                {
                    Assert.Fail("Build did not start");
                }

                SignalBuildToContinue(project1);

                if (await Task.WhenAny(build1, Task.Delay(5000)) != build1)
                {
                    Assert.Fail("Build did not end in time");
                }

                Assert.AreEqual(0, build1.Result.ErrorCount);
                Assert.NotNull(build2.Result);
            }
        }
Пример #6
0
        public async Task ConcurrentLongOperations()
        {
            // When a long operation is running and a new one is requested, a new builder is created

            await RemoteBuildEngineManager.RecycleAllBuilders();

            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

            FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                var project1 = sol.Items.FirstOrDefault(p => p.Name == "SyncBuildProject");
                var project2 = sol.Items.FirstOrDefault(p => p.Name == "App");

                InitBuildSyncEvent(project1);

                // Start the build
                var build1 = project1.Build(Util.GetMonitor(), sol.Configurations [0].Selector);

                // Wait for the build to reach the sync task
                await WaitForBuildSyncEvent(project1);

                // The build is now in progess. Start a new build

                var build2 = project2.Build(Util.GetMonitor(), sol.Configurations [0].Selector);
                if (await Task.WhenAny(build2, Task.Delay(5000)) != build2)
                {
                    Assert.Fail("Build did not start");
                }

                // The second build should finish before the first one

                SignalBuildToContinue(project1);

                if (await Task.WhenAny(build1, Task.Delay(5000)) != build1)
                {
                    Assert.Fail("Build did not end in time");
                }

                Assert.AreEqual(0, build1.Result.ErrorCount);
                Assert.AreEqual(0, build2.Result.ErrorCount);
            }
        }
Пример #7
0
        public async Task RecycleBuildersIsGraceful()
        {
            // RecycleBuilders can be called in the middle of a build and that should not interrupt
            // the build. Builders will be shut down when the build is finished.

            var currentDelay = RemoteBuildEngineManager.EngineDisposalDelay;

            try {
                RemoteBuildEngineManager.EngineDisposalDelay = 400;

                await RemoteBuildEngineManager.RecycleAllBuilders();

                Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

                FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");
                using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                    var project1 = sol.Items.FirstOrDefault(p => p.Name == "SyncBuildProject");
                    var project2 = sol.Items.FirstOrDefault(p => p.Name == "App");

                    InitBuildSyncEvent(project1);

                    // Start the build
                    var build1 = project1.Build(Util.GetMonitor(), sol.Configurations [0].Selector);

                    // Wait for the build to reach the sync task
                    await WaitForBuildSyncEvent(project1);

                    Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(0, await RemoteBuildEngineManager.CountActiveBuildersForProject(project2.FileName));

                    // The build is now in progess. Start a new build

                    var build2 = project2.Build(Util.GetMonitor(), sol.Configurations [0].Selector);
                    if (await Task.WhenAny(build2, Task.Delay(5000)) != build2)
                    {
                        Assert.Fail("Build did not start");
                    }

                    // There should be one builder for each build

                    Assert.AreEqual(2, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(2, RemoteBuildEngineManager.EnginesCount);

                    // Ask for all active builders to be shut down

                    await RemoteBuildEngineManager.RecycleAllBuilders();

                    // There is a build in progress, so there must still be one engine running

                    Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(1, RemoteBuildEngineManager.EnginesCount);

                    SignalBuildToContinue(project1);

                    if (await Task.WhenAny(build1, Task.Delay(5000)) != build1)
                    {
                        Assert.Fail("Build did not end in time");
                    }

                    Assert.AreEqual(0, build1.Result.ErrorCount);
                    Assert.AreEqual(0, build2.Result.ErrorCount);

                    // The builder that was running the build and was shutdown should be immediately stopped after build finishes
                    Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(0, RemoteBuildEngineManager.EnginesCount);
                }
            } finally {
                RemoteBuildEngineManager.EngineDisposalDelay = currentDelay;
            }
        }
Пример #8
0
        public async Task AtLeastOneBuilderPersolution()
        {
            // There should always be at least one builder running per solution,
            // until the solution is explicitly disposed

            var currentDelay = RemoteBuildEngineManager.EngineDisposalDelay;

            try {
                RemoteBuildEngineManager.EngineDisposalDelay = 400;

                await RemoteBuildEngineManager.RecycleAllBuilders();

                Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

                FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");
                using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                    var project1 = sol.Items.FirstOrDefault(p => p.Name == "SyncBuildProject");
                    var project2 = sol.Items.FirstOrDefault(p => p.Name == "App");

                    InitBuildSyncEvent(project1);

                    // Start the build
                    var build1 = project1.Build(Util.GetMonitor(), sol.Configurations [0].Selector);

                    // Wait for the build to reach the sync task
                    await WaitForBuildSyncEvent(project1);

                    Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(0, await RemoteBuildEngineManager.CountActiveBuildersForProject(project2.FileName));

                    // The build is now in progess. Start a new build

                    var build2 = project2.Build(Util.GetMonitor(), sol.Configurations [0].Selector);

                    if (await Task.WhenAny(build2, Task.Delay(5000)) != build2)
                    {
                        Assert.Fail("Build did not start");
                    }

                    Assert.AreEqual(2, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(2, RemoteBuildEngineManager.EnginesCount);
                    Assert.AreEqual(1, await RemoteBuildEngineManager.CountActiveBuildersForProject(project1.FileName));
                    Assert.AreEqual(1, await RemoteBuildEngineManager.CountActiveBuildersForProject(project2.FileName));

                    SignalBuildToContinue(project1);

                    if (await Task.WhenAny(build1, Task.Delay(5000)) != build1)
                    {
                        Assert.Fail("Build did not end in time");
                    }

                    // Build engine disposal delay is set to 400ms, so unused
                    // builders should go away after a 500ms wait.

                    await Task.Delay(500);

                    // There should be at least one builder left

                    Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(1, RemoteBuildEngineManager.EnginesCount);
                }
            } finally {
                RemoteBuildEngineManager.EngineDisposalDelay = currentDelay;
            }

            // All builders should be gone now
            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);
            Assert.AreEqual(0, RemoteBuildEngineManager.EnginesCount);
        }
Пример #9
0
        public async Task ExtraBuilderAutoShutdown()
        {
            // When an extra builder is created, it should be shut down when it is
            // not used anymore, after a delay

            var currentDelay = RemoteBuildEngineManager.EngineDisposalDelay;

            try {
                RemoteBuildEngineManager.EngineDisposalDelay = 400;

                await RemoteBuildEngineManager.RecycleAllBuilders();

                Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

                FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");
                using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                    var project1 = sol.Items.FirstOrDefault(p => p.Name == "SyncBuildProject");
                    var project2 = sol.Items.FirstOrDefault(p => p.Name == "App");

                    InitBuildSyncEvent(project1);

                    // Start the build
                    var build1 = project1.Build(Util.GetMonitor(), sol.Configurations [0].Selector);

                    // Wait for the build to reach the sync task
                    await WaitForBuildSyncEvent(project1);

                    Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(0, await RemoteBuildEngineManager.CountActiveBuildersForProject(project2.FileName));

                    // The build is now in progess. Start a new build

                    var build2 = project2.Build(Util.GetMonitor(), sol.Configurations [0].Selector);
                    if (await Task.WhenAny(build2, Task.Delay(5000)) != build2)
                    {
                        Assert.Fail("Build did not start");
                    }

                    Assert.AreEqual(2, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(1, await RemoteBuildEngineManager.CountActiveBuildersForProject(project2.FileName));

                    // Build engine disposal delay is set to 400ms, so it should be gone after waiting the following wait.

                    await Task.Delay(500);

                    // The second builder should now be gone

                    Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
                    Assert.AreEqual(1, RemoteBuildEngineManager.EnginesCount);
                    Assert.AreEqual(0, await RemoteBuildEngineManager.CountActiveBuildersForProject(project2.FileName));

                    SignalBuildToContinue(project1);

                    if (await Task.WhenAny(build1, Task.Delay(5000)) != build1)
                    {
                        Assert.Fail("Build did not end in time");
                    }
                }
            } finally {
                RemoteBuildEngineManager.EngineDisposalDelay = currentDelay;
            }
        }
Пример #10
0
        public async Task ConcurrentShortAndBuildOperations()
        {
            // If a builder is running a short operation and a build is started,
            // the build operation will wait for the sort operation to finish
            // and will use the same builder, instead of starting a new one.
            // Also, the build session should not start until the short operation
            // is finished.

            await RemoteBuildEngineManager.RecycleAllBuilders();

            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

            FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                var project1 = (Project)sol.Items.FirstOrDefault(p => p.Name == "SyncBuildProject");
                var project2 = (Project)sol.Items.FirstOrDefault(p => p.Name == "App");

                InitBuildSyncEvent(project1);

                // Start the first target. The FileSync target will pause until signaled to continue.
                // Select the ShortOperations build queue.
                var context = new TargetEvaluationContext {
                    BuilderQueue = BuilderQueue.ShortOperations
                };
                var build1 = project1.RunTarget(Util.GetMonitor(), "FileSync", sol.Configurations [0].Selector, context);

                // Wait for the build to reach the sync task
                await WaitForBuildSyncEvent(project1);

                Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);

                // The build is now in progess. Run a new target.

                var build2 = project2.Build(Util.GetMonitor(), sol.Configurations [0].Selector);

                // Wait a bit. This should be enough to ensure the build has started.
                await Task.Delay(1000);

                // The RunTarget request should be queued, no new builder should be spawned
                Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);

                // Continue building the first project
                SignalBuildToContinue(project1);

                // The first build should end now
                if (await Task.WhenAny(build1, Task.Delay(5000)) != build1)
                {
                    Assert.Fail("Build did not end in time");
                }

                // And now the second build should end
                if (await Task.WhenAny(build2, Task.Delay(5000)) != build2)
                {
                    Assert.Fail("Build did not end in time");
                }

                Assert.NotNull(build1.Result);
                Assert.AreEqual(0, build2.Result.ErrorCount);

                Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
            }
        }
Пример #11
0
        public async Task ShortOperationsInSingleBuilder()
        {
            // Tests that targets using BuilderQueue.ShortOperations share the same builder
            // and don't spawn a new builder when one of them is being executed and another
            // one starts executing.

            await RemoteBuildEngineManager.RecycleAllBuilders();

            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

            FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                var project1 = (Project)sol.Items.FirstOrDefault(p => p.Name == "SyncBuildProject");
                var project2 = (Project)sol.Items.FirstOrDefault(p => p.Name == "App");

                InitBuildSyncEvent(project1);

                // Start the first target. The FileSync target will pause until signaled to continue.
                // Select the ShortOperations build queue.
                var context = new TargetEvaluationContext {
                    BuilderQueue = BuilderQueue.ShortOperations
                };
                var build1 = project1.RunTarget(Util.GetMonitor(), "FileSync", sol.Configurations [0].Selector, context);

                // Wait for the build to reach the sync task
                await WaitForBuildSyncEvent(project1);

                Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);

                // The build is now in progess. Run a new target.

                context = new TargetEvaluationContext {
                    BuilderQueue = BuilderQueue.ShortOperations
                };
                var build2 = project2.RunTarget(Util.GetMonitor(), "QuickTarget", sol.Configurations [0].Selector, context);

                // Wait a bit. This should be enough to ensure the build has started.
                await Task.Delay(1000);

                // The RunTarget request should be queued, not new builder should be spawned
                Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);

                // Continue building the first project
                SignalBuildToContinue(project1);

                // The first build should end now
                if (await Task.WhenAny(build1, Task.Delay(5000)) != build1)
                {
                    Assert.Fail("Build did not end in time");
                }

                // And now the second build should end
                if (await Task.WhenAny(build2, Task.Delay(5000)) != build2)
                {
                    Assert.Fail("Build did not end in time");
                }

                Assert.NotNull(build1.Result);
                Assert.NotNull(build2.Result);
                Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
            }
        }
Пример #12
0
        public async Task ReloadProject_ProjectDisposedWhilstTargetRunning_AnotherTargetRun()
        {
            // When a long operation is running and a new one is requested, a new builder is created

            await RemoteBuildEngineManager.RecycleAllBuilders();

            Assert.AreEqual(0, RemoteBuildEngineManager.ActiveEnginesCount);

            FilePath solFile = Util.GetSampleProject("builder-manager-tests", "builder-manager-tests.sln");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile)) {
                var project1 = (Project)sol.Items.FirstOrDefault(p => p.Name == "SyncBuildProject");

                InitBuildSyncEvent(project1);

                // Start the build. Use RunTarget to avoid the BindTask which will cancel the build on project dispose.
                var build1 = project1.RunTarget(Util.GetMonitor(), "Build", sol.Configurations [0].Selector);

                // Wait for the build to reach the sync task
                await WaitForBuildSyncEvent(project1);

                // The build is now in progess. Simulate reloading the project.
                using (var project2 = (Project)await sol.RootFolder.ReloadItem(Util.GetMonitor(), project1)) {
                    var builderTask = project2.GetProjectBuilder(CancellationToken.None, null, allowBusy: true);

                    // Allow second build to finish and dispose its project builder. Have to do this here otherwise
                    // GetProjectBuilder will hang waiting for a connection response back after it creates a new
                    // project builder.
                    SignalBuildToContinue(project1);
                    if (await Task.WhenAny(build1, Task.Delay(timeoutMs)) != build1)
                    {
                        Assert.Fail("Build did not end in time");
                    }

                    Assert.AreEqual(0, build1.Result.BuildResult.ErrorCount);

                    using (var builder = await builderTask) {
                        // Sanity check. We should only have one project builder and one build engine.
                        Assert.AreEqual(1, RemoteBuildEngineManager.ActiveEnginesCount);
                        Assert.AreEqual(1, RemoteBuildEngineManager.EnginesCount);
                        Assert.AreEqual(1, await RemoteBuildEngineManager.CountActiveBuildersForProject(project2.FileName));

                        var configs = project2.GetConfigurations(sol.Configurations [0].Selector, false);

                        var build2 = await Task.Run(() => {
                            // Previously this would throw a NullReferenceException since the builder has been disposed
                            // and the engine is null.
                            return(builder.Run(
                                       configs,
                                       new StringWriter(),
                                       new MSBuildLogger(),
                                       MSBuildVerbosity.Quiet,
                                       new [] { "ResolveAssemblyReferences" },
                                       new string [0],
                                       new string [0],
                                       new System.Collections.Generic.Dictionary <string, string> (),
                                       CancellationToken.None));
                        });

                        Assert.AreEqual(0, build2.Errors.Length);
                    }
                }
            }
        }
Пример #13
0
        public async Task <SolutionFolderItem> ReloadItem(ProgressMonitor monitor, SolutionFolderItem sitem)
        {
            if (Items.IndexOf(sitem) == -1)
            {
                throw new InvalidOperationException("Solution item '" + sitem.Name + "' does not belong to folder '" + Name + "'");
            }

            if (sitem is SolutionItem item)
            {
                // Load the new item

                SolutionItem newItem;
                try {
                    if (ParentSolution.IsSolutionItemEnabled(item.FileName))
                    {
                        using (var ctx = new SolutionLoadContext(ParentSolution))
                            newItem = await Services.ProjectService.ReadSolutionItem(monitor, item.FileName, null, ctx : ctx, itemGuid : item.ItemId);
                    }
                    else
                    {
                        UnknownSolutionItem e = new UnloadedSolutionItem()
                        {
                            FileName = item.FileName
                        };
                        e.ItemId   = item.ItemId;
                        e.TypeGuid = item.TypeGuid;
                        newItem    = e;
                    }
                } catch (Exception ex) {
                    newItem = new UnknownSolutionItem {
                        LoadError = ex.Message,
                        FileName  = item.FileName
                    };
                }

                if (!Items.Contains(item))
                {
                    // The old item is gone, which probably means it has already been reloaded (BXC20615), or maybe removed.
                    // In this case, there isn't anything else we can do
                    newItem.Dispose();

                    // Find the replacement if it exists
                    return(Items.OfType <SolutionItem> ().FirstOrDefault(it => it.FileName == item.FileName));
                }

                // Replace in the file list
                Items.Replace(item, newItem);

                item.ParentFolder = null;
                DisconnectChildEntryEvents(item);
                ConnectChildEntryEvents(newItem);

                // Shutdown project builder before the ItemAdded event is fired. This should prevent the old out of
                // date project builder being used by the TypeSystemService when getting reference information. The
                // TypeSystemService loads the project when the ItemAdded event is fired before the item is disposed.
                // Disposing the project will also shutdown the project builder but this happens too late and can
                // result in the old project builder being used which does not have the latest project xml.
                if (item is Project)
                {
                    await RemoteBuildEngineManager.UnloadProject(item.FileName);
                }

                NotifyModified("Items");
                OnItemRemoved(new SolutionItemChangeEventArgs(item, ParentSolution, true)
                {
                    ReplacedItem = item
                }, true);
                OnItemAdded(new SolutionItemChangeEventArgs(newItem, ParentSolution, true)
                {
                    ReplacedItem = item
                }, true);

                item.Dispose();
                return(newItem);
            }

            return(sitem);
        }