Browse Source

New async-based API for the build engine.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
f42d52cfed
  1. 18
      src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestBuildProjectFactory.cs
  2. 6
      src/AddIns/Analysis/UnitTesting/Model/ITestProject.cs
  3. 5
      src/AddIns/Analysis/UnitTesting/Model/TestProjectBase.cs
  4. 2
      src/AddIns/Analysis/UnitTesting/Test/NUnit/CreateNUnitTestRunnerTestFixture.cs
  5. 17
      src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionManager.cs
  6. 2
      src/AddIns/Analysis/UnitTesting/UnitTesting.csproj
  7. 16
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs
  8. 1
      src/AddIns/Misc/UsageDataCollector/UsageDataCollector/UsageDataSessionWriter.cs
  9. 2
      src/Main/Base/Project/ICSharpCode.SharpDevelop.addin
  10. 22
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  11. 21
      src/Main/Base/Project/Project/Build/BuildDetection.cs
  12. 16
      src/Main/Base/Project/Project/Build/BuildError.cs
  13. 43
      src/Main/Base/Project/Project/Build/BuildEventArgs.cs
  14. 76
      src/Main/Base/Project/Project/Build/BuildOptions.cs
  15. 11
      src/Main/Base/Project/Project/Build/BuildOutputVerbosity.cs
  16. 41
      src/Main/Base/Project/Project/Build/BuildResults.cs
  17. 0
      src/Main/Base/Project/Project/Build/BuildTarget.cs
  18. 22
      src/Main/Base/Project/Project/Build/IBuildFeedbackSink.cs
  19. 77
      src/Main/Base/Project/Project/Build/IBuildService.cs
  20. 46
      src/Main/Base/Project/Project/Build/IBuildable.cs
  21. 13
      src/Main/Base/Project/Project/Build/MultipleProjectBuildable.cs
  22. 47
      src/Main/Base/Project/Project/Build/ProjectBuildOptions.cs
  23. 5
      src/Main/Base/Project/Services/SD.cs
  24. 76
      src/Main/Base/Project/Src/Commands/BuildCommands.cs
  25. 8
      src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/IDEOptions/ProjectAndSolutionOptions.xaml.cs
  26. 2
      src/Main/Base/Project/Src/Gui/IProgressMonitor.cs
  27. 1
      src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs
  28. 16
      src/Main/Base/Project/Src/Project/AbstractProject.cs
  29. 18
      src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs
  30. 2
      src/Main/Base/Project/Src/Project/BeforeBuildCustomToolRunner.cs
  31. 1
      src/Main/Base/Project/Src/Project/ConfigurationGuiHelper.cs
  32. 36
      src/Main/Base/Project/Src/Project/IProject.cs
  33. 14
      src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs
  34. 2
      src/Main/Base/Project/Src/Project/MSBuildEngine/BuildWorkerManager.cs
  35. 22
      src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildEngine.cs
  36. 6
      src/Main/Base/Project/Src/Project/MSBuildFileProject.cs
  37. 4
      src/Main/Base/Project/Src/Project/ProjectLoadInformation.cs
  38. 13
      src/Main/Base/Project/Src/Project/Solution/Solution.cs
  39. 84
      src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs
  40. 48
      src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs
  41. 1
      src/Main/Core/Project/Src/Services/PropertyService/PropertyServiceImpl.cs
  42. 57
      src/Main/SharpDevelop/Project/Build/BuildEngine.cs
  43. 155
      src/Main/SharpDevelop/Project/Build/BuildModifiedProjectsOnlyService.cs
  44. 117
      src/Main/SharpDevelop/Project/Build/BuildService.cs
  45. 46
      src/Main/SharpDevelop/Project/Build/UIBuildFeedbackSink.cs
  46. 6
      src/Main/SharpDevelop/SharpDevelop.csproj

18
src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestBuildProjectFactory.cs

@ -1,18 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Project.Commands;
namespace ICSharpCode.UnitTesting
{
public class UnitTestBuildProjectFactory : IBuildProjectFactory
{
public BuildProject CreateBuildProjectBeforeTestRun(IEnumerable<IBuildable> projects)
{
return new BuildProjectBeforeExecute(new MultipleProjectBuildable(projects));
}
}
}

6
src/AddIns/Analysis/UnitTesting/Model/ITestProject.cs

@ -28,11 +28,9 @@ namespace ICSharpCode.UnitTesting
IEnumerable<ITest> GetTestsForEntity(IEntity entity); IEnumerable<ITest> GetTestsForEntity(IEntity entity);
/// <summary> /// <summary>
/// Returns a SharpDevelop <see cref="IBuildable"/> that builds the project /// Gets whether the project needs to be compiled before the tests can be run.
/// for test execution.
/// May return null if the project does not require compilation.
/// </summary> /// </summary>
IBuildable GetBuildableForTesting(); bool IsBuildNeededBeforeTestRun { get; }
/// <summary> /// <summary>
/// Notifies the project that the parse information was changed. /// Notifies the project that the parse information was changed.

5
src/AddIns/Analysis/UnitTesting/Model/TestProjectBase.cs

@ -57,9 +57,8 @@ namespace ICSharpCode.UnitTesting
get { return project.Name; } get { return project.Name; }
} }
public virtual IBuildable GetBuildableForTesting() public virtual bool IsBuildNeededBeforeTestRun {
{ get { return true; }
return project;
} }
public override ImmutableStack<ITest> FindPathToDescendant(ITest test) public override ImmutableStack<ITest> FindPathToDescendant(ITest test)

2
src/AddIns/Analysis/UnitTesting/Test/NUnit/CreateNUnitTestRunnerTestFixture.cs

@ -39,7 +39,7 @@ namespace UnitTesting.Tests.NUnit
[Test] [Test]
public void NUnitTestProjectBuildsTheProject() public void NUnitTestProjectBuildsTheProject()
{ {
Assert.AreSame(project, testProject.GetBuildableForTesting()); Assert.IsTrue(testProject.IsBuildNeededBeforeTestRun);
} }
} }
} }

17
src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionManager.cs

@ -23,7 +23,7 @@ namespace ICSharpCode.UnitTesting.Frameworks
/// </summary> /// </summary>
public class TestExecutionManager public class TestExecutionManager
{ {
readonly IBuildProjectFactory buildProjectFactory; readonly IBuildService buildService;
readonly IUnitTestTaskService taskService; readonly IUnitTestTaskService taskService;
readonly IUnitTestSaveAllFilesCommand saveAllFilesCommand; readonly IUnitTestSaveAllFilesCommand saveAllFilesCommand;
readonly ITestService testService; readonly ITestService testService;
@ -34,7 +34,7 @@ namespace ICSharpCode.UnitTesting.Frameworks
public TestExecutionManager() public TestExecutionManager()
{ {
this.buildProjectFactory = new UnitTestBuildProjectFactory(); this.buildService = SD.BuildService;
this.taskService = new UnitTestTaskService(); this.taskService = new UnitTestTaskService();
this.saveAllFilesCommand = new UnitTestSaveAllFilesCommand(); this.saveAllFilesCommand = new UnitTestSaveAllFilesCommand();
this.testService = SD.GetRequiredService<ITestService>(); this.testService = SD.GetRequiredService<ITestService>();
@ -62,12 +62,15 @@ namespace ICSharpCode.UnitTesting.Frameworks
saveAllFilesCommand.SaveAllFiles(); saveAllFilesCommand.SaveAllFiles();
// Run the build, if necessary: // Run the build, if necessary:
var projectsToBuild = testsByProject.Keys.Select(p => p.GetBuildableForTesting()).Where(b => b != null).ToList(); var projectsToBuild = testsByProject.Keys.Where(p => p.IsBuildNeededBeforeTestRun).Select(p => p.Project).ToList();
if (projectsToBuild.Count > 0) { if (projectsToBuild.Count > 0) {
var buildCommand = buildProjectFactory.CreateBuildProjectBeforeTestRun(projectsToBuild); using (cancellationToken.Register(buildService.CancelBuild)) {
var buildResults = await buildCommand.BuildAsync(cancellationToken); var buildOptions = new BuildOptions(BuildTarget.Build);
if (buildResults.Result != BuildResultCode.Success) buildOptions.BuildDetection = BuildOptions.BuildOnExecute;
return; var buildResults = await buildService.BuildAsync(projectsToBuild, buildOptions);
if (buildResults.Result != BuildResultCode.Success)
return;
}
} }
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();

2
src/AddIns/Analysis/UnitTesting/UnitTesting.csproj

@ -80,7 +80,6 @@
<Compile Include="Model\ITestSolution.cs" /> <Compile Include="Model\ITestSolution.cs" />
<Compile Include="Model\TestBase.cs" /> <Compile Include="Model\TestBase.cs" />
<Compile Include="Interfaces\IBuildOptions.cs" /> <Compile Include="Interfaces\IBuildOptions.cs" />
<Compile Include="Interfaces\IBuildProjectFactory.cs" />
<Compile Include="Interfaces\IFileSystem.cs" /> <Compile Include="Interfaces\IFileSystem.cs" />
<Compile Include="Interfaces\IUnitTestDebuggerService.cs" /> <Compile Include="Interfaces\IUnitTestDebuggerService.cs" />
<Compile Include="Interfaces\IUnitTestSaveAllFilesCommand.cs" /> <Compile Include="Interfaces\IUnitTestSaveAllFilesCommand.cs" />
@ -100,7 +99,6 @@
<Compile Include="Pad\TestTreeView.cs" /> <Compile Include="Pad\TestTreeView.cs" />
<Compile Include="Pad\UnitTestNode.cs" /> <Compile Include="Pad\UnitTestNode.cs" />
<Compile Include="Pad\UnitTestsPad.cs" /> <Compile Include="Pad\UnitTestsPad.cs" />
<Compile Include="Interfaces\UnitTestBuildProjectFactory.cs" />
<Compile Include="Interfaces\UnitTestDebuggerService.cs" /> <Compile Include="Interfaces\UnitTestDebuggerService.cs" />
<Compile Include="Interfaces\UnitTestFileService.cs" /> <Compile Include="Interfaces\UnitTestFileService.cs" />
<Compile Include="Interfaces\UnitTestSaveAllFilesCommand.cs" /> <Compile Include="Interfaces\UnitTestSaveAllFilesCommand.cs" />

16
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs

@ -7,9 +7,12 @@ using System.ComponentModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Internal.Templates; using ICSharpCode.SharpDevelop.Internal.Templates;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Project.Converter; using ICSharpCode.SharpDevelop.Project.Converter;
@ -80,16 +83,15 @@ namespace CSharpBinding
InitializeProjectContent(new CSharpProjectContent()); InitializeProjectContent(new CSharpProjectContent());
} }
public override void StartBuild(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink) public override Task<bool> BuildAsync(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IProgressMonitor progressMonitor)
{ {
if (this.MinimumSolutionVersion == Solution.SolutionVersionVS2005) { if (this.MinimumSolutionVersion == Solution.SolutionVersionVS2005) {
MSBuildEngine.StartBuild(this, return MSBuildEngine.BuildAsync(
options, this, options, feedbackSink, progressMonitor.CancellationToken,
feedbackSink, MSBuildEngine.AdditionalTargetFiles.Concat(
MSBuildEngine.AdditionalTargetFiles.Concat( new [] { Path.Combine(MSBuildEngine.SharpDevelopBinPath, "SharpDevelop.CheckMSBuild35Features.targets") }));
new [] { Path.Combine(MSBuildEngine.SharpDevelopBinPath, "SharpDevelop.CheckMSBuild35Features.targets") }));
} else { } else {
base.StartBuild(options, feedbackSink); return base.BuildAsync(options, feedbackSink, progressMonitor);
} }
} }

1
src/AddIns/Misc/UsageDataCollector/UsageDataCollector/UsageDataSessionWriter.cs

@ -44,6 +44,7 @@ namespace ICSharpCode.UsageDataCollector
SQLiteConnectionStringBuilder conn = new SQLiteConnectionStringBuilder(); SQLiteConnectionStringBuilder conn = new SQLiteConnectionStringBuilder();
conn.DataSource = databaseFileName; conn.DataSource = databaseFileName;
Directory.CreateDirectory(Path.GetDirectoryName(databaseFileName));
connection = new SQLiteConnection(conn.ConnectionString); connection = new SQLiteConnection(conn.ConnectionString);
connection.Open(); connection.Open();
try { try {

2
src/Main/Base/Project/ICSharpCode.SharpDevelop.addin

@ -70,6 +70,8 @@
class="ICSharpCode.SharpDevelop.Dom.ModelFactory"/> class="ICSharpCode.SharpDevelop.Dom.ModelFactory"/>
<Service id="ICSharpCode.SharpDevelop.IClipboard" <Service id="ICSharpCode.SharpDevelop.IClipboard"
class="ICSharpCode.SharpDevelop.ClipboardWrapper"/> class="ICSharpCode.SharpDevelop.ClipboardWrapper"/>
<Service id="ICSharpCode.SharpDevelop.Project.IBuildService"
class="ICSharpCode.SharpDevelop.Project.BuildService"/>
<Service id="ICSharpCode.SharpDevelop.WinForms.IWinFormsService" <Service id="ICSharpCode.SharpDevelop.WinForms.IWinFormsService"
class="ICSharpCode.SharpDevelop.WinForms.WinFormsService"/> class="ICSharpCode.SharpDevelop.WinForms.WinFormsService"/>

22
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -123,6 +123,18 @@
<Compile Include="Parser\ParseInformation.cs" /> <Compile Include="Parser\ParseInformation.cs" />
<Compile Include="Parser\ParseInformationEventArgs.cs" /> <Compile Include="Parser\ParseInformationEventArgs.cs" />
<Compile Include="Parser\ProjectContentContainer.cs" /> <Compile Include="Parser\ProjectContentContainer.cs" />
<Compile Include="Project\Build\BuildDetection.cs" />
<Compile Include="Project\Build\BuildError.cs" />
<Compile Include="Project\Build\BuildEventArgs.cs" />
<Compile Include="Project\Build\BuildOptions.cs" />
<Compile Include="Project\Build\BuildOutputVerbosity.cs" />
<Compile Include="Project\Build\BuildResults.cs" />
<Compile Include="Project\Build\BuildTarget.cs" />
<Compile Include="Project\Build\IBuildable.cs" />
<Compile Include="Project\Build\IBuildFeedbackSink.cs" />
<Compile Include="Project\Build\IBuildService.cs" />
<Compile Include="Project\Build\MultipleProjectBuildable.cs" />
<Compile Include="Project\Build\ProjectBuildOptions.cs" />
<Compile Include="Services\IClipboard.cs" /> <Compile Include="Services\IClipboard.cs" />
<Compile Include="Services\IMessageLoop.cs" /> <Compile Include="Services\IMessageLoop.cs" />
<Compile Include="Services\SD.cs" /> <Compile Include="Services\SD.cs" />
@ -389,7 +401,6 @@
<Compile Include="Src\Project\Behaviors\ProjectBehaviorService.cs" /> <Compile Include="Src\Project\Behaviors\ProjectBehaviorService.cs" />
<Compile Include="Src\Project\Behaviors\ProjectBehaviorSupportedConditionEvaluator.cs" /> <Compile Include="Src\Project\Behaviors\ProjectBehaviorSupportedConditionEvaluator.cs" />
<Compile Include="Src\Project\Behaviors\ResXConverter.cs" /> <Compile Include="Src\Project\Behaviors\ResXConverter.cs" />
<Compile Include="Src\Project\BuildEngine.cs" />
<Compile Include="Src\Project\ContextSpecificProperties.cs" /> <Compile Include="Src\Project\ContextSpecificProperties.cs" />
<Compile Include="Src\Project\Converter\IUpgradableProject.cs" /> <Compile Include="Src\Project\Converter\IUpgradableProject.cs" />
<Compile Include="Src\Project\Converter\UpgradeView.xaml.cs"> <Compile Include="Src\Project\Converter\UpgradeView.xaml.cs">
@ -397,7 +408,6 @@
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Src\Project\Converter\UpgradeViewContent.cs" /> <Compile Include="Src\Project\Converter\UpgradeViewContent.cs" />
<Compile Include="Src\Project\IBuildFeedbackSink.cs" />
<Compile Include="Src\Project\IProjectChangeWatcher.cs" /> <Compile Include="Src\Project\IProjectChangeWatcher.cs" />
<Compile Include="Src\Project\IProjectItemBackendStore.cs" /> <Compile Include="Src\Project\IProjectItemBackendStore.cs" />
<Compile Include="Src\Project\Items\ServiceReferenceProjectItem.cs" /> <Compile Include="Src\Project\Items\ServiceReferenceProjectItem.cs" />
@ -411,7 +421,6 @@
<Compile Include="Src\Project\MSBuildEngine\WorkerProcess.cs" /> <Compile Include="Src\Project\MSBuildEngine\WorkerProcess.cs" />
<Compile Include="Src\Project\MSBuildFileProject.cs" /> <Compile Include="Src\Project\MSBuildFileProject.cs" />
<Compile Include="Src\Project\MSBuildItemWrapper.cs" /> <Compile Include="Src\Project\MSBuildItemWrapper.cs" />
<Compile Include="Src\Project\MultipleProjectBuildable.cs" />
<Compile Include="Src\Project\PortableLibrary\CheckPortableLibraryInstalled.cs" /> <Compile Include="Src\Project\PortableLibrary\CheckPortableLibraryInstalled.cs" />
<Compile Include="Src\Project\PortableLibrary\ConvertToPortableLibraryProjectBehavior.cs" /> <Compile Include="Src\Project\PortableLibrary\ConvertToPortableLibraryProjectBehavior.cs" />
<Compile Include="Src\Project\PortableLibrary\PickPortableTargetFramework.cs" /> <Compile Include="Src\Project\PortableLibrary\PickPortableTargetFramework.cs" />
@ -460,7 +469,6 @@
<Compile Include="Src\Internal\Doozers\IOptionPanelDescriptor.cs" /> <Compile Include="Src\Internal\Doozers\IOptionPanelDescriptor.cs" />
<Compile Include="Workbench\File\FileEventArgs.cs" /> <Compile Include="Workbench\File\FileEventArgs.cs" />
<Compile Include="Src\Services\MimeTypeDetection.cs" /> <Compile Include="Src\Services\MimeTypeDetection.cs" />
<Compile Include="Src\Services\ProjectService\CompileModifiedProjectsOnly.cs" />
<Compile Include="Src\Services\ProjectService\SolutionConfigurationEventHandler.cs" /> <Compile Include="Src\Services\ProjectService\SolutionConfigurationEventHandler.cs" />
<Compile Include="Src\Services\RefactoringService\ExtractInterfaceOptions.cs" /> <Compile Include="Src\Services\RefactoringService\ExtractInterfaceOptions.cs" />
<Compile Include="Src\Services\RefactoringService\FindReferenceService.cs" /> <Compile Include="Src\Services\RefactoringService\FindReferenceService.cs" />
@ -777,8 +785,6 @@
<Compile Include="Src\Services\NavigationService\NavigationService.cs" /> <Compile Include="Src\Services\NavigationService\NavigationService.cs" />
<Compile Include="Src\Commands\NavigationCommands.cs" /> <Compile Include="Src\Commands\NavigationCommands.cs" />
<Compile Include="Src\Internal\ConditionEvaluators\NavigationConditionEvaluators.cs" /> <Compile Include="Src\Internal\ConditionEvaluators\NavigationConditionEvaluators.cs" />
<Compile Include="Src\Project\BuildResults.cs" />
<Compile Include="Src\Project\BuildError.cs" />
<Compile Include="Src\Services\HelpProvider.cs" /> <Compile Include="Src\Services\HelpProvider.cs" />
<Compile Include="Src\Services\ParserService\CodeCompletionOptions.cs" /> <Compile Include="Src\Services\ParserService\CodeCompletionOptions.cs" />
<Compile Include="Src\Internal\ConditionEvaluators\CompareProjectPropertyConditionEvaluator.cs" /> <Compile Include="Src\Internal\ConditionEvaluators\CompareProjectPropertyConditionEvaluator.cs" />
@ -797,13 +803,11 @@
<Compile Include="Src\Project\MSBuildBasedProject.cs" /> <Compile Include="Src\Project\MSBuildBasedProject.cs" />
<Compile Include="Src\Project\MSBuildItemDefinitionGroup.cs" /> <Compile Include="Src\Project\MSBuildItemDefinitionGroup.cs" />
<Compile Include="Src\Project\AbstractProject.cs" /> <Compile Include="Src\Project\AbstractProject.cs" />
<Compile Include="Src\Project\BuildOptions.cs" />
<Compile Include="Src\Project\CompilableProject.cs" /> <Compile Include="Src\Project\CompilableProject.cs" />
<Compile Include="Src\Project\MSBuildInternals.cs" /> <Compile Include="Src\Project\MSBuildInternals.cs" />
<Compile Include="Src\Util\ScrollUtils.cs" /> <Compile Include="Src\Util\ScrollUtils.cs" />
<Compile Include="Src\Util\ReadOnlyCollectionWrapper.cs" /> <Compile Include="Src\Util\ReadOnlyCollectionWrapper.cs" />
<Compile Include="Src\Project\Items\ItemType.cs" /> <Compile Include="Src\Project\Items\ItemType.cs" />
<Compile Include="Src\Project\BuildTarget.cs" />
<Compile Include="Src\Util\GenericConverter.cs" /> <Compile Include="Src\Util\GenericConverter.cs" />
<Compile Include="Src\Internal\Templates\TemplateLoadException.cs" /> <Compile Include="Src\Internal\Templates\TemplateLoadException.cs" />
<Compile Include="Src\Util\UnclosableStream.cs" /> <Compile Include="Src\Util\UnclosableStream.cs" />
@ -867,7 +871,9 @@
</ProjectReference> </ProjectReference>
<Folder Include="Dom" /> <Folder Include="Dom" />
<Folder Include="Editor" /> <Folder Include="Editor" />
<Folder Include="Project" />
<Folder Include="Parser" /> <Folder Include="Parser" />
<Folder Include="Project\Build" />
<Folder Include="Services" /> <Folder Include="Services" />
<Folder Include="WinForms" /> <Folder Include="WinForms" />
<Folder Include="Workbench" /> <Folder Include="Workbench" />

21
src/Main/Base/Project/Project/Build/BuildDetection.cs

@ -0,0 +1,21 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.ComponentModel;
using System.Collections.Generic;
namespace ICSharpCode.SharpDevelop.Project
{
public enum BuildDetection
{
[Description("${res:Dialog.Options.IDEOptions.ProjectAndSolutionOptions.WhenRunning.DoNotBuild}")]
DoNotBuild,
[Description("${res:Dialog.Options.IDEOptions.ProjectAndSolutionOptions.WhenRunning.BuildOnlyModified}")]
BuildOnlyModified,
[Description("${res:Dialog.Options.IDEOptions.ProjectAndSolutionOptions.WhenRunning.BuildModifiedAndDependent}")]
BuildModifiedAndDependent,
[Description("${res:Dialog.Options.IDEOptions.ProjectAndSolutionOptions.WhenRunning.RegularBuild}")]
RegularBuild
}
}

16
src/Main/Base/Project/Src/Project/BuildError.cs → src/Main/Base/Project/Project/Build/BuildError.cs

@ -42,7 +42,8 @@ namespace ICSharpCode.SharpDevelop.Project
string errorText; string errorText;
string fileName; string fileName;
int line; int line;
bool warning; bool isWarning;
bool isMessage;
[NonSerialized] [NonSerialized]
object tag; object tag;
string contextMenuAddInTreeEntry; string contextMenuAddInTreeEntry;
@ -105,12 +106,13 @@ namespace ICSharpCode.SharpDevelop.Project
} }
public bool IsWarning { public bool IsWarning {
get { get { return isWarning; }
return warning; set { isWarning = value; }
} }
set {
warning = value; public bool IsMessage {
} get { return isMessage; }
set { isMessage = value; }
} }
/// <summary> /// <summary>

43
src/Main/Base/Project/Project/Build/BuildEventArgs.cs

@ -0,0 +1,43 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
namespace ICSharpCode.SharpDevelop.Project
{
public class BuildEventArgs : EventArgs
{
/// <summary>
/// The projects to be built.
/// </summary>
public readonly IReadOnlyList<IProject> Projects;
/// <summary>
/// The build options.
/// </summary>
public readonly BuildOptions Options;
/// <summary>
/// Gets the build results.
/// This property is null for build started events.
/// </summary>
public readonly BuildResults Results;
public BuildEventArgs(IReadOnlyList<IProject> projects, BuildOptions options)
: this(projects, options, null)
{
}
public BuildEventArgs(IReadOnlyList<IProject> projects, BuildOptions options, BuildResults results)
{
if (projects == null)
throw new ArgumentNullException("projects");
if (options == null)
throw new ArgumentNullException("options");
this.Projects = projects;
this.Options = options;
this.Results = results;
}
}
}

76
src/Main/Base/Project/Src/Project/BuildOptions.cs → src/Main/Base/Project/Project/Build/BuildOptions.cs

@ -4,60 +4,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.Core; using ICSharpCode.Core;
using Microsoft.Build.Framework;
namespace ICSharpCode.SharpDevelop.Project namespace ICSharpCode.SharpDevelop.Project
{ {
public delegate void BuildCallback(BuildResults results);
/// <summary>
/// Specifies options for building a single project.
/// </summary>
public class ProjectBuildOptions
{
BuildTarget target;
IDictionary<string, string> properties = new SortedList<string, string>();
public BuildTarget Target {
get { return target; }
}
public IDictionary<string, string> Properties {
get { return properties; }
}
public ProjectBuildOptions(BuildTarget target)
{
this.target = target;
}
/// <summary>
/// Specifies the project configuration used for the build.
/// </summary>
public string Configuration { get; set; }
/// <summary>
/// Specifies the project platform used for the build.
/// </summary>
public string Platform { get; set; }
/// <summary>
/// Gets/Sets the verbosity of build output.
/// </summary>
public BuildOutputVerbosity BuildOutputVerbosity { get; set; }
}
public enum BuildOutputVerbosity
{
Normal,
Diagnostic
}
/// <summary> /// <summary>
/// Specifies options when starting a build. /// Specifies options when starting a build.
/// </summary> /// </summary>
public class BuildOptions public class BuildOptions
{ {
#region static settings
public static bool ShowErrorListAfterBuild { public static bool ShowErrorListAfterBuild {
get { get {
return PropertyService.Get("SharpDevelop.ShowErrorListAfterBuild", true); return PropertyService.Get("SharpDevelop.ShowErrorListAfterBuild", true);
@ -76,6 +31,15 @@ namespace ICSharpCode.SharpDevelop.Project
} }
} }
public static BuildDetection BuildOnExecute {
get {
return PropertyService.Get("SharpDevelop.BuildOnExecute", BuildDetection.RegularBuild);
}
set {
PropertyService.Set("SharpDevelop.BuildOnExecute", value);
}
}
public static BuildOutputVerbosity DefaultBuildOutputVerbosity { public static BuildOutputVerbosity DefaultBuildOutputVerbosity {
get { get {
return PropertyService.Get("SharpDevelop.DefaultBuildOutputVerbosity", BuildOutputVerbosity.Normal); return PropertyService.Get("SharpDevelop.DefaultBuildOutputVerbosity", BuildOutputVerbosity.Normal);
@ -84,6 +48,7 @@ namespace ICSharpCode.SharpDevelop.Project
PropertyService.Set("SharpDevelop.DefaultBuildOutputVerbosity", value); PropertyService.Set("SharpDevelop.DefaultBuildOutputVerbosity", value);
} }
} }
#endregion
IDictionary<string, string> globalAdditionalProperties = new SortedList<string, string>(); IDictionary<string, string> globalAdditionalProperties = new SortedList<string, string>();
IDictionary<string, string> projectAdditionalProperties = new SortedList<string, string>(); IDictionary<string, string> projectAdditionalProperties = new SortedList<string, string>();
@ -113,24 +78,21 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary> /// </summary>
public BuildOutputVerbosity BuildOutputVerbosity { get; set; } public BuildOutputVerbosity BuildOutputVerbosity { get; set; }
public BuildOptions(BuildTarget target, BuildCallback callback) /// <summary>
/// Gets/Sets whether to build all projects or only modified ones.
/// The default is to build all projects.
/// </summary>
public BuildDetection BuildDetection { get; set; }
public BuildOptions(BuildTarget target)
{ {
this.callback = callback;
this.projectTarget = target; this.projectTarget = target;
this.TargetForDependencies = target; this.TargetForDependencies = target;
this.BuildDependentProjects = true; this.BuildDependentProjects = true;
this.ParallelProjectCount = DefaultParallelProjectCount; this.ParallelProjectCount = DefaultParallelProjectCount;
this.BuildOutputVerbosity = DefaultBuildOutputVerbosity; this.BuildOutputVerbosity = DefaultBuildOutputVerbosity;
} this.BuildDetection = BuildDetection.RegularBuild;
readonly BuildCallback callback;
/// <summary>
/// Gets the method to call when the build has finished.
/// </summary>
public BuildCallback Callback {
get { return callback; }
} }
readonly BuildTarget projectTarget; readonly BuildTarget projectTarget;

11
src/AddIns/Analysis/UnitTesting/Interfaces/IBuildProjectFactory.cs → src/Main/Base/Project/Project/Build/BuildOutputVerbosity.cs

@ -3,13 +3,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Project.Commands;
namespace ICSharpCode.UnitTesting namespace ICSharpCode.SharpDevelop.Project
{ {
public interface IBuildProjectFactory public enum BuildOutputVerbosity
{ {
BuildProject CreateBuildProjectBeforeTestRun(IEnumerable<IBuildable> projects); Normal,
Diagnostic
} }
} }

41
src/Main/Base/Project/Src/Project/BuildResults.cs → src/Main/Base/Project/Project/Build/BuildResults.cs

@ -30,11 +30,8 @@ namespace ICSharpCode.SharpDevelop.Project
List<BuildError> errors = new List<BuildError>(); List<BuildError> errors = new List<BuildError>();
ReadOnlyCollection<BuildError> readOnlyErrors; ReadOnlyCollection<BuildError> readOnlyErrors;
List<IBuildable> builtProjects = new List<IBuildable>();
ReadOnlyCollection<IBuildable> readOnlyBuiltProjects;
BuildResultCode result; BuildResultCode result;
int errorCount, warningCount; int errorCount, warningCount, messageCount;
/// <summary> /// <summary>
/// Adds a build error/warning to the results. /// Adds a build error/warning to the results.
@ -47,27 +44,15 @@ namespace ICSharpCode.SharpDevelop.Project
lock (errors) { lock (errors) {
readOnlyErrors = null; readOnlyErrors = null;
errors.Add(error); errors.Add(error);
if (error.IsWarning) if (error.IsMessage)
messageCount++;
else if (error.IsWarning)
warningCount++; warningCount++;
else else
errorCount++; errorCount++;
} }
} }
/// <summary>
/// Adds a project to the list of built projects.
/// This method is thread-safe.
/// </summary>
public void AddBuiltProject(IBuildable buildable)
{
if (buildable == null)
throw new ArgumentNullException("buildable");
lock (builtProjects) {
readOnlyBuiltProjects = null;
builtProjects.Add(buildable);
}
}
/// <summary> /// <summary>
/// Gets the list of build errors or warnings. /// Gets the list of build errors or warnings.
/// This property is thread-safe. /// This property is thread-safe.
@ -83,20 +68,6 @@ namespace ICSharpCode.SharpDevelop.Project
} }
} }
/// <summary>
/// Gets the list of projects that were built. This property is thread-safe.
/// </summary>
public ReadOnlyCollection<IBuildable> BuiltProjects {
get {
lock (builtProjects) {
if (readOnlyBuiltProjects == null) {
readOnlyBuiltProjects = Array.AsReadOnly(builtProjects.ToArray());
}
return readOnlyBuiltProjects;
}
}
}
public BuildResultCode Result { public BuildResultCode Result {
get { return result; } get { return result; }
set { result = value; } set { result = value; }
@ -109,5 +80,9 @@ namespace ICSharpCode.SharpDevelop.Project
public int WarningCount { public int WarningCount {
get { return warningCount; } get { return warningCount; }
} }
public int MessageCount {
get { return messageCount; }
}
} }
} }

0
src/Main/Base/Project/Src/Project/BuildTarget.cs → src/Main/Base/Project/Project/Build/BuildTarget.cs

22
src/Main/Base/Project/Src/Project/IBuildFeedbackSink.cs → src/Main/Base/Project/Project/Build/IBuildFeedbackSink.cs

@ -7,19 +7,16 @@ namespace ICSharpCode.SharpDevelop.Project
{ {
/// <summary> /// <summary>
/// Interface for reporting build results in real-time. /// Interface for reporting build results in real-time.
/// Project-specific build engines use this interface to report results to the main build engine.
/// </summary> /// </summary>
/// <remarks>
/// Implementations of this interface must be thread-safe.
/// Project-specific build engines use this interface to report results to the main build engine,
/// and the main build engine uses this interface to report the combined results to the IDE.
/// </remarks>
public interface IBuildFeedbackSink public interface IBuildFeedbackSink
{ {
/// <summary> /// <summary>
/// Gets the progress monitor associated with this build. /// Reports an build error/warning/message by adding it to the error list.
/// Does not return null.
/// This member is thread-safe.
/// </summary>
Gui.IProgressMonitor ProgressMonitor { get; }
/// <summary>
/// Reports an build error by adding it to the error list.
/// This member is thread-safe. /// This member is thread-safe.
/// </summary> /// </summary>
void ReportError(BuildError error); void ReportError(BuildError error);
@ -29,12 +26,5 @@ namespace ICSharpCode.SharpDevelop.Project
/// This member is thread-safe. /// This member is thread-safe.
/// </summary> /// </summary>
void ReportMessage(string message); void ReportMessage(string message);
/// <summary>
/// Notifies the build engine that the build of a project has finished.
/// You should not call any methods after the Done() call.
/// This member is thread-safe.
/// </summary>
void Done(bool success);
} }
} }

77
src/Main/Base/Project/Project/Build/IBuildService.cs

@ -0,0 +1,77 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// The service interface for accessing the build engine.
/// The build engine is responsible for constructing a dependency graph
/// between the <see cref="IBuildable"/>s, performing a topological sort
/// and scheduling the actual build.
/// </summary>
[SDService]
public interface IBuildService
{
/// <summary>
/// Builds the specified projects.
/// If tests are already running, the existing run is cancelled.
/// </summary>
/// <remarks>
/// The build progress will be shown in the SharpDevelop UI;
/// and the build can be cancelled by the user.
/// This method can only be used on the main thread.
/// </remarks>
Task<BuildResults> BuildAsync(IEnumerable<IProject> projects, BuildOptions options);
Task<BuildResults> BuildAsync(IProject project, BuildOptions options);
Task<BuildResults> BuildAsync(Solution solution, BuildOptions options);
/// <summary>
/// Raised when a build is started.
/// </summary>
/// <remarks>This event always occurs on the main thread.</remarks>
event EventHandler<BuildEventArgs> BuildStarted;
/// <summary>
/// Raised when a build is finished.
/// </summary>
/// <remarks>This event always occurs on the main thread.</remarks>
event EventHandler<BuildEventArgs> BuildFinished;
/// <summary>
/// Gets whether a build is currently running.
/// </summary>
bool IsBuilding { get; }
/// <summary>
/// Aborts the current build.
/// This method has no effect if no build is running.
/// </summary>
void CancelBuild();
/// <summary>
/// Performs a build in the background (not visible in the UI).
/// </summary>
/// <param name="buildable">The root buildable</param>
/// <param name="options">The build options that should be used</param>
/// <param name="buildFeedbackSink">The build feedback sink that receives the build output.</param>
/// <param name="progressMonitor">Progress monitor used to report progress about this build.</param>
/// <remarks>
/// This method does not set <see cref="IsBuilding"/> and cannot be cancelled using
/// <see cref="CancelBuild()"/>.
/// Cancellation is possible using the progress monitor's cancellation token, but
/// will not cause an <see cref="TaskCanceledException"/> - instead, the build results
/// will use <c>BuildResultCode.Cancelled</c>.
/// It does not raise the <see cref="BuildStarted"/>/<see cref="BuildFinished"/> events.
/// This method is thread-safe, and multiple background builds can run concurrently.
/// </remarks>
Task<BuildResults> BuildInBackgroundAsync(IBuildable buildable, BuildOptions options, IBuildFeedbackSink buildFeedbackSink, IProgressMonitor progressMonitor);
}
}

46
src/Main/Base/Project/Project/Build/IBuildable.cs

@ -0,0 +1,46 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// A project or solution.
/// The IBuildable interface members are thread-safe.
/// </summary>
public interface IBuildable
{
/// <summary>
/// Gets the list of projects on which this project depends.
/// This method is thread-safe.
/// </summary>
IEnumerable<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions);
/// <summary>
/// Starts building the project using the specified options.
/// This member must be implemented thread-safe.
/// </summary>
Task<bool> BuildAsync(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IProgressMonitor progressMonitor);
/// <summary>
/// Gets the name of the buildable item.
/// This property is thread-safe.
/// </summary>
string Name { get; }
/// <summary>
/// Creates the project-specific build options.
/// This member must be implemented thread-safe.
/// </summary>
/// <param name="options">The global build options.</param>
/// <param name="isRootBuildable">Specifies whether this project is the main buildable item.
/// The root buildable is the buildable for which <see cref="BuildOptions.ProjectTarget"/> and <see cref="BuildOptions.ProjectAdditionalProperties"/> apply.
/// The dependencies of that root buildable are the non-root buildables.</param>
/// <returns>The project-specific build options.</returns>
ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable);
}
}

13
src/Main/Base/Project/Src/Project/MultipleProjectBuildable.cs → src/Main/Base/Project/Project/Build/MultipleProjectBuildable.cs

@ -4,6 +4,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.SharpDevelop.Project namespace ICSharpCode.SharpDevelop.Project
@ -24,19 +27,15 @@ namespace ICSharpCode.SharpDevelop.Project
get { return string.Empty; } get { return string.Empty; }
} }
public Solution ParentSolution { public IEnumerable<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)
get { return projects.Length > 0 ? projects[0].ParentSolution : null; }
}
public ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)
{ {
return projects; return projects;
} }
public void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink) public Task<bool> BuildAsync(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IProgressMonitor progressMonitor)
{ {
// SharpDevelop already has built our dependencies, so we're done immediately. // SharpDevelop already has built our dependencies, so we're done immediately.
feedbackSink.Done(true); return Task.FromResult(true);
} }
public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable) public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable)

47
src/Main/Base/Project/Project/Build/ProjectBuildOptions.cs

@ -0,0 +1,47 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// Specifies options for building a single project.
/// </summary>
public class ProjectBuildOptions
{
BuildTarget target;
IDictionary<string, string> properties = new SortedList<string, string>();
public BuildTarget Target {
get { return target; }
}
public IDictionary<string, string> Properties {
get { return properties; }
}
public ProjectBuildOptions(BuildTarget target)
{
this.target = target;
}
/// <summary>
/// Specifies the project configuration used for the build.
/// </summary>
public string Configuration { get; set; }
/// <summary>
/// Specifies the project platform used for the build.
/// </summary>
public string Platform { get; set; }
/// <summary>
/// Gets/Sets the verbosity of build output.
/// </summary>
public BuildOutputVerbosity BuildOutputVerbosity { get; set; }
}
}

5
src/Main/Base/Project/Services/SD.cs

@ -11,6 +11,7 @@ using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Parser; using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.WinForms; using ICSharpCode.SharpDevelop.WinForms;
using ICSharpCode.SharpDevelop.Workbench; using ICSharpCode.SharpDevelop.Workbench;
@ -174,5 +175,9 @@ namespace ICSharpCode.SharpDevelop
public static IWinFormsService WinForms { public static IWinFormsService WinForms {
get { return GetRequiredService<IWinFormsService>(); } get { return GetRequiredService<IWinFormsService>(); }
} }
public static IBuildService BuildService {
get { return GetRequiredService<IBuildService>(); }
}
} }
} }

76
src/Main/Base/Project/Src/Commands/BuildCommands.cs

@ -25,9 +25,7 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
public virtual void BeforeBuild() public virtual void BeforeBuild()
{ {
TaskService.BuildMessageViewCategory.ClearText(); TaskService.BuildMessageViewCategory.ClearText();
TaskService.InUpdate = true;
TaskService.ClearExceptCommentTasks(); TaskService.ClearExceptCommentTasks();
TaskService.InUpdate = false;
ICSharpCode.SharpDevelop.Commands.SaveAllFiles.SaveAll(); ICSharpCode.SharpDevelop.Commands.SaveAllFiles.SaveAll();
} }
@ -77,26 +75,6 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
} }
} }
public Task<BuildResults> BuildAsync(CancellationToken cancellationToken)
{
var registration = cancellationToken.Register(BuildEngine.CancelGuiBuild, true);
var tcs = new TaskCompletionSource<BuildResults>();
this.BuildComplete += delegate {
registration.Dispose();
if (cancellationToken.IsCancellationRequested)
tcs.TrySetCanceled();
else
tcs.TrySetResult(this.LastBuildResults);
};
try {
StartBuild();
} catch (Exception ex) {
registration.Dispose();
tcs.TrySetException(ex);
}
return tcs.Task;
}
/// <summary> /// <summary>
/// Notifies the user that #develp's internal MSBuildEngine /// Notifies the user that #develp's internal MSBuildEngine
/// implementation only supports compiling solutions and projects; /// implementation only supports compiling solutions and projects;
@ -113,9 +91,9 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
public class Build : AbstractBuildMenuCommand public class Build : AbstractBuildMenuCommand
{ {
public override void StartBuild() public override async void StartBuild()
{ {
BuildEngine.BuildInGui(ProjectService.OpenSolution, new BuildOptions(BuildTarget.Build, CallbackMethod)); CallbackMethod(await SD.BuildService.BuildAsync(ProjectService.OpenSolution, new BuildOptions(BuildTarget.Build)));
} }
} }
@ -123,7 +101,7 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
{ {
public override void Run() public override void Run()
{ {
if (BuildModifiedProjectsOnlyService.Setting == BuildOnExecuteSetting.DoNotBuild) { if (BuildOptions.BuildOnExecute == BuildDetection.DoNotBuild) {
LastBuildResults = new BuildResults { Result = BuildResultCode.Success }; LastBuildResults = new BuildResults { Result = BuildResultCode.Success };
OnBuildComplete(EventArgs.Empty); OnBuildComplete(EventArgs.Empty);
} else { } else {
@ -131,22 +109,22 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
} }
} }
public override void StartBuild() public override async void StartBuild()
{ {
BuildEngine.BuildInGui(BuildModifiedProjectsOnlyService.WrapBuildable(ProjectService.OpenSolution), var options = new BuildOptions(BuildTarget.Build) { BuildDetection = BuildOptions.BuildOnExecute };
new BuildOptions(BuildTarget.Build, CallbackMethod)); CallbackMethod(await SD.BuildService.BuildAsync(ProjectService.OpenSolution, options));
} }
} }
public class BuildProjectBeforeExecute : BuildProject public class BuildProjectBeforeExecute : BuildProject
{ {
public BuildProjectBeforeExecute(IBuildable project) : base(project) public BuildProjectBeforeExecute(IProject project) : base(project)
{ {
} }
public override void Run() public override void Run()
{ {
if (BuildModifiedProjectsOnlyService.Setting == BuildOnExecuteSetting.DoNotBuild) { if (BuildOptions.BuildOnExecute == BuildDetection.DoNotBuild) {
LastBuildResults = new BuildResults { Result = BuildResultCode.Success }; LastBuildResults = new BuildResults { Result = BuildResultCode.Success };
OnBuildComplete(EventArgs.Empty); OnBuildComplete(EventArgs.Empty);
} else { } else {
@ -154,33 +132,33 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
} }
} }
public override void StartBuild() public override async void StartBuild()
{ {
BuildEngine.BuildInGui(BuildModifiedProjectsOnlyService.WrapBuildable(this.ProjectToBuild), var options = new BuildOptions(BuildTarget.Build) { BuildDetection = BuildOptions.BuildOnExecute };
new BuildOptions(BuildTarget.Build, CallbackMethod)); CallbackMethod(await SD.BuildService.BuildAsync(this.ProjectToBuild, options));
} }
} }
public class Rebuild : Build public class Rebuild : Build
{ {
public override void StartBuild() public override async void StartBuild()
{ {
BuildEngine.BuildInGui(ProjectService.OpenSolution, new BuildOptions(BuildTarget.Rebuild, CallbackMethod)); CallbackMethod(await SD.BuildService.BuildAsync(ProjectService.OpenSolution, new BuildOptions(BuildTarget.Rebuild)));
} }
} }
public class Clean : AbstractBuildMenuCommand public class Clean : AbstractBuildMenuCommand
{ {
public override void StartBuild() public override async void StartBuild()
{ {
BuildEngine.BuildInGui(ProjectService.OpenSolution, new BuildOptions(BuildTarget.Clean, CallbackMethod)); CallbackMethod(await SD.BuildService.BuildAsync(ProjectService.OpenSolution, new BuildOptions(BuildTarget.Clean)));
} }
} }
public abstract class AbstractProjectBuildMenuCommand : AbstractBuildMenuCommand public abstract class AbstractProjectBuildMenuCommand : AbstractBuildMenuCommand
{ {
protected IBuildable targetProject; protected IProject targetProject;
protected IBuildable ProjectToBuild { protected IProject ProjectToBuild {
get { get {
return targetProject ?? ProjectService.CurrentProject; return targetProject ?? ProjectService.CurrentProject;
} }
@ -197,33 +175,33 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
public BuildProject() public BuildProject()
{ {
} }
public BuildProject(IBuildable targetProject) public BuildProject(IProject targetProject)
{ {
this.targetProject = targetProject; this.targetProject = targetProject;
} }
public override void StartBuild() public override async void StartBuild()
{ {
BuildEngine.BuildInGui(this.ProjectToBuild, new BuildOptions(BuildTarget.Build, CallbackMethod)); CallbackMethod(await SD.BuildService.BuildAsync(this.ProjectToBuild, new BuildOptions(BuildTarget.Build)));
} }
} }
public class RebuildProject : BuildProject public class RebuildProject : BuildProject
{ {
public RebuildProject() {} public RebuildProject() {}
public RebuildProject(IBuildable targetProject) : base(targetProject) {} public RebuildProject(IProject targetProject) : base(targetProject) {}
public override void StartBuild() public override async void StartBuild()
{ {
BuildEngine.BuildInGui(this.ProjectToBuild, new BuildOptions(BuildTarget.Rebuild, CallbackMethod)); CallbackMethod(await SD.BuildService.BuildAsync(this.ProjectToBuild, new BuildOptions(BuildTarget.Rebuild)));
} }
} }
public class CleanProject : AbstractProjectBuildMenuCommand public class CleanProject : AbstractProjectBuildMenuCommand
{ {
public override void StartBuild() public override async void StartBuild()
{ {
BuildEngine.BuildInGui(this.ProjectToBuild, new BuildOptions(BuildTarget.Clean, CallbackMethod)); CallbackMethod(await SD.BuildService.BuildAsync(this.ProjectToBuild, new BuildOptions(BuildTarget.Clean)));
} }
} }
@ -231,11 +209,11 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
{ {
public override void Run() public override void Run()
{ {
BuildEngine.CancelGuiBuild(); SD.BuildService.CancelBuild();
} }
public override bool IsEnabled { public override bool IsEnabled {
get { return BuildEngine.IsGuiBuildRunning; } get { return SD.BuildService.IsBuilding; }
set { } set { }
} }
} }

8
src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/IDEOptions/ProjectAndSolutionOptions.xaml.cs

@ -17,13 +17,13 @@ namespace ICSharpCode.SharpDevelop.Gui.OptionPanels
{ {
InitializeComponent(); InitializeComponent();
FillComboBoxWithEnumValues(typeof(Project.BuildOnExecuteSetting), onExecuteComboBox); FillComboBoxWithEnumValues(typeof(Project.BuildDetection), onExecuteComboBox);
FillComboBoxWithEnumValues(typeof(Project.BuildOutputVerbosity), verbosityComboBox); FillComboBoxWithEnumValues(typeof(Project.BuildOutputVerbosity), verbosityComboBox);
} }
void FillComboBoxWithEnumValues(Type type, ComboBox comboBox) void FillComboBoxWithEnumValues(Type type, ComboBox comboBox)
{ {
foreach (Project.BuildOnExecuteSetting element in Enum.GetValues(type)) { foreach (Project.BuildDetection element in Enum.GetValues(type)) {
object[] attr = type.GetField(Enum.GetName(type, element)).GetCustomAttributes(typeof(DescriptionAttribute), false); object[] attr = type.GetField(Enum.GetName(type, element)).GetCustomAttributes(typeof(DescriptionAttribute), false);
string description; string description;
if (attr.Length > 0) { if (attr.Length > 0) {
@ -48,7 +48,7 @@ namespace ICSharpCode.SharpDevelop.Gui.OptionPanels
{ {
base.LoadOptions(); base.LoadOptions();
parallelBuildCount.Value = Project.BuildOptions.DefaultParallelProjectCount; parallelBuildCount.Value = Project.BuildOptions.DefaultParallelProjectCount;
onExecuteComboBox.SelectedIndex = (int)Project.BuildModifiedProjectsOnlyService.Setting; onExecuteComboBox.SelectedIndex = (int)Project.BuildOptions.BuildOnExecute;
verbosityComboBox.SelectedIndex = (int)Project.BuildOptions.DefaultBuildOutputVerbosity; verbosityComboBox.SelectedIndex = (int)Project.BuildOptions.DefaultBuildOutputVerbosity;
} }
@ -63,7 +63,7 @@ namespace ICSharpCode.SharpDevelop.Gui.OptionPanels
} }
} }
Project.BuildOptions.DefaultParallelProjectCount = (int)parallelBuildCount.Value; Project.BuildOptions.DefaultParallelProjectCount = (int)parallelBuildCount.Value;
Project.BuildModifiedProjectsOnlyService.Setting = (Project.BuildOnExecuteSetting)onExecuteComboBox.SelectedIndex; Project.BuildOptions.BuildOnExecute = (Project.BuildDetection)onExecuteComboBox.SelectedIndex;
Project.BuildOptions.DefaultBuildOutputVerbosity = (Project.BuildOutputVerbosity)verbosityComboBox.SelectedIndex; Project.BuildOptions.DefaultBuildOutputVerbosity = (Project.BuildOutputVerbosity)verbosityComboBox.SelectedIndex;
return base.SaveOptions(); return base.SaveOptions();
} }

2
src/Main/Base/Project/Src/Gui/IProgressMonitor.cs

@ -7,7 +7,7 @@ using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
namespace ICSharpCode.SharpDevelop.Gui namespace ICSharpCode.SharpDevelop
{ {
/// <summary> /// <summary>
/// Represents a target where an active task reports progress to. /// Represents a target where an active task reports progress to.

1
src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs

@ -74,7 +74,6 @@ namespace ICSharpCode.SharpDevelop.Gui
TaskService.Initialize(); TaskService.Initialize();
Bookmarks.BookmarkManager.Initialize(); Bookmarks.BookmarkManager.Initialize();
Project.CustomToolsService.Initialize(); Project.CustomToolsService.Initialize();
Project.BuildModifiedProjectsOnlyService.Initialize();
workbench.Initialize(); workbench.Initialize();
workbench.SetMemento(PropertyService.NestedProperties(workbenchMemento)); workbench.SetMemento(PropertyService.NestedProperties(workbenchMemento));

16
src/Main/Base/Project/Src/Project/AbstractProject.cs

@ -10,6 +10,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
@ -495,14 +496,14 @@ namespace ICSharpCode.SharpDevelop.Project
return referenceItems; return referenceItems;
} }
public virtual void StartBuild(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink) public virtual Task<bool> BuildAsync(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IProgressMonitor progressMonitor)
{ {
feedbackSink.ReportError(new BuildError { ErrorText = "Building project " + Name + " is not supported.", IsWarning = true }); feedbackSink.ReportError(new BuildError { ErrorText = "Building project " + Name + " is not supported.", IsWarning = true });
// we don't know how to build anything, report that we're done. // we don't know how to build anything, report that we're done.
feedbackSink.Done(true); return Task.FromResult(true);
} }
public virtual ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions) public virtual IEnumerable<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)
{ {
lock (SyncRoot) { lock (SyncRoot) {
List<IBuildable> result = new List<IBuildable>(); List<IBuildable> result = new List<IBuildable>();
@ -525,8 +526,11 @@ namespace ICSharpCode.SharpDevelop.Project
{ {
if (options == null) if (options == null)
throw new ArgumentNullException("options"); throw new ArgumentNullException("options");
string solutionConfiguration = options.SolutionConfiguration ?? ParentSolution.Preferences.ActiveConfiguration;
string solutionPlatform = options.SolutionPlatform ?? ParentSolution.Preferences.ActivePlatform;
// start of default implementation // start of default implementation
var configMatchings = this.ParentSolution.GetActiveConfigurationsAndPlatformsForProjects(options.SolutionConfiguration, options.SolutionPlatform); var configMatchings = this.ParentSolution.GetActiveConfigurationsAndPlatformsForProjects(solutionConfiguration, solutionPlatform);
ProjectBuildOptions projectOptions = new ProjectBuildOptions(isRootBuildable ? options.ProjectTarget : options.TargetForDependencies); ProjectBuildOptions projectOptions = new ProjectBuildOptions(isRootBuildable ? options.ProjectTarget : options.TargetForDependencies);
projectOptions.BuildOutputVerbosity = options.BuildOutputVerbosity; projectOptions.BuildOutputVerbosity = options.BuildOutputVerbosity;
// find the project configuration // find the project configuration
@ -538,9 +542,9 @@ namespace ICSharpCode.SharpDevelop.Project
} }
// fall back to solution config if we don't find any entries for the project // fall back to solution config if we don't find any entries for the project
if (string.IsNullOrEmpty(projectOptions.Configuration)) if (string.IsNullOrEmpty(projectOptions.Configuration))
projectOptions.Configuration = options.SolutionConfiguration; projectOptions.Configuration = solutionConfiguration;
if (string.IsNullOrEmpty(projectOptions.Platform)) if (string.IsNullOrEmpty(projectOptions.Platform))
projectOptions.Platform = options.SolutionPlatform; projectOptions.Platform = solutionPlatform;
// copy global properties to project options // copy global properties to project options
foreach (var pair in options.GlobalAdditionalProperties) foreach (var pair in options.GlobalAdditionalProperties)

18
src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs

@ -10,11 +10,11 @@ namespace ICSharpCode.SharpDevelop.Project
{ {
public class BeforeBuildCustomToolProjectItems public class BeforeBuildCustomToolProjectItems
{ {
IBuildable buildable; IReadOnlyList<IProject> projects;
public BeforeBuildCustomToolProjectItems(IBuildable buildable) public BeforeBuildCustomToolProjectItems(IReadOnlyList<IProject> projects)
{ {
this.buildable = buildable; this.projects = projects;
} }
public IEnumerable<FileProjectItem> GetProjectItems() public IEnumerable<FileProjectItem> GetProjectItems()
@ -26,17 +26,7 @@ namespace ICSharpCode.SharpDevelop.Project
IEnumerable<IProject> GetProjects() IEnumerable<IProject> GetProjects()
{ {
IProject project = buildable as IProject; return projects;
if (project != null) {
return new IProject[] { project };
}
var solution = buildable as Solution;
if (solution != null) {
return solution.Projects;
}
return new IProject[0];
} }
IEnumerable<FileProjectItem> GetConfiguredCustomToolProjectItems(IProject project) IEnumerable<FileProjectItem> GetConfiguredCustomToolProjectItems(IProject project)

2
src/Main/Base/Project/Src/Project/BeforeBuildCustomToolRunner.cs

@ -16,7 +16,7 @@ namespace ICSharpCode.SharpDevelop.Project
void ProjectBuildStarted(object sender, BuildEventArgs e) void ProjectBuildStarted(object sender, BuildEventArgs e)
{ {
var projectItems = new BeforeBuildCustomToolProjectItems(e.Buildable); var projectItems = new BeforeBuildCustomToolProjectItems(e.Projects);
RunCustomTool(projectItems.GetProjectItems()); RunCustomTool(projectItems.GetProjectItems());
} }

1
src/Main/Base/Project/Src/Project/ConfigurationGuiHelper.cs

@ -37,6 +37,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// <summary> /// <summary>
/// Class that helps connecting configuration GUI controls to MsBuild properties. /// Class that helps connecting configuration GUI controls to MsBuild properties.
/// </summary> /// </summary>
[Obsolete]
public class ConfigurationGuiHelper : ICanBeDirty public class ConfigurationGuiHelper : ICanBeDirty
{ {
MSBuildBasedProject project; MSBuildBasedProject project;

36
src/Main/Base/Project/Src/Project/IProject.cs

@ -330,48 +330,12 @@ namespace ICSharpCode.SharpDevelop.Project
/// Never returns null, but may return a permanently empty collection if this project does not support such models. /// Never returns null, but may return a permanently empty collection if this project does not support such models.
/// </summary> /// </summary>
ITypeDefinitionModelCollection TypeDefinitionModels { get; } ITypeDefinitionModelCollection TypeDefinitionModels { get; }
}
/// <summary>
/// A project or solution.
/// The IBuildable interface members are thread-safe.
/// </summary>
public interface IBuildable
{
/// <summary>
/// Gets the list of projects on which this project depends.
/// This method is thread-safe.
/// </summary>
ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions);
/// <summary>
/// Starts building the project using the specified options.
/// This member must be implemented thread-safe.
/// </summary>
void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink);
/// <summary>
/// Gets the name of the buildable item.
/// This property is thread-safe.
/// </summary>
string Name { get; }
/// <summary> /// <summary>
/// Gets the parent solution. /// Gets the parent solution.
/// This property is thread-safe. /// This property is thread-safe.
/// </summary> /// </summary>
Solution ParentSolution { get; } Solution ParentSolution { get; }
/// <summary>
/// Creates the project-specific build options.
/// This member must be implemented thread-safe.
/// </summary>
/// <param name="options">The global build options.</param>
/// <param name="isRootBuildable">Specifies whether this project is the main buildable item.
/// The root buildable is the buildable for which <see cref="BuildOptions.ProjectTarget"/> and <see cref="BuildOptions.ProjectAdditionalProperties"/> apply.
/// The dependencies of that root buildable are the non-root buildables.</param>
/// <returns>The project-specific build options.</returns>
ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable);
} }
/// <summary> /// <summary>

14
src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs

@ -10,6 +10,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using System.Xml; using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
@ -1101,9 +1102,9 @@ namespace ICSharpCode.SharpDevelop.Project
#endregion #endregion
#region Building #region Building
public override ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions) public override IEnumerable<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)
{ {
ICollection<IBuildable> result = base.GetBuildDependencies(buildOptions); var result = base.GetBuildDependencies(buildOptions).ToList();
foreach (ProjectItem item in GetItemsOfType(ItemType.ProjectReference)) { foreach (ProjectItem item in GetItemsOfType(ItemType.ProjectReference)) {
ProjectReferenceProjectItem prpi = item as ProjectReferenceProjectItem; ProjectReferenceProjectItem prpi = item as ProjectReferenceProjectItem;
if (prpi != null && prpi.ReferencedProject != null) if (prpi != null && prpi.ReferencedProject != null)
@ -1112,16 +1113,19 @@ namespace ICSharpCode.SharpDevelop.Project
return result; return result;
} }
public override void StartBuild(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink) public override Task<bool> BuildAsync(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IProgressMonitor progressMonitor)
{ {
MSBuildEngine.StartBuild(this, options, feedbackSink, MSBuildEngine.AdditionalTargetFiles); return MSBuildEngine.BuildAsync(this, options, feedbackSink, progressMonitor.CancellationToken, MSBuildEngine.AdditionalTargetFiles);
} }
public override ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable) public override ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable)
{ {
ProjectBuildOptions projectOptions = base.CreateProjectBuildOptions(options, isRootBuildable); ProjectBuildOptions projectOptions = base.CreateProjectBuildOptions(options, isRootBuildable);
Solution solution = this.ParentSolution; Solution solution = this.ParentSolution;
var configMatchings = solution.GetActiveConfigurationsAndPlatformsForProjects(options.SolutionConfiguration, options.SolutionPlatform); string solutionConfiguration = options.SolutionConfiguration ?? solution.Preferences.ActiveConfiguration;
string solutionPlatform = options.SolutionPlatform ?? solution.Preferences.ActivePlatform;
var configMatchings = solution.GetActiveConfigurationsAndPlatformsForProjects(solutionConfiguration, solutionPlatform);
// Find the project configuration, and build an XML string containing all configurations from the solution // Find the project configuration, and build an XML string containing all configurations from the solution
StringWriter solutionConfigurationXml = new StringWriter(); StringWriter solutionConfigurationXml = new StringWriter();
using (XmlTextWriter solutionConfigurationWriter = new XmlTextWriter(solutionConfigurationXml)) { using (XmlTextWriter solutionConfigurationWriter = new XmlTextWriter(solutionConfigurationXml)) {

2
src/Main/Base/Project/Src/Project/MSBuildEngine/BuildWorkerManager.cs

@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.BuildWorker; using ICSharpCode.SharpDevelop.BuildWorker;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;

22
src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildEngine.cs

@ -6,10 +6,12 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml; using System.Xml;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.BuildWorker; using ICSharpCode.SharpDevelop.BuildWorker;
using ICSharpCode.SharpDevelop.Gui;
using Microsoft.Build.Framework; using Microsoft.Build.Framework;
namespace ICSharpCode.SharpDevelop.Project namespace ICSharpCode.SharpDevelop.Project
@ -89,7 +91,7 @@ namespace ICSharpCode.SharpDevelop.Project
MSBuildLoggerFilters = AddInTree.BuildItems<IMSBuildLoggerFilter>(LoggerFiltersPath, null, false); MSBuildLoggerFilters = AddInTree.BuildItems<IMSBuildLoggerFilter>(LoggerFiltersPath, null, false);
} }
public static void StartBuild(IProject project, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IEnumerable<string> additionalTargetFiles) public static Task<bool> BuildAsync(IProject project, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, CancellationToken cancellationToken, IEnumerable<string> additionalTargetFiles)
{ {
if (project == null) if (project == null)
throw new ArgumentNullException("project"); throw new ArgumentNullException("project");
@ -105,7 +107,7 @@ namespace ICSharpCode.SharpDevelop.Project
if (project.MinimumSolutionVersion >= Solution.SolutionVersionVS2010) { if (project.MinimumSolutionVersion >= Solution.SolutionVersionVS2010) {
engine.additionalTargetFiles.Add(Path.Combine(Path.GetDirectoryName(typeof(MSBuildEngine).Assembly.Location), "SharpDevelop.TargetingPack.targets")); engine.additionalTargetFiles.Add(Path.Combine(Path.GetDirectoryName(typeof(MSBuildEngine).Assembly.Location), "SharpDevelop.TargetingPack.targets"));
} }
engine.StartBuild(); return engine.RunBuildAsync(cancellationToken);
} }
readonly string projectFileName; readonly string projectFileName;
@ -192,7 +194,7 @@ namespace ICSharpCode.SharpDevelop.Project
List<ILogger> loggers = new List<ILogger>(); List<ILogger> loggers = new List<ILogger>();
IMSBuildChainedLoggerFilter loggerChain; IMSBuildChainedLoggerFilter loggerChain;
void StartBuild() Task<bool> RunBuildAsync(CancellationToken cancellationToken)
{ {
Dictionary<string, string> globalProperties = new Dictionary<string, string>(); Dictionary<string, string> globalProperties = new Dictionary<string, string>();
MSBuildBasedProject.InitializeMSBuildProjectProperties(globalProperties); MSBuildBasedProject.InitializeMSBuildProjectProperties(globalProperties);
@ -264,24 +266,28 @@ namespace ICSharpCode.SharpDevelop.Project
logger.Initialize(eventSource); logger.Initialize(eventSource);
} }
tcs = new TaskCompletionSource<bool>();
if (projectMinimumSolutionVersion <= Solution.SolutionVersionVS2008) { if (projectMinimumSolutionVersion <= Solution.SolutionVersionVS2008) {
if (DotnetDetection.IsDotnet35SP1Installed()) { if (DotnetDetection.IsDotnet35SP1Installed()) {
BuildWorkerManager.MSBuild35.RunBuildJob(job, loggerChain, OnDone, feedbackSink.ProgressMonitor.CancellationToken); BuildWorkerManager.MSBuild35.RunBuildJob(job, loggerChain, OnDone, cancellationToken);
} else { } else {
loggerChain.HandleError(new BuildError(job.ProjectFileName, ".NET 3.5 SP1 is required to build this project.")); loggerChain.HandleError(new BuildError(job.ProjectFileName, ".NET 3.5 SP1 is required to build this project."));
OnDone(false); tcs.SetResult(false);
} }
} else { } else {
BuildWorkerManager.MSBuild40.RunBuildJob(job, loggerChain, OnDone, feedbackSink.ProgressMonitor.CancellationToken); BuildWorkerManager.MSBuild40.RunBuildJob(job, loggerChain, OnDone, cancellationToken);
} }
return tcs.Task;
} }
TaskCompletionSource<bool> tcs;
void OnDone(bool success) void OnDone(bool success)
{ {
foreach (ILogger logger in loggers) { foreach (ILogger logger in loggers) {
logger.Shutdown(); logger.Shutdown();
} }
feedbackSink.Done(success); tcs.SetResult(success);
} }
void WriteAdditionalTargetsToTempFile(Dictionary<string, string> globalProperties) void WriteAdditionalTargetsToTempFile(Dictionary<string, string> globalProperties)

6
src/Main/Base/Project/Src/Project/MSBuildFileProject.cs

@ -2,7 +2,9 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.Threading.Tasks;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.SharpDevelop.Project namespace ICSharpCode.SharpDevelop.Project
{ {
@ -18,9 +20,9 @@ namespace ICSharpCode.SharpDevelop.Project
TypeGuid = "{00000000-0000-0000-0000-000000000000}"; TypeGuid = "{00000000-0000-0000-0000-000000000000}";
} }
public override void StartBuild(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink) public override Task<bool> BuildAsync(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IProgressMonitor progressMonitor)
{ {
MSBuildEngine.StartBuild(this, options, feedbackSink, MSBuildEngine.AdditionalTargetFiles); return MSBuildEngine.BuildAsync(this, options, feedbackSink, progressMonitor.CancellationToken, MSBuildEngine.AdditionalTargetFiles);
} }
} }
} }

4
src/Main/Base/Project/Src/Project/ProjectLoadInformation.cs

@ -29,13 +29,13 @@ namespace ICSharpCode.SharpDevelop.Project
internal bool? upgradeToolsVersion; internal bool? upgradeToolsVersion;
Gui.IProgressMonitor progressMonitor = new Gui.DummyProgressMonitor(); IProgressMonitor progressMonitor = new DummyProgressMonitor();
/// <summary> /// <summary>
/// Gets/Sets the progress monitor used during the load. /// Gets/Sets the progress monitor used during the load.
/// This property never returns null. /// This property never returns null.
/// </summary> /// </summary>
public Gui.IProgressMonitor ProgressMonitor { public IProgressMonitor ProgressMonitor {
get { return progressMonitor; } get { return progressMonitor; }
set { set {
if (value == null) if (value == null)

13
src/Main/Base/Project/Src/Project/Solution/Solution.cs

@ -8,7 +8,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
@ -1253,18 +1253,15 @@ namespace ICSharpCode.SharpDevelop.Project
#endregion #endregion
#region Building #region Building
ICollection<IBuildable> IBuildable.GetBuildDependencies(ProjectBuildOptions buildOptions) IEnumerable<IBuildable> IBuildable.GetBuildDependencies(ProjectBuildOptions buildOptions)
{ {
List<IBuildable> result = new List<IBuildable>(); return this.Projects;
foreach (IProject p in this.Projects)
result.Add(p);
return result;
} }
void IBuildable.StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink) Task<bool> IBuildable.BuildAsync(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IProgressMonitor progressMonitor)
{ {
// building a solution finishes immediately: we only care for the dependencies // building a solution finishes immediately: we only care for the dependencies
feedbackSink.Done(true); return Task.FromResult(true);
} }
ProjectBuildOptions IBuildable.CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable) ProjectBuildOptions IBuildable.CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable)

84
src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs

@ -540,7 +540,7 @@ namespace ICSharpCode.SharpDevelop.Project
// If a build is running, cancel it. // If a build is running, cancel it.
// If we would let a build run but unload the MSBuild projects, the next project.StartBuild call // If we would let a build run but unload the MSBuild projects, the next project.StartBuild call
// could cause an exception. // could cause an exception.
BuildEngine.CancelGuiBuild(); SD.BuildService.CancelBuild();
if (openSolution != null) { if (openSolution != null) {
CurrentProject = null; CurrentProject = null;
@ -610,44 +610,13 @@ namespace ICSharpCode.SharpDevelop.Project
} }
} }
static bool building; [Obsolete]
public static bool IsBuilding { public static bool IsBuilding {
get { get {
return building; return SD.BuildService.IsBuilding;
} }
} }
/// <summary>
/// Raises the <see cref="BuildStarted"/> event.
///
/// You do not need to call this method if you use BuildEngine.BuildInGui - the build
/// engine will call these events itself.
/// </summary>
public static void RaiseEventBuildStarted(BuildEventArgs e)
{
if (e == null)
throw new ArgumentNullException("e");
WorkbenchSingleton.AssertMainThread();
building = true;
BuildStarted.RaiseEvent(null, e);
}
/// <summary>
/// Raises the <see cref="BuildFinished"/> event.
///
/// You do not need to call this method if you use BuildEngine.BuildInGui - the build
/// engine will call these events itself.
/// </summary>
public static void RaiseEventBuildFinished(BuildEventArgs e)
{
if (e == null)
throw new ArgumentNullException("e");
WorkbenchSingleton.AssertMainThread();
building = false;
BuildFinished.RaiseEvent(null, e);
}
public static void RemoveSolutionFolder(string guid) public static void RemoveSolutionFolder(string guid)
{ {
if (OpenSolution == null) { if (OpenSolution == null) {
@ -740,8 +709,16 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary> /// </summary>
public static event SolutionFolderEventHandler SolutionFolderRemoved; public static event SolutionFolderEventHandler SolutionFolderRemoved;
public static event EventHandler<BuildEventArgs> BuildStarted; [Obsolete]
public static event EventHandler<BuildEventArgs> BuildFinished; public static event EventHandler<BuildEventArgs> BuildStarted {
add { SD.BuildService.BuildStarted += value; }
remove { SD.BuildService.BuildFinished -= value; }
}
[Obsolete]
public static event EventHandler<BuildEventArgs> BuildFinished {
add { SD.BuildService.BuildFinished += value; }
remove { SD.BuildService.BuildFinished -= value; }
}
public static event SolutionConfigurationEventHandler SolutionConfigurationChanged; public static event SolutionConfigurationEventHandler SolutionConfigurationChanged;
@ -774,39 +751,4 @@ namespace ICSharpCode.SharpDevelop.Project
public static event EventHandler<ProjectItemEventArgs> ProjectItemAdded; public static event EventHandler<ProjectItemEventArgs> ProjectItemAdded;
public static event EventHandler<ProjectItemEventArgs> ProjectItemRemoved; public static event EventHandler<ProjectItemEventArgs> ProjectItemRemoved;
} }
public class BuildEventArgs : EventArgs
{
/// <summary>
/// The project/solution to be built.
/// </summary>
public readonly IBuildable Buildable;
/// <summary>
/// The build options.
/// </summary>
public readonly BuildOptions Options;
/// <summary>
/// Gets the build results.
/// This property is null for build started events.
/// </summary>
public readonly BuildResults Results;
public BuildEventArgs(IBuildable buildable, BuildOptions options)
: this(buildable, options, null)
{
}
public BuildEventArgs(IBuildable buildable, BuildOptions options, BuildResults results)
{
if (buildable == null)
throw new ArgumentNullException("buildable");
if (options == null)
throw new ArgumentNullException("options");
this.Buildable = buildable;
this.Options = options;
this.Results = results;
}
}
} }

48
src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs

@ -5,8 +5,9 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Tests.Utils; using ICSharpCode.SharpDevelop.Tests.Utils;
using NUnit.Framework; using NUnit.Framework;
@ -21,27 +22,6 @@ namespace ICSharpCode.SharpDevelop.Tests.Project
BeforeBuildCustomToolProjectItems beforeBuildCustomToolProjectItems; BeforeBuildCustomToolProjectItems beforeBuildCustomToolProjectItems;
Solution solution; Solution solution;
class UnknownBuildable : IBuildable
{
public string Name { get; set; }
public Solution ParentSolution { get; set; }
public ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)
{
return new IBuildable[0];
}
public void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink)
{
}
public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable)
{
return new ProjectBuildOptions(BuildTarget.Build);
}
}
IProject CreateProject(string fileName = @"d:\MyProject\MyProject.csproj") IProject CreateProject(string fileName = @"d:\MyProject\MyProject.csproj")
{ {
projectHelper = new ProjectHelper(fileName); projectHelper = new ProjectHelper(fileName);
@ -84,17 +64,17 @@ namespace ICSharpCode.SharpDevelop.Tests.Project
void CreateBeforeBuildCustomToolProjectItems() void CreateBeforeBuildCustomToolProjectItems()
{ {
CreateBeforeBuildCustomToolProjectItems(projectHelper.Project as IBuildable); CreateBeforeBuildCustomToolProjectItems(new[] { projectHelper.Project });
} }
void CreateBeforeBuildCustomToolProjectItems(IBuildable buildable) void CreateBeforeBuildCustomToolProjectItems(IReadOnlyList<IProject> projects)
{ {
beforeBuildCustomToolProjectItems = new BeforeBuildCustomToolProjectItems(buildable); beforeBuildCustomToolProjectItems = new BeforeBuildCustomToolProjectItems(projects);
} }
void CreateBeforeBuildCustomToolProjectItemsUsingSolution() void CreateBeforeBuildCustomToolProjectItemsUsingSolution()
{ {
CreateBeforeBuildCustomToolProjectItems(solution as IBuildable); CreateBeforeBuildCustomToolProjectItems(solution.Projects.ToList());
} }
FileProjectItem AddFileToProject(string include) FileProjectItem AddFileToProject(string include)
@ -104,12 +84,6 @@ namespace ICSharpCode.SharpDevelop.Tests.Project
return projectItem; return projectItem;
} }
void CreateBeforeBuildCustomToolProjectItemsWithUnknownIBuildableDerivedClass()
{
var unknownBuildable = new UnknownBuildable();
CreateBeforeBuildCustomToolProjectItems(unknownBuildable);
}
[Test] [Test]
public void GetProjectItems_BuildSingleProjectNotConfiguredToRunCustomToolsOnBuild_ReturnsNoItems() public void GetProjectItems_BuildSingleProjectNotConfiguredToRunCustomToolsOnBuild_ReturnsNoItems()
{ {
@ -290,15 +264,5 @@ namespace ICSharpCode.SharpDevelop.Tests.Project
}; };
CollectionAssert.AreEqual(expectedProjectItems, projectItems); CollectionAssert.AreEqual(expectedProjectItems, projectItems);
} }
[Test]
public void GetProjectItems_UnknownIBuildableDerivedClass_NullReferenceExceptionIsNotThrown()
{
CreateBeforeBuildCustomToolProjectItemsWithUnknownIBuildableDerivedClass();
List<FileProjectItem> projectItems = GetProjectItems();
Assert.AreEqual(0, projectItems.Count);
}
} }
} }

1
src/Main/Core/Project/Src/Services/PropertyService/PropertyServiceImpl.cs

@ -35,6 +35,7 @@ namespace ICSharpCode.Core
this.configDirectory = configDirectory; this.configDirectory = configDirectory;
this.dataDirectory = dataDirectory; this.dataDirectory = dataDirectory;
this.propertyFileName = propertiesName + ".xml"; this.propertyFileName = propertiesName + ".xml";
Directory.CreateDirectory(configDirectory);
LoadPropertiesFromStream(Path.Combine(configDirectory, propertyFileName)); LoadPropertiesFromStream(Path.Combine(configDirectory, propertyFileName));
} }

57
src/Main/Base/Project/Src/Project/BuildEngine.cs → src/Main/SharpDevelop/Project/Build/BuildEngine.cs

@ -8,6 +8,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
@ -20,10 +21,10 @@ namespace ICSharpCode.SharpDevelop.Project
/// ///
/// This class is not related to MSBuild: it simply "builds" a project by calling IBuildable.StartBuild. /// This class is not related to MSBuild: it simply "builds" a project by calling IBuildable.StartBuild.
/// </summary> /// </summary>
public sealed class BuildEngine sealed class BuildEngine
{ {
#region Building in the SharpDevelop GUI #region Building in the SharpDevelop GUI
static CancellationTokenSource guiBuildCancellation; /*static CancellationTokenSource guiBuildCancellation;
static IAnalyticsMonitorTrackedFeature guiBuildTrackedFeature; static IAnalyticsMonitorTrackedFeature guiBuildTrackedFeature;
/// <summary> /// <summary>
@ -151,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Project
ProjectService.RaiseEventBuildFinished(new BuildEventArgs(buildable, options, results)); ProjectService.RaiseEventBuildFinished(new BuildEventArgs(buildable, options, results));
}); });
} }
} }*/
#endregion #endregion
#region StartBuild #region StartBuild
@ -165,26 +166,17 @@ namespace ICSharpCode.SharpDevelop.Project
/// will ensure that output from two projects building in parallel isn't interleaved.</param> /// will ensure that output from two projects building in parallel isn't interleaved.</param>
/// <param name="progressMonitor">The progress monitor that receives build progress. The monitor will be disposed /// <param name="progressMonitor">The progress monitor that receives build progress. The monitor will be disposed
/// when the build completes.</param> /// when the build completes.</param>
public static void StartBuild(IBuildable project, BuildOptions options, IBuildFeedbackSink realtimeBuildFeedbackSink) public static Task<BuildResults> BuildAsync(IBuildable project, BuildOptions options, IBuildFeedbackSink buildFeedbackSink, IProgressMonitor progressMonitor)
{ {
if (project == null) if (project == null)
throw new ArgumentNullException("solution"); throw new ArgumentNullException("solution");
if (options == null) if (options == null)
throw new ArgumentNullException("options"); throw new ArgumentNullException("options");
Solution solution = project.ParentSolution;
if (solution == null)
throw new ArgumentException("project.ParentSolution must not be null", "project");
if (string.IsNullOrEmpty(options.SolutionConfiguration))
options.SolutionConfiguration = solution.Preferences.ActiveConfiguration;
if (string.IsNullOrEmpty(options.SolutionPlatform))
options.SolutionPlatform = solution.Preferences.ActivePlatform;
BuildEngine engine = new BuildEngine(options, project); BuildEngine engine = new BuildEngine(options, project);
engine.buildStart = DateTime.Now; engine.buildStart = DateTime.Now;
engine.combinedBuildFeedbackSink = realtimeBuildFeedbackSink; engine.combinedBuildFeedbackSink = buildFeedbackSink;
engine.progressMonitor = realtimeBuildFeedbackSink.ProgressMonitor; engine.progressMonitor = progressMonitor;
try { try {
engine.rootNode = engine.CreateBuildGraph(project); engine.rootNode = engine.CreateBuildGraph(project);
} catch (CyclicDependencyException ex) { } catch (CyclicDependencyException ex) {
@ -201,7 +193,7 @@ namespace ICSharpCode.SharpDevelop.Project
engine.results.Result = BuildResultCode.BuildFileError; engine.results.Result = BuildResultCode.BuildFileError;
engine.ReportDone(); engine.ReportDone();
return; return engine.tcs.Task;
} }
engine.workersToStart = options.ParallelProjectCount; engine.workersToStart = options.ParallelProjectCount;
@ -213,6 +205,7 @@ namespace ICSharpCode.SharpDevelop.Project
engine.ReportMessageLine("${res:MainWindow.CompilerMessages.BuildStarted}"); engine.ReportMessageLine("${res:MainWindow.CompilerMessages.BuildStarted}");
engine.StartBuildProjects(); engine.StartBuildProjects();
engine.UpdateProgressTaskName(); engine.UpdateProgressTaskName();
return engine.tcs.Task;
} }
#endregion #endregion
@ -280,12 +273,13 @@ namespace ICSharpCode.SharpDevelop.Project
this.project = project; this.project = project;
} }
public void DoStartBuild(object state) public async void DoStartBuild(object state)
{ {
string name = string.Empty; string name = string.Empty;
try { try {
name = project.Name; name = project.Name;
project.StartBuild(options, this); bool success = await project.BuildAsync(options, this, perNodeProgressMonitor).ConfigureAwait(false);
Done(success);
} catch (ObjectDisposedException) { } catch (ObjectDisposedException) {
// Handle ObjectDisposedException that occurs when trying to build a project that was unloaded. // Handle ObjectDisposedException that occurs when trying to build a project that was unloaded.
ReportError(new BuildError(null, "The project '" + name + "' was unloaded.")); ReportError(new BuildError(null, "The project '" + name + "' was unloaded."));
@ -313,15 +307,6 @@ namespace ICSharpCode.SharpDevelop.Project
{ {
engine.OnBuildFinished(this, success); engine.OnBuildFinished(this, success);
} }
IProgressMonitor IBuildFeedbackSink.ProgressMonitor {
get {
// property should be accessed only while build is running and progress monitor available
if (perNodeProgressMonitor == null)
throw new InvalidOperationException();
return perNodeProgressMonitor;
}
}
} }
#endregion #endregion
@ -330,6 +315,7 @@ namespace ICSharpCode.SharpDevelop.Project
readonly BuildOptions options; readonly BuildOptions options;
IProgressMonitor progressMonitor; IProgressMonitor progressMonitor;
CancellationTokenRegistration cancellationRegistration; CancellationTokenRegistration cancellationRegistration;
readonly TaskCompletionSource<BuildResults> tcs = new TaskCompletionSource<BuildResults>();
BuildNode rootNode; BuildNode rootNode;
readonly IBuildable rootProject; readonly IBuildable rootProject;
readonly BuildResults results = new BuildResults(); readonly BuildResults results = new BuildResults();
@ -500,7 +486,6 @@ namespace ICSharpCode.SharpDevelop.Project
node.hasErrors = !success; node.hasErrors = !success;
projectsCurrentlyBuilding.Remove(node); projectsCurrentlyBuilding.Remove(node);
results.AddBuiltProject(node.project);
foreach (BuildNode n in node.dependentOnThis) { foreach (BuildNode n in node.dependentOnThis) {
n.outstandingDependencies--; n.outstandingDependencies--;
@ -546,7 +531,6 @@ namespace ICSharpCode.SharpDevelop.Project
ReportMessageLine("${res:MainWindow.CompilerMessages.BuildFinished}" + buildTime); ReportMessageLine("${res:MainWindow.CompilerMessages.BuildFinished}" + buildTime);
} }
cancellationRegistration.Dispose(); cancellationRegistration.Dispose();
progressMonitor.Dispose();
ReportDone(); ReportDone();
} }
@ -555,20 +539,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary> /// </summary>
void ReportDone() void ReportDone()
{ {
if (combinedBuildFeedbackSink != null) { tcs.SetResult(results);
if (combinedBuildFeedbackSink is MessageViewSink) {
// Special case GUI-builds so that they have more information available:
// (non-GUI builds can get the same information from the options.Callback,
// but the GUI cannot use the callback because the build options are set by
// the code triggering the build)
((MessageViewSink)combinedBuildFeedbackSink).Done(rootProject, options, results);
} else {
combinedBuildFeedbackSink.Done(results.Result == BuildResultCode.Success);
}
}
if (options.Callback != null) {
Gui.WorkbenchSingleton.SafeThreadAsyncCall(delegate { options.Callback(results); });
}
} }
#endregion #endregion

155
src/Main/Base/Project/Src/Services/ProjectService/CompileModifiedProjectsOnly.cs → src/Main/SharpDevelop/Project/Build/BuildModifiedProjectsOnlyService.cs

@ -3,65 +3,43 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using ICSharpCode.Core; using ICSharpCode.Core;
using System.Diagnostics; using ICSharpCode.SharpDevelop.Gui;
using System.ComponentModel;
namespace ICSharpCode.SharpDevelop.Project namespace ICSharpCode.SharpDevelop.Project
{ {
public enum BuildOnExecuteSetting
{
[Description("${res:Dialog.Options.IDEOptions.ProjectAndSolutionOptions.WhenRunning.DoNotBuild}")]
DoNotBuild,
[Description("${res:Dialog.Options.IDEOptions.ProjectAndSolutionOptions.WhenRunning.BuildOnlyModified}")]
BuildOnlyModified,
[Description("${res:Dialog.Options.IDEOptions.ProjectAndSolutionOptions.WhenRunning.BuildModifiedAndDependent}")]
BuildModifiedAndDependent,
[Description("${res:Dialog.Options.IDEOptions.ProjectAndSolutionOptions.WhenRunning.RegularBuild}")]
RegularBuild
}
/// <summary> /// <summary>
/// Tracks changes to projects and causes only modified projects /// Tracks changes to projects and causes only modified projects
/// to be recompiled. /// to be recompiled.
/// </summary> /// </summary>
static class BuildModifiedProjectsOnlyService class BuildModifiedProjectsOnlyService
{ {
public static BuildOnExecuteSetting Setting {
get { return PropertyService.Get("BuildOnExecute", BuildOnExecuteSetting.RegularBuild); }
set { PropertyService.Set("BuildOnExecute", value); }
}
static readonly Dictionary<IProject, CompilationPass> unmodifiedProjects = new Dictionary<IProject, CompilationPass>(); static readonly Dictionary<IProject, CompilationPass> unmodifiedProjects = new Dictionary<IProject, CompilationPass>();
static BuildModifiedProjectsOnlyService() public BuildModifiedProjectsOnlyService(IBuildService buildService)
{ {
// these actions cause a full recompilation: // these actions cause a full recompilation:
ProjectService.SolutionClosed += MarkAllForRecompilation; ProjectService.SolutionClosed += MarkAllForRecompilation;
ProjectService.SolutionConfigurationChanged += MarkAllForRecompilation; ProjectService.SolutionConfigurationChanged += MarkAllForRecompilation;
ProjectService.SolutionSaved += MarkAllForRecompilation; ProjectService.SolutionSaved += MarkAllForRecompilation;
ProjectService.BuildFinished += ProjectService_BuildFinished; buildService.BuildFinished += BuildService_BuildFinished;
FileUtility.FileSaved += OnFileSaved; FileUtility.FileSaved += OnFileSaved;
} }
public static void Initialize() void BuildService_BuildFinished(object sender, BuildEventArgs e)
{
// first call to init causes static ctor calls
}
static void ProjectService_BuildFinished(object sender, BuildEventArgs e)
{ {
// at the end of an successful build, mark all built projects as unmodified // at the end of an successful build, mark all built projects as unmodified
if (e.Results.Result == BuildResultCode.Success) { if (e.Results.Result == BuildResultCode.Success) {
lock (unmodifiedProjects) { lock (unmodifiedProjects) {
CompilationPass pass = new CompilationPass(); CompilationPass pass = new CompilationPass();
foreach (IBuildable b in e.Results.BuiltProjects) { foreach (IProject p in e.Projects) {
IProject p = GetProjectFromBuildable(b); unmodifiedProjects[p] = pass;
if (p != null) {
unmodifiedProjects[p] = pass;
}
} }
} }
} }
@ -73,21 +51,14 @@ namespace ICSharpCode.SharpDevelop.Project
} }
} }
static IProject GetProjectFromBuildable(IBuildable b) void MarkAllForRecompilation(object sender, EventArgs e)
{
while (b is Wrapper)
b = ((Wrapper)b).wrapped;
return b as IProject;
}
static void MarkAllForRecompilation(object sender, EventArgs e)
{ {
lock (unmodifiedProjects) { lock (unmodifiedProjects) {
unmodifiedProjects.Clear(); unmodifiedProjects.Clear();
} }
} }
static void OnFileSaved(object sender, FileNameEventArgs e) void OnFileSaved(object sender, FileNameEventArgs e)
{ {
if (ProjectService.OpenSolution != null) { if (ProjectService.OpenSolution != null) {
foreach (IProject p in ProjectService.OpenSolution.Projects) { foreach (IProject p in ProjectService.OpenSolution.Projects) {
@ -100,20 +71,20 @@ namespace ICSharpCode.SharpDevelop.Project
} }
} }
public static IBuildable WrapBuildable(IBuildable buildable) public IBuildable WrapBuildable(IBuildable buildable, BuildDetection setting)
{ {
switch (Setting) { switch (setting) {
case BuildOnExecuteSetting.DoNotBuild: case BuildDetection.DoNotBuild:
return new DummyBuildable(buildable); return new DummyBuildable(buildable);
case BuildOnExecuteSetting.BuildModifiedAndDependent: case BuildDetection.BuildModifiedAndDependent:
case BuildOnExecuteSetting.BuildOnlyModified: case BuildDetection.BuildOnlyModified:
lock (unmodifiedProjects) { lock (unmodifiedProjects) {
foreach (var pair in unmodifiedProjects) { foreach (var pair in unmodifiedProjects) {
LoggingService.Debug(pair.Key.Name + ": " + pair.Value); LoggingService.Debug(pair.Key.Name + ": " + pair.Value);
} }
} }
return new WrapperFactory().GetWrapper(buildable); return new WrapperFactory(setting).GetWrapper(buildable);
case BuildOnExecuteSetting.RegularBuild: case BuildDetection.RegularBuild:
return buildable; return buildable;
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
@ -133,22 +104,19 @@ namespace ICSharpCode.SharpDevelop.Project
get { return wrappedBuildable.Name; } get { return wrappedBuildable.Name; }
} }
public Solution ParentSolution {
get { return wrappedBuildable.ParentSolution; }
}
public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable) public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable)
{ {
return null; return null;
} }
public ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions) public IEnumerable<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)
{ {
return new IBuildable[0]; return Enumerable.Empty<IBuildable>();
} }
public void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink) public Task<bool> BuildAsync(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IProgressMonitor progressMonitor)
{ {
return Task.FromResult(true);
} }
} }
@ -171,9 +139,15 @@ namespace ICSharpCode.SharpDevelop.Project
sealed class WrapperFactory sealed class WrapperFactory
{ {
public readonly BuildDetection Setting;
public readonly CompilationPass CurrentPass = new CompilationPass(); public readonly CompilationPass CurrentPass = new CompilationPass();
readonly Dictionary<IBuildable, IBuildable> dict = new Dictionary<IBuildable, IBuildable>(); readonly Dictionary<IBuildable, IBuildable> dict = new Dictionary<IBuildable, IBuildable>();
public WrapperFactory(BuildDetection setting)
{
this.Setting = setting;
}
public IBuildable GetWrapper(IBuildable wrapped) public IBuildable GetWrapper(IBuildable wrapped)
{ {
IBuildable b; IBuildable b;
@ -200,10 +174,6 @@ namespace ICSharpCode.SharpDevelop.Project
get { return wrapped.Name; } get { return wrapped.Name; }
} }
public Solution ParentSolution {
get { return wrapped.ParentSolution; }
}
public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable) public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable)
{ {
return wrapped.CreateProjectBuildOptions(options, isRootBuildable); return wrapped.CreateProjectBuildOptions(options, isRootBuildable);
@ -211,8 +181,8 @@ namespace ICSharpCode.SharpDevelop.Project
Dictionary<ProjectBuildOptions, ICollection<IBuildable>> cachedBuildDependencies = new Dictionary<ProjectBuildOptions, ICollection<IBuildable>>(); Dictionary<ProjectBuildOptions, ICollection<IBuildable>> cachedBuildDependencies = new Dictionary<ProjectBuildOptions, ICollection<IBuildable>>();
ICollection<IBuildable> cachedBuildDependenciesForNullOptions; ICollection<IBuildable> cachedBuildDependenciesForNullOptions;
public ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions) public IEnumerable<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)
{ {
List<IBuildable> result = new List<IBuildable>(); List<IBuildable> result = new List<IBuildable>();
foreach (IBuildable b in wrapped.GetBuildDependencies(buildOptions)) { foreach (IBuildable b in wrapped.GetBuildDependencies(buildOptions)) {
@ -241,20 +211,20 @@ namespace ICSharpCode.SharpDevelop.Project
return lastCompilationPass.Index > comparisonPass.Index; return lastCompilationPass.Index > comparisonPass.Index;
} }
public void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink) public async Task<bool> BuildAsync(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IProgressMonitor progressMonitor)
{ {
IProject p = wrapped as IProject; IProject p = wrapped as IProject;
if (p == null) { if (p == null) {
wrapped.StartBuild(buildOptions, feedbackSink); return await wrapped.BuildAsync(options, feedbackSink, progressMonitor);
} else { } else {
lock (unmodifiedProjects) { lock (unmodifiedProjects) {
if (!unmodifiedProjects.TryGetValue(p, out lastCompilationPass)) { if (!unmodifiedProjects.TryGetValue(p, out lastCompilationPass)) {
lastCompilationPass = null; lastCompilationPass = null;
} }
} }
if (lastCompilationPass != null && Setting == BuildOnExecuteSetting.BuildModifiedAndDependent) { if (lastCompilationPass != null && factory.Setting == BuildDetection.BuildModifiedAndDependent) {
lock (cachedBuildDependencies) { lock (cachedBuildDependencies) {
var dependencies = buildOptions != null ? cachedBuildDependencies[buildOptions] : cachedBuildDependenciesForNullOptions; var dependencies = options != null ? cachedBuildDependencies[options] : cachedBuildDependenciesForNullOptions;
if (dependencies.OfType<Wrapper>().Any(w=>w.WasRecompiledAfter(lastCompilationPass))) { if (dependencies.OfType<Wrapper>().Any(w=>w.WasRecompiledAfter(lastCompilationPass))) {
lastCompilationPass = null; lastCompilationPass = null;
} }
@ -265,56 +235,17 @@ namespace ICSharpCode.SharpDevelop.Project
StringParser.Parse("${res:MainWindow.CompilerMessages.SkipProjectNoChanges}", StringParser.Parse("${res:MainWindow.CompilerMessages.SkipProjectNoChanges}",
new StringTagPair("Name", p.Name)) new StringTagPair("Name", p.Name))
); );
feedbackSink.Done(true); return true;
} else { } else {
lastCompilationPass = factory.CurrentPass; lastCompilationPass = factory.CurrentPass;
wrapped.StartBuild(buildOptions, new BuildFeedbackSink(p, feedbackSink, factory.CurrentPass)); var success = await wrapped.BuildAsync(options, feedbackSink, progressMonitor);
} if (success) {
} lock (unmodifiedProjects) {
} unmodifiedProjects[p] = factory.CurrentPass;
}
/// <summary>
/// Wraps a build feedback sink and marks a project as requiring recompilation when
/// compilation was not successful.
/// </summary>
sealed class BuildFeedbackSink : IBuildFeedbackSink
{
IProject project;
IBuildFeedbackSink sink;
CompilationPass currentPass;
public BuildFeedbackSink(IProject p, IBuildFeedbackSink sink, CompilationPass currentPass)
{
Debug.Assert(p != null);
Debug.Assert(sink != null);
Debug.Assert(currentPass != null);
this.project = p;
this.sink = sink;
this.currentPass = currentPass;
}
public Gui.IProgressMonitor ProgressMonitor {
get { return sink.ProgressMonitor; }
}
public void ReportError(BuildError error)
{
sink.ReportError(error);
}
public void ReportMessage(string message)
{
sink.ReportMessage(message);
}
public void Done(bool success)
{
if (success) {
lock (unmodifiedProjects) {
unmodifiedProjects[project] = currentPass;
} }
return success;
} }
sink.Done(success);
} }
} }
} }

117
src/Main/SharpDevelop/Project/Build/BuildService.cs

@ -0,0 +1,117 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Project
{
sealed class BuildService : IBuildService
{
readonly BuildModifiedProjectsOnlyService buildModifiedProjectsOnly;
public BuildService()
{
this.buildModifiedProjectsOnly = new BuildModifiedProjectsOnlyService(this);
}
public event EventHandler<BuildEventArgs> BuildStarted;
public event EventHandler<BuildEventArgs> BuildFinished;
CancellationTokenSource guiBuildCancellation;
public bool IsBuilding {
get { return guiBuildCancellation != null; }
}
public void CancelBuild()
{
if (guiBuildCancellation != null)
guiBuildCancellation.Cancel();
}
public async Task<BuildResults> BuildAsync(IEnumerable<IProject> projects, BuildOptions options)
{
if (projects == null)
throw new ArgumentNullException("projects");
if (options == null)
throw new ArgumentNullException("options");
SD.MainThread.VerifyAccess();
if (guiBuildCancellation != null) {
BuildResults results = new BuildResults();
SD.StatusBar.SetMessage(ResourceService.GetString("MainWindow.CompilerMessages.MSBuildAlreadyRunning"));
BuildError error = new BuildError(null, ResourceService.GetString("MainWindow.CompilerMessages.MSBuildAlreadyRunning"));
results.Add(error);
TaskService.Add(new SDTask(error));
results.Result = BuildResultCode.MSBuildAlreadyRunning;
return results;
}
var projectsList = projects.ToList();
guiBuildCancellation = new CancellationTokenSource();
using (var progressMonitor = SD.StatusBar.CreateProgressMonitor(guiBuildCancellation.Token)) {
if (BuildStarted != null)
BuildStarted(this, new BuildEventArgs(projectsList, options));
var trackedFeature = SD.AnalyticsMonitor.TrackFeature("ICSharpCode.SharpDevelop.Project.BuildEngine.Build");
SD.StatusBar.SetMessage(StringParser.Parse("${res:MainWindow.CompilerMessages.BuildVerb}..."));
IBuildable buildable;
if (projectsList.Count == 1)
buildable = projectsList[0];
else
buildable = new MultipleProjectBuildable(projectsList);
buildable = buildModifiedProjectsOnly.WrapBuildable(buildable, options.BuildDetection);
var sink = new UIBuildFeedbackSink(TaskService.BuildMessageViewCategory, SD.StatusBar);
var results = await BuildInBackgroundAsync(buildable, options, sink, progressMonitor);
string message;
if (results.Result == BuildResultCode.Cancelled) {
message = "${res:MainWindow.CompilerMessages.BuildCancelled}";
} else {
if (results.Result == BuildResultCode.Success)
message = "${res:MainWindow.CompilerMessages.BuildFinished}";
else
message = "${res:MainWindow.CompilerMessages.BuildFailed}";
if (results.ErrorCount > 0)
message += " " + results.ErrorCount + " error(s)";
if (results.WarningCount > 0)
message += " " + results.WarningCount + " warning(s)";
}
SD.StatusBar.SetMessage(message);
trackedFeature.EndTracking();
if (BuildFinished != null)
BuildFinished(this, new BuildEventArgs(projectsList, options, results));
return results;
}
}
public Task<BuildResults> BuildAsync(IProject project, BuildOptions options)
{
if (project != null)
return BuildAsync(new[] { project }, options);
else
return Task.FromResult(new BuildResults { Result = BuildResultCode.Error });
}
public Task<BuildResults> BuildAsync(Solution solution, BuildOptions options)
{
if (solution != null)
return BuildAsync(solution.Projects, options);
else
return Task.FromResult(new BuildResults { Result = BuildResultCode.Error });
}
public Task<BuildResults> BuildInBackgroundAsync(IBuildable buildable, BuildOptions options, IBuildFeedbackSink buildFeedbackSink, IProgressMonitor progressMonitor)
{
return BuildEngine.BuildAsync(buildable, options, buildFeedbackSink, progressMonitor);
}
}
}

46
src/Main/SharpDevelop/Project/Build/UIBuildFeedbackSink.cs

@ -0,0 +1,46 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// This error message sink is used for GUI builds.
/// </summary>
sealed class UIBuildFeedbackSink : IBuildFeedbackSink
{
MessageViewCategory messageView;
IStatusBarService statusBarService;
public UIBuildFeedbackSink(MessageViewCategory messageView, IStatusBarService statusBarService)
{
Debug.Assert(messageView != null);
Debug.Assert(statusBarService != null);
this.messageView = messageView;
this.statusBarService = statusBarService;
}
public void ReportError(BuildError error)
{
WorkbenchSingleton.SafeThreadAsyncCall(
delegate {
TaskService.Add(new SDTask(error));
});
}
public void ReportMessage(string message)
{
messageView.AppendLine(message);
}
}
}

6
src/Main/SharpDevelop/SharpDevelop.csproj

@ -93,6 +93,10 @@
<Compile Include="Parser\AssemblyParserService.cs" /> <Compile Include="Parser\AssemblyParserService.cs" />
<Compile Include="Parser\LoadSolutionProjects.cs" /> <Compile Include="Parser\LoadSolutionProjects.cs" />
<Compile Include="Parser\SharpDevelopSolutionSnapshot.cs" /> <Compile Include="Parser\SharpDevelopSolutionSnapshot.cs" />
<Compile Include="Project\Build\BuildEngine.cs" />
<Compile Include="Project\Build\BuildModifiedProjectsOnlyService.cs" />
<Compile Include="Project\Build\BuildService.cs" />
<Compile Include="Project\Build\UIBuildFeedbackSink.cs" />
<Compile Include="Services\ClipboardWrapper.cs" /> <Compile Include="Services\ClipboardWrapper.cs" />
<Compile Include="Services\DispatcherMessageLoop.cs" /> <Compile Include="Services\DispatcherMessageLoop.cs" />
<Compile Include="Startup\App.xaml.cs" /> <Compile Include="Startup\App.xaml.cs" />
@ -216,6 +220,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Dom" /> <Folder Include="Dom" />
<Folder Include="Project" />
<Folder Include="Project\Build" />
<Folder Include="Services" /> <Folder Include="Services" />
<Folder Include="WinForms" /> <Folder Include="WinForms" />
<Folder Include="OptionPanels" /> <Folder Include="OptionPanels" />

Loading…
Cancel
Save